source: osm/applications/editors/josm/plugins/OSMRecPlugin/src/org/openstreetmap/josm/plugins/osmrec/OSMRecToggleDialog.java@ 34539

Last change on this file since 34539 was 34539, checked in by donvip, 6 years ago

update to JOSM 14153

File size: 16.4 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.plugins.osmrec;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.awt.GridBagLayout;
7import java.awt.event.ActionEvent;
8import java.awt.event.KeyEvent;
9import java.awt.event.MouseAdapter;
10import java.awt.event.MouseEvent;
11import java.util.ArrayList;
12import java.util.Arrays;
13import java.util.Collection;
14import java.util.Collections;
15import java.util.Comparator;
16import java.util.HashMap;
17import java.util.HashSet;
18import java.util.List;
19import java.util.Map;
20import java.util.Map.Entry;
21import java.util.Set;
22import java.util.TreeMap;
23
24import javax.swing.JLabel;
25import javax.swing.JPanel;
26import javax.swing.JScrollPane;
27import javax.swing.JTable;
28import javax.swing.event.ListSelectionEvent;
29import javax.swing.event.ListSelectionListener;
30import javax.swing.table.DefaultTableModel;
31import javax.swing.table.TableModel;
32
33import org.openstreetmap.josm.actions.JosmAction;
34import org.openstreetmap.josm.data.osm.DataSelectionListener;
35import org.openstreetmap.josm.data.osm.DefaultNameFormatter;
36import org.openstreetmap.josm.data.osm.IRelation;
37import org.openstreetmap.josm.data.osm.OsmDataManager;
38import org.openstreetmap.josm.data.osm.OsmPrimitive;
39import org.openstreetmap.josm.data.osm.Relation;
40import org.openstreetmap.josm.data.osm.RelationMember;
41import org.openstreetmap.josm.data.osm.Tag;
42import org.openstreetmap.josm.data.osm.event.AbstractDatasetChangedEvent;
43import org.openstreetmap.josm.data.osm.event.DataSetListenerAdapter;
44import org.openstreetmap.josm.gui.MainApplication;
45import org.openstreetmap.josm.gui.SideButton;
46import org.openstreetmap.josm.gui.dialogs.ToggleDialog;
47import org.openstreetmap.josm.gui.dialogs.relation.RelationEditor;
48import org.openstreetmap.josm.tools.Shortcut;
49
50/**
51 * This class is a modification of the PropertiesDialog for the OSMRec.
52 *
53 *
54 * This dialog displays the tags of the current selected primitives.
55 *
56 * If no object is selected, the dialog list is empty.
57 * If only one is selected, all tags of this object are selected.
58 * If more than one object are selected, the sum of all tags are displayed. If the
59 * different objects share the same tag, the shared value is displayed. If they have
60 * different values, all of them are put in a combo box and the string "<different>"
61 * is displayed in italic.
62 *
63 * Below the list, the user can click on an add, modify and delete tag button to
64 * edit the table selection value.
65 *
66 * The command is applied to all selected entries.
67 *
68 * @author imi
69 * @author nkaragiannakis
70 */
71public class OSMRecToggleDialog extends ToggleDialog
72implements DataSelectionListener, DataSetListenerAdapter.Listener {
73
74 /**
75 * The tag data of selected objects.
76 */
77 private final DefaultTableModel tagData = new ReadOnlyTableModel();
78
79 /**
80 * The membership data of selected objects.
81 */
82 private final DefaultTableModel membershipData = new ReadOnlyTableModel();
83
84 /**
85 * The tags table.
86 */
87 private final JTable tagTable = new JTable(tagData);
88
89 /**
90 * The membership table.
91 */
92 private final JTable membershipTable = new JTable(membershipData);
93
94 /** JPanel containing both previous tables */
95 private final JPanel bothTables = new JPanel();
96
97 private final transient Map<String, Map<String, Integer>> valueCount = new TreeMap<>();
98 /**
99 * This sub-object is responsible for all adding and editing of tags
100 */
101 private final transient OSMRecPluginHelper editHelper = new OSMRecPluginHelper(tagData, valueCount);
102
103 private final AddAction addAction = new AddAction();
104 private final EditActionTrain editAction = new EditActionTrain();
105 // private final DeleteAction deleteAction = new DeleteAction();
106 // private final JosmAction[] josmActions = new JosmAction[]{addAction, editAction, deleteAction};
107
108 /**
109 * The Add button (needed to be able to disable it)
110 */
111 private final SideButton btnAdd = new SideButton(addAction);
112 /**
113 * The Edit button (needed to be able to disable it)
114 */
115 private final SideButton btnEdit = new SideButton(editAction);
116
117 /**
118 * Text to display when nothing selected.
119 */
120 private final JLabel selectSth = new JLabel("<html><p>"
121 + tr("Select objects or create new objects and get recommendation.") + "</p></html>");
122
123 // <editor-fold defaultstate="collapsed" desc="Dialog construction and helper methods">
124
125 /**
126 * Create a new OSMRecToggleDialog
127 */
128 public OSMRecToggleDialog() {
129 super(tr("Tags/Memberships"), "propertiesdialog", tr("Tags for selected objects."),
130 Shortcut.registerShortcut("subwindow:properties", tr("Toggle: {0}", tr("Tags/Memberships")), KeyEvent.VK_P,
131 Shortcut.ALT_SHIFT), 150, true);
132
133 System.out.println("cleaning test..");
134 bothTables.setLayout(new GridBagLayout());
135 bothTables.setVisible(false); //my
136 // Let the actions know when selection in the tables change
137 tagTable.getSelectionModel().addListSelectionListener(editAction);
138 membershipTable.getSelectionModel().addListSelectionListener(editAction);
139
140 JScrollPane scrollPane = (JScrollPane) createLayout(bothTables, true,
141 Arrays.asList(this.btnAdd, this.btnEdit));
142
143 MouseClickWatch mouseClickWatch = new MouseClickWatch();
144 tagTable.addMouseListener(mouseClickWatch);
145 membershipTable.addMouseListener(mouseClickWatch);
146 scrollPane.addMouseListener(mouseClickWatch);
147 editHelper.loadTagsIfNeeded();
148
149 }
150
151 /**
152 * This simply fires up an {@link RelationEditor} for the relation shown; everything else
153 * is the editor's business.
154 *
155 * @param row position
156 */
157 private void editMembership(int row) {
158 Relation relation = (Relation) membershipData.getValueAt(row, 0);
159 MainApplication.getMap().relationListDialog.selectRelation(relation);
160 }
161
162 private int findRow(TableModel model, Object value) {
163 for (int i = 0; i < model.getRowCount(); i++) {
164 if (model.getValueAt(i, 0).equals(value))
165 return i;
166 }
167 return -1;
168 }
169
170 /**
171 * Update selection status, call @{link #selectionChanged} function.
172 */
173 private void updateSelection() {
174 // Parameter is ignored in this class
175 selectionChanged(null);
176 }
177
178 // </editor-fold>
179
180 // <editor-fold defaultstate="collapsed" desc="Event listeners methods">
181
182 @Override
183 public void selectionChanged(SelectionChangeEvent event) {
184 if (tagTable == null)
185 return; // selection changed may be received in base class constructor before init
186 if (tagTable.getCellEditor() != null) {
187 tagTable.getCellEditor().cancelCellEditing();
188 }
189
190 // Ignore parameter as we do not want to operate always on real selection here, especially in draw mode
191 Collection<OsmPrimitive> newSel = OsmDataManager.getInstance().getInProgressSelection();
192 if (newSel == null) {
193 newSel = Collections.<OsmPrimitive>emptyList();
194 }
195
196 String selectedTag;
197 Relation selectedRelation = null;
198 selectedTag = editHelper.getChangedKey(); // select last added or last edited key by default
199 if (selectedTag == null && tagTable.getSelectedRowCount() == 1) {
200 selectedTag = (String) tagData.getValueAt(tagTable.getSelectedRow(), 0);
201 }
202 if (membershipTable.getSelectedRowCount() == 1) {
203 selectedRelation = (Relation) membershipData.getValueAt(membershipTable.getSelectedRow(), 0);
204 }
205
206 // re-load tag data
207 tagData.setRowCount(0);
208
209 final Map<String, String> tags = new HashMap<>();
210 valueCount.clear();
211 for (Entry<String, Map<String, Integer>> e : valueCount.entrySet()) {
212 int count = 0;
213 for (Entry<String, Integer> e1 : e.getValue().entrySet()) {
214 count += e1.getValue();
215 }
216 if (count < newSel.size()) {
217 e.getValue().put("", newSel.size() - count);
218 }
219 tagData.addRow(new Object[]{e.getKey(), e.getValue()});
220 tags.put(e.getKey(), e.getValue().size() == 1
221 ? e.getValue().keySet().iterator().next() : tr("<different>"));
222 }
223
224 membershipData.setRowCount(0);
225
226 Map<Relation, MemberInfo> roles = new HashMap<>();
227 for (OsmPrimitive primitive: newSel) {
228 for (OsmPrimitive ref: primitive.getReferrers(true)) {
229 if (ref instanceof Relation && !ref.isIncomplete() && !ref.isDeleted()) {
230 Relation r = (Relation) ref;
231 MemberInfo mi = roles.get(r);
232 if (mi == null) {
233 mi = new MemberInfo();
234 }
235 roles.put(r, mi);
236 int i = 1;
237 for (RelationMember m : r.getMembers()) {
238 if (m.getMember() == primitive) {
239 mi.add(m, i);
240 }
241 ++i;
242 }
243 }
244 }
245 }
246
247 List<Relation> sortedRelations = new ArrayList<>(roles.keySet());
248 Collections.sort(sortedRelations, new Comparator<Relation>() {
249 @Override public int compare(Relation o1, Relation o2) {
250 int comp = Boolean.valueOf(o1.isDisabledAndHidden()).compareTo(o2.isDisabledAndHidden());
251 return comp != 0 ? comp : DefaultNameFormatter.getInstance().getRelationComparator().compare(o1, o2);
252 } });
253
254 for (Relation r: sortedRelations) {
255 membershipData.addRow(new Object[]{r, roles.get(r)});
256 }
257
258 membershipTable.getTableHeader().setVisible(membershipData.getRowCount() > 0);
259 membershipTable.setVisible(membershipData.getRowCount() > 0);
260
261 boolean hasSelection = !newSel.isEmpty();
262 boolean hasTags = hasSelection && tagData.getRowCount() > 0;
263 boolean hasMemberships = hasSelection && membershipData.getRowCount() > 0;
264
265 addAction.setEnabled(hasSelection);
266 //editAction.setEnabled(hasTags || hasMemberships);
267 editAction.setEnabled(true);
268 tagTable.setVisible(hasTags);
269 tagTable.getTableHeader().setVisible(hasTags);
270 selectSth.setVisible(!hasSelection);
271
272 int selectedIndex;
273 if (selectedTag != null && (selectedIndex = findRow(tagData, selectedTag)) != -1) {
274 tagTable.changeSelection(selectedIndex, 0, false, false);
275 } else if (selectedRelation != null && (selectedIndex = findRow(membershipData, selectedRelation)) != -1) {
276 membershipTable.changeSelection(selectedIndex, 0, false, false);
277 } else if (hasTags) {
278 tagTable.changeSelection(0, 0, false, false);
279 } else if (hasMemberships) {
280 membershipTable.changeSelection(0, 0, false, false);
281 }
282 }
283
284 @Override
285 public void processDatasetEvent(AbstractDatasetChangedEvent event) {
286 updateSelection();
287 }
288
289 // </editor-fold>
290
291 // <editor-fold defaultstate="collapsed" desc="Methods that are called by plugins to extend fuctionality ">
292
293
294 /**
295 * Returns the selected tag.
296 * @return The current selected tag
297 */
298 @SuppressWarnings("unchecked")
299 public Tag getSelectedProperty() {
300 int row = tagTable.getSelectedRow();
301 if (row == -1) return null;
302 Map<String, Integer> map = (TreeMap<String, Integer>) tagData.getValueAt(row, 1);
303 return new Tag(
304 tagData.getValueAt(row, 0).toString(),
305 map.size() > 1 ? "" : map.keySet().iterator().next());
306 }
307
308 /**
309 * Returns the selected relation membership.
310 * @return The current selected relation membership
311 */
312 public IRelation<?> getSelectedMembershipRelation() {
313 int row = membershipTable.getSelectedRow();
314 return row > -1 ? (IRelation<?>) membershipData.getValueAt(row, 0) : null;
315 }
316
317 // </editor-fold>
318
319 /**
320 * Class that watches for mouse clicks
321 * @author imi
322 */
323 public class MouseClickWatch extends MouseAdapter {
324 @Override
325 public void mouseClicked(MouseEvent e) {
326 if (e.getClickCount() < 2) {
327 // single click, clear selection in other table not clicked in
328 if (e.getSource() == tagTable) {
329 membershipTable.clearSelection();
330 } else if (e.getSource() == membershipTable) {
331 tagTable.clearSelection();
332 }
333 } else if (e.getSource() == tagTable) {
334 // double click, edit or add tag
335 int row = tagTable.rowAtPoint(e.getPoint());
336 if (row > -1) {
337 boolean focusOnKey = tagTable.columnAtPoint(e.getPoint()) == 0;
338 editHelper.editTag(row, focusOnKey);
339 } else {
340 editHelper.addTag();
341 }
342 } else if (e.getSource() == membershipTable) {
343 int row = membershipTable.rowAtPoint(e.getPoint());
344 if (row > -1) {
345 editMembership(row);
346 }
347 } else {
348 editHelper.addTag();
349 }
350 }
351
352 @Override
353 public void mousePressed(MouseEvent e) {
354 if (e.getSource() == tagTable) {
355 membershipTable.clearSelection();
356 } else if (e.getSource() == membershipTable) {
357 tagTable.clearSelection();
358 }
359 }
360 }
361
362 static class MemberInfo {
363 private List<RelationMember> role = new ArrayList<>();
364 private Set<OsmPrimitive> members = new HashSet<>();
365 private List<Integer> position = new ArrayList<>();
366 private String positionString;
367 private String roleString;
368
369 MemberInfo() {
370 }
371
372 void add(RelationMember r, Integer p) {
373 role.add(r);
374 members.add(r.getMember());
375 position.add(p);
376 }
377
378 @Override
379 public String toString() {
380 return "MemberInfo{" +
381 "roles='" + roleString + '\'' +
382 ", positions='" + positionString + '\'' +
383 '}';
384 }
385 }
386
387 /**
388 * Class that allows fast creation of read-only table model with String columns
389 */
390 public static class ReadOnlyTableModel extends DefaultTableModel {
391 @Override
392 public boolean isCellEditable(int row, int column) {
393 return false;
394 }
395
396 @Override
397 public Class<?> getColumnClass(int columnIndex) {
398 return String.class;
399 }
400 }
401
402 /**
403 * Action handling add button press in properties dialog.
404 */
405 class AddAction extends JosmAction {
406 AddAction() {
407 super(tr("Add Recommendation"), /* ICON() */ "dialogs/add", tr("Add a recommended key/value pair to your object"),
408 Shortcut.registerShortcut("properties:add", tr("Add Tag"), KeyEvent.VK_A,
409 Shortcut.ALT), false);
410 }
411
412 @Override
413 public void actionPerformed(ActionEvent e) {
414 editHelper.addTag();
415 btnAdd.requestFocusInWindow();
416 }
417 }
418
419 /**
420 * Action handling edit button press in properties dialog.
421 * training process dialog/configuration
422 */
423 class EditActionTrain extends JosmAction implements ListSelectionListener {
424 EditActionTrain() {
425 super(tr("Train a Model"), /* ICON() */ "dialogs/fix", tr("Start the training engine!"),
426 Shortcut.registerShortcut("properties:edit", tr("Edit Tags"), KeyEvent.VK_S,
427 Shortcut.ALT), false);
428 setEnabled(true);
429 updateEnabledState();
430 }
431
432 @Override
433 public void actionPerformed(ActionEvent e) {
434 if (!isEnabled())
435 return;
436 if (tagTable.getSelectedRowCount() == 1) {
437 int row = tagTable.getSelectedRow();
438 editHelper.editTag(row, false);
439 } else if (membershipTable.getSelectedRowCount() == 1) {
440 int row = membershipTable.getSelectedRow();
441 editHelper.editTag(row, false);
442 } else {
443 editHelper.editTag(1, false);
444 }
445 }
446
447 @Override
448 protected void updateEnabledState() {
449 setEnabled(true);
450 }
451
452 @Override
453 public void valueChanged(ListSelectionEvent e) {
454 updateEnabledState();
455 }
456 }
457}
Note: See TracBrowser for help on using the repository browser.