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

Last change on this file since 32954 was 32398, checked in by donvip, 9 years ago

checkstyle

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