source: josm/trunk/src/org/openstreetmap/josm/gui/dialogs/RelationListDialog.java@ 2301

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

fixed #3765: Unable to resolve conflict
Improved warning message for conflicting relation versions and added help page

  • Property svn:eol-style set to native
File size: 16.3 KB
Line 
1package org.openstreetmap.josm.gui.dialogs;
2
3import static org.openstreetmap.josm.tools.I18n.tr;
4
5import java.awt.BorderLayout;
6import java.awt.GridLayout;
7import java.awt.event.ActionEvent;
8import java.awt.event.KeyEvent;
9import java.awt.event.MouseAdapter;
10import java.awt.event.MouseEvent;
11import java.util.ArrayList;
12import java.util.Collection;
13import java.util.Collections;
14import java.util.Comparator;
15import java.util.HashSet;
16import java.util.logging.Logger;
17
18import javax.swing.AbstractAction;
19import javax.swing.AbstractListModel;
20import javax.swing.JList;
21import javax.swing.JPanel;
22import javax.swing.JScrollPane;
23import javax.swing.KeyStroke;
24import javax.swing.ListSelectionModel;
25import javax.swing.SwingUtilities;
26import javax.swing.event.ListSelectionEvent;
27import javax.swing.event.ListSelectionListener;
28
29import org.openstreetmap.josm.Main;
30import org.openstreetmap.josm.data.osm.DataSet;
31import org.openstreetmap.josm.data.osm.NameFormatter;
32import org.openstreetmap.josm.data.osm.OsmPrimitive;
33import org.openstreetmap.josm.data.osm.Relation;
34import org.openstreetmap.josm.data.osm.RelationMember;
35import org.openstreetmap.josm.gui.DefaultNameFormatter;
36import org.openstreetmap.josm.gui.OsmPrimitivRenderer;
37import org.openstreetmap.josm.gui.SideButton;
38import org.openstreetmap.josm.gui.dialogs.relation.RelationEditor;
39import org.openstreetmap.josm.gui.layer.DataChangeListener;
40import org.openstreetmap.josm.gui.layer.Layer;
41import org.openstreetmap.josm.gui.layer.OsmDataLayer;
42import org.openstreetmap.josm.gui.layer.Layer.LayerChangeListener;
43import org.openstreetmap.josm.tools.GBC;
44import org.openstreetmap.josm.tools.ImageProvider;
45import org.openstreetmap.josm.tools.Shortcut;
46
47/**
48 * A dialog showing all known relations, with buttons to add, edit, and
49 * delete them.
50 *
51 * We don't have such dialogs for nodes, segments, and ways, because those
52 * objects are visible on the map and can be selected there. Relations are not.
53 */
54public class RelationListDialog extends ToggleDialog implements LayerChangeListener, DataChangeListener {
55 private static final Logger logger = Logger.getLogger(RelationListDialog.class.getName());
56
57 /** The display list. */
58 private JList displaylist;
59 /** the list model used */
60 private RelationListModel model;
61
62 /** the edit action */
63 private EditAction editAction;
64 /** the delete action */
65 private DeleteAction deleteAction;
66
67
68 /**
69 * constructor
70 */
71 public RelationListDialog() {
72 super(tr("Relations"), "relationlist", tr("Open a list of all relations."),
73 Shortcut.registerShortcut("subwindow:relations", tr("Toggle: {0}", tr("Relations")), KeyEvent.VK_R, Shortcut.GROUP_LAYER), 150);
74
75 // create the list of relations
76 //
77 model = new RelationListModel();
78 displaylist = new JList(model);
79 displaylist.setCellRenderer(new OsmPrimitivRenderer());
80 displaylist.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
81 displaylist.addMouseListener(new DoubleClickAdapter());
82 add(new JScrollPane(displaylist), BorderLayout.CENTER);
83
84 // create the panel with buttons
85 //
86 JPanel buttonPanel = new JPanel(new GridLayout(1,3));
87
88 // the new action
89 //
90 NewAction newAction = new NewAction();
91 Layer.listeners.add(newAction);
92 buttonPanel.add(new SideButton(newAction), GBC.std());
93
94 // the edit action
95 //
96 editAction = new EditAction();
97 displaylist.addListSelectionListener(editAction);
98 buttonPanel.add(new SideButton(editAction), GBC.std());
99
100 // the duplicate action
101 //
102 DuplicateAction duplicateAction = new DuplicateAction();
103 displaylist.addListSelectionListener(duplicateAction);
104 buttonPanel.add(new SideButton(duplicateAction), GBC.std());
105
106 // the delete action
107 //
108 deleteAction = new DeleteAction();
109 displaylist.addListSelectionListener(deleteAction);
110 buttonPanel.add(new SideButton(deleteAction), GBC.eol());
111
112 // the select action
113 //
114 SelectAction selectAction = new SelectAction();
115 displaylist.addListSelectionListener(selectAction);
116 buttonPanel.add(new SideButton(selectAction), GBC.eol());
117
118 add(buttonPanel, BorderLayout.SOUTH);
119 displaylist.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE,0), "deleteRelation");
120 displaylist.getActionMap().put("deleteRelation", deleteAction);
121
122 // register as layer listener
123 //
124 Layer.listeners.add(this);
125 }
126
127 @Override public void setVisible(boolean b) {
128 super.setVisible(b);
129 if (b) {
130 updateList();
131 }
132 }
133
134 protected int getNumRelations() {
135 if (Main.main.getCurrentDataSet() == null) return 0;
136 return Main.main.getCurrentDataSet().relations.size();
137 }
138
139 /**
140 * Replies the list of complete, non-deleted relations in the dataset <code>ds</code>,
141 * sorted by display name.
142 *
143 * @param ds the dataset
144 * @return the list of relations
145 */
146 protected ArrayList<Relation> getDisplayedRelationsInSortOrder(DataSet ds) {
147 ArrayList<Relation> relations = new ArrayList<Relation>(ds.relations.size());
148 for (Relation r: ds.relations ){
149 if (!r.isUsable() || !r.isVisible()) {
150 continue;
151 }
152 relations.add(r);
153 }
154
155 Collections.sort(
156 relations,
157 new Comparator<Relation>() {
158 NameFormatter formatter = DefaultNameFormatter.getInstance();
159 public int compare(Relation r1, Relation r2) {
160 return r1.getDisplayName(formatter).compareTo(r2.getDisplayName(formatter));
161 }
162 }
163 );
164 return relations;
165 }
166
167 public void updateList() {
168 if (Main.main.getCurrentDataSet() == null) {
169 model.setRelations(null);
170 return;
171 }
172 Relation selected = getSelected();
173
174 model.setRelations(getDisplayedRelationsInSortOrder(Main.main.getCurrentDataSet()));
175 if(model.getSize() > 0) {
176 setTitle(tr("Relations: {0}", model.getSize()));
177 } else {
178 setTitle(tr("Relations"));
179 }
180 selectRelation(selected);
181 }
182
183 public void activeLayerChange(Layer a, Layer b) {
184 updateList();
185 }
186
187 public void layerRemoved(Layer a) {
188 if (a instanceof OsmDataLayer) {
189 ((OsmDataLayer)a).listenerDataChanged.remove(this);
190 }
191 updateList();
192 }
193
194 public void layerAdded(Layer a) {
195 if (a instanceof OsmDataLayer) {
196 ((OsmDataLayer)a).listenerDataChanged.add(this);
197 }
198 }
199
200 public void dataChanged(OsmDataLayer l) {
201 updateList();
202 }
203
204 /**
205 * Returns the currently selected relation, or null.
206 *
207 * @return the currently selected relation, or null
208 */
209 public Relation getCurrentRelation() {
210 return (Relation) displaylist.getSelectedValue();
211 }
212
213 /**
214 * Adds a selection listener to the relation list.
215 *
216 * @param listener the listener to add
217 */
218 public void addListSelectionListener(ListSelectionListener listener) {
219 displaylist.addListSelectionListener(listener);
220 }
221
222 /**
223 * Removes a selection listener from the relation list.
224 *
225 * @param listener the listener to remove
226 */
227 public void removeListSelectionListener(ListSelectionListener listener) {
228 displaylist.removeListSelectionListener(listener);
229 }
230
231 /**
232 * @return The selected relation in the list
233 */
234 private Relation getSelected() {
235 if(model.getSize() == 1) {
236 displaylist.setSelectedIndex(0);
237 }
238 return (Relation) displaylist.getSelectedValue();
239 }
240
241 /**
242 * Selects the relation <code>relation</code> in the list of relations.
243 *
244 * @param relation the relation
245 */
246 public void selectRelation(Relation relation) {
247 if (relation == null){
248 displaylist.clearSelection();
249 return;
250 }
251 int idx = model.getIndexOfRelation(relation);
252 if (idx == -1) {
253 displaylist.clearSelection();
254 } else {
255 displaylist.setSelectedIndex(idx);
256 displaylist.scrollRectToVisible(displaylist.getCellBounds(idx,idx));
257 }
258 }
259
260 class DoubleClickAdapter extends MouseAdapter {
261 protected void setCurrentRelationAsSelection() {
262 Main.main.getCurrentDataSet().setSelected((Relation)displaylist.getSelectedValue());
263 }
264
265 protected void editCurrentRelation() {
266 new EditAction().launchEditor(getSelected());
267 }
268
269 @Override public void mouseClicked(MouseEvent e) {
270 if (e.getClickCount() == 2 && SwingUtilities.isLeftMouseButton(e)) {
271 if (e.isControlDown()) {
272 editCurrentRelation();
273 } else {
274 setCurrentRelationAsSelection();
275 }
276 }
277 }
278 }
279
280 /**
281 * The edit action
282 *
283 */
284 class EditAction extends AbstractAction implements ListSelectionListener{
285 public EditAction() {
286 putValue(SHORT_DESCRIPTION,tr( "Open an editor for the selected relation"));
287 //putValue(NAME, tr("Edit"));
288 putValue(SMALL_ICON, ImageProvider.get("dialogs", "edit"));
289 setEnabled(false);
290 }
291 protected Collection<RelationMember> getMembersForCurrentSelection(Relation r) {
292 Collection<RelationMember> members = new HashSet<RelationMember>();
293 Collection<OsmPrimitive> selection = Main.map.mapView.getEditLayer().data.getSelected();
294 for (RelationMember member: r.getMembers()) {
295 if (selection.contains(member.getMember())) {
296 members.add(member);
297 }
298 }
299 return members;
300 }
301
302 public void launchEditor(Relation toEdit) {
303 if (toEdit == null)
304 return;
305 RelationEditor.getEditor(Main.map.mapView.getEditLayer(),toEdit, getMembersForCurrentSelection(toEdit)).setVisible(true);
306 }
307
308 public void actionPerformed(ActionEvent e) {
309 if (!isEnabled())
310 return;
311 launchEditor(getSelected());
312 }
313
314 public void valueChanged(ListSelectionEvent e) {
315 setEnabled(displaylist.getSelectedIndices() != null && displaylist.getSelectedIndices().length == 1);
316 }
317 }
318
319 /**
320 * The delete action
321 *
322 */
323 class DeleteAction extends AbstractAction implements ListSelectionListener {
324 class AbortException extends Exception {}
325
326 public DeleteAction() {
327 putValue(SHORT_DESCRIPTION,tr("Delete the selected relation"));
328 //putValue(NAME, tr("Delete"));
329 putValue(SMALL_ICON, ImageProvider.get("dialogs", "delete"));
330 setEnabled(false);
331 }
332
333 protected void deleteRelation(Relation toDelete) {
334 if (toDelete == null)
335 return;
336 org.openstreetmap.josm.actions.mapmode.DeleteAction.deleteRelation(
337 Main.main.getEditLayer(),
338 toDelete
339 );
340 }
341
342 public void actionPerformed(ActionEvent e) {
343 if (!isEnabled()) return;
344 int [] idx = displaylist.getSelectedIndices();
345 ArrayList<Relation> toDelete = new ArrayList<Relation>(idx.length);
346 for (int i: idx) {
347 toDelete.add(model.getRelation(i));
348 }
349 for (Relation r: toDelete) {
350 deleteRelation(r);
351 }
352 }
353
354 public void valueChanged(ListSelectionEvent e) {
355 setEnabled(displaylist.getSelectedIndices() != null && displaylist.getSelectedIndices().length > 0);
356 }
357 }
358
359 /**
360 * The edit action
361 *
362 */
363 class NewAction extends AbstractAction implements LayerChangeListener{
364 public NewAction() {
365 putValue(SHORT_DESCRIPTION,tr("Create a new relation"));
366 //putValue(NAME, tr("New"));
367 putValue(SMALL_ICON, ImageProvider.get("dialogs", "addrelation"));
368 setEnabled(false);
369 }
370
371 public void run() {
372 RelationEditor.getEditor(Main.map.mapView.getEditLayer(),null, null).setVisible(true);
373 }
374
375 public void actionPerformed(ActionEvent e) {
376 run();
377 }
378
379 protected void updateEnabledState() {
380 setEnabled(Main.main != null && Main.main.getEditLayer() != null);
381 }
382
383 public void activeLayerChange(Layer oldLayer, Layer newLayer) {
384 updateEnabledState();
385 }
386
387 public void layerAdded(Layer newLayer) {
388 updateEnabledState();
389 }
390
391 public void layerRemoved(Layer oldLayer) {
392 updateEnabledState();
393 }
394 }
395
396 /**
397 * Creates a new relation with a copy of the current editor state
398 *
399 */
400 class DuplicateAction extends AbstractAction implements ListSelectionListener {
401 public DuplicateAction() {
402 putValue(SHORT_DESCRIPTION, tr("Create a copy of this relation and open it in another editor window"));
403 putValue(SMALL_ICON, ImageProvider.get("duplicate"));
404 //putValue(NAME, tr("Duplicate"));
405 updateEnabledState();
406 }
407
408 public void launchEditorForDuplicate(Relation original) {
409 Relation copy = new Relation(original.getId());
410 copy.cloneFrom(original);
411 copy.clearOsmId();
412 copy.setModified(true);
413 RelationEditor editor = RelationEditor.getEditor(
414 Main.main.getEditLayer(),
415 copy,
416 null /* no selected members */
417 );
418 editor.setVisible(true);
419 }
420
421 public void actionPerformed(ActionEvent e) {
422 if (!isEnabled())
423 return;
424 launchEditorForDuplicate(getSelected());
425 }
426
427 protected void updateEnabledState() {
428 setEnabled(displaylist.getSelectedIndices() != null && displaylist.getSelectedIndices().length == 1);
429 }
430
431 public void valueChanged(ListSelectionEvent e) {
432 updateEnabledState();
433 }
434 }
435
436 /**
437 * Sets the current selection to the list of relations selected in this dialog
438 *
439 */
440 class SelectAction extends AbstractAction implements ListSelectionListener{
441 public SelectAction() {
442 putValue(SHORT_DESCRIPTION,tr("Set the current selection to the list of selected relations"));
443 //putValue(NAME, tr("Select"));
444 putValue(SMALL_ICON, ImageProvider.get("dialogs", "select"));
445 setEnabled(false);
446 }
447
448 public void actionPerformed(ActionEvent e) {
449 if (!isEnabled()) return;
450 int [] idx = displaylist.getSelectedIndices();
451 if (idx == null || idx.length == 0) return;
452 ArrayList<OsmPrimitive> selection = new ArrayList<OsmPrimitive>(idx.length);
453 for (int i: idx) {
454 selection.add(model.getRelation(i));
455 }
456 Main.map.mapView.getEditLayer().data.setSelected(selection);
457 DataSet.fireSelectionChanged(selection);
458 }
459
460 public void valueChanged(ListSelectionEvent e) {
461 setEnabled(displaylist.getSelectedIndices() != null && displaylist.getSelectedIndices().length > 0);
462 }
463 }
464
465 private static class RelationListModel extends AbstractListModel {
466 private ArrayList<Relation> relations;
467
468 public ArrayList<Relation> getRelations() {
469 return relations;
470 }
471
472 public Relation getRelation(int idx) {
473 return relations.get(idx);
474 }
475
476 public void setRelations(ArrayList<Relation> relations) {
477 this.relations = relations;
478 fireIntervalAdded(this, 0, getSize());
479 }
480
481 public Object getElementAt(int index) {
482 if (relations == null) return null;
483 return relations.get(index);
484 }
485
486 public int getSize() {
487 if (relations == null) return 0;
488 return relations.size();
489 }
490
491 public int getIndexOfRelation(Relation relation) {
492 if (relation == null) return -1;
493 return relations.indexOf(relation);
494 }
495 }
496}
Note: See TracBrowser for help on using the repository browser.