source: josm/trunk/src/org/openstreetmap/josm/gui/dialogs/SelectionListDialog.java@ 7120

Last change on this file since 7120 was 7120, checked in by Don-vip, 10 years ago

code refactoring/cleanup

  • Property svn:eol-style set to native
File size: 28.8 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.dialogs;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5import static org.openstreetmap.josm.tools.I18n.trn;
6
7import java.awt.Component;
8import java.awt.Rectangle;
9import java.awt.event.ActionEvent;
10import java.awt.event.ActionListener;
11import java.awt.event.KeyEvent;
12import java.awt.event.MouseEvent;
13import java.util.ArrayList;
14import java.util.Arrays;
15import java.util.Collection;
16import java.util.Collections;
17import java.util.HashSet;
18import java.util.Iterator;
19import java.util.LinkedList;
20import java.util.List;
21import java.util.Set;
22
23import javax.swing.AbstractAction;
24import javax.swing.AbstractListModel;
25import javax.swing.DefaultListSelectionModel;
26import javax.swing.JList;
27import javax.swing.JMenuItem;
28import javax.swing.JPopupMenu;
29import javax.swing.ListSelectionModel;
30import javax.swing.event.ListDataEvent;
31import javax.swing.event.ListDataListener;
32import javax.swing.event.ListSelectionEvent;
33import javax.swing.event.ListSelectionListener;
34
35import org.openstreetmap.josm.Main;
36import org.openstreetmap.josm.actions.AutoScaleAction;
37import org.openstreetmap.josm.actions.relation.DownloadSelectedIncompleteMembersAction;
38import org.openstreetmap.josm.actions.relation.EditRelationAction;
39import org.openstreetmap.josm.actions.relation.SelectInRelationListAction;
40import org.openstreetmap.josm.actions.search.SearchAction.SearchSetting;
41import org.openstreetmap.josm.data.SelectionChangedListener;
42import org.openstreetmap.josm.data.osm.Node;
43import org.openstreetmap.josm.data.osm.OsmPrimitive;
44import org.openstreetmap.josm.data.osm.OsmPrimitiveComparator;
45import org.openstreetmap.josm.data.osm.Relation;
46import org.openstreetmap.josm.data.osm.Way;
47import org.openstreetmap.josm.data.osm.event.AbstractDatasetChangedEvent;
48import org.openstreetmap.josm.data.osm.event.DataChangedEvent;
49import org.openstreetmap.josm.data.osm.event.DataSetListener;
50import org.openstreetmap.josm.data.osm.event.DatasetEventManager;
51import org.openstreetmap.josm.data.osm.event.DatasetEventManager.FireMode;
52import org.openstreetmap.josm.data.osm.event.NodeMovedEvent;
53import org.openstreetmap.josm.data.osm.event.PrimitivesAddedEvent;
54import org.openstreetmap.josm.data.osm.event.PrimitivesRemovedEvent;
55import org.openstreetmap.josm.data.osm.event.RelationMembersChangedEvent;
56import org.openstreetmap.josm.data.osm.event.SelectionEventManager;
57import org.openstreetmap.josm.data.osm.event.TagsChangedEvent;
58import org.openstreetmap.josm.data.osm.event.WayNodesChangedEvent;
59import org.openstreetmap.josm.data.osm.visitor.BoundingXYVisitor;
60import org.openstreetmap.josm.gui.DefaultNameFormatter;
61import org.openstreetmap.josm.gui.MapView;
62import org.openstreetmap.josm.gui.MapView.EditLayerChangeListener;
63import org.openstreetmap.josm.gui.OsmPrimitivRenderer;
64import org.openstreetmap.josm.gui.PopupMenuHandler;
65import org.openstreetmap.josm.gui.SideButton;
66import org.openstreetmap.josm.gui.layer.OsmDataLayer;
67import org.openstreetmap.josm.gui.util.GuiHelper;
68import org.openstreetmap.josm.gui.util.HighlightHelper;
69import org.openstreetmap.josm.gui.widgets.ListPopupMenu;
70import org.openstreetmap.josm.gui.widgets.PopupMenuLauncher;
71import org.openstreetmap.josm.tools.ImageProvider;
72import org.openstreetmap.josm.tools.InputMapUtils;
73import org.openstreetmap.josm.tools.Shortcut;
74import org.openstreetmap.josm.tools.SubclassFilteredCollection;
75import org.openstreetmap.josm.tools.Utils;
76
77/**
78 * A small tool dialog for displaying the current selection.
79 * @since 8
80 */
81public class SelectionListDialog extends ToggleDialog {
82 private JList<OsmPrimitive> lstPrimitives;
83 private DefaultListSelectionModel selectionModel = new DefaultListSelectionModel();
84 private SelectionListModel model = new SelectionListModel(selectionModel);
85
86 private SelectAction actSelect = new SelectAction();
87 private SearchAction actSearch = new SearchAction();
88 private ZoomToJOSMSelectionAction actZoomToJOSMSelection = new ZoomToJOSMSelectionAction();
89 private ZoomToListSelection actZoomToListSelection = new ZoomToListSelection();
90 private SelectInRelationListAction actSetRelationSelection = new SelectInRelationListAction();
91 private EditRelationAction actEditRelationSelection = new EditRelationAction();
92 private DownloadSelectedIncompleteMembersAction actDownloadSelectedIncompleteMembers = new DownloadSelectedIncompleteMembersAction();
93
94 /** the popup menu and its handler */
95 private final ListPopupMenu popupMenu;
96 private final PopupMenuHandler popupMenuHandler;
97
98 /**
99 * Builds the content panel for this dialog
100 */
101 protected void buildContentPanel() {
102 lstPrimitives = new JList<>(model);
103 lstPrimitives.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
104 lstPrimitives.setSelectionModel(selectionModel);
105 lstPrimitives.setCellRenderer(new OsmPrimitivRenderer());
106 lstPrimitives.setTransferHandler(null); // Fix #6290. Drag & Drop is not supported anyway and Copy/Paste is better propagated to main window
107
108 // the select action
109 final SideButton selectButton = new SideButton(actSelect);
110 lstPrimitives.getSelectionModel().addListSelectionListener(actSelect);
111 selectButton.createArrow(new ActionListener() {
112 @Override
113 public void actionPerformed(ActionEvent e) {
114 SelectionHistoryPopup.launch(selectButton, model.getSelectionHistory());
115 }
116 });
117
118 // the search button
119 final SideButton searchButton = new SideButton(actSearch);
120 searchButton.createArrow(new ActionListener() {
121 @Override
122 public void actionPerformed(ActionEvent e) {
123 SearchPopupMenu.launch(searchButton);
124 }
125 });
126
127 createLayout(lstPrimitives, true, Arrays.asList(new SideButton[] {
128 selectButton, searchButton
129 }));
130 }
131
132 /**
133 * Constructs a new {@code SelectionListDialog}.
134 */
135 public SelectionListDialog() {
136 super(tr("Selection"), "selectionlist", tr("Open a selection list window."),
137 Shortcut.registerShortcut("subwindow:selection", tr("Toggle: {0}",
138 tr("Current Selection")), KeyEvent.VK_T, Shortcut.ALT_SHIFT),
139 150, // default height
140 true // default is "show dialog"
141 );
142
143 buildContentPanel();
144 model.addListDataListener(new TitleUpdater());
145 model.addListDataListener(actZoomToJOSMSelection);
146
147 popupMenu = new ListPopupMenu(lstPrimitives);
148 popupMenuHandler = setupPopupMenuHandler();
149
150 lstPrimitives.addListSelectionListener(new ListSelectionListener() {
151 @Override
152 public void valueChanged(ListSelectionEvent e) {
153 actZoomToListSelection.valueChanged(e);
154 popupMenuHandler.setPrimitives(model.getSelected());
155 }
156 });
157
158 lstPrimitives.addMouseListener(new MouseEventHandler());
159
160 InputMapUtils.addEnterAction(lstPrimitives, actZoomToListSelection);
161 }
162
163 @Override
164 public void showNotify() {
165 MapView.addEditLayerChangeListener(model);
166 SelectionEventManager.getInstance().addSelectionListener(model, FireMode.IN_EDT_CONSOLIDATED);
167 DatasetEventManager.getInstance().addDatasetListener(model, FireMode.IN_EDT);
168 MapView.addEditLayerChangeListener(actSearch);
169 // editLayerChanged also gets the selection history of the level
170 OsmDataLayer editLayer = Main.main.getEditLayer();
171 model.editLayerChanged(null, editLayer);
172 if (editLayer != null) {
173 model.setJOSMSelection(editLayer.data.getAllSelected());
174 }
175 actSearch.updateEnabledState();
176 }
177
178 @Override
179 public void hideNotify() {
180 MapView.removeEditLayerChangeListener(actSearch);
181 MapView.removeEditLayerChangeListener(model);
182 SelectionEventManager.getInstance().removeSelectionListener(model);
183 DatasetEventManager.getInstance().removeDatasetListener(model);
184 }
185
186 /**
187 * Responds to double clicks on the list of selected objects and launches the popup menu
188 */
189 class MouseEventHandler extends PopupMenuLauncher {
190 private final HighlightHelper helper = new HighlightHelper();
191 private boolean highlightEnabled = Main.pref.getBoolean("draw.target-highlight", true);
192 public MouseEventHandler() {
193 super(popupMenu);
194 }
195
196 @Override
197 public void mouseClicked(MouseEvent e) {
198 int idx = lstPrimitives.locationToIndex(e.getPoint());
199 if (idx < 0) return;
200 if (isDoubleClick(e)) {
201 OsmDataLayer layer = Main.main.getEditLayer();
202 if (layer == null) return;
203 layer.data.setSelected(Collections.singleton(model.getElementAt(idx)));
204 } else if (highlightEnabled && Main.isDisplayingMapView()) {
205 if (helper.highlightOnly(model.getElementAt(idx))) {
206 Main.map.mapView.repaint();
207 }
208 }
209 }
210
211 @Override
212 public void mouseExited(MouseEvent me) {
213 if (highlightEnabled) helper.clear();
214 super.mouseExited(me);
215 }
216 }
217
218 private PopupMenuHandler setupPopupMenuHandler() {
219 PopupMenuHandler handler = new PopupMenuHandler(popupMenu);
220 handler.addAction(actZoomToJOSMSelection);
221 handler.addAction(actZoomToListSelection);
222 handler.addSeparator();
223 handler.addAction(actSetRelationSelection);
224 handler.addAction(actEditRelationSelection);
225 handler.addSeparator();
226 handler.addAction(actDownloadSelectedIncompleteMembers);
227 return handler;
228 }
229
230 /**
231 * Replies the popup menu handler.
232 * @return The popup menu handler
233 */
234 public PopupMenuHandler getPopupMenuHandler() {
235 return popupMenuHandler;
236 }
237
238 /**
239 * Replies the selected OSM primitives.
240 * @return The selected OSM primitives
241 */
242 public Collection<OsmPrimitive> getSelectedPrimitives() {
243 return model.getSelected();
244 }
245
246 /**
247 * Updates the dialog title with a summary of the current JOSM selection
248 */
249 class TitleUpdater implements ListDataListener {
250 protected void updateTitle() {
251 setTitle(model.getJOSMSelectionSummary());
252 }
253
254 @Override
255 public void contentsChanged(ListDataEvent e) {
256 updateTitle();
257 }
258
259 @Override
260 public void intervalAdded(ListDataEvent e) {
261 updateTitle();
262 }
263
264 @Override
265 public void intervalRemoved(ListDataEvent e) {
266 updateTitle();
267 }
268 }
269
270 /**
271 * Launches the search dialog
272 */
273 static class SearchAction extends AbstractAction implements EditLayerChangeListener {
274 public SearchAction() {
275 putValue(NAME, tr("Search"));
276 putValue(SHORT_DESCRIPTION, tr("Search for objects"));
277 putValue(SMALL_ICON, ImageProvider.get("dialogs","search"));
278 updateEnabledState();
279 }
280
281 @Override
282 public void actionPerformed(ActionEvent e) {
283 if (!isEnabled()) return;
284 org.openstreetmap.josm.actions.search.SearchAction.search();
285 }
286
287 public void updateEnabledState() {
288 setEnabled(Main.main != null && Main.main.hasEditLayer());
289 }
290
291 @Override
292 public void editLayerChanged(OsmDataLayer oldLayer, OsmDataLayer newLayer) {
293 updateEnabledState();
294 }
295 }
296
297 /**
298 * Sets the current JOSM selection to the OSM primitives selected in the list
299 * of this dialog
300 */
301 class SelectAction extends AbstractAction implements ListSelectionListener {
302 public SelectAction() {
303 putValue(NAME, tr("Select"));
304 putValue(SHORT_DESCRIPTION, tr("Set the selected elements on the map to the selected items in the list above."));
305 putValue(SMALL_ICON, ImageProvider.get("dialogs","select"));
306 updateEnabledState();
307 }
308
309 @Override
310 public void actionPerformed(ActionEvent e) {
311 Collection<OsmPrimitive> sel = model.getSelected();
312 if (sel.isEmpty())return;
313 OsmDataLayer editLayer = Main.main.getEditLayer();
314 if (editLayer == null) return;
315 editLayer.data.setSelected(sel);
316 }
317
318 public void updateEnabledState() {
319 setEnabled(!model.getSelected().isEmpty());
320 }
321
322 @Override
323 public void valueChanged(ListSelectionEvent e) {
324 updateEnabledState();
325 }
326 }
327
328 /**
329 * The action for zooming to the primitives in the current JOSM selection
330 *
331 */
332 class ZoomToJOSMSelectionAction extends AbstractAction implements ListDataListener {
333
334 public ZoomToJOSMSelectionAction() {
335 putValue(NAME,tr("Zoom to selection"));
336 putValue(SHORT_DESCRIPTION, tr("Zoom to selection"));
337 putValue(SMALL_ICON, ImageProvider.get("dialogs/autoscale", "selection"));
338 updateEnabledState();
339 }
340
341 @Override
342 public void actionPerformed(ActionEvent e) {
343 AutoScaleAction.autoScale("selection");
344 }
345
346 public void updateEnabledState() {
347 setEnabled(model.getSize() > 0);
348 }
349
350 @Override
351 public void contentsChanged(ListDataEvent e) {
352 updateEnabledState();
353 }
354
355 @Override
356 public void intervalAdded(ListDataEvent e) {
357 updateEnabledState();
358 }
359
360 @Override
361 public void intervalRemoved(ListDataEvent e) {
362 updateEnabledState();
363 }
364 }
365
366 /**
367 * The action for zooming to the primitives which are currently selected in
368 * the list displaying the JOSM selection
369 *
370 */
371 class ZoomToListSelection extends AbstractAction implements ListSelectionListener{
372 public ZoomToListSelection() {
373 putValue(NAME, tr("Zoom to selected element(s)"));
374 putValue(SHORT_DESCRIPTION, tr("Zoom to selected element(s)"));
375 putValue(SMALL_ICON, ImageProvider.get("dialogs/autoscale", "selection"));
376 updateEnabledState();
377 }
378
379 @Override
380 public void actionPerformed(ActionEvent e) {
381 BoundingXYVisitor box = new BoundingXYVisitor();
382 Collection<OsmPrimitive> sel = model.getSelected();
383 if (sel.isEmpty()) return;
384 box.computeBoundingBox(sel);
385 if (box.getBounds() == null)
386 return;
387 box.enlargeBoundingBox();
388 Main.map.mapView.recalculateCenterScale(box);
389 }
390
391 public void updateEnabledState() {
392 setEnabled(!model.getSelected().isEmpty());
393 }
394
395 @Override
396 public void valueChanged(ListSelectionEvent e) {
397 updateEnabledState();
398 }
399 }
400
401 /**
402 * The list model for the list of OSM primitives in the current JOSM selection.
403 *
404 * The model also maintains a history of the last {@link SelectionListModel#SELECTION_HISTORY_SIZE}
405 * JOSM selection.
406 *
407 */
408 private static class SelectionListModel extends AbstractListModel<OsmPrimitive> implements EditLayerChangeListener, SelectionChangedListener, DataSetListener{
409
410 private static final int SELECTION_HISTORY_SIZE = 10;
411
412 // Variable to store history from currentDataSet()
413 private LinkedList<Collection<? extends OsmPrimitive>> history;
414 private final List<OsmPrimitive> selection = new ArrayList<>();
415 private DefaultListSelectionModel selectionModel;
416
417 /**
418 * Constructor
419 * @param selectionModel the selection model used in the list
420 */
421 public SelectionListModel(DefaultListSelectionModel selectionModel) {
422 this.selectionModel = selectionModel;
423 }
424
425 /**
426 * Replies a summary of the current JOSM selection
427 *
428 * @return a summary of the current JOSM selection
429 */
430 public String getJOSMSelectionSummary() {
431 if (selection.isEmpty()) return tr("Selection");
432 int numNodes = 0;
433 int numWays = 0;
434 int numRelations = 0;
435 for (OsmPrimitive p: selection) {
436 switch(p.getType()) {
437 case NODE: numNodes++; break;
438 case WAY: numWays++; break;
439 case RELATION: numRelations++; break;
440 }
441 }
442 return tr("Sel.: Rel.:{0} / Ways:{1} / Nodes:{2}", numRelations, numWays, numNodes);
443 }
444
445 /**
446 * Remembers a JOSM selection the history of JOSM selections
447 *
448 * @param selection the JOSM selection. Ignored if null or empty.
449 */
450 public void remember(Collection<? extends OsmPrimitive> selection) {
451 if (selection == null)return;
452 if (selection.isEmpty())return;
453 if (history == null) return;
454 if (history.isEmpty()) {
455 history.add(selection);
456 return;
457 }
458 if (history.getFirst().equals(selection)) return;
459 history.addFirst(selection);
460 for(int i = 1; i < history.size(); ++i) {
461 if(history.get(i).equals(selection)) {
462 history.remove(i);
463 break;
464 }
465 }
466 int maxsize = Main.pref.getInteger("select.history-size", SELECTION_HISTORY_SIZE);
467 while (history.size() > maxsize) {
468 history.removeLast();
469 }
470 }
471
472 /**
473 * Replies the history of JOSM selections
474 *
475 * @return history of JOSM selections
476 */
477 public List<Collection<? extends OsmPrimitive>> getSelectionHistory() {
478 return history;
479 }
480
481 @Override
482 public OsmPrimitive getElementAt(int index) {
483 return selection.get(index);
484 }
485
486 @Override
487 public int getSize() {
488 return selection.size();
489 }
490
491 /**
492 * Replies the collection of OSM primitives currently selected in the view
493 * of this model
494 *
495 * @return choosen elements in the view
496 */
497 public Collection<OsmPrimitive> getSelected() {
498 Set<OsmPrimitive> sel = new HashSet<>();
499 for(int i=0; i< getSize();i++) {
500 if (selectionModel.isSelectedIndex(i)) {
501 sel.add(selection.get(i));
502 }
503 }
504 return sel;
505 }
506
507 /**
508 * Sets the OSM primitives to be selected in the view of this model
509 *
510 * @param sel the collection of primitives to select
511 */
512 public void setSelected(Collection<OsmPrimitive> sel) {
513 selectionModel.clearSelection();
514 if (sel == null) return;
515 for (OsmPrimitive p: sel){
516 int i = selection.indexOf(p);
517 if (i >= 0){
518 selectionModel.addSelectionInterval(i, i);
519 }
520 }
521 }
522
523 @Override
524 protected void fireContentsChanged(Object source, int index0, int index1) {
525 Collection<OsmPrimitive> sel = getSelected();
526 super.fireContentsChanged(source, index0, index1);
527 setSelected(sel);
528 }
529
530 /**
531 * Sets the collection of currently selected OSM objects
532 *
533 * @param selection the collection of currently selected OSM objects
534 */
535 public void setJOSMSelection(final Collection<? extends OsmPrimitive> selection) {
536 this.selection.clear();
537 if (selection != null) {
538 this.selection.addAll(selection);
539 sort();
540 }
541 GuiHelper.runInEDTAndWait(new Runnable() {
542 @Override public void run() {
543 fireContentsChanged(this, 0, getSize());
544 if (selection != null) {
545 remember(selection);
546 if (selection.size() == 2) {
547 Iterator<? extends OsmPrimitive> it = selection.iterator();
548 OsmPrimitive n1 = it.next(), n2=it.next();
549 // show distance between two selected nodes
550 if (n1 instanceof Node && n2 instanceof Node) {
551 double d = ((Node) n1).getCoor().greatCircleDistance(((Node) n2).getCoor());
552 Main.map.statusLine.setDist(d);
553 return;
554 }
555 }
556 Main.map.statusLine.setDist(new SubclassFilteredCollection<OsmPrimitive, Way>(selection, OsmPrimitive.wayPredicate));
557 }
558 }
559 });
560 }
561
562 /**
563 * Triggers a refresh of the view for all primitives in {@code toUpdate}
564 * which are currently displayed in the view
565 *
566 * @param toUpdate the collection of primitives to update
567 */
568 public void update(Collection<? extends OsmPrimitive> toUpdate) {
569 if (toUpdate == null) return;
570 if (toUpdate.isEmpty()) return;
571 Collection<OsmPrimitive> sel = getSelected();
572 for (OsmPrimitive p: toUpdate){
573 int i = selection.indexOf(p);
574 if (i >= 0) {
575 super.fireContentsChanged(this, i,i);
576 }
577 }
578 setSelected(sel);
579 }
580
581 /**
582 * Sorts the current elements in the selection
583 */
584 public void sort() {
585 if (this.selection.size() <= Main.pref.getInteger("selection.no_sort_above", 100000)) {
586 boolean quick = this.selection.size() > Main.pref.getInteger("selection.fast_sort_above", 10000);
587 Collections.sort(this.selection, new OsmPrimitiveComparator(quick, false));
588 }
589 }
590
591 /* ------------------------------------------------------------------------ */
592 /* interface EditLayerChangeListener */
593 /* ------------------------------------------------------------------------ */
594 @Override
595 public void editLayerChanged(OsmDataLayer oldLayer, OsmDataLayer newLayer) {
596 if (newLayer == null) {
597 setJOSMSelection(null);
598 history = null;
599 } else {
600 history = newLayer.data.getSelectionHistory();
601 setJOSMSelection(newLayer.data.getAllSelected());
602 }
603 }
604
605 /* ------------------------------------------------------------------------ */
606 /* interface SelectionChangeListener */
607 /* ------------------------------------------------------------------------ */
608 @Override
609 public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) {
610 setJOSMSelection(newSelection);
611 }
612
613 /* ------------------------------------------------------------------------ */
614 /* interface DataSetListener */
615 /* ------------------------------------------------------------------------ */
616 @Override
617 public void dataChanged(DataChangedEvent event) {
618 // refresh the whole list
619 fireContentsChanged(this, 0, getSize());
620 }
621
622 @Override
623 public void nodeMoved(NodeMovedEvent event) {
624 // may influence the display name of primitives, update the data
625 update(event.getPrimitives());
626 }
627
628 @Override
629 public void otherDatasetChange(AbstractDatasetChangedEvent event) {
630 // may influence the display name of primitives, update the data
631 update(event.getPrimitives());
632 }
633
634 @Override
635 public void relationMembersChanged(RelationMembersChangedEvent event) {
636 // may influence the display name of primitives, update the data
637 update(event.getPrimitives());
638 }
639
640 @Override
641 public void tagsChanged(TagsChangedEvent event) {
642 // may influence the display name of primitives, update the data
643 update(event.getPrimitives());
644 }
645
646 @Override
647 public void wayNodesChanged(WayNodesChangedEvent event) {
648 // may influence the display name of primitives, update the data
649 update(event.getPrimitives());
650 }
651
652 @Override
653 public void primitivesAdded(PrimitivesAddedEvent event) {/* ignored - handled by SelectionChangeListener */}
654 @Override
655 public void primitivesRemoved(PrimitivesRemovedEvent event) {/* ignored - handled by SelectionChangeListener*/}
656 }
657
658 /**
659 * A specialized {@link JMenuItem} for presenting one entry of the search history
660 *
661 * @author Jan Peter Stotz
662 */
663 protected static class SearchMenuItem extends JMenuItem implements ActionListener {
664 protected final SearchSetting s;
665
666 public SearchMenuItem(SearchSetting s) {
667 super(Utils.shortenString(s.toString(), org.openstreetmap.josm.actions.search.SearchAction.MAX_LENGTH_SEARCH_EXPRESSION_DISPLAY));
668 this.s = s;
669 addActionListener(this);
670 }
671
672 @Override
673 public void actionPerformed(ActionEvent e) {
674 org.openstreetmap.josm.actions.search.SearchAction.searchWithoutHistory(s);
675 }
676 }
677
678 /**
679 * The popup menu for the search history entries
680 *
681 */
682 protected static class SearchPopupMenu extends JPopupMenu {
683 public static void launch(Component parent) {
684 if (org.openstreetmap.josm.actions.search.SearchAction.getSearchHistory().isEmpty())
685 return;
686 JPopupMenu menu = new SearchPopupMenu();
687 Rectangle r = parent.getBounds();
688 menu.show(parent, r.x, r.y + r.height);
689 }
690
691 public SearchPopupMenu() {
692 for (SearchSetting ss: org.openstreetmap.josm.actions.search.SearchAction.getSearchHistory()) {
693 add(new SearchMenuItem(ss));
694 }
695 }
696 }
697
698 /**
699 * A specialized {@link JMenuItem} for presenting one entry of the selection history
700 *
701 * @author Jan Peter Stotz
702 */
703 protected static class SelectionMenuItem extends JMenuItem implements ActionListener {
704 private final DefaultNameFormatter df = DefaultNameFormatter.getInstance();
705 protected Collection<? extends OsmPrimitive> sel;
706
707 public SelectionMenuItem(Collection<? extends OsmPrimitive> sel) {
708 super();
709 this.sel = sel;
710 int ways = 0;
711 int nodes = 0;
712 int relations = 0;
713 for (OsmPrimitive o : sel) {
714 if (! o.isSelectable()) continue; // skip unselectable primitives
715 if (o instanceof Way) {
716 ways++;
717 } else if (o instanceof Node) {
718 nodes++;
719 } else if (o instanceof Relation) {
720 relations++;
721 }
722 }
723 StringBuilder text = new StringBuilder();
724 if(ways != 0) {
725 text.append(text.length() > 0 ? ", " : "")
726 .append(trn("{0} way", "{0} ways", ways, ways));
727 }
728 if(nodes != 0) {
729 text.append(text.length() > 0 ? ", " : "")
730 .append(trn("{0} node", "{0} nodes", nodes, nodes));
731 }
732 if(relations != 0) {
733 text.append(text.length() > 0 ? ", " : "")
734 .append(trn("{0} relation", "{0} relations", relations, relations));
735 }
736 if(ways + nodes + relations == 0) {
737 text.append(tr("Unselectable now"));
738 this.sel=new ArrayList<>(); // empty selection
739 }
740 if(ways + nodes + relations == 1)
741 {
742 text.append(": ");
743 for(OsmPrimitive o : sel) {
744 text.append(o.getDisplayName(df));
745 }
746 setText(text.toString());
747 } else {
748 setText(tr("Selection: {0}", text));
749 }
750 addActionListener(this);
751 }
752
753 @Override
754 public void actionPerformed(ActionEvent e) {
755 Main.main.getCurrentDataSet().setSelected(sel);
756 }
757 }
758
759 /**
760 * The popup menu for the JOSM selection history entries
761 */
762 protected static class SelectionHistoryPopup extends JPopupMenu {
763 public static void launch(Component parent, Collection<Collection<? extends OsmPrimitive>> history) {
764 if (history == null || history.isEmpty()) return;
765 JPopupMenu menu = new SelectionHistoryPopup(history);
766 Rectangle r = parent.getBounds();
767 menu.show(parent, r.x, r.y + r.height);
768 }
769
770 public SelectionHistoryPopup(Collection<Collection<? extends OsmPrimitive>> history) {
771 for (Collection<? extends OsmPrimitive> sel : history) {
772 add(new SelectionMenuItem(sel));
773 }
774 }
775 }
776}
Note: See TracBrowser for help on using the repository browser.