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

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

new: Ctrl-DblClick in the relation list dialog opens the relation editor
new: Duplicate button in the relation list dialog
new: autocompletion on member roles in the member table
new: autocompletion on the member field for role assignments on multiple members
new: two-way synchronization between the selection in the map and the selection in the member table of the relation editor

  • Property svn:eol-style set to native
File size: 12.9 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.Collection;
12import java.util.HashSet;
13import java.util.logging.Logger;
14
15import javax.swing.AbstractAction;
16import javax.swing.DefaultListModel;
17import javax.swing.JList;
18import javax.swing.JPanel;
19import javax.swing.JScrollPane;
20import javax.swing.ListSelectionModel;
21import javax.swing.SwingUtilities;
22import javax.swing.event.ListSelectionEvent;
23import javax.swing.event.ListSelectionListener;
24
25import org.openstreetmap.josm.Main;
26import org.openstreetmap.josm.data.osm.DataSet;
27import org.openstreetmap.josm.data.osm.OsmPrimitive;
28import org.openstreetmap.josm.data.osm.Relation;
29import org.openstreetmap.josm.data.osm.RelationMember;
30import org.openstreetmap.josm.gui.OsmPrimitivRenderer;
31import org.openstreetmap.josm.gui.PrimitiveNameFormatter;
32import org.openstreetmap.josm.gui.SideButton;
33import org.openstreetmap.josm.gui.dialogs.relation.RelationEditor;
34import org.openstreetmap.josm.gui.layer.DataChangeListener;
35import org.openstreetmap.josm.gui.layer.Layer;
36import org.openstreetmap.josm.gui.layer.OsmDataLayer;
37import org.openstreetmap.josm.gui.layer.Layer.LayerChangeListener;
38import org.openstreetmap.josm.tools.GBC;
39import org.openstreetmap.josm.tools.ImageProvider;
40import org.openstreetmap.josm.tools.Shortcut;
41
42/**
43 * A dialog showing all known relations, with buttons to add, edit, and
44 * delete them.
45 *
46 * We don't have such dialogs for nodes, segments, and ways, because those
47 * objects are visible on the map and can be selected there. Relations are not.
48 */
49public class RelationListDialog extends ToggleDialog implements LayerChangeListener, DataChangeListener {
50 private static final Logger logger = Logger.getLogger(RelationListDialog.class.getName());
51 static private final PrimitiveNameFormatter NAME_FORMATTER = new PrimitiveNameFormatter();
52
53 /**
54 * The selection's list data.
55 */
56 private final DefaultListModel list = new DefaultListModel();
57
58 /**
59 * The display list.
60 */
61 private JList displaylist = new JList(list);
62
63 /** the edit action */
64 private EditAction editAction;
65 /** the delete action */
66 private DeleteAction deleteAction;
67
68
69 /**
70 * constructor
71 */
72 public RelationListDialog() {
73 super(tr("Relations"), "relationlist", tr("Open a list of all relations."),
74 Shortcut.registerShortcut("subwindow:relations", tr("Toggle: {0}", tr("Relations")), KeyEvent.VK_R, Shortcut.GROUP_LAYER), 150);
75
76 // create the list of relations
77 //
78 displaylist.setCellRenderer(new OsmPrimitivRenderer());
79 displaylist.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
80 displaylist.addMouseListener(new DoubleClickAdapter());
81 add(new JScrollPane(displaylist), BorderLayout.CENTER);
82
83 // create the panel with buttons
84 //
85 JPanel buttonPanel = new JPanel(new GridLayout(1,3));
86
87 // the new action
88 //
89 NewAction newAction = new NewAction();
90 Layer.listeners.add(newAction);
91 buttonPanel.add(new SideButton(newAction), GBC.std());
92
93 // the edit action
94 //
95 editAction = new EditAction();
96 displaylist.addListSelectionListener(editAction);
97 buttonPanel.add(new SideButton(editAction), GBC.std());
98
99 // the edit action
100 //
101 DuplicateAction duplicateAction = new DuplicateAction();
102 displaylist.addListSelectionListener(duplicateAction);
103 buttonPanel.add(new SideButton(duplicateAction), GBC.std());
104
105 // the delete action
106 //
107 deleteAction = new DeleteAction();
108 displaylist.addListSelectionListener(deleteAction);
109 buttonPanel.add(new SideButton(deleteAction), GBC.eol());
110 add(buttonPanel, BorderLayout.SOUTH);
111
112 // register as layer listener
113 //
114 Layer.listeners.add(this);
115 }
116
117 @Override public void setVisible(boolean b) {
118 super.setVisible(b);
119 if (b) {
120 updateList();
121 }
122 }
123
124 protected int getNumRelations() {
125 if (Main.main.getCurrentDataSet() == null) return 0;
126 return Main.main.getCurrentDataSet().relations.size();
127 }
128
129 public void updateList() {
130 if (Main.main.getCurrentDataSet() == null) {
131 list.setSize(0);
132 return;
133 }
134 Relation selected = getSelected();
135 list.setSize(getNumRelations());
136 if (getNumRelations() > 0 ) {
137 int i = 0;
138 for (OsmPrimitive e : DataSet.sort(Main.main.getCurrentDataSet().relations)) {
139 if (!e.deleted && !e.incomplete) {
140 list.setElementAt(e, i++);
141 }
142 }
143 list.setSize(i);
144 }
145 if(getNumRelations() != 0) {
146 setTitle(tr("Relations: {0}", Main.main.getCurrentDataSet().relations.size()), true);
147 } else {
148 setTitle(tr("Relations"), false);
149 }
150 selectRelation(selected);
151 }
152
153 public void activeLayerChange(Layer a, Layer b) {
154 updateList();
155 }
156
157 public void layerRemoved(Layer a) {
158 if (a instanceof OsmDataLayer) {
159 ((OsmDataLayer)a).listenerDataChanged.remove(this);
160 }
161 }
162
163 public void layerAdded(Layer a) {
164 if (a instanceof OsmDataLayer) {
165 ((OsmDataLayer)a).listenerDataChanged.add(this);
166 }
167 }
168
169 public void dataChanged(OsmDataLayer l) {
170 updateList();
171 }
172
173 /**
174 * Returns the currently selected relation, or null.
175 *
176 * @return the currently selected relation, or null
177 */
178 public Relation getCurrentRelation() {
179 return (Relation) displaylist.getSelectedValue();
180 }
181
182 /**
183 * Adds a selection listener to the relation list.
184 *
185 * @param listener the listener to add
186 */
187 public void addListSelectionListener(ListSelectionListener listener) {
188 displaylist.addListSelectionListener(listener);
189 }
190
191 /**
192 * Removes a selection listener from the relation list.
193 *
194 * @param listener the listener to remove
195 */
196 public void removeListSelectionListener(ListSelectionListener listener) {
197 displaylist.removeListSelectionListener(listener);
198 }
199
200 /**
201 * @return The selected relation in the list
202 */
203 private Relation getSelected() {
204 if(list.size() == 1) {
205 displaylist.setSelectedIndex(0);
206 }
207 return (Relation) displaylist.getSelectedValue();
208 }
209
210 /**
211 * Selects the relation <code>relation</code> in the list of relations.
212 *
213 * @param relation the relation
214 */
215 public void selectRelation(Relation relation) {
216 if (relation == null)
217 {
218 displaylist.clearSelection();
219 return;
220 }
221 int i = -1;
222 for (i=0; i < list.getSize(); i++) {
223 Relation r = (Relation)list.get(i);
224 if (r == relation) {
225 break;
226 }
227 }
228 if (i >= 0 && i < list.getSize()) {
229 displaylist.setSelectedIndex(i);
230 displaylist.ensureIndexIsVisible(i);
231 }
232 else
233 {
234 displaylist.clearSelection();
235 }
236 }
237
238 class DoubleClickAdapter extends MouseAdapter {
239 protected void setCurrentRelationAsSelection() {
240 Main.main.getCurrentDataSet().setSelected((Relation)displaylist.getSelectedValue());
241 }
242
243 protected void editCurrentRelation() {
244 new EditAction().launchEditor(getSelected());
245 }
246
247 @Override public void mouseClicked(MouseEvent e) {
248 if (e.getClickCount() == 2 && SwingUtilities.isLeftMouseButton(e)) {
249 if (e.isControlDown()) {
250 editCurrentRelation();
251 } else {
252 setCurrentRelationAsSelection();
253 }
254 }
255 }
256 }
257
258 /**
259 * The edit action
260 *
261 */
262 class EditAction extends AbstractAction implements ListSelectionListener{
263 public EditAction() {
264 putValue(SHORT_DESCRIPTION,tr( "Open an editor for the selected relation"));
265 putValue(NAME, tr("Edit"));
266 putValue(SMALL_ICON, ImageProvider.get("dialogs", "edit"));
267 setEnabled(false);
268 }
269 protected Collection<RelationMember> getMembersForCurrentSelection(Relation r) {
270 Collection<RelationMember> members = new HashSet<RelationMember>();
271 Collection<OsmPrimitive> selection = Main.map.mapView.getEditLayer().data.getSelected();
272 for (RelationMember member: r.members) {
273 if (selection.contains(member.member)) {
274 members.add(member);
275 }
276 }
277 return members;
278 }
279
280 public void launchEditor(Relation toEdit) {
281 if (toEdit == null)
282 return;
283 RelationEditor.getEditor(Main.map.mapView.getEditLayer(),toEdit, getMembersForCurrentSelection(toEdit)).setVisible(true);
284 }
285
286 public void actionPerformed(ActionEvent e) {
287 if (!isEnabled())
288 return;
289 launchEditor(getSelected());
290 }
291
292 public void valueChanged(ListSelectionEvent e) {
293 setEnabled(displaylist.getSelectedIndices() != null && displaylist.getSelectedIndices().length > 0);
294 }
295 }
296
297 /**
298 * The delete action
299 *
300 */
301 class DeleteAction extends AbstractAction implements ListSelectionListener, Runnable {
302 class AbortException extends Exception {}
303
304 public DeleteAction() {
305 putValue(SHORT_DESCRIPTION,tr("Delete the selected relation"));
306 putValue(NAME, tr("Delete"));
307 putValue(SMALL_ICON, ImageProvider.get("dialogs", "delete"));
308 setEnabled(false);
309 }
310
311 public void run() {
312 if (!isEnabled()) return;
313 Relation toDelete = getSelected();
314 if (toDelete == null)
315 return;
316 org.openstreetmap.josm.actions.mapmode.DeleteAction.deleteRelation(
317 Main.main.getEditLayer(),
318 toDelete
319 );
320 }
321
322 public void actionPerformed(ActionEvent e) {
323 run();
324 }
325
326 public void valueChanged(ListSelectionEvent e) {
327 setEnabled(displaylist.getSelectedIndices() != null && displaylist.getSelectedIndices().length > 0);
328 }
329 }
330
331 /**
332 * The edit action
333 *
334 */
335 class NewAction extends AbstractAction implements LayerChangeListener{
336 public NewAction() {
337 putValue(SHORT_DESCRIPTION,tr("Create a new relation"));
338 putValue(NAME, tr("New"));
339 putValue(SMALL_ICON, ImageProvider.get("dialogs", "addrelation"));
340 setEnabled(false);
341 }
342
343 public void run() {
344 RelationEditor.getEditor(Main.map.mapView.getEditLayer(),null, null).setVisible(true);
345 }
346
347 public void actionPerformed(ActionEvent e) {
348 run();
349 }
350
351 protected void updateEnabledState() {
352 setEnabled(Main.main != null && Main.main.getEditLayer() != null);
353 }
354
355 public void activeLayerChange(Layer oldLayer, Layer newLayer) {
356 updateEnabledState();
357 }
358
359 public void layerAdded(Layer newLayer) {
360 updateEnabledState();
361 }
362
363 public void layerRemoved(Layer oldLayer) {
364 updateEnabledState();
365 }
366 }
367
368 /**
369 * Creates a new relation with a copy of the current editor state
370 *
371 */
372 class DuplicateAction extends AbstractAction implements ListSelectionListener {
373 public DuplicateAction() {
374 putValue(SHORT_DESCRIPTION, tr("Create a copy of this relation and open it in another editor window"));
375 // FIXME provide an icon
376 putValue(SMALL_ICON, ImageProvider.get("duplicate"));
377 putValue(NAME, tr("Duplicate"));
378 updateEnabledState();
379 }
380
381 public void launchEditorForDuplicate(Relation original) {
382 Relation copy = new Relation();
383 copy.cloneFrom(original);
384 copy.id = 0;
385 copy.modified = true;
386 RelationEditor editor = RelationEditor.getEditor(
387 Main.main.getEditLayer(),
388 copy,
389 null /* no selected members */
390 );
391 editor.setVisible(true);
392 }
393
394 public void actionPerformed(ActionEvent e) {
395 if (!isEnabled())
396 return;
397 launchEditorForDuplicate(getSelected());
398 }
399
400 protected void updateEnabledState() {
401 setEnabled(displaylist.getSelectedIndices() != null && displaylist.getSelectedIndices().length == 1);
402 }
403
404 public void valueChanged(ListSelectionEvent e) {
405 updateEnabledState();
406 }
407 }
408}
Note: See TracBrowser for help on using the repository browser.