// License: GPL. For details, see LICENSE file. package relcontext; import static org.openstreetmap.josm.tools.I18n.tr; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.Dialog.ModalityType; import java.awt.Dimension; import java.awt.GridBagLayout; import java.awt.Point; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.StringTokenizer; import java.util.TreeSet; import javax.swing.AbstractListModel; import javax.swing.Action; import javax.swing.Box; import javax.swing.ComboBoxModel; import javax.swing.JButton; import javax.swing.JCheckBoxMenuItem; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JDialog; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.ListSelectionModel; import javax.swing.SwingUtilities; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import javax.swing.table.DefaultTableCellRenderer; import javax.swing.table.DefaultTableModel; import javax.swing.table.TableColumnModel; import org.openstreetmap.josm.Main; import org.openstreetmap.josm.actions.JosmAction; import org.openstreetmap.josm.command.ChangeRelationMemberRoleCommand; import org.openstreetmap.josm.command.Command; import org.openstreetmap.josm.command.SequenceCommand; import org.openstreetmap.josm.data.SelectionChangedListener; import org.openstreetmap.josm.data.osm.OsmPrimitive; import org.openstreetmap.josm.data.osm.Relation; import org.openstreetmap.josm.data.osm.RelationMember; import org.openstreetmap.josm.data.osm.event.DatasetEventManager; import org.openstreetmap.josm.data.osm.event.DatasetEventManager.FireMode; import org.openstreetmap.josm.data.osm.event.SelectionEventManager; import org.openstreetmap.josm.gui.DefaultNameFormatter; import org.openstreetmap.josm.gui.OsmPrimitivRenderer; import org.openstreetmap.josm.gui.dialogs.ToggleDialog; import org.openstreetmap.josm.gui.layer.MainLayerManager.ActiveLayerChangeEvent; import org.openstreetmap.josm.gui.layer.MainLayerManager.ActiveLayerChangeListener; import org.openstreetmap.josm.gui.tagging.ac.AutoCompletingComboBox; import org.openstreetmap.josm.tools.GBC; import org.openstreetmap.josm.tools.Shortcut; import relcontext.actions.AddRemoveMemberAction; import relcontext.actions.ClearChosenRelationAction; import relcontext.actions.CreateMultipolygonAction; import relcontext.actions.CreateRelationAction; import relcontext.actions.DeleteChosenRelationAction; import relcontext.actions.DownloadChosenRelationAction; import relcontext.actions.DownloadParentsAction; import relcontext.actions.DuplicateChosenRelationAction; import relcontext.actions.EditChosenRelationAction; import relcontext.actions.FindRelationAction; import relcontext.actions.ReconstructPolygonAction; import relcontext.actions.ReconstructRouteAction; import relcontext.actions.RelationHelpAction; import relcontext.actions.SelectInRelationPanelAction; import relcontext.actions.SelectMembersAction; import relcontext.actions.SelectRelationAction; import relcontext.actions.SortAndFixAction; /** * The new, advanced relation editing panel. * * @author Zverik */ public class RelContextDialog extends ToggleDialog implements ActiveLayerChangeListener, ChosenRelationListener, SelectionChangedListener { public static final String PREF_PREFIX = "reltoolbox"; private final DefaultTableModel relationsData; private ChosenRelation chosenRelation; private JPanel chosenRelationPanel; private ChosenRelationPopupMenu popupMenu; private MultipolygonSettingsPopup multiPopupMenu; private RoleComboBoxModel roleBoxModel; private SortAndFixAction sortAndFixAction; // actions saved for unregistering on dialog destroying private final EnterRoleAction enterRoleAction; private final FindRelationAction findRelationAction; private final CreateMultipolygonAction createMultipolygonAction; private final CreateRelationAction createRelationAction; private final AddRemoveMemberAction addRemoveMemberAction; public RelContextDialog() { super(tr("Relation Toolbox"), PREF_PREFIX, tr("Open relation/multipolygon editor panel"), null, 150, true); chosenRelation = new ChosenRelation(); chosenRelation.addChosenRelationListener(this); Main.getLayerManager().addActiveLayerChangeListener(chosenRelation); popupMenu = new ChosenRelationPopupMenu(chosenRelation); multiPopupMenu = new MultipolygonSettingsPopup(); JPanel rcPanel = new JPanel(new BorderLayout()); relationsData = new RelationTableModel(); relationsData.setColumnIdentifiers(new String[] {tr("Member Of"), tr("Role")}); final JTable relationsTable = new JTable(relationsData); configureRelationsTable(relationsTable); rcPanel.add(new JScrollPane(relationsTable, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER), BorderLayout.CENTER); final MouseListener relationMouseAdapter = new ChosenRelationMouseAdapter(); final JComboBox<String> roleBox = new JComboBox<>(); roleBoxModel = new RoleComboBoxModel(roleBox); roleBox.setModel(roleBoxModel); roleBox.addMouseListener(relationMouseAdapter); roleBox.addItemListener(new ItemListener() { @Override public void itemStateChanged(ItemEvent e) { if (e.getStateChange() == ItemEvent.DESELECTED) return; String memberRole = roleBoxModel.getSelectedMembersRole(); String selectedRole = roleBoxModel.isAnotherRoleSelected() ? askForRoleName() : roleBoxModel.getSelectedRole(); if (memberRole != null && selectedRole != null && !memberRole.equals(selectedRole)) { applyRoleToSelection(selectedRole.trim()); } } }); roleBox.setVisible(false); enterRoleAction = new EnterRoleAction(); // just for the shortcut sortAndFixAction = new SortAndFixAction(chosenRelation); // [±][X] relation U [AZ][Down][Edit] chosenRelationPanel = new JPanel(new GridBagLayout()); addRemoveMemberAction = new AddRemoveMemberAction(chosenRelation, sortAndFixAction); chosenRelationPanel.add(new JButton(addRemoveMemberAction), GBC.std()); chosenRelationPanel.add(sizeButton(new JButton(new ClearChosenRelationAction(chosenRelation)), 32, 0), GBC.std()); final ChosenRelationComponent chosenRelationComponent = new ChosenRelationComponent(chosenRelation); chosenRelationComponent.addMouseListener(relationMouseAdapter); chosenRelationPanel.add(chosenRelationComponent, GBC.std().fill().insets(5, 0, 5, 0)); chosenRelationPanel.add(roleBox, GBC.std().fill().insets(5, 0, 5, 0)); final JButton sortAndFixButton = (JButton) sizeButton(new JButton(sortAndFixAction), 32, 0); chosenRelationPanel.add(sortAndFixButton, GBC.std().fill(GBC.VERTICAL)); final Action downloadChosenRelationAction = new DownloadChosenRelationAction(chosenRelation); final JButton downloadButton = (JButton) sizeButton(new JButton(downloadChosenRelationAction), 32, 0); chosenRelationPanel.add(downloadButton, GBC.std().fill(GBC.VERTICAL)); chosenRelationPanel.add(new JButton(new EditChosenRelationAction(chosenRelation)), GBC.eol().fill(GBC.VERTICAL)); rcPanel.add(chosenRelationPanel, BorderLayout.NORTH); roleBox.addPropertyChangeListener("enabled", new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { boolean showRoleBox = roleBox.isEnabled(); roleBox.setVisible(showRoleBox); chosenRelationComponent.setVisible(!showRoleBox); } }); sortAndFixAction.addPropertyChangeListener(new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { sortAndFixButton.setVisible(sortAndFixAction.isEnabled()); } }); sortAndFixButton.setVisible(false); downloadChosenRelationAction.addPropertyChangeListener(new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { downloadButton.setVisible(downloadChosenRelationAction.isEnabled()); } }); downloadButton.setVisible(false); if (Main.pref.getBoolean(PREF_PREFIX + ".hidetopline", false)) { chosenRelationPanel.setVisible(false); } // [+][Multi] [X]Adm [X]Tags [X]1 JPanel bottomLine = new JPanel(new GridBagLayout()); createRelationAction = new CreateRelationAction(chosenRelation); bottomLine.add(new JButton(createRelationAction), GBC.std()); createMultipolygonAction = new CreateMultipolygonAction(chosenRelation); final JButton multipolygonButton = new JButton(createMultipolygonAction); bottomLine.add(multipolygonButton, GBC.std()); // bottomLine.add(sizeButton(new JButton(new MultipolygonSettingsAction()), 16, 0), GBC.std().fill(GBC.VERTICAL)); bottomLine.add(Box.createHorizontalGlue(), GBC.std().fill()); findRelationAction = new FindRelationAction(chosenRelation); bottomLine.add(new JButton(findRelationAction), GBC.eol()); rcPanel.add(sizeButton(bottomLine, 0, 24), BorderLayout.SOUTH); multipolygonButton.addMouseListener(new MouseAdapter() { @Override public void mousePressed(MouseEvent e) { checkPopup(e); } @Override public void mouseReleased(MouseEvent e) { checkPopup(e); } private void checkPopup(MouseEvent e) { if (e.isPopupTrigger()) { multiPopupMenu.show(e.getComponent(), e.getX(), e.getY()); } } }); createLayout(rcPanel, false, null); } private static final Color CHOSEN_RELATION_COLOR = new Color(255, 255, 128); private void configureRelationsTable(final JTable relationsTable) { relationsTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); relationsTable.setTableHeader(null); relationsTable.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { Point p = e.getPoint(); int row = relationsTable.rowAtPoint(p); if (SwingUtilities.isLeftMouseButton(e) && row >= 0) { Relation relation = (Relation) relationsData.getValueAt(row, 0); if (e.getClickCount() > 1) { Main.getLayerManager().getEditLayer().data.setSelected(relation); } } } @Override public void mousePressed(MouseEvent e) { checkPopup(e); } @Override public void mouseReleased(MouseEvent e) { checkPopup(e); } public void checkPopup(MouseEvent e) { if (e.isPopupTrigger()) { Point p = e.getPoint(); int row = relationsTable.rowAtPoint(p); if (row > -1) { Relation relation = (Relation) relationsData.getValueAt(row, 0); JPopupMenu menu = chosenRelation.isSame(relation) ? popupMenu : new ChosenRelationPopupMenu(new StaticChosenRelation(relation)); menu.show(relationsTable, p.x, p.y-5); } } } }); TableColumnModel columns = relationsTable.getColumnModel(); columns.getColumn(0).setCellRenderer(new OsmPrimitivRenderer() { @Override protected String getComponentToolTipText(OsmPrimitive value) { return null; } @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { Component c = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); if (!isSelected && value instanceof Relation && chosenRelation.isSame(value)) { c.setBackground(CHOSEN_RELATION_COLOR); } else { c.setBackground(table.getBackground()); } return c; } }); columns.getColumn(1).setCellRenderer(new DefaultTableCellRenderer() { @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { Component c = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); if (!isSelected && chosenRelation.isSame(table.getValueAt(row, 0))) { c.setBackground(CHOSEN_RELATION_COLOR); } else { c.setBackground(table.getBackground()); } return c; } }); columns.getColumn(1).setPreferredWidth(40); columns.getColumn(0).setPreferredWidth(220); relationsTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() { @Override public void valueChanged(ListSelectionEvent e) { int selectedRow = relationsTable.getSelectedRow(); if (selectedRow >= 0) { chosenRelation.set((Relation) relationsData.getValueAt(selectedRow, 0)); relationsTable.clearSelection(); } } }); } private JComponent sizeButton(JComponent b, int width, int height) { Dimension pref = b.getPreferredSize(); b.setPreferredSize(new Dimension(width <= 0 ? pref.width : width, height <= 0 ? pref.height : height)); return b; } @Override public void hideNotify() { SelectionEventManager.getInstance().removeSelectionListener(this); Main.getLayerManager().removeActiveLayerChangeListener(this); DatasetEventManager.getInstance().removeDatasetListener(chosenRelation); chosenRelation.clear(); } @Override public void showNotify() { SelectionEventManager.getInstance().addSelectionListener(this, FireMode.IN_EDT_CONSOLIDATED); Main.getLayerManager().addActiveLayerChangeListener(this); DatasetEventManager.getInstance().addDatasetListener(chosenRelation, FireMode.IN_EDT); } public ChosenRelation getChosenRelation() { return chosenRelation; } @Override public void chosenRelationChanged(Relation oldRelation, Relation newRelation) { if (chosenRelationPanel != null && Main.pref.getBoolean(PREF_PREFIX + ".hidetopline", false)) { chosenRelationPanel.setVisible(newRelation != null); } if (Main.getLayerManager().getEditDataSet() != null) { selectionChanged(Main.getLayerManager().getEditDataSet().getSelected()); } roleBoxModel.update(); } @Override public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) { if (!isVisible() || relationsData == null) return; roleBoxModel.update(); // repopulate relations table relationsData.setRowCount(0); sortAndFixAction.chosenRelationChanged(chosenRelation.get(), chosenRelation.get()); if (newSelection == null) return; Set<Relation> relations = new TreeSet<>( DefaultNameFormatter.getInstance().getRelationComparator()); for (OsmPrimitive element : newSelection) { for (OsmPrimitive ref : element.getReferrers()) { if (ref instanceof Relation && !ref.isIncomplete() && !ref.isDeleted()) { relations.add((Relation) ref); } } } for (Relation rel : relations) { String role = null; for (RelationMember m : rel.getMembers()) { for (OsmPrimitive element : newSelection) { if (m.getMember().equals(element)) { if (role == null) { role = m.getRole(); } else if (!role.equals(m.getRole())) { role = tr("<different>"); break; } } } } relationsData.addRow(new Object[] {rel, role == null ? "" : role}); } for (OsmPrimitive element : newSelection) { if (element instanceof Relation && !chosenRelation.isSame(element)) { relationsData.addRow(new Object[] {element, ""}); } } } private void updateSelection() { if (Main.getLayerManager().getEditDataSet() == null) { selectionChanged(Collections.<OsmPrimitive>emptyList()); } else { selectionChanged(Main.getLayerManager().getEditDataSet().getSelected()); } } @Override public void activeOrEditLayerChanged(ActiveLayerChangeEvent e) { updateSelection(); } @Override public void destroy() { enterRoleAction.destroy(); findRelationAction.destroy(); createMultipolygonAction.destroy(); createRelationAction.destroy(); addRemoveMemberAction.destroy(); super.destroy(); } private static final String POSSIBLE_ROLES_FILE = "relcontext/possible_roles.txt"; private static final Map<String, List<String>> possibleRoles = loadRoles(); private static Map<String, List<String>> loadRoles() { Map<String, List<String>> result = new HashMap<>(); ClassLoader classLoader = RelContextDialog.class.getClassLoader(); try (InputStream possibleRolesStream = classLoader.getResourceAsStream(POSSIBLE_ROLES_FILE); BufferedReader r = new BufferedReader(new InputStreamReader(possibleRolesStream, StandardCharsets.UTF_8)); ) { while (r.ready()) { String line = r.readLine(); String[] typeAndRoles = line.split(":", 2); if (typeAndRoles.length == 2 && typeAndRoles[1].length() > 0) { String type = typeAndRoles[0].trim(); StringTokenizer t = new StringTokenizer(typeAndRoles[1], " ,;\""); List<String> roles = new ArrayList<>(); while (t.hasMoreTokens()) { roles.add(t.nextToken()); } result.put(type, roles); } } } catch (Exception e) { Main.error("[RelToolbox] Error reading possible roles file."); Main.error(e); } return result; } private String askForRoleName() { JPanel panel = new JPanel(new GridBagLayout()); List<String> items = new ArrayList<>(); for (String role : roleBoxModel.getRoles()) { if (role.length() > 1) { items.add(role); } } final AutoCompletingComboBox role = new AutoCompletingComboBox(); role.setPossibleItems(items); role.setEditable(true); panel.add(new JLabel(tr("Role")), GBC.std()); panel.add(Box.createHorizontalStrut(10), GBC.std()); panel.add(role, GBC.eol().fill(GBC.HORIZONTAL)); final JOptionPane optionPane = new JOptionPane(panel, JOptionPane.QUESTION_MESSAGE, JOptionPane.OK_CANCEL_OPTION) { @Override public void selectInitialValue() { role.requestFocusInWindow(); role.getEditor().selectAll(); } }; final JDialog dlg = optionPane.createDialog(Main.parent, tr("Specify role")); dlg.setModalityType(ModalityType.DOCUMENT_MODAL); role.getEditor().addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { dlg.setVisible(false); optionPane.setValue(JOptionPane.OK_OPTION); } }); dlg.setVisible(true); Object answer = optionPane.getValue(); if (answer == null || answer == JOptionPane.UNINITIALIZED_VALUE || (answer instanceof Integer && (Integer) answer != JOptionPane.OK_OPTION)) return null; return role.getEditor().getItem().toString().trim(); } private class ChosenRelationMouseAdapter extends MouseAdapter { @Override public void mouseClicked(MouseEvent e) { if (e.isControlDown() || !(e.getComponent() instanceof JComboBox)) // do not use left click handler on combo box if (SwingUtilities.isLeftMouseButton(e) && chosenRelation.get() != null && Main.getLayerManager().getEditLayer() != null) { Main.getLayerManager().getEditLayer().data.setSelected(chosenRelation.get()); } } @Override public void mousePressed(MouseEvent e) { checkPopup(e); } @Override public void mouseReleased(MouseEvent e) { checkPopup(e); } private void checkPopup(MouseEvent e) { if (e.isPopupTrigger() && chosenRelation.get() != null) { popupMenu.show(e.getComponent(), e.getX(), e.getY() - 5); } } } private static class ChosenRelationPopupMenu extends JPopupMenu { ChosenRelationPopupMenu(ChosenRelation chosenRelation) { add(new SelectMembersAction(chosenRelation)); add(new SelectRelationAction(chosenRelation)); add(new DuplicateChosenRelationAction(chosenRelation)); add(new DeleteChosenRelationAction(chosenRelation)); add(new DownloadParentsAction(chosenRelation)); add(new ReconstructPolygonAction(chosenRelation)); add(new ReconstructRouteAction(chosenRelation)); addSeparator(); add(new SelectInRelationPanelAction(chosenRelation)); add(new RelationHelpAction(chosenRelation)); } } protected void applyRoleToSelection(String role) { if (chosenRelation != null && chosenRelation.get() != null && Main.getLayerManager().getEditDataSet() != null && !Main.getLayerManager().getEditDataSet().selectionEmpty()) { Collection<OsmPrimitive> selected = Main.getLayerManager().getEditDataSet().getSelected(); Relation r = chosenRelation.get(); List<Command> commands = new ArrayList<>(); for (int i = 0; i < r.getMembersCount(); i++) { RelationMember m = r.getMember(i); if (selected.contains(m.getMember())) { if (!role.equals(m.getRole())) { commands.add(new ChangeRelationMemberRoleCommand(r, i, role)); } } } if (!commands.isEmpty()) { // Main.main.undoRedo.add(new ChangeCommand(chosenRelation.get(), r)); Main.main.undoRedo.add(new SequenceCommand(tr("Change relation member roles to {0}", role), commands)); } } } private static class RelationTableModel extends DefaultTableModel { @Override public boolean isCellEditable(int row, int column) { return false; } @Override public Class<?> getColumnClass(int columnIndex) { return columnIndex == 0 ? Relation.class : String.class; } } private static class MultipolygonSettingsPopup extends JPopupMenu implements ActionListener { MultipolygonSettingsPopup() { addMenuItem("boundary", tr("Create administrative boundary relations")); addMenuItem("boundaryways", tr("Add tags boundary and admin_level to boundary relation ways")); addMenuItem("tags", tr("Move area tags from contour to relation")); addMenuItem("alltags", tr("When moving tags, consider even non-repeating ones")); addMenuItem("allowsplit", tr("Always split ways of neighbouring multipolygons")); } protected final JCheckBoxMenuItem addMenuItem(String property, String title) { String fullProperty = PREF_PREFIX + ".multipolygon." + property; JCheckBoxMenuItem item = new JCheckBoxMenuItem(tr(title)); item.setSelected(Main.pref.getBoolean(fullProperty, CreateMultipolygonAction.getDefaultPropertyValue(property))); item.setActionCommand(fullProperty); item.addActionListener(this); add(item); return item; } @Override public void actionPerformed(ActionEvent e) { String property = e.getActionCommand(); if (property != null && property.length() > 0 && e.getSource() instanceof JCheckBoxMenuItem) { boolean value = ((JCheckBoxMenuItem) e.getSource()).isSelected(); Main.pref.put(property, value); show(getInvoker(), getX(), getY()); } } } private class EnterRoleAction extends JosmAction implements ChosenRelationListener { EnterRoleAction() { super(tr("Change role"), (String) null, tr("Enter role for selected members"), Shortcut.registerShortcut("reltoolbox:changerole", tr("Relation Toolbox: {0}", tr("Enter role for selected members")), KeyEvent.VK_R, Shortcut.ALT_CTRL), false, "relcontext/enterrole", true); chosenRelation.addChosenRelationListener(this); updateEnabledState(); } @Override public void actionPerformed(ActionEvent e) { if (roleBoxModel.membersRole != null) { String role = askForRoleName(); if (role != null) { applyRoleToSelection(role); } } } @Override public void chosenRelationChanged(Relation oldRelation, Relation newRelation) { setEnabled(newRelation != null); } } private class RoleComboBoxModel extends AbstractListModel<String> implements ComboBoxModel<String> { private List<String> roles = new ArrayList<>(); private int selectedIndex = -1; private JComboBox<String> combobox; private String membersRole; private final String EMPTY_ROLE = tr("<empty>"); private final String ANOTHER_ROLE = tr("another..."); RoleComboBoxModel(JComboBox<String> combobox) { super(); this.combobox = combobox; update(); } public void update() { membersRole = getSelectedMembersRoleIntl(); if (membersRole == null) { if (combobox.isEnabled()) { combobox.setEnabled(false); } return; } if (!combobox.isEnabled()) { combobox.setEnabled(true); } List<String> items = new ArrayList<>(); if (chosenRelation != null && chosenRelation.get() != null) { if (chosenRelation.isMultipolygon()) { items.add("outer"); items.add("inner"); } if (chosenRelation.get().get("type") != null) { List<String> values = possibleRoles.get(chosenRelation.get().get("type")); if (values != null) { items.addAll(values); } } for (RelationMember m : chosenRelation.get().getMembers()) { if (m.getRole().length() > 0 && !items.contains(m.getRole())) { items.add(m.getRole()); } } } items.add(EMPTY_ROLE); if (!items.contains(membersRole)) { items.add(0, membersRole); } items.add(ANOTHER_ROLE); roles = Collections.unmodifiableList(items); if (membersRole != null) { setSelectedItem(membersRole); } else { fireContentsChanged(this, -1, -1); } combobox.repaint(); } public String getSelectedMembersRole() { return membersRole == EMPTY_ROLE ? "" : membersRole; } public boolean isAnotherRoleSelected() { return getSelectedRole() != null && getSelectedRole().equals(ANOTHER_ROLE); } private String getSelectedMembersRoleIntl() { String role = null; if (chosenRelation != null && chosenRelation.get() != null && Main.getLayerManager().getEditDataSet() != null && !Main.getLayerManager().getEditDataSet().selectionEmpty()) { Collection<OsmPrimitive> selected = Main.getLayerManager().getEditDataSet().getSelected(); for (RelationMember m : chosenRelation.get().getMembers()) { if (selected.contains(m.getMember())) { if (role == null) { role = m.getRole(); } else if (m.getRole() != null && !role.equals(m.getRole())) { role = tr("<different>"); break; } } } } return role == null ? null : role.length() == 0 ? EMPTY_ROLE : role; } public List<String> getRoles() { return roles; } @Override public int getSize() { return roles.size(); } @Override public String getElementAt(int index) { return getRole(index); } public String getRole(int index) { return roles.get(index); } @Override public void setSelectedItem(Object anItem) { int newIndex = anItem == null ? -1 : roles.indexOf(anItem); if (newIndex != selectedIndex) { selectedIndex = newIndex; fireContentsChanged(this, -1, -1); } } @Override public Object getSelectedItem() { return selectedIndex < 0 || selectedIndex >= getSize() ? null : getRole(selectedIndex); } public String getSelectedRole() { String role = selectedIndex < 0 || selectedIndex >= getSize() ? null : getRole(selectedIndex); return role != null && role.equals(EMPTY_ROLE) ? "" : role; } } }