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

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

fix #josm14386 - StackOverflowError

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