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

Last change on this file since 36102 was 36102, checked in by taylor.smock, 2 years ago

reltoolbox: Clean up a bunch of lint warnings

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