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

Last change on this file since 5726 was 5726, checked in by akks, 11 years ago

fix #4828: "Paste value" added to context menu of properties toggle dialog

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