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

Last change on this file since 4864 was 4536, checked in by Don-vip, 13 years ago

Improved plugin interaction with selection and popups of Relation, Selection and Properties dialogs.

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