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

Last change on this file since 28857 was 28857, checked in by larry0ua, 13 years ago

'RelToolbox: make natural sort for relation and find relation lists'

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