source: josm/trunk/src/org/openstreetmap/josm/actions/search/SearchAction.java@ 2070

Last change on this file since 2070 was 2070, checked in by Gubaer, 15 years ago

new: rewrite of CombineWay action
new: conflict resolution dialog for CombineWay, including conflicts for different relation memberships
cleanup: cleanup in OsmReader, reduces memory footprint and reduces parsing time
cleanup: made most of the public fields in OsmPrimitive @deprecated, added accessors and changed the code
cleanup: replaced usages of @deprecated constructors for ExtendedDialog
fixed #3208: Combine ways brokes relation order

WARNING: this changeset touches a lot of code all over the code base. "latest" might become slightly unstable in the next days. Also experience incompatibility issues with plugins in the next few days.

  • Property svn:eol-style set to native
File size: 11.2 KB
Line 
1// License: GPL. Copyright 2007 by Immanuel Scholz and others
2package org.openstreetmap.josm.actions.search;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.awt.Font;
7import java.awt.GridBagLayout;
8import java.awt.event.ActionEvent;
9import java.awt.event.KeyEvent;
10import java.util.Collection;
11import java.util.LinkedList;
12
13import javax.swing.ButtonGroup;
14import javax.swing.JCheckBox;
15import javax.swing.JLabel;
16import javax.swing.JOptionPane;
17import javax.swing.JPanel;
18import javax.swing.JRadioButton;
19import javax.swing.JTextField;
20
21import org.openstreetmap.josm.Main;
22import org.openstreetmap.josm.actions.JosmAction;
23import org.openstreetmap.josm.data.osm.OsmPrimitive;
24import org.openstreetmap.josm.gui.ExtendedDialog;
25import org.openstreetmap.josm.tools.GBC;
26import org.openstreetmap.josm.tools.Shortcut;
27
28public class SearchAction extends JosmAction{
29
30 public static final int SEARCH_HISTORY_SIZE = 10;
31
32 public static enum SearchMode {
33 replace, add, remove
34 }
35
36 public static final LinkedList<SearchSetting> searchHistory = new LinkedList<SearchSetting>();
37
38 private static SearchSetting lastSearch = null;
39
40 public SearchAction() {
41 super(tr("Search..."), "dialogs/search", tr("Search for objects."),
42 Shortcut.registerShortcut("system:find", tr("Search..."), KeyEvent.VK_F, Shortcut.GROUP_HOTKEY), true);
43 }
44
45 public void actionPerformed(ActionEvent e) {
46 if (!isEnabled())
47 return;
48 if (Main.map == null) {
49 JOptionPane.showMessageDialog(
50 Main.parent,
51 tr("Can't search because there is no loaded data."),
52 tr("Warning"),
53 JOptionPane.WARNING_MESSAGE
54 );
55 return;
56 }
57 SearchSetting s = lastSearch;
58 if (s == null) {
59 s = new SearchSetting("", false, false, SearchMode.replace);
60 }
61 showSearchDialog(s);
62 }
63
64 public void showSearchDialog(SearchSetting initialValues) {
65 JLabel label = new JLabel(tr("Please enter a search string."));
66 final JTextField input = new JTextField(initialValues.text);
67 input.selectAll();
68 input.requestFocusInWindow();
69 JRadioButton replace = new JRadioButton(tr("replace selection"), initialValues.mode == SearchMode.replace);
70 JRadioButton add = new JRadioButton(tr("add to selection"), initialValues.mode == SearchMode.add);
71 JRadioButton remove = new JRadioButton(tr("remove from selection"), initialValues.mode == SearchMode.remove);
72 ButtonGroup bg = new ButtonGroup();
73 bg.add(replace);
74 bg.add(add);
75 bg.add(remove);
76
77 JCheckBox caseSensitive = new JCheckBox(tr("case sensitive"), initialValues.caseSensitive);
78 JCheckBox regexSearch = new JCheckBox(tr("regular expression"), initialValues.regexSearch);
79
80 JPanel left = new JPanel(new GridBagLayout());
81 left.add(label, GBC.eop());
82 left.add(input, GBC.eop().fill(GBC.HORIZONTAL));
83 left.add(replace, GBC.eol());
84 left.add(add, GBC.eol());
85 left.add(remove, GBC.eop());
86 left.add(caseSensitive, GBC.eol());
87 left.add(regexSearch, GBC.eol());
88
89 JPanel right = new JPanel();
90 JLabel description =
91 new JLabel("<html><ul>"
92 + "<li>"+tr("<b>Baker Street</b> - 'Baker' and 'Street' in any key or name.")+"</li>"
93 + "<li>"+tr("<b>\"Baker Street\"</b> - 'Baker Street' in any key or name.")+"</li>"
94 + "<li>"+tr("<b>name:Bak</b> - 'Bak' anywhere in the name.")+"</li>"
95 + "<li>"+tr("<b>type=route</b> - key 'type' with value exactly 'route'.") + "</li>"
96 + "<li>"+tr("<b>type=*</b> - key 'type' with any value. Try also <b>*=value</b>, <b>type=</b>, <b>*=*</b>, <b>*=</b>") + "</li>"
97 + "<li>"+tr("<b>-name:Bak</b> - not 'Bak' in the name.")+"</li>"
98 + "<li>"+tr("<b>foot:</b> - key=foot set to any value.")+"</li>"
99 + "<li>"+tr("<u>Special targets:</u>")+"</li>"
100 + "<li>"+tr("<b>type:</b> - type of the object (<b>node</b>, <b>way</b>, <b>relation</b>)")+"</li>"
101 + "<li>"+tr("<b>user:</b>... - all objects changed by user")+"</li>"
102 + "<li>"+tr("<b>id:</b>... - object with given ID (0 for new objects)")+"</li>"
103 + "<li>"+tr("<b>nodes:</b>... - object with given number of nodes")+"</li>"
104 + "<li>"+tr("<b>modified</b> - all changed objects")+"</li>"
105 + "<li>"+tr("<b>selected</b> - all selected objects")+"</li>"
106 + "<li>"+tr("<b>incomplete</b> - all incomplete objects")+"</li>"
107 + "<li>"+tr("<b>untagged</b> - all untagged objects")+"</li>"
108 + "<li>"+tr("<b>child <i>expr</i></b> - all children of objects matching the expression")+"</li>"
109 + "<li>"+tr("<b>parent <i>expr</i></b> - all parents of objects matching the expression")+"</li>"
110 + "<li>"+tr("Use <b>|</b> or <b>OR</b> to combine with logical or")+"</li>"
111 + "<li>"+tr("Use <b>\"</b> to quote operators (e.g. if key contains :)")+"</li>"
112 + "<li>"+tr("Use <b>(</b> and <b>)</b> to group expressions")+"</li>"
113 + "</ul></html>");
114 description.setFont(description.getFont().deriveFont(Font.PLAIN));
115 right.add(description);
116
117 final JPanel p = new JPanel();
118 p.add(left);
119 p.add(right);
120 ExtendedDialog dialog = new ExtendedDialog(
121 Main.parent,
122 tr("Search"),
123 new String[] {tr("Start Search"), tr("Cancel")}
124 );
125 dialog.setButtonIcons(new String[] {"dialogs/search.png", "cancel.png"});
126 dialog.setContent(p);
127 dialog.showDialog();
128 int result = dialog.getValue();
129
130 if(result != 1) return;
131
132 // User pressed OK - let's perform the search
133 SearchMode mode = replace.isSelected() ? SearchAction.SearchMode.replace
134 : (add.isSelected() ? SearchAction.SearchMode.add : SearchAction.SearchMode.remove);
135 SearchSetting setting = new SearchSetting(input.getText(), caseSensitive.isSelected(), regexSearch.isSelected(), mode);
136 searchWithHistory(setting);
137 }
138
139 /**
140 * Adds the search specified by the settings in <code>s</code> to the
141 * search history and performs the search.
142 *
143 * @param s
144 */
145 public static void searchWithHistory(SearchSetting s) {
146 if(searchHistory.isEmpty() || !s.equals(searchHistory.getFirst())) {
147 searchHistory.addFirst(s);
148 }
149 while (searchHistory.size() > SEARCH_HISTORY_SIZE) {
150 searchHistory.removeLast();
151 }
152 lastSearch = s;
153 search(s.text, s.mode, s.caseSensitive, s.regexSearch);
154 }
155
156 public static void searchWithoutHistory(SearchSetting s) {
157 lastSearch = s;
158 search(s.text, s.mode, s.caseSensitive, s.regexSearch);
159 }
160
161 public static void search(String search, SearchMode mode, boolean caseSensitive, boolean regexSearch) {
162 // FIXME: This is confusing. The GUI says nothing about loading primitives from an URL. We'd like to *search*
163 // for URLs in the current data set.
164 // Disabling until a better solution is in place
165 //
166 // if (search.startsWith("http://") || search.startsWith("ftp://") || search.startsWith("https://")
167 // || search.startsWith("file:/")) {
168 // SelectionWebsiteLoader loader = new SelectionWebsiteLoader(search, mode);
169 // if (loader.url != null && loader.url.getHost() != null) {
170 // Main.worker.execute(loader);
171 // return;
172 // }
173 // }
174 try {
175 Collection<OsmPrimitive> sel = Main.main.getCurrentDataSet().getSelected();
176 SearchCompiler.Match matcher = SearchCompiler.compile(search, caseSensitive, regexSearch);
177 int foundMatches = 0;
178 for (OsmPrimitive osm : Main.main.getCurrentDataSet().allNonDeletedCompletePrimitives()) {
179 if (mode == SearchMode.replace) {
180 if (matcher.match(osm)) {
181 sel.add(osm);
182 ++foundMatches;
183 } else {
184 sel.remove(osm);
185 }
186 } else if (mode == SearchMode.add && !osm.isSelected() && matcher.match(osm)) {
187 sel.add(osm);
188 ++foundMatches;
189 } else if (mode == SearchMode.remove && osm.isSelected() && matcher.match(osm)) {
190 sel.remove(osm);
191 ++foundMatches;
192 }
193 }
194 Main.main.getCurrentDataSet().setSelected(sel);
195 if (foundMatches == 0) {
196 String msg = null;
197 if (mode == SearchMode.replace) {
198 msg = tr("No match found for ''{0}''", search);
199 } else if (mode == SearchMode.add) {
200 msg = tr("Nothing added to selection by searching for ''{0}''", search);
201 } else if (mode == SearchMode.remove) {
202 msg = tr("Nothing removed from selection by searching for ''{0}''", search);
203 }
204 Main.map.statusLine.setHelpText(msg);
205 JOptionPane.showMessageDialog(
206 Main.parent,
207 msg,
208 tr("Warning"),
209 JOptionPane.WARNING_MESSAGE
210 );
211 } else {
212 Main.map.statusLine.setHelpText(tr("Found {0} matches", foundMatches));
213 }
214 } catch (SearchCompiler.ParseError e) {
215 JOptionPane.showMessageDialog(
216 Main.parent,
217 e.getMessage(),
218 tr("Error"),
219 JOptionPane.ERROR_MESSAGE
220
221 );
222 }
223 }
224
225 public static class SearchSetting {
226 String text;
227 SearchMode mode;
228 boolean caseSensitive;
229 boolean regexSearch;
230
231 public SearchSetting(String text, boolean caseSensitive, boolean regexSearch, SearchMode mode) {
232 super();
233 this.caseSensitive = caseSensitive;
234 this.regexSearch = regexSearch;
235 this.mode = mode;
236 this.text = text;
237 }
238
239 @Override
240 public String toString() {
241 String cs = caseSensitive ? tr("CS") : tr("CI");
242 String rx = regexSearch ? (", " + tr("RX")) : "";
243 return "\"" + text + "\" (" + cs + rx + ", " + mode + ")";
244 }
245
246 @Override
247 public boolean equals(Object other) {
248 if(!(other instanceof SearchSetting))
249 return false;
250 SearchSetting o = (SearchSetting) other;
251 return (o.caseSensitive == this.caseSensitive
252 && o.regexSearch == this.regexSearch
253 && o.mode.equals(this.mode)
254 && o.text.equals(this.text));
255 }
256 }
257
258 /**
259 * Refreshes the enabled state
260 *
261 */
262 @Override
263 protected void updateEnabledState() {
264 setEnabled(getEditLayer() != null);
265 }
266}
Note: See TracBrowser for help on using the repository browser.