source: josm/trunk/src/org/openstreetmap/josm/gui/dialogs/properties/PropertiesDialog.java@ 4141

Last change on this file since 4141 was 4141, checked in by stoecker, 13 years ago

fix #6430 - don't prefill single characters

  • Property svn:eol-style set to native
File size: 53.7 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.dialogs.properties;
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.Component;
9import java.awt.Dialog.ModalityType;
10import java.awt.Dimension;
11import java.awt.Font;
12import java.awt.GridBagLayout;
13import java.awt.Point;
14import java.awt.event.ActionEvent;
15import java.awt.event.ActionListener;
16import java.awt.event.FocusAdapter;
17import java.awt.event.FocusEvent;
18import java.awt.event.KeyEvent;
19import java.awt.event.MouseAdapter;
20import java.awt.event.MouseEvent;
21import java.net.HttpURLConnection;
22import java.net.URI;
23import java.net.URLEncoder;
24import java.util.ArrayList;
25import java.util.Collection;
26import java.util.Collections;
27import java.util.Comparator;
28import java.util.HashMap;
29import java.util.HashSet;
30import java.util.Iterator;
31import java.util.List;
32import java.util.Map;
33import java.util.Map.Entry;
34import java.util.TreeMap;
35import java.util.Vector;
36import java.util.Set;
37
38import javax.swing.AbstractAction;
39import javax.swing.Box;
40import javax.swing.DefaultListCellRenderer;
41import javax.swing.JComboBox;
42import javax.swing.JComponent;
43import javax.swing.JDialog;
44import javax.swing.JLabel;
45import javax.swing.JList;
46import javax.swing.JOptionPane;
47import javax.swing.JPanel;
48import javax.swing.JPopupMenu;
49import javax.swing.JScrollPane;
50import javax.swing.JTable;
51import javax.swing.KeyStroke;
52import javax.swing.ListSelectionModel;
53import javax.swing.event.ListSelectionEvent;
54import javax.swing.event.ListSelectionListener;
55import javax.swing.table.DefaultTableCellRenderer;
56import javax.swing.table.DefaultTableModel;
57import javax.swing.table.TableColumnModel;
58import javax.swing.table.TableModel;
59import javax.swing.text.JTextComponent;
60
61import org.openstreetmap.josm.Main;
62import org.openstreetmap.josm.command.ChangeCommand;
63import org.openstreetmap.josm.command.ChangePropertyCommand;
64import org.openstreetmap.josm.command.Command;
65import org.openstreetmap.josm.command.SequenceCommand;
66import org.openstreetmap.josm.data.SelectionChangedListener;
67import org.openstreetmap.josm.data.osm.Node;
68import org.openstreetmap.josm.data.osm.OsmPrimitive;
69import org.openstreetmap.josm.data.osm.Relation;
70import org.openstreetmap.josm.data.osm.RelationMember;
71import org.openstreetmap.josm.data.osm.Tag;
72import org.openstreetmap.josm.data.osm.Way;
73import org.openstreetmap.josm.data.osm.event.AbstractDatasetChangedEvent;
74import org.openstreetmap.josm.data.osm.event.DataSetListenerAdapter;
75import org.openstreetmap.josm.data.osm.event.DatasetEventManager;
76import org.openstreetmap.josm.data.osm.event.DatasetEventManager.FireMode;
77import org.openstreetmap.josm.data.osm.event.SelectionEventManager;
78import org.openstreetmap.josm.gui.DefaultNameFormatter;
79import org.openstreetmap.josm.gui.ExtendedDialog;
80import org.openstreetmap.josm.gui.MapFrame;
81import org.openstreetmap.josm.gui.MapView;
82import org.openstreetmap.josm.gui.SideButton;
83import org.openstreetmap.josm.gui.dialogs.ToggleDialog;
84import org.openstreetmap.josm.gui.dialogs.properties.PresetListPanel.PresetHandler;
85import org.openstreetmap.josm.gui.dialogs.relation.DownloadRelationMemberTask;
86import org.openstreetmap.josm.gui.dialogs.relation.RelationEditor;
87import org.openstreetmap.josm.gui.layer.OsmDataLayer;
88import org.openstreetmap.josm.gui.tagging.TaggingPreset;
89import org.openstreetmap.josm.gui.tagging.ac.AutoCompletingComboBox;
90import org.openstreetmap.josm.gui.tagging.ac.AutoCompletionListItem;
91import org.openstreetmap.josm.gui.tagging.ac.AutoCompletionManager;
92import org.openstreetmap.josm.gui.widgets.PopupMenuLauncher;
93import org.openstreetmap.josm.tools.GBC;
94import org.openstreetmap.josm.tools.ImageProvider;
95import org.openstreetmap.josm.tools.LanguageInfo;
96import org.openstreetmap.josm.tools.OpenBrowser;
97import org.openstreetmap.josm.tools.Shortcut;
98
99/**
100 * This dialog displays the properties of the current selected primitives.
101 *
102 * If no object is selected, the dialog list is empty.
103 * If only one is selected, all properties of this object are selected.
104 * If more than one object are selected, the sum of all properties are displayed. If the
105 * different objects share the same property, the shared value is displayed. If they have
106 * different values, all of them are put in a combo box and the string "<different>"
107 * is displayed in italic.
108 *
109 * Below the list, the user can click on an add, modify and delete property button to
110 * edit the table selection value.
111 *
112 * The command is applied to all selected entries.
113 *
114 * @author imi
115 */
116public class PropertiesDialog extends ToggleDialog implements SelectionChangedListener, MapView.EditLayerChangeListener, DataSetListenerAdapter.Listener {
117 /**
118 * Watches for double clicks and from editing or new property, depending on the
119 * location, the click was.
120 * @author imi
121 */
122 public class DblClickWatch extends MouseAdapter {
123 @Override public void mouseClicked(MouseEvent e) {
124 if (e.getClickCount() < 2)
125 {
126 if (e.getSource() == propertyTable) {
127 membershipTable.clearSelection();
128 } else if (e.getSource() == membershipTable) {
129 propertyTable.clearSelection();
130 }
131 }
132 else if (e.getSource() == propertyTable)
133 {
134 int row = propertyTable.rowAtPoint(e.getPoint());
135 if (row > -1) {
136 propertyEdit(row);
137 }
138 } else if (e.getSource() == membershipTable) {
139 int row = membershipTable.rowAtPoint(e.getPoint());
140 if (row > -1) {
141 membershipEdit(row);
142 }
143 }
144 else
145 {
146 add();
147 }
148 }
149 @Override public void mousePressed(MouseEvent e) {
150 if (e.getSource() == propertyTable) {
151 membershipTable.clearSelection();
152 } else if (e.getSource() == membershipTable) {
153 propertyTable.clearSelection();
154 }
155 }
156 }
157
158 // hook for roadsigns plugin to display a small
159 // button in the upper right corner of this dialog
160 public static JPanel pluginHook = new JPanel();
161
162 private final Map<String, Map<String, Integer>> valueCount = new TreeMap<String, Map<String, Integer>>();
163
164 Comparator<AutoCompletionListItem> defaultACItemComparator = new Comparator<AutoCompletionListItem>() {
165 public int compare(AutoCompletionListItem o1, AutoCompletionListItem o2) {
166 return String.CASE_INSENSITIVE_ORDER.compare(o1.getValue(), o2.getValue());
167 }
168 };
169
170 private DataSetListenerAdapter dataChangedAdapter = new DataSetListenerAdapter(this);
171 private HelpAction helpAction = new HelpAction();
172 private AddAction addAction = new AddAction();
173 private Shortcut addActionShortcut = Shortcut.registerShortcut("properties:add", tr("Add Properties"), KeyEvent.VK_B,
174 Shortcut.GROUP_MNEMONIC);
175
176 @Override
177 public void showNotify() {
178 DatasetEventManager.getInstance().addDatasetListener(dataChangedAdapter, FireMode.IN_EDT_CONSOLIDATED);
179 SelectionEventManager.getInstance().addSelectionListener(this, FireMode.IN_EDT_CONSOLIDATED);
180 MapView.addEditLayerChangeListener(this);
181 updateSelection();
182 Main.registerActionShortcut(addAction, addActionShortcut);
183 }
184
185 @Override
186 public void hideNotify() {
187 DatasetEventManager.getInstance().removeDatasetListener(dataChangedAdapter);
188 SelectionEventManager.getInstance().removeSelectionListener(this);
189 MapView.removeEditLayerChangeListener(this);
190 Main.unregisterActionShortcut(addAction, addActionShortcut);
191 }
192
193 /**
194 * Edit the value in the properties table row
195 * @param row The row of the table from which the value is edited.
196 */
197 @SuppressWarnings("unchecked")
198 void propertyEdit(int row) {
199 Collection<OsmPrimitive> sel = Main.main.getCurrentDataSet().getSelected();
200 if (sel.isEmpty()) return;
201
202 String key = propertyData.getValueAt(row, 0).toString();
203 objKey=key;
204
205 String msg = "<html>"+trn("This will change {0} object.",
206 "This will change up to {0} objects.", sel.size(), sel.size())
207 +"<br><br>("+tr("An empty value deletes the tag.", key)+")</html>";
208
209 JPanel panel = new JPanel(new BorderLayout());
210 panel.add(new JLabel(msg), BorderLayout.NORTH);
211
212 JPanel p = new JPanel(new GridBagLayout());
213 panel.add(p, BorderLayout.CENTER);
214
215 AutoCompletionManager autocomplete = Main.main.getEditLayer().data.getAutoCompletionManager();
216 List<AutoCompletionListItem> keyList = autocomplete.getKeys();
217 Collections.sort(keyList, defaultACItemComparator);
218
219 final AutoCompletingComboBox keys = new AutoCompletingComboBox();
220 keys.setPossibleACItems(keyList);
221 keys.setEditable(true);
222 keys.setSelectedItem(key);
223
224 p.add(new JLabel(tr("Key")), GBC.std());
225 p.add(Box.createHorizontalStrut(10), GBC.std());
226 p.add(keys, GBC.eol().fill(GBC.HORIZONTAL));
227
228 final AutoCompletingComboBox values = new AutoCompletingComboBox();
229 values.setRenderer(new DefaultListCellRenderer() {
230 @Override public Component getListCellRendererComponent(JList list,
231 Object value, int index, boolean isSelected, boolean cellHasFocus){
232 Component c = super.getListCellRendererComponent(list, value,
233 index, isSelected, cellHasFocus);
234 if (c instanceof JLabel) {
235 String str = null;
236 str=((AutoCompletionListItem) value).getValue();
237 if (valueCount.containsKey(objKey)){
238 Map<String, Integer> m=valueCount.get(objKey);
239 if (m.containsKey(str)) {
240 str+="("+m.get(str)+")";
241 c.setFont(c.getFont().deriveFont(Font.ITALIC+Font.BOLD));
242 }
243 }
244 ((JLabel)c).setText(str);
245 }
246 return c;
247 }
248 });
249 values.setEditable(true);
250
251 List<AutoCompletionListItem> valueList = autocomplete.getValues(key);
252 Collections.sort(valueList, defaultACItemComparator);
253
254 values.setPossibleACItems(valueList);
255 Map<String, Integer> m=(Map<String, Integer>)propertyData.getValueAt(row, 1);
256 final String selection= m.size()!=1?tr("<different>"):m.entrySet().iterator().next().getKey();
257 values.setSelectedItem(selection);
258 values.getEditor().setItem(selection);
259 p.add(new JLabel(tr("Value")), GBC.std());
260 p.add(Box.createHorizontalStrut(10), GBC.std());
261 p.add(values, GBC.eol().fill(GBC.HORIZONTAL));
262 addFocusAdapter(row, keys, values, autocomplete);
263
264 final JOptionPane optionPane = new JOptionPane(panel, JOptionPane.QUESTION_MESSAGE, JOptionPane.OK_CANCEL_OPTION) {
265 @Override public void selectInitialValue() {
266 values.requestFocusInWindow();
267 values.getEditor().selectAll();
268 }
269 };
270 final JDialog dlg = optionPane.createDialog(Main.parent, tr("Change values?"));
271 dlg.setModalityType(ModalityType.DOCUMENT_MODAL);
272 Dimension dlgSize = dlg.getSize();
273 if(dlgSize.width > Main.parent.getSize().width) {
274 dlgSize.width = Math.max(250, Main.parent.getSize().width);
275 dlg.setSize(dlgSize);
276 }
277 dlg.setLocationRelativeTo(Main.parent);
278 values.getEditor().addActionListener(new ActionListener() {
279 public void actionPerformed(ActionEvent e) {
280 dlg.setVisible(false);
281 optionPane.setValue(JOptionPane.OK_OPTION);
282 }
283 });
284
285 String oldValue = values.getEditor().getItem().toString();
286 dlg.setVisible(true);
287
288 Object answer = optionPane.getValue();
289 if (answer == null || answer == JOptionPane.UNINITIALIZED_VALUE ||
290 (answer instanceof Integer && (Integer)answer != JOptionPane.OK_OPTION)) {
291 values.getEditor().setItem(oldValue);
292 return;
293 }
294
295 String value = values.getEditor().getItem().toString().trim();
296 // is not Java 1.5
297 //value = java.text.Normalizer.normalize(value, java.text.Normalizer.Form.NFC);
298 if (value.equals("")) {
299 value = null; // delete the key
300 }
301 String newkey = keys.getEditor().getItem().toString().trim();
302 //newkey = java.text.Normalizer.normalize(newkey, java.text.Normalizer.Form.NFC);
303 if (newkey.equals("")) {
304 newkey = key;
305 value = null; // delete the key instead
306 }
307 if (key.equals(newkey) && tr("<different>").equals(value))
308 return;
309 if (key.equals(newkey) || value == null) {
310 Main.main.undoRedo.add(new ChangePropertyCommand(sel, newkey, value));
311 } else {
312 for (OsmPrimitive osm: sel) {
313 if(osm.get(newkey) != null) {
314 ExtendedDialog ed = new ExtendedDialog(
315 Main.parent,
316 tr("Overwrite key"),
317 new String[]{tr("Replace"), tr("Cancel")});
318 ed.setButtonIcons(new String[]{"purge", "cancel"});
319 ed.setContent(tr("You changed the key from ''{0}'' to ''{1}''.\n"
320 + "The new key is already used, overwrite values?", key, newkey));
321 ed.setCancelButton(2);
322 ed.toggleEnable("overwriteEditKey");
323 ed.showDialog();
324
325 if (ed.getValue() != 1) {
326 return;
327 }
328 break;
329 }
330 }
331 Collection<Command> commands=new Vector<Command>();
332 commands.add(new ChangePropertyCommand(sel, key, null));
333 if (value.equals(tr("<different>"))) {
334 HashMap<String, Vector<OsmPrimitive>> map=new HashMap<String, Vector<OsmPrimitive>>();
335 for (OsmPrimitive osm: sel) {
336 String val=osm.get(key);
337 if(val != null)
338 {
339 if (map.containsKey(val)) {
340 map.get(val).add(osm);
341 } else {
342 Vector<OsmPrimitive> v = new Vector<OsmPrimitive>();
343 v.add(osm);
344 map.put(val, v);
345 }
346 }
347 }
348 for (Entry<String, Vector<OsmPrimitive>> e: map.entrySet()) {
349 commands.add(new ChangePropertyCommand(e.getValue(), newkey, e.getKey()));
350 }
351 } else {
352 commands.add(new ChangePropertyCommand(sel, newkey, value));
353 }
354 Main.main.undoRedo.add(new SequenceCommand(
355 trn("Change properties of up to {0} object",
356 "Change properties of up to {0} objects", sel.size(), sel.size()),
357 commands));
358 }
359
360 if(!key.equals(newkey)) {
361 for(int i=0; i < propertyTable.getRowCount(); i++)
362 if(propertyData.getValueAt(i, 0).toString().equals(newkey)) {
363 row=i;
364 break;
365 }
366 }
367 propertyTable.changeSelection(row, 0, false, false);
368 }
369
370 /**
371 * This simply fires up an relation editor for the relation shown; everything else
372 * is the editor's business.
373 *
374 * @param row
375 */
376 void membershipEdit(int row) {
377 Relation relation = (Relation)membershipData.getValueAt(row, 0);
378 Main.map.relationListDialog.selectRelation(relation);
379 RelationEditor.getEditor(
380 Main.map.mapView.getEditLayer(),
381 relation,
382 ((MemberInfo) membershipData.getValueAt(row, 1)).role).setVisible(true);
383 }
384
385 private static String lastAddKey = null;
386 private static String lastAddValue = null;
387 /**
388 * Open the add selection dialog and add a new key/value to the table (and
389 * to the dataset, of course).
390 */
391 void add() {
392 Collection<OsmPrimitive> sel = Main.main.getCurrentDataSet().getSelected();
393 if (sel.isEmpty()) return;
394
395 JPanel p = new JPanel(new BorderLayout());
396 p.add(new JLabel("<html>"+trn("This will change up to {0} object.",
397 "This will change up to {0} objects.", sel.size(),sel.size())
398 +"<br><br>"+tr("Please select a key")), BorderLayout.NORTH);
399 final AutoCompletingComboBox keys = new AutoCompletingComboBox();
400 AutoCompletionManager autocomplete = Main.main.getEditLayer().data.getAutoCompletionManager();
401 List<AutoCompletionListItem> keyList = autocomplete.getKeys();
402
403 AutoCompletionListItem itemToSelect = null;
404 // remove the object's tag keys from the list
405 Iterator<AutoCompletionListItem> iter = keyList.iterator();
406 while (iter.hasNext()) {
407 AutoCompletionListItem item = iter.next();
408 if (item.getValue().equals(lastAddKey)) {
409 itemToSelect = item;
410 }
411 for (int i = 0; i < propertyData.getRowCount(); ++i) {
412 if (item.getValue().equals(propertyData.getValueAt(i, 0))) {
413 if (itemToSelect == item)
414 itemToSelect = null;
415 iter.remove();
416 break;
417 }
418 }
419 }
420
421 Collections.sort(keyList, defaultACItemComparator);
422 keys.setPossibleACItems(keyList);
423 keys.setEditable(true);
424
425 p.add(keys, BorderLayout.CENTER);
426
427 JPanel p2 = new JPanel(new BorderLayout());
428 p.add(p2, BorderLayout.SOUTH);
429 p2.add(new JLabel(tr("Please select a value")), BorderLayout.NORTH);
430 final AutoCompletingComboBox values = new AutoCompletingComboBox();
431 values.setEditable(true);
432 p2.add(values, BorderLayout.CENTER);
433 if (itemToSelect != null) {
434 keys.setSelectedItem(itemToSelect);
435 /* don't add single chars, as they are no properly selected */
436 if(lastAddValue != null && lastAddValue.length() > 1)
437 values.setSelectedItem(lastAddValue);
438 }
439
440 FocusAdapter focus = addFocusAdapter(-1, keys, values, autocomplete);
441 // fire focus event in advance or otherwise the popup list will be too small at first
442 focus.focusGained(null);
443
444 JOptionPane pane = new JOptionPane(p, JOptionPane.PLAIN_MESSAGE, JOptionPane.OK_CANCEL_OPTION){
445 @Override public void selectInitialValue() {
446 keys.requestFocusInWindow();
447 keys.getEditor().selectAll();
448 }
449 };
450 JDialog dialog = pane.createDialog(Main.parent, tr("Change values?"));
451 dialog.setModalityType(ModalityType.DOCUMENT_MODAL);
452 dialog.setVisible(true);
453
454 if (!Integer.valueOf(JOptionPane.OK_OPTION).equals(pane.getValue()))
455 return;
456 String key = keys.getEditor().getItem().toString().trim();
457 String value = values.getEditor().getItem().toString().trim();
458 if (value.equals(""))
459 return;
460 lastAddKey = key;
461 lastAddValue = value;
462 Main.main.undoRedo.add(new ChangePropertyCommand(sel, key, value));
463 btnAdd.requestFocusInWindow();
464 }
465
466 /**
467 * @param allData
468 * @param keys
469 * @param values
470 */
471 private FocusAdapter addFocusAdapter(final int row, final AutoCompletingComboBox keys, final AutoCompletingComboBox values, final AutoCompletionManager autocomplete) {
472 // get the combo box' editor component
473 JTextComponent editor = (JTextComponent)values.getEditor()
474 .getEditorComponent();
475 // Refresh the values model when focus is gained
476 FocusAdapter focus = new FocusAdapter() {
477 @Override public void focusGained(FocusEvent e) {
478 String key = keys.getEditor().getItem().toString();
479
480 List<AutoCompletionListItem> valueList = autocomplete.getValues(key);
481 Collections.sort(valueList, defaultACItemComparator);
482
483 values.setPossibleACItems(valueList);
484 objKey=key;
485 }
486 };
487 editor.addFocusListener(focus);
488 return focus;
489 }
490 private String objKey;
491
492 /**
493 * The property data.
494 */
495 private final DefaultTableModel propertyData = new DefaultTableModel() {
496 @Override public boolean isCellEditable(int row, int column) {
497 return false;
498 }
499 @Override public Class<?> getColumnClass(int columnIndex) {
500 return String.class;
501 }
502 };
503
504 /**
505 * The membership data.
506 */
507 private final DefaultTableModel membershipData = new DefaultTableModel() {
508 @Override public boolean isCellEditable(int row, int column) {
509 return false;
510 }
511 @Override public Class<?> getColumnClass(int columnIndex) {
512 return String.class;
513 }
514 };
515
516 /**
517 * The properties list.
518 */
519 private final JTable propertyTable = new JTable(propertyData);
520 private final JTable membershipTable = new JTable(membershipData);
521
522 public JComboBox taggingPresets = new JComboBox();
523
524 /**
525 * The Add/Edit/Delete buttons (needed to be able to disable them)
526 */
527 private final SideButton btnAdd;
528 private final SideButton btnEdit;
529 private final SideButton btnDel;
530 private final PresetListPanel presets = new PresetListPanel();
531
532 private final JLabel selectSth = new JLabel("<html><p>"
533 + tr("Please select the objects you want to change properties for.") + "</p></html>");
534
535 static class MemberInfo {
536 List<RelationMember> role = new ArrayList<RelationMember>();
537 List<Integer> position = new ArrayList<Integer>();
538 private String positionString = null;
539 void add(RelationMember r, Integer p)
540 {
541 role.add(r);
542 position.add(p);
543 }
544 String getPositionString()
545 {
546 if(positionString == null)
547 {
548 Collections.sort(position);
549 positionString = String.valueOf(position.get(0));
550 int cnt = 0;
551 int last = position.get(0);
552 for(int i = 1; i < position.size(); ++i) {
553 int cur = position.get(i);
554 if(cur == last+1) {
555 ++cnt;
556 } else {
557 if(cnt == 1) {
558 positionString += ","+String.valueOf(last);
559 } else if(cnt > 1) {
560 positionString += "-"+String.valueOf(last);
561 }
562 positionString += "-"+String.valueOf(cur);
563 cnt = 0;
564 }
565 last = cur;
566 }
567 if(cnt == 1) {
568 positionString += ","+String.valueOf(last);
569 } else if(cnt > 1) {
570 positionString += "-"+String.valueOf(last);
571 }
572 }
573 if(positionString.length() > 20) {
574 positionString = positionString.substring(0,17)+"...";
575 }
576 return positionString;
577 }
578 }
579
580 /**
581 * Create a new PropertiesDialog
582 */
583 public PropertiesDialog(MapFrame mapFrame) {
584 super(tr("Properties/Memberships"), "propertiesdialog", tr("Properties for selected objects."),
585 Shortcut.registerShortcut("subwindow:properties", tr("Toggle: {0}", tr("Properties/Memberships")), KeyEvent.VK_P,
586 Shortcut.GROUP_LAYER, Shortcut.SHIFT_DEFAULT), 150, true);
587
588 // setting up the properties table
589 propertyData.setColumnIdentifiers(new String[]{tr("Key"),tr("Value")});
590 propertyTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
591 propertyTable.getTableHeader().setReorderingAllowed(false);
592 propertyTable.addMouseListener(new PopupMenuLauncher() {
593 @Override
594 public void launch(MouseEvent evt) {
595 Point p = evt.getPoint();
596 int row = propertyTable.rowAtPoint(p);
597 if (row > -1) {
598 propertyTable.changeSelection(row, 0, false, false);
599 JPopupMenu menu = new JPopupMenu();
600 menu.add(helpAction);
601 menu.show(propertyTable, p.x, p.y-3);
602 }
603 }
604 });
605
606 propertyTable.getColumnModel().getColumn(1).setCellRenderer(new DefaultTableCellRenderer(){
607 @Override public Component getTableCellRendererComponent(JTable table, Object value,
608 boolean isSelected, boolean hasFocus, int row, int column) {
609 Component c = super.getTableCellRendererComponent(table, value, isSelected, false, row, column);
610 if (value == null)
611 return this;
612 if (c instanceof JLabel) {
613 String str = null;
614 if (value instanceof String) {
615 str = (String) value;
616 } else if (value instanceof Map<?, ?>) {
617 Map<?, ?> v = (Map<?, ?>) value;
618 if (v.size() != 1) {
619 str=tr("<different>");
620 c.setFont(c.getFont().deriveFont(Font.ITALIC));
621 } else {
622 final Map.Entry<?, ?> entry = v.entrySet().iterator().next();
623 str = (String) entry.getKey();
624 }
625 }
626 ((JLabel)c).setText(str);
627 }
628 return c;
629 }
630 });
631
632 // setting up the membership table
633
634 membershipData.setColumnIdentifiers(new String[]{tr("Member Of"),tr("Role"),tr("Position")});
635 membershipTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
636 membershipTable.addMouseListener(new PopupMenuLauncher() {
637 @Override
638 public void launch(MouseEvent evt) {
639 Point p = evt.getPoint();
640 int row = membershipTable.rowAtPoint(p);
641 if (row > -1) {
642 membershipTable.changeSelection(row, 0, false, false);
643 JPopupMenu menu = new JPopupMenu();
644 Relation relation = (Relation)membershipData.getValueAt(row, 0);
645 menu.add(new SelectRelationAction(relation, true));
646 menu.add(new SelectRelationAction(relation, false));
647 menu.add(new SelectRelationMembersAction(relation));
648 menu.add(new DownloadIncompleteMembersAction(relation));
649 menu.addSeparator();
650 menu.add(helpAction);
651 menu.show(membershipTable, p.x, p.y-3);
652 }
653 }
654 });
655
656 TableColumnModel mod = membershipTable.getColumnModel();
657 membershipTable.getTableHeader().setReorderingAllowed(false);
658 mod.getColumn(0).setCellRenderer(new DefaultTableCellRenderer() {
659 @Override public Component getTableCellRendererComponent(JTable table, Object value,
660 boolean isSelected, boolean hasFocus, int row, int column) {
661 Component c = super.getTableCellRendererComponent(table, value, isSelected, false, row, column);
662 if (value == null)
663 return this;
664 if (c instanceof JLabel) {
665 JLabel label = (JLabel)c;
666 Relation r = (Relation)value;
667 label.setText(r.getDisplayName(DefaultNameFormatter.getInstance()));
668 if (r.isDisabledAndHidden()) {
669 label.setFont(label.getFont().deriveFont(Font.ITALIC));
670 }
671 }
672 return c;
673 }
674 });
675
676 mod.getColumn(1).setCellRenderer(new DefaultTableCellRenderer() {
677 @Override public Component getTableCellRendererComponent(JTable table, Object value,
678 boolean isSelected, boolean hasFocus, int row, int column) {
679 if (value == null)
680 return this;
681 Component c = super.getTableCellRendererComponent(table, value, isSelected, false, row, column);
682 boolean isDisabledAndHidden = (((Relation)table.getValueAt(row, 0))).isDisabledAndHidden();
683 if (c instanceof JLabel) {
684 JLabel label = (JLabel)c;
685 MemberInfo col = (MemberInfo) value;
686
687 String text = null;
688 for (RelationMember r : col.role) {
689 if (text == null) {
690 text = r.getRole();
691 }
692 else if (!text.equals(r.getRole())) {
693 text = tr("<different>");
694 break;
695 }
696 }
697
698 label.setText(text);
699 if (isDisabledAndHidden) {
700 label.setFont(label.getFont().deriveFont(Font.ITALIC));
701 }
702 }
703 return c;
704 }
705 });
706
707 mod.getColumn(2).setCellRenderer(new DefaultTableCellRenderer() {
708 @Override public Component getTableCellRendererComponent(JTable table, Object value,
709 boolean isSelected, boolean hasFocus, int row, int column) {
710 Component c = super.getTableCellRendererComponent(table, value, isSelected, false, row, column);
711 boolean isDisabledAndHidden = (((Relation)table.getValueAt(row, 0))).isDisabledAndHidden();
712 if (c instanceof JLabel) {
713 JLabel label = (JLabel)c;
714 label.setText(((MemberInfo) table.getValueAt(row, 1)).getPositionString());
715 if (isDisabledAndHidden) {
716 label.setFont(label.getFont().deriveFont(Font.ITALIC));
717 }
718 }
719 return c;
720 }
721 });
722 mod.getColumn(2).setPreferredWidth(20);
723 mod.getColumn(1).setPreferredWidth(40);
724 mod.getColumn(0).setPreferredWidth(200);
725
726 // combine both tables and wrap them in a scrollPane
727 JPanel bothTables = new JPanel();
728 boolean top = Main.pref.getBoolean("properties.presets.top", true);
729 bothTables.setLayout(new GridBagLayout());
730 if(top) {
731 bothTables.add(presets, GBC.std().fill(GBC.HORIZONTAL).insets(5, 2, 5, 2).anchor(GBC.NORTHWEST));
732 double epsilon = Double.MIN_VALUE; // need to set a weight or else anchor value is ignored
733 bothTables.add(pluginHook, GBC.eol().insets(0,1,1,1).anchor(GBC.NORTHEAST).weight(epsilon, epsilon));
734 }
735 bothTables.add(selectSth, GBC.eol().fill().insets(10, 10, 10, 10));
736 bothTables.add(propertyTable.getTableHeader(), GBC.eol().fill(GBC.HORIZONTAL));
737 bothTables.add(propertyTable, GBC.eol().fill(GBC.BOTH));
738 bothTables.add(membershipTable.getTableHeader(), GBC.eol().fill(GBC.HORIZONTAL));
739 bothTables.add(membershipTable, GBC.eol().fill(GBC.BOTH));
740 if(!top) {
741 bothTables.add(presets, GBC.eol().fill(GBC.HORIZONTAL).insets(5, 2, 5, 2));
742 }
743
744 DblClickWatch dblClickWatch = new DblClickWatch();
745 propertyTable.addMouseListener(dblClickWatch);
746 membershipTable.addMouseListener(dblClickWatch);
747 JScrollPane scrollPane = new JScrollPane(bothTables);
748 scrollPane.addMouseListener(dblClickWatch);
749 add(scrollPane, BorderLayout.CENTER);
750
751 selectSth.setPreferredSize(scrollPane.getSize());
752 presets.setSize(scrollPane.getSize());
753
754 JPanel buttonPanel = getButtonPanel(3);
755
756 // -- add action and shortcut
757 this.btnAdd = new SideButton(addAction);
758 btnAdd.setFocusable(true);
759 buttonPanel.add(this.btnAdd);
760 btnAdd.getInputMap(JComponent.WHEN_FOCUSED).put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "onEnter");
761 btnAdd.getActionMap().put("onEnter", addAction);
762
763 // -- edit action
764 //
765 EditAction editAction = new EditAction();
766 propertyTable.getSelectionModel().addListSelectionListener(editAction);
767 membershipTable.getSelectionModel().addListSelectionListener(editAction);
768 this.btnEdit = new SideButton(editAction);
769 buttonPanel.add(this.btnEdit);
770
771 // -- delete action
772 //
773 DeleteAction deleteAction = new DeleteAction();
774 this.btnDel = new SideButton(deleteAction);
775 membershipTable.getSelectionModel().addListSelectionListener(deleteAction);
776 propertyTable.getSelectionModel().addListSelectionListener(deleteAction);
777 getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(
778 KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0),"delete"
779 );
780 getActionMap().put("delete", deleteAction);
781 buttonPanel.add(this.btnDel);
782 add(buttonPanel, BorderLayout.SOUTH);
783
784 // -- help action
785 //
786 getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(
787 KeyStroke.getKeyStroke(KeyEvent.VK_F1, 0), "onHelp");
788 getActionMap().put("onHelp", helpAction);
789 }
790
791 @Override public void setVisible(boolean b) {
792 super.setVisible(b);
793 if (b && Main.main.getCurrentDataSet() != null) {
794 selectionChanged(Main.main.getCurrentDataSet().getSelected());
795 }
796 }
797
798 private int findRow(TableModel model, Object value) {
799 for (int i=0; i<model.getRowCount(); i++) {
800 if (model.getValueAt(i, 0).equals(value))
801 return i;
802 }
803 return -1;
804 }
805
806 private PresetHandler presetHandler = new PresetHandler() {
807
808 @Override
809 public void updateTags(List<Tag> tags) {
810 Command command = TaggingPreset.createCommand(getSelection(), tags);
811 if (command != null) {
812 Main.main.undoRedo.add(command);
813 }
814 }
815
816 @Override
817 public Collection<OsmPrimitive> getSelection() {
818 if (Main.main == null) return null;
819 if (Main.main.getCurrentDataSet() == null) return null;
820
821 return Main.main.getCurrentDataSet().getSelected();
822 }
823 };
824
825 public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) {
826 if (!isVisible())
827 return;
828 if (propertyTable == null)
829 return; // selection changed may be received in base class constructor before init
830 if (propertyTable.getCellEditor() != null) {
831 propertyTable.getCellEditor().cancelCellEditing();
832 }
833
834 String selectedTag = null;
835 Relation selectedRelation = null;
836 if (propertyTable.getSelectedRowCount() == 1) {
837 selectedTag = (String)propertyData.getValueAt(propertyTable.getSelectedRow(), 0);
838 }
839 if (membershipTable.getSelectedRowCount() == 1) {
840 selectedRelation = (Relation)membershipData.getValueAt(membershipTable.getSelectedRow(), 0);
841 }
842
843 // re-load property data
844 propertyData.setRowCount(0);
845 int nodes = 0;
846 int ways = 0;
847 int relations = 0;
848 int closedways = 0;
849
850 Map<String, Integer> keyCount = new HashMap<String, Integer>();
851 valueCount.clear();
852 for (OsmPrimitive osm : newSelection) {
853 if(osm instanceof Node) {
854 ++nodes;
855 } else if(osm instanceof Relation) {
856 ++relations;
857 } else if(((Way)osm).isClosed()) {
858 ++closedways;
859 } else {
860 ++ways;
861 }
862 for (String key: osm.keySet()) {
863 String value = osm.get(key);
864 keyCount.put(key, keyCount.containsKey(key) ? keyCount.get(key) + 1 : 1);
865 if (valueCount.containsKey(key)) {
866 Map<String, Integer> v = valueCount.get(key);
867 v.put(value, v.containsKey(value)? v.get(value) + 1 : 1 );
868 } else {
869 TreeMap<String,Integer> v = new TreeMap<String, Integer>();
870 v.put(value, 1);
871 valueCount.put(key, v);
872 }
873 }
874 }
875 for (Entry<String, Map<String, Integer>> e : valueCount.entrySet()) {
876 int count=0;
877 for (Entry<String, Integer> e1: e.getValue().entrySet()) {
878 count+=e1.getValue();
879 }
880 if (count < newSelection.size()) {
881 e.getValue().put("", newSelection.size()-count);
882 }
883 propertyData.addRow(new Object[]{e.getKey(), e.getValue()});
884 }
885
886 membershipData.setRowCount(0);
887
888 Map<Relation, MemberInfo> roles = new HashMap<Relation, MemberInfo>();
889 for (OsmPrimitive primitive: newSelection) {
890 for (OsmPrimitive ref: primitive.getReferrers()) {
891 if (ref instanceof Relation && !ref.isIncomplete() && !ref.isDeleted()) {
892 Relation r = (Relation) ref;
893 MemberInfo mi = roles.get(r);
894 if(mi == null) {
895 mi = new MemberInfo();
896 }
897 roles.put(r, mi);
898 int i = 1;
899 for (RelationMember m : r.getMembers()) {
900 if (m.getMember() == primitive) {
901 mi.add(m, i);
902 }
903 ++i;
904 }
905 }
906 }
907 }
908
909 List<Relation> sortedRelations = new ArrayList<Relation>(roles.keySet());
910 Collections.sort(sortedRelations, new Comparator<Relation>() {
911 public int compare(Relation o1, Relation o2) {
912 int comp = Boolean.valueOf(o1.isDisabledAndHidden()).compareTo(o2.isDisabledAndHidden());
913 if (comp == 0) {
914 comp = o1.getDisplayName(DefaultNameFormatter.getInstance()).compareTo(o2.getDisplayName(DefaultNameFormatter.getInstance()));
915 }
916 return comp;
917 }}
918 );
919
920 for (Relation r: sortedRelations) {
921 membershipData.addRow(new Object[]{r, roles.get(r)});
922 }
923
924 presets.updatePresets(nodes, ways, relations, closedways, valueCount, presetHandler);
925
926 membershipTable.getTableHeader().setVisible(membershipData.getRowCount() > 0);
927 membershipTable.setVisible(membershipData.getRowCount() > 0);
928
929 boolean hasSelection = !newSelection.isEmpty();
930 boolean hasTags = hasSelection && propertyData.getRowCount() > 0;
931 boolean hasMemberships = hasSelection && membershipData.getRowCount() > 0;
932 btnAdd.setEnabled(hasSelection);
933 btnEdit.setEnabled(hasTags || hasMemberships);
934 btnDel.setEnabled(hasTags || hasMemberships);
935 propertyTable.setVisible(hasTags);
936 propertyTable.getTableHeader().setVisible(hasTags);
937 selectSth.setVisible(!hasSelection);
938 pluginHook.setVisible(hasSelection);
939
940 int selectedIndex;
941 if (selectedTag != null && (selectedIndex = findRow(propertyData, selectedTag)) != -1) {
942 propertyTable.changeSelection(selectedIndex, 0, false, false);
943 } else if (selectedRelation != null && (selectedIndex = findRow(membershipData, selectedRelation)) != -1) {
944 membershipTable.changeSelection(selectedIndex, 0, false, false);
945 } else if(hasTags) {
946 propertyTable.changeSelection(0, 0, false, false);
947 } else if(hasMemberships) {
948 membershipTable.changeSelection(0, 0, false, false);
949 }
950
951 if(propertyData.getRowCount() != 0 || membershipData.getRowCount() != 0) {
952 setTitle(tr("Properties: {0} / Memberships: {1}",
953 propertyData.getRowCount(), membershipData.getRowCount()));
954 } else {
955 setTitle(tr("Properties / Memberships"));
956 }
957 }
958
959 private void updateSelection() {
960 if (Main.main.getCurrentDataSet() == null) {
961 selectionChanged(Collections.<OsmPrimitive>emptyList());
962 } else {
963 selectionChanged(Main.main.getCurrentDataSet().getSelected());
964 }
965 }
966
967 /* ---------------------------------------------------------------------------------- */
968 /* EditLayerChangeListener */
969 /* ---------------------------------------------------------------------------------- */
970 public void editLayerChanged(OsmDataLayer oldLayer, OsmDataLayer newLayer) {
971 updateSelection();
972 }
973
974 public void processDatasetEvent(AbstractDatasetChangedEvent event) {
975 updateSelection();
976 }
977
978 class DeleteAction extends AbstractAction implements ListSelectionListener {
979
980 protected void deleteProperty(int row){
981 String key = propertyData.getValueAt(row, 0).toString();
982
983 String nextKey = null;
984 int rowCount = propertyData.getRowCount();
985 if (rowCount > 1) {
986 nextKey = (String)propertyData.getValueAt((row + 1 < rowCount ? row + 1 : row - 1), 0);
987 }
988
989 Collection<OsmPrimitive> sel = Main.main.getCurrentDataSet().getSelected();
990 Main.main.undoRedo.add(new ChangePropertyCommand(sel, key, null));
991
992 membershipTable.clearSelection();
993 if (nextKey != null) {
994 propertyTable.changeSelection(findRow(propertyData, nextKey), 0, false, false);
995 }
996 }
997
998 protected void deleteFromRelation(int row) {
999 Relation cur = (Relation)membershipData.getValueAt(row, 0);
1000
1001 Relation nextRelation = null;
1002 int rowCount = membershipTable.getRowCount();
1003 if (rowCount > 1) {
1004 nextRelation = (Relation)membershipData.getValueAt((row + 1 < rowCount ? row + 1 : row - 1), 0);
1005 }
1006
1007 ExtendedDialog ed = new ExtendedDialog(Main.parent,
1008 tr("Change relation"),
1009 new String[] {tr("Delete from relation"), tr("Cancel")});
1010 ed.setButtonIcons(new String[] {"dialogs/delete.png", "cancel.png"});
1011 ed.setContent(tr("Really delete selection from relation {0}?", cur.getDisplayName(DefaultNameFormatter.getInstance())));
1012 ed.toggleEnable("delete_from_relation");
1013 ed.showDialog();
1014
1015 if(ed.getValue() != 1)
1016 return;
1017
1018 Relation rel = new Relation(cur);
1019 Collection<OsmPrimitive> sel = Main.main.getCurrentDataSet().getSelected();
1020 for (OsmPrimitive primitive: sel) {
1021 rel.removeMembersFor(primitive);
1022 }
1023 Main.main.undoRedo.add(new ChangeCommand(cur, rel));
1024
1025 propertyTable.clearSelection();
1026 if (nextRelation != null) {
1027 membershipTable.changeSelection(findRow(membershipData, nextRelation), 0, false, false);
1028 }
1029 }
1030
1031 public DeleteAction() {
1032 putValue(NAME, tr("Delete"));
1033 putValue(SHORT_DESCRIPTION, tr("Delete the selected key in all objects"));
1034 putValue(SMALL_ICON, ImageProvider.get("dialogs", "delete"));
1035 Shortcut s = Shortcut.registerShortcut("properties:delete", tr("Delete Properties"), KeyEvent.VK_Q,
1036 Shortcut.GROUP_MNEMONIC);
1037 putValue(MNEMONIC_KEY, (int) KeyEvent.getKeyText(s.getAssignedKey()).charAt(0));
1038 updateEnabledState();
1039 }
1040
1041 public void actionPerformed(ActionEvent e) {
1042 if (propertyTable.getSelectedRowCount() >0 ) {
1043 int row = propertyTable.getSelectedRow();
1044 deleteProperty(row);
1045 } else if (membershipTable.getSelectedRowCount() > 0) {
1046 int row = membershipTable.getSelectedRow();
1047 deleteFromRelation(row);
1048 }
1049 }
1050
1051 protected void updateEnabledState() {
1052 setEnabled(
1053 PropertiesDialog.this.propertyTable.getSelectedRowCount() >0
1054 || PropertiesDialog.this.membershipTable.getSelectedRowCount() > 0
1055 );
1056 }
1057
1058 public void valueChanged(ListSelectionEvent e) {
1059 updateEnabledState();
1060 }
1061 }
1062
1063 class AddAction extends AbstractAction {
1064 public AddAction() {
1065 putValue(NAME, tr("Add"));
1066 putValue(SHORT_DESCRIPTION, tr("Add a new key/value pair to all objects"));
1067 putValue(SMALL_ICON, ImageProvider.get("dialogs", "add"));
1068 }
1069
1070 public void actionPerformed(ActionEvent e) {
1071 add();
1072 }
1073 }
1074
1075 class EditAction extends AbstractAction implements ListSelectionListener {
1076 public EditAction() {
1077 putValue(NAME, tr("Edit"));
1078 putValue(SHORT_DESCRIPTION, tr("Edit the value of the selected key for all objects"));
1079 putValue(SMALL_ICON, ImageProvider.get("dialogs", "edit"));
1080 updateEnabledState();
1081 }
1082
1083 public void actionPerformed(ActionEvent e) {
1084 if (!isEnabled())
1085 return;
1086 if (propertyTable.getSelectedRowCount() == 1) {
1087 int row = propertyTable.getSelectedRow();
1088 propertyEdit(row);
1089 } else if (membershipTable.getSelectedRowCount() == 1) {
1090 int row = membershipTable.getSelectedRow();
1091 membershipEdit(row);
1092 }
1093 }
1094
1095 protected void updateEnabledState() {
1096 setEnabled(
1097 propertyTable.getSelectedRowCount() == 1
1098 ^ membershipTable.getSelectedRowCount() == 1
1099 );
1100 }
1101
1102 public void valueChanged(ListSelectionEvent e) {
1103 updateEnabledState();
1104 }
1105 }
1106
1107 class HelpAction extends AbstractAction {
1108 public HelpAction() {
1109 putValue(NAME, tr("Go to OSM wiki for tag help (F1)"));
1110 putValue(SHORT_DESCRIPTION, tr("Launch browser with wiki help for selected object"));
1111 putValue(SMALL_ICON, ImageProvider.get("dialogs", "search"));
1112 }
1113
1114 public void actionPerformed(ActionEvent e) {
1115 try {
1116 String base = Main.pref.get("url.openstreetmap-wiki", "http://wiki.openstreetmap.org/wiki/");
1117 String lang = LanguageInfo.getWikiLanguagePrefix();
1118 final List<URI> uris = new ArrayList<URI>();
1119 int row;
1120 if (propertyTable.getSelectedRowCount() == 1) {
1121 row = propertyTable.getSelectedRow();
1122 String key = URLEncoder.encode(propertyData.getValueAt(row, 0).toString(), "UTF-8");
1123 String val = URLEncoder.encode(
1124 ((Map<String,Integer>)propertyData.getValueAt(row, 1))
1125 .entrySet().iterator().next().getKey(), "UTF-8"
1126 );
1127
1128 uris.add(new URI(String.format("%s%sTag:%s=%s", base, lang, key, val)));
1129 uris.add(new URI(String.format("%sTag:%s=%s", base, key, val)));
1130 uris.add(new URI(String.format("%s%sKey:%s", base, lang, key)));
1131 uris.add(new URI(String.format("%sKey:%s", base, key)));
1132 uris.add(new URI(String.format("%s%sMap_Features", base, lang)));
1133 uris.add(new URI(String.format("%sMap_Features", base)));
1134 } else if (membershipTable.getSelectedRowCount() == 1) {
1135 row = membershipTable.getSelectedRow();
1136 String type = URLEncoder.encode(
1137 ((Relation)membershipData.getValueAt(row, 0)).get("type"), "UTF-8"
1138 );
1139
1140 if (type != null && !type.equals("")) {
1141 uris.add(new URI(String.format("%s%sRelation:%s", base, lang, type)));
1142 uris.add(new URI(String.format("%sRelation:%s", base, type)));
1143 }
1144
1145 uris.add(new URI(String.format("%s%sRelations", base, lang)));
1146 uris.add(new URI(String.format("%sRelations", base)));
1147 } else {
1148 // give the generic help page, if more than one element is selected
1149 uris.add(new URI(String.format("%s%sMap_Features", base, lang)));
1150 uris.add(new URI(String.format("%sMap_Features", base)));
1151 }
1152
1153 Main.worker.execute(new Runnable(){
1154 public void run() {
1155 try {
1156 // find a page that actually exists in the wiki
1157 HttpURLConnection conn;
1158 for (URI u : uris) {
1159 conn = (HttpURLConnection) u.toURL().openConnection();
1160 conn.setConnectTimeout(5000);
1161
1162 if (conn.getResponseCode() != 200) {
1163 System.out.println("INFO: " + u + " does not exist");
1164 conn.disconnect();
1165 } else {
1166 int osize = conn.getContentLength();
1167 conn.disconnect();
1168
1169 conn = (HttpURLConnection) new URI(u.toString()
1170 .replace("=", "%3D") /* do not URLencode whole string! */
1171 .replaceFirst("/wiki/", "/w/index.php?redirect=no&title=")
1172 ).toURL().openConnection();
1173 conn.setConnectTimeout(5000);
1174
1175 /* redirect pages have different content length, but retrieving a "nonredirect"
1176 * page using index.php and the direct-link method gives slightly different
1177 * content lengths, so we have to be fuzzy.. (this is UGLY, recode if u know better)
1178 */
1179 if (Math.abs(conn.getContentLength() - osize) > 200) {
1180 System.out.println("INFO: " + u + " is a mediawiki redirect");
1181 conn.disconnect();
1182 } else {
1183 System.out.println("INFO: browsing to " + u);
1184 conn.disconnect();
1185
1186 OpenBrowser.displayUrl(u.toString());
1187 break;
1188 }
1189 }
1190 }
1191 } catch (Exception e) {
1192 e.printStackTrace();
1193 }
1194 }
1195 });
1196 } catch (Exception e1) {
1197 e1.printStackTrace();
1198 }
1199 }
1200 }
1201
1202 static class SelectRelationAction extends AbstractAction {
1203 boolean selectionmode;
1204 Relation relation;
1205 public SelectRelationAction(Relation r, boolean select) {
1206 selectionmode = select;
1207 relation = r;
1208 if(select) {
1209 putValue(NAME, tr("Select relation"));
1210 putValue(SHORT_DESCRIPTION, tr("Select relation in main selection."));
1211 putValue(SMALL_ICON, ImageProvider.get("dialogs", "select"));
1212 } else {
1213 putValue(NAME, tr("Select in relation list"));
1214 putValue(SHORT_DESCRIPTION, tr("Select relation in relation list."));
1215 putValue(SMALL_ICON, ImageProvider.get("dialogs", "relationlist"));
1216 }
1217 }
1218
1219 public void actionPerformed(ActionEvent e) {
1220 if(selectionmode) {
1221 Main.map.mapView.getEditLayer().data.setSelected(relation);
1222 } else {
1223 Main.map.relationListDialog.selectRelation(relation);
1224 Main.map.relationListDialog.unfurlDialog();
1225 }
1226 }
1227 }
1228
1229
1230 /**
1231 * Sets the current selection to the members of selected relation
1232 *
1233 */
1234 class SelectRelationMembersAction extends AbstractAction {
1235 Relation relation;
1236 public SelectRelationMembersAction(Relation r) {
1237 relation = r;
1238 putValue(SHORT_DESCRIPTION,tr("Select the members of selected relation"));
1239 putValue(SMALL_ICON, ImageProvider.get("selectall"));
1240 putValue(NAME, tr("Select members"));
1241 }
1242
1243 public void actionPerformed(ActionEvent e) {
1244 HashSet<OsmPrimitive> members = new HashSet<OsmPrimitive>();
1245 members.addAll(relation.getMemberPrimitives());
1246 Main.map.mapView.getEditLayer().data.setSelected(members);
1247 }
1248
1249 }
1250
1251 /**
1252 * Action for downloading incomplete members of selected relation
1253 *
1254 */
1255 class DownloadIncompleteMembersAction extends AbstractAction {
1256 Relation relation;
1257 public DownloadIncompleteMembersAction(Relation r) {
1258 relation = r;
1259 putValue(SHORT_DESCRIPTION, tr("Download incomplete members of selected relations"));
1260 putValue(SMALL_ICON, ImageProvider.get("dialogs/relation", "downloadincompleteselected"));
1261 putValue(NAME, tr("Download incomplete members"));
1262 }
1263
1264 public Set<OsmPrimitive> buildSetOfIncompleteMembers(Relation r) {
1265 Set<OsmPrimitive> ret = new HashSet<OsmPrimitive>();
1266 ret.addAll(r.getIncompleteMembers());
1267 return ret;
1268 }
1269
1270 public void actionPerformed(ActionEvent e) {
1271 if (!relation.hasIncompleteMembers()) return;
1272 ArrayList<Relation> rels = new ArrayList<Relation>();
1273 rels.add(relation);
1274 Main.worker.submit(new DownloadRelationMemberTask(
1275 rels,
1276 buildSetOfIncompleteMembers(relation),
1277 Main.map.mapView.getEditLayer()
1278 ));
1279 }
1280 }
1281}
Note: See TracBrowser for help on using the repository browser.