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

Last change on this file since 33530 was 33530, checked in by donvip, 7 years ago

update to JOSM 12663

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