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

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

update license/copyright information

  • Property svn:eol-style set to native
File size: 29.3 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.Comparator;
18import java.util.HashSet;
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.OsmPrimitiveType;
46import org.openstreetmap.josm.data.osm.Relation;
47import org.openstreetmap.josm.data.osm.Way;
48import org.openstreetmap.josm.data.osm.event.AbstractDatasetChangedEvent;
49import org.openstreetmap.josm.data.osm.event.DataChangedEvent;
50import org.openstreetmap.josm.data.osm.event.DataSetListener;
51import org.openstreetmap.josm.data.osm.event.DatasetEventManager;
52import org.openstreetmap.josm.data.osm.event.DatasetEventManager.FireMode;
53import org.openstreetmap.josm.data.osm.event.NodeMovedEvent;
54import org.openstreetmap.josm.data.osm.event.PrimitivesAddedEvent;
55import org.openstreetmap.josm.data.osm.event.PrimitivesRemovedEvent;
56import org.openstreetmap.josm.data.osm.event.RelationMembersChangedEvent;
57import org.openstreetmap.josm.data.osm.event.SelectionEventManager;
58import org.openstreetmap.josm.data.osm.event.TagsChangedEvent;
59import org.openstreetmap.josm.data.osm.event.WayNodesChangedEvent;
60import org.openstreetmap.josm.data.osm.visitor.BoundingXYVisitor;
61import org.openstreetmap.josm.gui.DefaultNameFormatter;
62import org.openstreetmap.josm.gui.MapView;
63import org.openstreetmap.josm.gui.MapView.EditLayerChangeListener;
64import org.openstreetmap.josm.gui.OsmPrimitivRenderer;
65import org.openstreetmap.josm.gui.PopupMenuHandler;
66import org.openstreetmap.josm.gui.SideButton;
67import org.openstreetmap.josm.gui.layer.OsmDataLayer;
68import org.openstreetmap.josm.gui.util.GuiHelper;
69import org.openstreetmap.josm.gui.util.HighlightHelper;
70import org.openstreetmap.josm.gui.widgets.ListPopupMenu;
71import org.openstreetmap.josm.gui.widgets.PopupMenuLauncher;
72import org.openstreetmap.josm.tools.ImageProvider;
73import org.openstreetmap.josm.tools.InputMapUtils;
74import org.openstreetmap.josm.tools.Shortcut;
75import org.openstreetmap.josm.tools.SubclassFilteredCollection;
76
77/**
78 * A small tool dialog for displaying the current selection.
79 * @since 8
80 */
81public class SelectionListDialog extends ToggleDialog {
82 private JList 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((OsmPrimitive)model.getElementAt(idx)));
204 } else if (highlightEnabled && Main.isDisplayingMapView()) {
205 if (helper.highlightOnly((OsmPrimitive)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","select"));
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 static private class SelectionListModel extends AbstractListModel 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<OsmPrimitive>();
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 Object 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<OsmPrimitive>();
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 Main.map.statusLine.setDist(new SubclassFilteredCollection<OsmPrimitive, Way>(selection, OsmPrimitive.wayPredicate));
547 }
548 }
549 });
550 }
551
552 /**
553 * Triggers a refresh of the view for all primitives in {@code toUpdate}
554 * which are currently displayed in the view
555 *
556 * @param toUpdate the collection of primitives to update
557 */
558 public void update(Collection<? extends OsmPrimitive> toUpdate) {
559 if (toUpdate == null) return;
560 if (toUpdate.isEmpty()) return;
561 Collection<OsmPrimitive> sel = getSelected();
562 for (OsmPrimitive p: toUpdate){
563 int i = selection.indexOf(p);
564 if (i >= 0) {
565 super.fireContentsChanged(this, i,i);
566 }
567 }
568 setSelected(sel);
569 }
570
571 /**
572 * Sorts the current elements in the selection
573 */
574 public void sort() {
575 if (this.selection.size()>Main.pref.getInteger("selection.no_sort_above",100000)) return;
576 if (this.selection.size()>Main.pref.getInteger("selection.fast_sort_above",10000)) {
577 Collections.sort(this.selection, new OsmPrimitiveQuickComparator());
578 } else {
579 Collections.sort(this.selection, new OsmPrimitiveComparator());
580 }
581 }
582
583 /* ------------------------------------------------------------------------ */
584 /* interface EditLayerChangeListener */
585 /* ------------------------------------------------------------------------ */
586 @Override
587 public void editLayerChanged(OsmDataLayer oldLayer, OsmDataLayer newLayer) {
588 if (newLayer == null) {
589 setJOSMSelection(null);
590 history = null;
591 } else {
592 history = newLayer.data.getSelectionHistory();
593 setJOSMSelection(newLayer.data.getAllSelected());
594 }
595 }
596
597 /* ------------------------------------------------------------------------ */
598 /* interface SelectionChangeListener */
599 /* ------------------------------------------------------------------------ */
600 @Override
601 public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) {
602 setJOSMSelection(newSelection);
603 }
604
605 /* ------------------------------------------------------------------------ */
606 /* interface DataSetListener */
607 /* ------------------------------------------------------------------------ */
608 @Override
609 public void dataChanged(DataChangedEvent event) {
610 // refresh the whole list
611 fireContentsChanged(this, 0, getSize());
612 }
613
614 @Override
615 public void nodeMoved(NodeMovedEvent event) {
616 // may influence the display name of primitives, update the data
617 update(event.getPrimitives());
618 }
619
620 @Override
621 public void otherDatasetChange(AbstractDatasetChangedEvent event) {
622 // may influence the display name of primitives, update the data
623 update(event.getPrimitives());
624 }
625
626 @Override
627 public void relationMembersChanged(RelationMembersChangedEvent event) {
628 // may influence the display name of primitives, update the data
629 update(event.getPrimitives());
630 }
631
632 @Override
633 public void tagsChanged(TagsChangedEvent event) {
634 // may influence the display name of primitives, update the data
635 update(event.getPrimitives());
636 }
637
638 @Override
639 public void wayNodesChanged(WayNodesChangedEvent event) {
640 // may influence the display name of primitives, update the data
641 update(event.getPrimitives());
642 }
643
644 @Override
645 public void primitivesAdded(PrimitivesAddedEvent event) {/* ignored - handled by SelectionChangeListener */}
646 @Override
647 public void primitivesRemoved(PrimitivesRemovedEvent event) {/* ignored - handled by SelectionChangeListener*/}
648 }
649
650 /**
651 * A specialized {@link JMenuItem} for presenting one entry of the search history
652 *
653 * @author Jan Peter Stotz
654 */
655 protected static class SearchMenuItem extends JMenuItem implements ActionListener {
656 final protected SearchSetting s;
657
658 public SearchMenuItem(SearchSetting s) {
659 super(s.toString());
660 this.s = s;
661 addActionListener(this);
662 }
663
664 @Override
665 public void actionPerformed(ActionEvent e) {
666 org.openstreetmap.josm.actions.search.SearchAction.searchWithoutHistory(s);
667 }
668 }
669
670 /**
671 * The popup menu for the search history entries
672 *
673 */
674 protected static class SearchPopupMenu extends JPopupMenu {
675 static public void launch(Component parent) {
676 if (org.openstreetmap.josm.actions.search.SearchAction.getSearchHistory().isEmpty())
677 return;
678 JPopupMenu menu = new SearchPopupMenu();
679 Rectangle r = parent.getBounds();
680 menu.show(parent, r.x, r.y + r.height);
681 }
682
683 public SearchPopupMenu() {
684 for (SearchSetting ss: org.openstreetmap.josm.actions.search.SearchAction.getSearchHistory()) {
685 add(new SearchMenuItem(ss));
686 }
687 }
688 }
689
690 /**
691 * A specialized {@link JMenuItem} for presenting one entry of the selection history
692 *
693 * @author Jan Peter Stotz
694 */
695 protected static class SelectionMenuItem extends JMenuItem implements ActionListener {
696 final private DefaultNameFormatter df = DefaultNameFormatter.getInstance();
697 protected Collection<? extends OsmPrimitive> sel;
698
699 public SelectionMenuItem(Collection<? extends OsmPrimitive> sel) {
700 super();
701 this.sel = sel;
702 int ways = 0;
703 int nodes = 0;
704 int relations = 0;
705 for (OsmPrimitive o : sel) {
706 if (! o.isSelectable()) continue; // skip unselectable primitives
707 if (o instanceof Way) {
708 ways++;
709 } else if (o instanceof Node) {
710 nodes++;
711 } else if (o instanceof Relation) {
712 relations++;
713 }
714 }
715 StringBuffer text = new StringBuffer();
716 if(ways != 0) {
717 text.append(text.length() > 0 ? ", " : "")
718 .append(trn("{0} way", "{0} ways", ways, ways));
719 }
720 if(nodes != 0) {
721 text.append(text.length() > 0 ? ", " : "")
722 .append(trn("{0} node", "{0} nodes", nodes, nodes));
723 }
724 if(relations != 0) {
725 text.append(text.length() > 0 ? ", " : "")
726 .append(trn("{0} relation", "{0} relations", relations, relations));
727 }
728 if(ways + nodes + relations == 0) {
729 text.append(tr("Unselectable now"));
730 this.sel=new ArrayList<OsmPrimitive>(); // empty selection
731 }
732 if(ways + nodes + relations == 1)
733 {
734 text.append(": ");
735 for(OsmPrimitive o : sel) {
736 text.append(o.getDisplayName(df));
737 }
738 setText(text.toString());
739 } else {
740 setText(tr("Selection: {0}", text));
741 }
742 addActionListener(this);
743 }
744
745 @Override
746 public void actionPerformed(ActionEvent e) {
747 Main.main.getCurrentDataSet().setSelected(sel);
748 }
749 }
750
751 /**
752 * The popup menu for the JOSM selection history entries
753 */
754 protected static class SelectionHistoryPopup extends JPopupMenu {
755 static public void launch(Component parent, Collection<Collection<? extends OsmPrimitive>> history) {
756 if (history == null || history.isEmpty()) return;
757 JPopupMenu menu = new SelectionHistoryPopup(history);
758 Rectangle r = parent.getBounds();
759 menu.show(parent, r.x, r.y + r.height);
760 }
761
762 public SelectionHistoryPopup(Collection<Collection<? extends OsmPrimitive>> history) {
763 for (Collection<? extends OsmPrimitive> sel : history) {
764 add(new SelectionMenuItem(sel));
765 }
766 }
767 }
768
769 /** Quicker comparator, comparing just by type and ID's */
770 static private class OsmPrimitiveQuickComparator implements Comparator<OsmPrimitive> {
771
772 private int compareId(OsmPrimitive a, OsmPrimitive b) {
773 long id_a=a.getUniqueId();
774 long id_b=b.getUniqueId();
775 if (id_a<id_b) return -1;
776 if (id_a>id_b) return 1;
777 return 0;
778 }
779
780 private int compareType(OsmPrimitive a, OsmPrimitive b) {
781 // show ways before relations, then nodes
782 if (a.getType().equals(OsmPrimitiveType.WAY)) return -1;
783 if (a.getType().equals(OsmPrimitiveType.NODE)) return 1;
784 // a is a relation
785 if (b.getType().equals(OsmPrimitiveType.WAY)) return 1;
786 // b is a node
787 return -1;
788 }
789
790 @Override
791 public int compare(OsmPrimitive a, OsmPrimitive b) {
792 if (a.getType().equals(b.getType()))
793 return compareId(a, b);
794 return compareType(a, b);
795 }
796 }
797
798}
Note: See TracBrowser for help on using the repository browser.