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

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

fixed #2691: Exception when trying to search for "http://"

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