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

Last change on this file since 34412 was 34346, checked in by donvip, 8 years ago

update to JOSM 13959

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