source: osm/applications/editors/josm/plugins/reltoolbox/src/relcontext/RelContextDialog.java@ 34334

Last change on this file since 34334 was 34130, checked in by donvip, 8 years ago

update to JOSM 13564

  • Property svn:eol-style set to native
File size: 31.6 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package relcontext;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.awt.BorderLayout;
7import java.awt.Color;
8import java.awt.Component;
9import java.awt.Dialog.ModalityType;
10import java.awt.Dimension;
11import java.awt.GridBagLayout;
12import java.awt.Point;
13import java.awt.event.ActionEvent;
14import java.awt.event.ActionListener;
15import java.awt.event.ItemEvent;
16import java.awt.event.ItemListener;
17import java.awt.event.KeyEvent;
18import java.awt.event.MouseAdapter;
19import java.awt.event.MouseEvent;
20import java.awt.event.MouseListener;
21import java.beans.PropertyChangeEvent;
22import java.beans.PropertyChangeListener;
23import java.io.BufferedReader;
24import java.io.InputStream;
25import java.io.InputStreamReader;
26import java.nio.charset.StandardCharsets;
27import java.util.ArrayList;
28import java.util.Collection;
29import java.util.Collections;
30import java.util.HashMap;
31import java.util.List;
32import java.util.Map;
33import java.util.Set;
34import java.util.StringTokenizer;
35import java.util.TreeSet;
36
37import javax.swing.AbstractListModel;
38import javax.swing.Action;
39import javax.swing.Box;
40import javax.swing.ComboBoxModel;
41import javax.swing.JButton;
42import javax.swing.JCheckBoxMenuItem;
43import javax.swing.JComboBox;
44import javax.swing.JComponent;
45import javax.swing.JDialog;
46import javax.swing.JLabel;
47import javax.swing.JOptionPane;
48import javax.swing.JPanel;
49import javax.swing.JPopupMenu;
50import javax.swing.JScrollPane;
51import javax.swing.JTable;
52import javax.swing.ListSelectionModel;
53import javax.swing.SwingUtilities;
54import javax.swing.event.ListSelectionEvent;
55import javax.swing.event.ListSelectionListener;
56import javax.swing.table.DefaultTableCellRenderer;
57import javax.swing.table.DefaultTableModel;
58import javax.swing.table.TableColumnModel;
59
60import org.openstreetmap.josm.Main;
61import org.openstreetmap.josm.actions.JosmAction;
62import org.openstreetmap.josm.command.ChangeRelationMemberRoleCommand;
63import org.openstreetmap.josm.command.Command;
64import org.openstreetmap.josm.command.SequenceCommand;
65import org.openstreetmap.josm.data.SelectionChangedListener;
66import org.openstreetmap.josm.data.osm.DefaultNameFormatter;
67import org.openstreetmap.josm.data.osm.IPrimitive;
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.event.DatasetEventManager;
72import org.openstreetmap.josm.data.osm.event.DatasetEventManager.FireMode;
73import org.openstreetmap.josm.data.osm.event.SelectionEventManager;
74import org.openstreetmap.josm.gui.MainApplication;
75import org.openstreetmap.josm.gui.PrimitiveRenderer;
76import org.openstreetmap.josm.gui.dialogs.ToggleDialog;
77import org.openstreetmap.josm.gui.layer.MainLayerManager.ActiveLayerChangeEvent;
78import org.openstreetmap.josm.gui.layer.MainLayerManager.ActiveLayerChangeListener;
79import org.openstreetmap.josm.gui.tagging.ac.AutoCompletingComboBox;
80import org.openstreetmap.josm.tools.GBC;
81import org.openstreetmap.josm.tools.Logging;
82import org.openstreetmap.josm.tools.Shortcut;
83
84import relcontext.actions.AddRemoveMemberAction;
85import relcontext.actions.ClearChosenRelationAction;
86import relcontext.actions.CreateMultipolygonAction;
87import relcontext.actions.CreateRelationAction;
88import relcontext.actions.DeleteChosenRelationAction;
89import relcontext.actions.DownloadChosenRelationAction;
90import relcontext.actions.DownloadParentsAction;
91import relcontext.actions.DuplicateChosenRelationAction;
92import relcontext.actions.EditChosenRelationAction;
93import relcontext.actions.FindRelationAction;
94import relcontext.actions.ReconstructPolygonAction;
95import relcontext.actions.ReconstructRouteAction;
96import relcontext.actions.RelationHelpAction;
97import relcontext.actions.SelectInRelationPanelAction;
98import relcontext.actions.SelectMembersAction;
99import relcontext.actions.SelectRelationAction;
100import relcontext.actions.SortAndFixAction;
101
102/**
103 * The new, advanced relation editing panel.
104 *
105 * @author Zverik
106 */
107public class RelContextDialog extends ToggleDialog implements ActiveLayerChangeListener, ChosenRelationListener, SelectionChangedListener {
108
109 public static final String PREF_PREFIX = "reltoolbox";
110
111 private final DefaultTableModel relationsData;
112 private ChosenRelation chosenRelation;
113 private JPanel chosenRelationPanel;
114 private ChosenRelationPopupMenu popupMenu;
115 private MultipolygonSettingsPopup multiPopupMenu;
116 private RoleComboBoxModel roleBoxModel;
117 private SortAndFixAction sortAndFixAction;
118 // actions saved for unregistering on dialog destroying
119 private final EnterRoleAction enterRoleAction;
120 private final FindRelationAction findRelationAction;
121 private final CreateMultipolygonAction createMultipolygonAction;
122 private final CreateRelationAction createRelationAction;
123 private final AddRemoveMemberAction addRemoveMemberAction;
124
125 public RelContextDialog() {
126 super(tr("Relation Toolbox"), PREF_PREFIX, tr("Open relation/multipolygon editor panel"), null, 150, true);
127
128 chosenRelation = new ChosenRelation();
129 chosenRelation.addChosenRelationListener(this);
130 MainApplication.getLayerManager().addActiveLayerChangeListener(chosenRelation);
131
132 popupMenu = new ChosenRelationPopupMenu(chosenRelation);
133 multiPopupMenu = new MultipolygonSettingsPopup();
134
135 JPanel rcPanel = new JPanel(new BorderLayout());
136
137 relationsData = new RelationTableModel();
138 relationsData.setColumnIdentifiers(new String[] {tr("Member Of"), tr("Role")});
139 final JTable relationsTable = new JTable(relationsData);
140 configureRelationsTable(relationsTable);
141 rcPanel.add(new JScrollPane(relationsTable,
142 JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER), BorderLayout.CENTER);
143
144 final MouseListener relationMouseAdapter = new ChosenRelationMouseAdapter();
145 final JComboBox<String> roleBox = new JComboBox<>();
146 roleBoxModel = new RoleComboBoxModel(roleBox);
147 roleBox.setModel(roleBoxModel);
148 roleBox.addMouseListener(relationMouseAdapter);
149 roleBox.addItemListener(new ItemListener() {
150 @Override
151 public void itemStateChanged(ItemEvent e) {
152 if (e.getStateChange() == ItemEvent.DESELECTED) return;
153 String memberRole = roleBoxModel.getSelectedMembersRole();
154 String selectedRole = roleBoxModel.isAnotherRoleSelected() ? askForRoleName() : roleBoxModel.getSelectedRole();
155 if (memberRole != null && selectedRole != null && !memberRole.equals(selectedRole)) {
156 applyRoleToSelection(selectedRole.trim());
157 }
158 }
159 });
160 roleBox.setVisible(false);
161 enterRoleAction = new EnterRoleAction(); // just for the shortcut
162 sortAndFixAction = new SortAndFixAction(chosenRelation);
163
164 // [±][X] relation U [AZ][Down][Edit]
165 chosenRelationPanel = new JPanel(new GridBagLayout());
166 addRemoveMemberAction = new AddRemoveMemberAction(chosenRelation, sortAndFixAction);
167 chosenRelationPanel.add(new JButton(addRemoveMemberAction), GBC.std());
168 chosenRelationPanel.add(sizeButton(new JButton(new ClearChosenRelationAction(chosenRelation)), 32, 0), GBC.std());
169 final ChosenRelationComponent chosenRelationComponent = new ChosenRelationComponent(chosenRelation);
170 chosenRelationComponent.addMouseListener(relationMouseAdapter);
171 chosenRelationPanel.add(chosenRelationComponent, GBC.std().fill().insets(5, 0, 5, 0));
172 chosenRelationPanel.add(roleBox, GBC.std().fill().insets(5, 0, 5, 0));
173 final JButton sortAndFixButton = (JButton) sizeButton(new JButton(sortAndFixAction), 32, 0);
174 chosenRelationPanel.add(sortAndFixButton, GBC.std().fill(GBC.VERTICAL));
175 final Action downloadChosenRelationAction = new DownloadChosenRelationAction(chosenRelation);
176 final JButton downloadButton = (JButton) sizeButton(new JButton(downloadChosenRelationAction), 32, 0);
177 chosenRelationPanel.add(downloadButton, GBC.std().fill(GBC.VERTICAL));
178 chosenRelationPanel.add(new JButton(new EditChosenRelationAction(chosenRelation)), GBC.eol().fill(GBC.VERTICAL));
179
180 rcPanel.add(chosenRelationPanel, BorderLayout.NORTH);
181
182 roleBox.addPropertyChangeListener("enabled", new PropertyChangeListener() {
183 @Override
184 public void propertyChange(PropertyChangeEvent evt) {
185 boolean showRoleBox = roleBox.isEnabled();
186 roleBox.setVisible(showRoleBox);
187 chosenRelationComponent.setVisible(!showRoleBox);
188 }
189 });
190
191 sortAndFixAction.addPropertyChangeListener(new PropertyChangeListener() {
192 @Override
193 public void propertyChange(PropertyChangeEvent evt) {
194 sortAndFixButton.setVisible(sortAndFixAction.isEnabled());
195 }
196 });
197 sortAndFixButton.setVisible(false);
198
199 downloadChosenRelationAction.addPropertyChangeListener(new PropertyChangeListener() {
200 @Override
201 public void propertyChange(PropertyChangeEvent evt) {
202 downloadButton.setVisible(downloadChosenRelationAction.isEnabled());
203 }
204 });
205 downloadButton.setVisible(false);
206 if (Main.pref.getBoolean(PREF_PREFIX + ".hidetopline", false)) {
207 chosenRelationPanel.setVisible(false);
208 }
209
210 // [+][Multi] [X]Adm [X]Tags [X]1
211 JPanel bottomLine = new JPanel(new GridBagLayout());
212 createRelationAction = new CreateRelationAction(chosenRelation);
213 bottomLine.add(new JButton(createRelationAction), GBC.std());
214 createMultipolygonAction = new CreateMultipolygonAction(chosenRelation);
215 final JButton multipolygonButton = new JButton(createMultipolygonAction);
216 bottomLine.add(multipolygonButton, GBC.std());
217 // bottomLine.add(sizeButton(new JButton(new MultipolygonSettingsAction()), 16, 0), GBC.std().fill(GBC.VERTICAL));
218 bottomLine.add(Box.createHorizontalGlue(), GBC.std().fill());
219 findRelationAction = new FindRelationAction(chosenRelation);
220 bottomLine.add(new JButton(findRelationAction), GBC.eol());
221 rcPanel.add(sizeButton(bottomLine, 0, 24), BorderLayout.SOUTH);
222
223 multipolygonButton.addMouseListener(new MouseAdapter() {
224 @Override
225 public void mousePressed(MouseEvent e) {
226 checkPopup(e);
227 }
228
229 @Override
230 public void mouseReleased(MouseEvent e) {
231 checkPopup(e);
232 }
233
234 private void checkPopup(MouseEvent e) {
235 if (e.isPopupTrigger()) {
236 multiPopupMenu.show(e.getComponent(), e.getX(), e.getY());
237 }
238 }
239 });
240
241 createLayout(rcPanel, false, null);
242 }
243
244 private static final Color CHOSEN_RELATION_COLOR = new Color(255, 255, 128);
245
246 private void configureRelationsTable(final JTable relationsTable) {
247 relationsTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
248 relationsTable.setTableHeader(null);
249 relationsTable.addMouseListener(new MouseAdapter() {
250 @Override
251 public void mouseClicked(MouseEvent e) {
252 Point p = e.getPoint();
253 int row = relationsTable.rowAtPoint(p);
254 if (SwingUtilities.isLeftMouseButton(e) && row >= 0) {
255 Relation relation = (Relation) relationsData.getValueAt(row, 0);
256 if (e.getClickCount() > 1) {
257 MainApplication.getLayerManager().getEditLayer().data.setSelected(relation);
258 }
259 }
260 }
261
262 @Override
263 public void mousePressed(MouseEvent e) {
264 checkPopup(e);
265 }
266
267 @Override
268 public void mouseReleased(MouseEvent e) {
269 checkPopup(e);
270 }
271
272 public void checkPopup(MouseEvent e) {
273 if (e.isPopupTrigger()) {
274 Point p = e.getPoint();
275 int row = relationsTable.rowAtPoint(p);
276 if (row > -1) {
277 Relation relation = (Relation) relationsData.getValueAt(row, 0);
278 JPopupMenu menu = chosenRelation.isSame(relation) ? popupMenu
279 : new ChosenRelationPopupMenu(new StaticChosenRelation(relation));
280 menu.show(relationsTable, p.x, p.y-5);
281 }
282 }
283 }
284 });
285
286 TableColumnModel columns = relationsTable.getColumnModel();
287 columns.getColumn(0).setCellRenderer(new PrimitiveRenderer() {
288 @Override
289 protected String getComponentToolTipText(IPrimitive value) {
290 return null;
291 }
292
293 @Override
294 public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus,
295 int row, int column) {
296 Component c = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
297 if (!isSelected && value instanceof Relation && chosenRelation.isSame(value)) {
298 c.setBackground(CHOSEN_RELATION_COLOR);
299 } else {
300 c.setBackground(table.getBackground());
301 }
302 return c;
303 }
304
305 });
306 columns.getColumn(1).setCellRenderer(new DefaultTableCellRenderer() {
307 @Override
308 public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus,
309 int row, int column) {
310 Component c = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
311 if (!isSelected && chosenRelation.isSame(table.getValueAt(row, 0))) {
312 c.setBackground(CHOSEN_RELATION_COLOR);
313 } else {
314 c.setBackground(table.getBackground());
315 }
316 return c;
317 }
318 });
319 columns.getColumn(1).setPreferredWidth(40);
320 columns.getColumn(0).setPreferredWidth(220);
321 relationsTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
322 @Override
323 public void valueChanged(ListSelectionEvent e) {
324 int selectedRow = relationsTable.getSelectedRow();
325 if (selectedRow >= 0) {
326 chosenRelation.set((Relation) relationsData.getValueAt(selectedRow, 0));
327 relationsTable.clearSelection();
328 }
329 }
330 });
331 }
332
333 private JComponent sizeButton(JComponent b, int width, int height) {
334 Dimension pref = b.getPreferredSize();
335 b.setPreferredSize(new Dimension(width <= 0 ? pref.width : width, height <= 0 ? pref.height : height));
336 return b;
337 }
338
339 @Override
340 public void hideNotify() {
341 SelectionEventManager.getInstance().removeSelectionListener(this);
342 MainApplication.getLayerManager().removeActiveLayerChangeListener(this);
343 DatasetEventManager.getInstance().removeDatasetListener(chosenRelation);
344 chosenRelation.clear();
345 }
346
347 @Override
348 public void showNotify() {
349 SelectionEventManager.getInstance().addSelectionListener(this, FireMode.IN_EDT_CONSOLIDATED);
350 MainApplication.getLayerManager().addActiveLayerChangeListener(this);
351 DatasetEventManager.getInstance().addDatasetListener(chosenRelation, FireMode.IN_EDT);
352 }
353
354 public ChosenRelation getChosenRelation() {
355 return chosenRelation;
356 }
357
358 @Override
359 public void chosenRelationChanged(Relation oldRelation, Relation newRelation) {
360 if (chosenRelationPanel != null && Main.pref.getBoolean(PREF_PREFIX + ".hidetopline", false)) {
361 chosenRelationPanel.setVisible(newRelation != null);
362 }
363 if (MainApplication.getLayerManager().getEditDataSet() != null) {
364 selectionChanged(MainApplication.getLayerManager().getEditDataSet().getSelected());
365 }
366 roleBoxModel.update();
367 }
368
369 @Override
370 public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) {
371 if (!isVisible() || relationsData == null)
372 return;
373 roleBoxModel.update();
374 // repopulate relations table
375 relationsData.setRowCount(0);
376 sortAndFixAction.chosenRelationChanged(chosenRelation.get(), chosenRelation.get());
377 if (newSelection == null)
378 return;
379
380 Set<Relation> relations = new TreeSet<>(
381 DefaultNameFormatter.getInstance().getRelationComparator());
382 for (OsmPrimitive element : newSelection) {
383 for (OsmPrimitive ref : element.getReferrers()) {
384 if (ref instanceof Relation && !ref.isIncomplete() && !ref.isDeleted()) {
385 relations.add((Relation) ref);
386 }
387 }
388 }
389
390 for (Relation rel : relations) {
391 String role = null;
392 for (RelationMember m : rel.getMembers()) {
393 for (OsmPrimitive element : newSelection) {
394 if (m.getMember().equals(element)) {
395 if (role == null) {
396 role = m.getRole();
397 } else if (!role.equals(m.getRole())) {
398 role = tr("<different>");
399 break;
400 }
401 }
402 }
403 }
404 relationsData.addRow(new Object[] {rel, role == null ? "" : role});
405 }
406 for (OsmPrimitive element : newSelection) {
407 if (element instanceof Relation && !chosenRelation.isSame(element)) {
408 relationsData.addRow(new Object[] {element, ""});
409 }
410 }
411 }
412
413 private void updateSelection() {
414 if (MainApplication.getLayerManager().getEditDataSet() == null) {
415 selectionChanged(Collections.<OsmPrimitive>emptyList());
416 } else {
417 selectionChanged(MainApplication.getLayerManager().getEditDataSet().getSelected());
418 }
419 }
420
421 @Override
422 public void activeOrEditLayerChanged(ActiveLayerChangeEvent e) {
423 updateSelection();
424 }
425
426 @Override
427 public void destroy() {
428 enterRoleAction.destroy();
429 findRelationAction.destroy();
430 createMultipolygonAction.destroy();
431 createRelationAction.destroy();
432 addRemoveMemberAction.destroy();
433 super.destroy();
434 }
435
436 private static final String POSSIBLE_ROLES_FILE = "relcontext/possible_roles.txt";
437 private static final Map<String, List<String>> possibleRoles = loadRoles();
438
439 private static Map<String, List<String>> loadRoles() {
440 Map<String, List<String>> result = new HashMap<>();
441
442 ClassLoader classLoader = RelContextDialog.class.getClassLoader();
443 try (InputStream possibleRolesStream = classLoader.getResourceAsStream(POSSIBLE_ROLES_FILE);
444 BufferedReader r = new BufferedReader(new InputStreamReader(possibleRolesStream, StandardCharsets.UTF_8));
445 ) {
446 while (r.ready()) {
447 String line = r.readLine();
448 String[] typeAndRoles = line.split(":", 2);
449 if (typeAndRoles.length == 2 && typeAndRoles[1].length() > 0) {
450 String type = typeAndRoles[0].trim();
451 StringTokenizer t = new StringTokenizer(typeAndRoles[1], " ,;\"");
452 List<String> roles = new ArrayList<>();
453 while (t.hasMoreTokens()) {
454 roles.add(t.nextToken());
455 }
456 result.put(type, roles);
457 }
458 }
459 } catch (Exception e) {
460 Logging.error("[RelToolbox] Error reading possible roles file.");
461 Logging.error(e);
462 }
463 return result;
464 }
465
466 private String askForRoleName() {
467 JPanel panel = new JPanel(new GridBagLayout());
468
469 List<String> items = new ArrayList<>();
470 for (String role : roleBoxModel.getRoles()) {
471 if (role.length() > 1) {
472 items.add(role);
473 }
474 }
475 final AutoCompletingComboBox role = new AutoCompletingComboBox();
476 role.setPossibleItems(items);
477 role.setEditable(true);
478
479 panel.add(new JLabel(tr("Role")), GBC.std());
480 panel.add(Box.createHorizontalStrut(10), GBC.std());
481 panel.add(role, GBC.eol().fill(GBC.HORIZONTAL));
482
483 final JOptionPane optionPane = new JOptionPane(panel, JOptionPane.QUESTION_MESSAGE, JOptionPane.OK_CANCEL_OPTION) {
484 @Override
485 public void selectInitialValue() {
486 role.requestFocusInWindow();
487 role.getEditor().selectAll();
488 }
489 };
490 final JDialog dlg = optionPane.createDialog(Main.parent, tr("Specify role"));
491 dlg.setModalityType(ModalityType.DOCUMENT_MODAL);
492
493 role.getEditor().addActionListener(new ActionListener() {
494 @Override
495 public void actionPerformed(ActionEvent e) {
496 dlg.setVisible(false);
497 optionPane.setValue(JOptionPane.OK_OPTION);
498 }
499 });
500
501 dlg.setVisible(true);
502
503 Object answer = optionPane.getValue();
504 if (answer == null || answer == JOptionPane.UNINITIALIZED_VALUE
505 || (answer instanceof Integer && (Integer) answer != JOptionPane.OK_OPTION))
506 return null;
507
508 return role.getEditor().getItem().toString().trim();
509 }
510
511 private class ChosenRelationMouseAdapter extends MouseAdapter {
512 @Override
513 public void mouseClicked(MouseEvent e) {
514 if (e.isControlDown() || !(e.getComponent() instanceof JComboBox)) // do not use left click handler on combo box
515 if (SwingUtilities.isLeftMouseButton(e) && chosenRelation.get() != null
516 && MainApplication.getLayerManager().getEditLayer() != null) {
517 MainApplication.getLayerManager().getEditLayer().data.setSelected(chosenRelation.get());
518 }
519 }
520
521 @Override
522 public void mousePressed(MouseEvent e) {
523 checkPopup(e);
524 }
525
526 @Override
527 public void mouseReleased(MouseEvent e) {
528 checkPopup(e);
529 }
530
531 private void checkPopup(MouseEvent e) {
532 if (e.isPopupTrigger() && chosenRelation.get() != null) {
533 popupMenu.show(e.getComponent(), e.getX(), e.getY() - 5);
534 }
535 }
536 }
537
538 private static class ChosenRelationPopupMenu extends JPopupMenu {
539 ChosenRelationPopupMenu(ChosenRelation chosenRelation) {
540 add(new SelectMembersAction(chosenRelation));
541 add(new SelectRelationAction(chosenRelation));
542 add(new DuplicateChosenRelationAction(chosenRelation));
543 add(new DeleteChosenRelationAction(chosenRelation));
544 add(new DownloadParentsAction(chosenRelation));
545 add(new ReconstructPolygonAction(chosenRelation));
546 add(new ReconstructRouteAction(chosenRelation));
547 addSeparator();
548 add(new SelectInRelationPanelAction(chosenRelation));
549 add(new RelationHelpAction(chosenRelation));
550 }
551 }
552
553 protected void applyRoleToSelection(String role) {
554 if (chosenRelation != null && chosenRelation.get() != null
555 && MainApplication.getLayerManager().getEditDataSet() != null
556 && !MainApplication.getLayerManager().getEditDataSet().selectionEmpty()) {
557 Collection<OsmPrimitive> selected = MainApplication.getLayerManager().getEditDataSet().getSelected();
558 Relation r = chosenRelation.get();
559 List<Command> commands = new ArrayList<>();
560 for (int i = 0; i < r.getMembersCount(); i++) {
561 RelationMember m = r.getMember(i);
562 if (selected.contains(m.getMember())) {
563 if (!role.equals(m.getRole())) {
564 commands.add(new ChangeRelationMemberRoleCommand(r, i, role));
565 }
566 }
567 }
568 if (!commands.isEmpty()) {
569 // Main.main.undoRedo.add(new ChangeCommand(chosenRelation.get(), r));
570 MainApplication.undoRedo.add(new SequenceCommand(tr("Change relation member roles to {0}", role), commands));
571 }
572 }
573 }
574
575 private static class RelationTableModel extends DefaultTableModel {
576 @Override
577 public boolean isCellEditable(int row, int column) {
578 return false;
579 }
580
581 @Override
582 public Class<?> getColumnClass(int columnIndex) {
583 return columnIndex == 0 ? Relation.class : String.class;
584 }
585 }
586
587 private static class MultipolygonSettingsPopup extends JPopupMenu implements ActionListener {
588 MultipolygonSettingsPopup() {
589 addMenuItem("boundary", tr("Create administrative boundary relations"));
590 addMenuItem("boundaryways", tr("Add tags boundary and admin_level to boundary relation ways"));
591 addMenuItem("tags", tr("Move area tags from contour to relation"));
592 addMenuItem("alltags", tr("When moving tags, consider even non-repeating ones"));
593 addMenuItem("allowsplit", tr("Always split ways of neighbouring multipolygons"));
594 }
595
596 protected final JCheckBoxMenuItem addMenuItem(String property, String title) {
597 String fullProperty = PREF_PREFIX + ".multipolygon." + property;
598 JCheckBoxMenuItem item = new JCheckBoxMenuItem(tr(title));
599 item.setSelected(Main.pref.getBoolean(fullProperty, CreateMultipolygonAction.getDefaultPropertyValue(property)));
600 item.setActionCommand(fullProperty);
601 item.addActionListener(this);
602 add(item);
603 return item;
604 }
605
606 @Override
607 public void actionPerformed(ActionEvent e) {
608 String property = e.getActionCommand();
609 if (property != null && property.length() > 0 && e.getSource() instanceof JCheckBoxMenuItem) {
610 boolean value = ((JCheckBoxMenuItem) e.getSource()).isSelected();
611 Main.pref.putBoolean(property, value);
612 show(getInvoker(), getX(), getY());
613 }
614 }
615 }
616
617 private class EnterRoleAction extends JosmAction implements ChosenRelationListener {
618
619 EnterRoleAction() {
620 super(tr("Change role"), (String) null, tr("Enter role for selected members"),
621 Shortcut.registerShortcut("reltoolbox:changerole", tr("Relation Toolbox: {0}", tr("Enter role for selected members")),
622 KeyEvent.VK_R, Shortcut.ALT_CTRL), false, "relcontext/enterrole", true);
623 chosenRelation.addChosenRelationListener(this);
624 updateEnabledState();
625 }
626
627 @Override
628 public void actionPerformed(ActionEvent e) {
629 if (roleBoxModel.membersRole != null) {
630 String role = askForRoleName();
631 if (role != null) {
632 applyRoleToSelection(role);
633 }
634 }
635 }
636
637 @Override
638 public void chosenRelationChanged(Relation oldRelation, Relation newRelation) {
639 setEnabled(newRelation != null);
640 }
641 }
642
643 private class RoleComboBoxModel extends AbstractListModel<String> implements ComboBoxModel<String> {
644 private List<String> roles = new ArrayList<>();
645 private int selectedIndex = -1;
646 private JComboBox<String> combobox;
647 private String membersRole;
648 private final String EMPTY_ROLE = tr("<empty>");
649 private final String ANOTHER_ROLE = tr("another...");
650
651 RoleComboBoxModel(JComboBox<String> combobox) {
652 super();
653 this.combobox = combobox;
654 update();
655 }
656
657 public void update() {
658 membersRole = getSelectedMembersRoleIntl();
659 if (membersRole == null) {
660 if (combobox.isEnabled()) {
661 combobox.setEnabled(false);
662 }
663 return;
664 }
665 if (!combobox.isEnabled()) {
666 combobox.setEnabled(true);
667 }
668
669 List<String> items = new ArrayList<>();
670 if (chosenRelation != null && chosenRelation.get() != null) {
671 if (chosenRelation.isMultipolygon()) {
672 items.add("outer");
673 items.add("inner");
674 }
675 if (chosenRelation.get().get("type") != null) {
676 List<String> values = possibleRoles.get(chosenRelation.get().get("type"));
677 if (values != null) {
678 items.addAll(values);
679 }
680 }
681 for (RelationMember m : chosenRelation.get().getMembers()) {
682 if (m.getRole().length() > 0 && !items.contains(m.getRole())) {
683 items.add(m.getRole());
684 }
685 }
686 }
687 items.add(EMPTY_ROLE);
688 if (!items.contains(membersRole)) {
689 items.add(0, membersRole);
690 }
691 items.add(ANOTHER_ROLE);
692 roles = Collections.unmodifiableList(items);
693
694 if (membersRole != null) {
695 setSelectedItem(membersRole);
696 } else {
697 fireContentsChanged(this, -1, -1);
698 }
699 combobox.repaint();
700 }
701
702 public String getSelectedMembersRole() {
703 return membersRole == EMPTY_ROLE ? "" : membersRole;
704 }
705
706 public boolean isAnotherRoleSelected() {
707 return getSelectedRole() != null && getSelectedRole().equals(ANOTHER_ROLE);
708 }
709
710 private String getSelectedMembersRoleIntl() {
711 String role = null;
712 if (chosenRelation != null && chosenRelation.get() != null
713 && MainApplication.getLayerManager().getEditDataSet() != null
714 && !MainApplication.getLayerManager().getEditDataSet().selectionEmpty()) {
715 Collection<OsmPrimitive> selected = MainApplication.getLayerManager().getEditDataSet().getSelected();
716 for (RelationMember m : chosenRelation.get().getMembers()) {
717 if (selected.contains(m.getMember())) {
718 if (role == null) {
719 role = m.getRole();
720 } else if (m.getRole() != null && !role.equals(m.getRole())) {
721 role = tr("<different>");
722 break;
723 }
724 }
725 }
726 }
727 return role == null ? null : role.length() == 0 ? EMPTY_ROLE : role;
728 }
729
730 public List<String> getRoles() {
731 return roles;
732 }
733
734 @Override
735 public int getSize() {
736 return roles.size();
737 }
738
739 @Override
740 public String getElementAt(int index) {
741 return getRole(index);
742 }
743
744 public String getRole(int index) {
745 return roles.get(index);
746 }
747
748 @Override
749 public void setSelectedItem(Object anItem) {
750 int newIndex = anItem == null ? -1 : roles.indexOf(anItem);
751 if (newIndex != selectedIndex) {
752 selectedIndex = newIndex;
753 fireContentsChanged(this, -1, -1);
754 }
755 }
756
757 @Override
758 public Object getSelectedItem() {
759 return selectedIndex < 0 || selectedIndex >= getSize() ? null : getRole(selectedIndex);
760 }
761
762 public String getSelectedRole() {
763 String role = selectedIndex < 0 || selectedIndex >= getSize() ? null : getRole(selectedIndex);
764 return role != null && role.equals(EMPTY_ROLE) ? "" : role;
765 }
766 }
767}
Note: See TracBrowser for help on using the repository browser.