source: subversion/applications/editors/josm/plugins/reltoolbox/src/relcontext/RelContextDialog.java

Last change on this file was 34788, checked in by gerdp, 4 months ago

see #17040 call removeActiveLayerChangeListener() in destroy()

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