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

Last change on this file since 3102 was 3102, checked in by Gubaer, 14 years ago

fixed #4651: Ability to download incomplete relation from selection
fixed #4098: Popup Menu entry "download relation members" in relation dialog should be "download incomplete relation members"
fixed two NPEs in RelationListDialog and SelectionListDialog
refactored SelectionListDialog to support better user feedback (enabled/disabled buttons and menu items)
Finally removed the sort() method on DataSet, marked as FIXME since a long time.

CAVEAT: DataSet.getSelected() now returns an unmodifiable list instead of a copy of the selection list. This may lead to UnsupportedOperationExceptions in the next few days. I tried to make sure the JOSM core uses getSelected() only for reading, but I didn't check the plugins.

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