Changeset 9496 in josm for trunk/src/org
- Timestamp:
- 2016-01-17T02:54:22+01:00 (9 years ago)
- Location:
- trunk/src/org/openstreetmap/josm
- Files:
-
- 29 added
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/org/openstreetmap/josm/actions/mapmode/DeleteAction.java
r9472 r9496 331 331 * 332 332 * @param layer the layer in whose context the relations are deleted. Must not be null. 333 * @param toDelete 333 * @param toDelete the relations to be deleted. Must not be null. 334 334 * @throws IllegalArgumentException if layer is null 335 335 * @throws IllegalArgumentException if toDelete is null … … 344 344 Main.main.undoRedo.add(cmd); 345 345 for (Relation relation : toDelete) { 346 if ( getCurrentDataSet().getSelectedRelations().contains(relation)) {347 getCurrentDataSet().toggleSelected(relation);346 if (layer.data.getSelectedRelations().contains(relation)) { 347 layer.data.toggleSelected(relation); 348 348 } 349 349 RelationDialogManager.getRelationDialogManager().close(layer, relation); -
trunk/src/org/openstreetmap/josm/gui/ConditionalOptionPaneUtil.java
r8958 r9496 5 5 6 6 import java.awt.Component; 7 import java.awt.GraphicsEnvironment; 7 8 import java.awt.GridBagLayout; 8 import java.awt.HeadlessException;9 9 import java.util.HashMap; 10 10 import java.util.HashSet; … … 113 113 * @param defaultOption the default option; only meaningful if options is used; can be null 114 114 * 115 * @return the option selected by user. {@link JOptionPane#CLOSED_OPTION} if the dialog was closed. 116 * @throws HeadlessException if <code>GraphicsEnvironment.isHeadless</code> returns <code>true</code> 115 * @return the option selected by user. 116 * {@link JOptionPane#CLOSED_OPTION} if the dialog was closed. 117 * {@link JOptionPane#YES_OPTION} if <code>GraphicsEnvironment.isHeadless</code> returns <code>true</code> 117 118 */ 118 119 public static int showOptionDialog(String preferenceKey, Component parent, Object message, String title, int optionType, 119 int messageType, Object[] options, Object defaultOption) throws HeadlessException{120 int messageType, Object[] options, Object defaultOption) { 120 121 int ret = getDialogReturnValue(preferenceKey); 121 122 if (isYesOrNo(ret)) 122 123 return ret; 123 124 MessagePanel pnl = new MessagePanel(message, isInBulkOperation(preferenceKey)); 124 ret = JOptionPane.showOptionDialog(parent, pnl, title, optionType, messageType, null, options, defaultOption); 125 if (GraphicsEnvironment.isHeadless()) { 126 // for unit tests 127 ret = JOptionPane.YES_OPTION; 128 } else { 129 ret = JOptionPane.showOptionDialog(parent, pnl, title, optionType, messageType, null, options, defaultOption); 130 } 125 131 if (isYesOrNo(ret)) { 126 132 pnl.getNotShowAgain().store(preferenceKey, ret); … … 151 157 * @param optionType the option type 152 158 * @param messageType the message type 153 * @param trueOption 159 * @param trueOption if this option is selected the method replies true 154 160 * 155 161 * 156 162 * @return true, if the selected option is equal to <code>trueOption</code>, otherwise false. 157 * @throws HeadlessExceptionif <code>GraphicsEnvironment.isHeadless</code> returns <code>true</code>163 * {@code trueOption} if <code>GraphicsEnvironment.isHeadless</code> returns <code>true</code> 158 164 * 159 165 * @see JOptionPane#INFORMATION_MESSAGE … … 162 168 */ 163 169 public static boolean showConfirmationDialog(String preferenceKey, Component parent, Object message, String title, 164 int optionType, int messageType, int trueOption) throws HeadlessException{170 int optionType, int messageType, int trueOption) { 165 171 int ret = getDialogReturnValue(preferenceKey); 166 172 if (isYesOrNo(ret)) 167 173 return ret == trueOption; 168 174 MessagePanel pnl = new MessagePanel(message, isInBulkOperation(preferenceKey)); 169 ret = JOptionPane.showConfirmDialog(parent, pnl, title, optionType, messageType); 175 if (GraphicsEnvironment.isHeadless()) { 176 // for unit tests 177 ret = trueOption; 178 } else { 179 ret = JOptionPane.showConfirmDialog(parent, pnl, title, optionType, messageType); 180 } 170 181 if (isYesOrNo(ret)) { 171 182 pnl.getNotShowAgain().store(preferenceKey, ret); -
trunk/src/org/openstreetmap/josm/gui/dialogs/relation/GenericRelationEditor.java
r9438 r9496 4 4 import static org.openstreetmap.josm.gui.help.HelpUtil.ht; 5 5 import static org.openstreetmap.josm.tools.I18n.tr; 6 import static org.openstreetmap.josm.tools.I18n.trn;7 6 8 7 import java.awt.BorderLayout; … … 21 20 import java.awt.event.WindowAdapter; 22 21 import java.awt.event.WindowEvent; 23 import java.beans.PropertyChangeEvent;24 import java.beans.PropertyChangeListener;25 22 import java.util.ArrayList; 26 23 import java.util.Collection; … … 46 43 import javax.swing.JToolBar; 47 44 import javax.swing.KeyStroke; 48 import javax.swing.SwingUtilities;49 45 import javax.swing.event.ChangeEvent; 50 46 import javax.swing.event.ChangeListener; 51 import javax.swing.event.DocumentEvent;52 import javax.swing.event.DocumentListener;53 47 import javax.swing.event.ListSelectionEvent; 54 48 import javax.swing.event.ListSelectionListener; 55 import javax.swing.event.TableModelEvent;56 import javax.swing.event.TableModelListener;57 49 58 50 import org.openstreetmap.josm.Main; 59 import org.openstreetmap.josm.actions.CopyAction;60 51 import org.openstreetmap.josm.actions.ExpertToggleAction; 61 52 import org.openstreetmap.josm.actions.JosmAction; 62 import org.openstreetmap.josm.command.AddCommand;63 53 import org.openstreetmap.josm.command.ChangeCommand; 64 54 import org.openstreetmap.josm.command.Command; 65 import org.openstreetmap.josm.command.conflict.ConflictAddCommand;66 import org.openstreetmap.josm.data.conflict.Conflict;67 import org.openstreetmap.josm.data.osm.DataSet;68 55 import org.openstreetmap.josm.data.osm.OsmPrimitive; 69 import org.openstreetmap.josm.data.osm.PrimitiveData;70 56 import org.openstreetmap.josm.data.osm.Relation; 71 57 import org.openstreetmap.josm.data.osm.RelationMember; … … 73 59 import org.openstreetmap.josm.gui.ConditionalOptionPaneUtil; 74 60 import org.openstreetmap.josm.gui.DefaultNameFormatter; 75 import org.openstreetmap.josm.gui.HelpAwareOptionPane;76 import org.openstreetmap.josm.gui.HelpAwareOptionPane.ButtonSpec;77 61 import org.openstreetmap.josm.gui.MainMenu; 78 62 import org.openstreetmap.josm.gui.SideButton; 63 import org.openstreetmap.josm.gui.dialogs.relation.actions.AddSelectedAfterSelection; 64 import org.openstreetmap.josm.gui.dialogs.relation.actions.AddSelectedAtEndAction; 65 import org.openstreetmap.josm.gui.dialogs.relation.actions.AddSelectedAtStartAction; 66 import org.openstreetmap.josm.gui.dialogs.relation.actions.AddSelectedBeforeSelection; 67 import org.openstreetmap.josm.gui.dialogs.relation.actions.ApplyAction; 68 import org.openstreetmap.josm.gui.dialogs.relation.actions.CancelAction; 69 import org.openstreetmap.josm.gui.dialogs.relation.actions.CopyMembersAction; 70 import org.openstreetmap.josm.gui.dialogs.relation.actions.DeleteCurrentRelationAction; 71 import org.openstreetmap.josm.gui.dialogs.relation.actions.DownloadIncompleteMembersAction; 72 import org.openstreetmap.josm.gui.dialogs.relation.actions.DownloadSelectedIncompleteMembersAction; 73 import org.openstreetmap.josm.gui.dialogs.relation.actions.DuplicateRelationAction; 74 import org.openstreetmap.josm.gui.dialogs.relation.actions.EditAction; 75 import org.openstreetmap.josm.gui.dialogs.relation.actions.MoveDownAction; 76 import org.openstreetmap.josm.gui.dialogs.relation.actions.MoveUpAction; 77 import org.openstreetmap.josm.gui.dialogs.relation.actions.OKAction; 78 import org.openstreetmap.josm.gui.dialogs.relation.actions.PasteMembersAction; 79 import org.openstreetmap.josm.gui.dialogs.relation.actions.RemoveAction; 80 import org.openstreetmap.josm.gui.dialogs.relation.actions.RemoveSelectedAction; 81 import org.openstreetmap.josm.gui.dialogs.relation.actions.ReverseAction; 82 import org.openstreetmap.josm.gui.dialogs.relation.actions.SelectPrimitivesForSelectedMembersAction; 83 import org.openstreetmap.josm.gui.dialogs.relation.actions.SelectedMembersForSelectionAction; 84 import org.openstreetmap.josm.gui.dialogs.relation.actions.SetRoleAction; 85 import org.openstreetmap.josm.gui.dialogs.relation.actions.SortAction; 86 import org.openstreetmap.josm.gui.dialogs.relation.actions.SortBelowAction; 79 87 import org.openstreetmap.josm.gui.help.ContextSensitiveHelpAction; 80 88 import org.openstreetmap.josm.gui.help.HelpUtil; 81 89 import org.openstreetmap.josm.gui.layer.OsmDataLayer; 82 import org.openstreetmap.josm.gui.tagging.TagEditorModel;83 90 import org.openstreetmap.josm.gui.tagging.TagEditorPanel; 84 91 import org.openstreetmap.josm.gui.tagging.ac.AutoCompletingTextField; … … 88 95 import org.openstreetmap.josm.gui.tagging.presets.TaggingPresetType; 89 96 import org.openstreetmap.josm.gui.tagging.presets.TaggingPresets; 90 import org.openstreetmap.josm.io.OnlineResource;91 97 import org.openstreetmap.josm.tools.CheckParameterUtil; 92 import org.openstreetmap.josm.tools.ImageProvider;93 98 import org.openstreetmap.josm.tools.Shortcut; 94 99 import org.openstreetmap.josm.tools.WindowGeometry; … … 119 124 private JMenuItem windowMenuItem; 120 125 /** 121 * Button for performing the {@link org.openstreetmap.josm.gui.dialogs.relation. GenericRelationEditor.SortBelowAction}.126 * Button for performing the {@link org.openstreetmap.josm.gui.dialogs.relation.actions.SortBelowAction}. 122 127 */ 123 128 private JButton sortBelowButton; … … 134 139 */ 135 140 public GenericRelationEditor(OsmDataLayer layer, Relation relation, Collection<RelationMember> selectedMembers) { 136 super(layer, relation , selectedMembers);141 super(layer, relation); 137 142 138 143 setRememberWindowGeometry(getClass().getName() + ".geometry", … … 227 232 Shortcut.registerShortcut("system:pastestyle", tr("Edit: {0}", tr("Paste Tags")), KeyEvent.VK_V, Shortcut.CTRL_SHIFT).getKeyStroke()); 228 233 // CHECKSTYLE.ON: LineLength 229 registerCopyPasteAction(new PasteMembersAction(), "PASTE_MEMBERS", Shortcut.getPasteKeyStroke()); 230 registerCopyPasteAction(new CopyMembersAction(), "COPY_MEMBERS", Shortcut.getCopyKeyStroke()); 234 235 registerCopyPasteAction(new PasteMembersAction(memberTableModel, getLayer(), this) { 236 @Override 237 public void actionPerformed(ActionEvent e) { 238 super.actionPerformed(e); 239 tfRole.requestFocusInWindow(); 240 } 241 }, "PASTE_MEMBERS", Shortcut.getPasteKeyStroke()); 242 243 registerCopyPasteAction(new CopyMembersAction(memberTableModel, getLayer(), this), 244 "COPY_MEMBERS", Shortcut.getCopyKeyStroke()); 231 245 232 246 tagEditorPanel.setNextFocusComponent(memberTable); … … 244 258 JToolBar tb = new JToolBar(); 245 259 tb.setFloatable(false); 246 tb.add(new ApplyAction( ));247 tb.add(new DuplicateRelationAction( ));248 DeleteCurrentRelationAction deleteAction = new DeleteCurrentRelationAction( );260 tb.add(new ApplyAction(memberTable, memberTableModel, tagEditorPanel.getModel(), getLayer(), this)); 261 tb.add(new DuplicateRelationAction(memberTableModel, tagEditorPanel.getModel(), getLayer())); 262 DeleteCurrentRelationAction deleteAction = new DeleteCurrentRelationAction(getLayer(), this); 249 263 addPropertyChangeListener(deleteAction); 250 264 tb.add(deleteAction); … … 258 272 */ 259 273 protected JPanel buildOkCancelButtonPanel() { 260 JPanel pnl = new JPanel(); 261 pnl.setLayout(new FlowLayout(FlowLayout.CENTER)); 262 263 pnl.add(new SideButton(new OKAction())); 264 pnl.add(new SideButton(new CancelAction())); 274 JPanel pnl = new JPanel(new FlowLayout(FlowLayout.CENTER)); 275 pnl.add(new SideButton(new OKAction(memberTable, memberTableModel, tagEditorPanel.getModel(), getLayer(), this, tfRole))); 276 pnl.add(new SideButton(new CancelAction(memberTable, memberTableModel, tagEditorPanel.getModel(), getLayer(), this, tfRole))); 265 277 pnl.add(new SideButton(new ContextSensitiveHelpAction(ht("/Dialog/RelationEditor")))); 266 278 return pnl; … … 273 285 */ 274 286 protected JPanel buildTagEditorPanel() { 275 JPanel pnl = new JPanel(); 276 pnl.setLayout(new GridBagLayout()); 287 JPanel pnl = new JPanel(new GridBagLayout()); 277 288 278 289 GridBagConstraints gc = new GridBagConstraints(); … … 366 377 tfRole.setText(Main.pref.get("relation.editor.generic.lastrole", "")); 367 378 p3.add(tfRole); 368 SetRoleAction setRoleAction = new SetRoleAction( );379 SetRoleAction setRoleAction = new SetRoleAction(memberTable, memberTableModel, tfRole); 369 380 memberTableModel.getSelectionModel().addListSelectionListener(setRoleAction); 370 381 tfRole.getDocument().addDocumentListener(setRoleAction); … … 488 499 489 500 // -- move up action 490 MoveUpAction moveUpAction = new MoveUpAction( );501 MoveUpAction moveUpAction = new MoveUpAction(memberTable, memberTableModel, "moveUp"); 491 502 memberTableModel.getSelectionModel().addListSelectionListener(moveUpAction); 492 503 tb.add(moveUpAction); 493 memberTable.getActionMap().put("moveUp", moveUpAction);494 504 495 505 // -- move down action 496 MoveDownAction moveDownAction = new MoveDownAction( );506 MoveDownAction moveDownAction = new MoveDownAction(memberTable, memberTableModel, "moveDown"); 497 507 memberTableModel.getSelectionModel().addListSelectionListener(moveDownAction); 498 508 tb.add(moveDownAction); 499 memberTable.getActionMap().put("moveDown", moveDownAction);500 509 501 510 tb.addSeparator(); 502 511 503 512 // -- edit action 504 EditAction editAction = new EditAction( );513 EditAction editAction = new EditAction(memberTable, memberTableModel, getLayer()); 505 514 memberTableModel.getSelectionModel().addListSelectionListener(editAction); 506 515 tb.add(editAction); 507 516 508 517 // -- delete action 509 RemoveAction removeSelectedAction = new RemoveAction( );518 RemoveAction removeSelectedAction = new RemoveAction(memberTable, memberTableModel, "removeSelected"); 510 519 memberTable.getSelectionModel().addListSelectionListener(removeSelectedAction); 511 520 tb.add(removeSelectedAction); 512 memberTable.getActionMap().put("removeSelected", removeSelectedAction);513 521 514 522 tb.addSeparator(); 515 523 // -- sort action 516 SortAction sortAction = new SortAction( );524 SortAction sortAction = new SortAction(memberTable, memberTableModel); 517 525 memberTableModel.addTableModelListener(sortAction); 518 526 tb.add(sortAction); 519 final SortBelowAction sortBelowAction = new SortBelowAction( );527 final SortBelowAction sortBelowAction = new SortBelowAction(memberTable, memberTableModel); 520 528 memberTableModel.addTableModelListener(sortBelowAction); 521 529 memberTableModel.getSelectionModel().addListSelectionListener(sortBelowAction); … … 523 531 524 532 // -- reverse action 525 ReverseAction reverseAction = new ReverseAction( );533 ReverseAction reverseAction = new ReverseAction(memberTable, memberTableModel); 526 534 memberTableModel.addTableModelListener(reverseAction); 527 535 tb.add(reverseAction); … … 530 538 531 539 // -- download action 532 DownloadIncompleteMembersAction downloadIncompleteMembersAction = new DownloadIncompleteMembersAction(); 540 DownloadIncompleteMembersAction downloadIncompleteMembersAction = new DownloadIncompleteMembersAction( 541 memberTable, memberTableModel, "downloadIncomplete", getLayer(), this); 533 542 memberTable.getModel().addTableModelListener(downloadIncompleteMembersAction); 534 543 tb.add(downloadIncompleteMembersAction); 535 memberTable.getActionMap().put("downloadIncomplete", downloadIncompleteMembersAction);536 544 537 545 // -- download selected action 538 DownloadSelectedIncompleteMembersAction downloadSelectedIncompleteMembersAction = new DownloadSelectedIncompleteMembersAction(); 546 DownloadSelectedIncompleteMembersAction downloadSelectedIncompleteMembersAction = new DownloadSelectedIncompleteMembersAction( 547 memberTable, memberTableModel, null, getLayer(), this); 539 548 memberTable.getModel().addTableModelListener(downloadSelectedIncompleteMembersAction); 540 549 memberTable.getSelectionModel().addListSelectionListener(downloadSelectedIncompleteMembersAction); … … 560 569 561 570 // -- add at start action 562 AddSelectedAtStartAction addSelectionAction = new AddSelectedAtStartAction(); 571 AddSelectedAtStartAction addSelectionAction = new AddSelectedAtStartAction( 572 memberTableModel, selectionTableModel, this); 563 573 selectionTableModel.addTableModelListener(addSelectionAction); 564 574 tb.add(addSelectionAction); 565 575 566 576 // -- add before selected action 567 AddSelectedBeforeSelection addSelectedBeforeSelectionAction = new AddSelectedBeforeSelection(); 577 AddSelectedBeforeSelection addSelectedBeforeSelectionAction = new AddSelectedBeforeSelection( 578 memberTableModel, selectionTableModel, this); 568 579 selectionTableModel.addTableModelListener(addSelectedBeforeSelectionAction); 569 580 memberTableModel.getSelectionModel().addListSelectionListener(addSelectedBeforeSelectionAction); … … 571 582 572 583 // -- add after selected action 573 AddSelectedAfterSelection addSelectedAfterSelectionAction = new AddSelectedAfterSelection(); 584 AddSelectedAfterSelection addSelectedAfterSelectionAction = new AddSelectedAfterSelection( 585 memberTableModel, selectionTableModel, this); 574 586 selectionTableModel.addTableModelListener(addSelectedAfterSelectionAction); 575 587 memberTableModel.getSelectionModel().addListSelectionListener(addSelectedAfterSelectionAction); … … 577 589 578 590 // -- add at end action 579 AddSelectedAtEndAction addSelectedAtEndAction = new AddSelectedAtEndAction(); 591 AddSelectedAtEndAction addSelectedAtEndAction = new AddSelectedAtEndAction( 592 memberTableModel, selectionTableModel, this); 580 593 selectionTableModel.addTableModelListener(addSelectedAtEndAction); 581 594 tb.add(addSelectedAtEndAction); … … 584 597 585 598 // -- select members action 586 SelectedMembersForSelectionAction selectMembersForSelectionAction = new SelectedMembersForSelectionAction(); 599 SelectedMembersForSelectionAction selectMembersForSelectionAction = new SelectedMembersForSelectionAction( 600 memberTableModel, selectionTableModel, getLayer()); 587 601 selectionTableModel.addTableModelListener(selectMembersForSelectionAction); 588 602 memberTableModel.addTableModelListener(selectMembersForSelectionAction); … … 590 604 591 605 // -- select action 592 SelectPrimitivesForSelectedMembersAction selectAction = new SelectPrimitivesForSelectedMembersAction(); 606 SelectPrimitivesForSelectedMembersAction selectAction = new SelectPrimitivesForSelectedMembersAction( 607 memberTable, memberTableModel, getLayer()); 593 608 memberTable.getSelectionModel().addListSelectionListener(selectAction); 594 609 tb.add(selectAction); … … 597 612 598 613 // -- remove selected action 599 RemoveSelectedAction removeSelectedAction = new RemoveSelectedAction( );614 RemoveSelectedAction removeSelectedAction = new RemoveSelectedAction(memberTableModel, selectionTableModel, getLayer()); 600 615 selectionTableModel.addTableModelListener(removeSelectedAction); 601 616 tb.add(removeSelectedAction); … … 708 723 } 709 724 710 static class AddAbortException extends Exception { 711 } 712 713 static boolean confirmAddingPrimitive(OsmPrimitive primitive) throws AddAbortException { 725 /** 726 * Exception thrown when user aborts add operation. 727 */ 728 public static class AddAbortException extends Exception { 729 } 730 731 /** 732 * Asks confirmationbefore adding a primitive. 733 * @param primitive primitive to add 734 * @return {@code true} is user confirms the operation, {@code false} otherwise 735 * @throws AddAbortException if user aborts operation 736 */ 737 public static boolean confirmAddingPrimitive(OsmPrimitive primitive) throws AddAbortException { 714 738 String msg = tr("<html>This relation already has one or more members referring to<br>" 715 739 + "the object ''{0}''<br>" … … 736 760 return false; 737 761 case JOptionPane.CANCEL_OPTION: 762 default: 738 763 throw new AddAbortException(); 739 764 } 740 // should not happen 741 return false; 742 } 743 744 static void warnOfCircularReferences(OsmPrimitive primitive) { 765 } 766 767 /** 768 * Warn about circular references. 769 * @param primitive the concerned primitive 770 */ 771 public static void warnOfCircularReferences(OsmPrimitive primitive) { 745 772 String msg = tr("<html>You are trying to add a relation to itself.<br>" 746 773 + "<br>" … … 800 827 } 801 828 802 abstract class AddFromSelectionAction extends AbstractAction {803 protected boolean isPotentialDuplicate(OsmPrimitive primitive) {804 return memberTableModel.hasMembersReferringTo(Collections.singleton(primitive));805 }806 807 protected List<OsmPrimitive> filterConfirmedPrimitives(List<OsmPrimitive> primitives) throws AddAbortException {808 if (primitives == null || primitives.isEmpty())809 return primitives;810 List<OsmPrimitive> ret = new ArrayList<>();811 ConditionalOptionPaneUtil.startBulkOperation("add_primitive_to_relation");812 for (OsmPrimitive primitive : primitives) {813 if (primitive instanceof Relation && getRelation() != null && getRelation().equals(primitive)) {814 warnOfCircularReferences(primitive);815 continue;816 }817 if (isPotentialDuplicate(primitive)) {818 if (confirmAddingPrimitive(primitive)) {819 ret.add(primitive);820 }821 continue;822 } else {823 ret.add(primitive);824 }825 }826 ConditionalOptionPaneUtil.endBulkOperation("add_primitive_to_relation");827 return ret;828 }829 }830 831 class AddSelectedAtStartAction extends AddFromSelectionAction implements TableModelListener {832 AddSelectedAtStartAction() {833 putValue(SHORT_DESCRIPTION,834 tr("Add all objects selected in the current dataset before the first member"));835 putValue(SMALL_ICON, ImageProvider.get("dialogs/conflict", "copystartright"));836 refreshEnabled();837 }838 839 protected void refreshEnabled() {840 setEnabled(selectionTableModel.getRowCount() > 0);841 }842 843 @Override844 public void actionPerformed(ActionEvent e) {845 try {846 List<OsmPrimitive> toAdd = filterConfirmedPrimitives(selectionTableModel.getSelection());847 memberTableModel.addMembersAtBeginning(toAdd);848 } catch (AddAbortException ex) {849 // do nothing850 if (Main.isTraceEnabled()) {851 Main.trace(ex.getMessage());852 }853 }854 }855 856 @Override857 public void tableChanged(TableModelEvent e) {858 refreshEnabled();859 }860 }861 862 class AddSelectedAtEndAction extends AddFromSelectionAction implements TableModelListener {863 AddSelectedAtEndAction() {864 putValue(SHORT_DESCRIPTION, tr("Add all objects selected in the current dataset after the last member"));865 putValue(SMALL_ICON, ImageProvider.get("dialogs/conflict", "copyendright"));866 refreshEnabled();867 }868 869 protected void refreshEnabled() {870 setEnabled(selectionTableModel.getRowCount() > 0);871 }872 873 @Override874 public void actionPerformed(ActionEvent e) {875 try {876 List<OsmPrimitive> toAdd = filterConfirmedPrimitives(selectionTableModel.getSelection());877 memberTableModel.addMembersAtEnd(toAdd);878 } catch (AddAbortException ex) {879 // do nothing880 if (Main.isTraceEnabled()) {881 Main.trace(ex.getMessage());882 }883 }884 }885 886 @Override887 public void tableChanged(TableModelEvent e) {888 refreshEnabled();889 }890 }891 892 class AddSelectedBeforeSelection extends AddFromSelectionAction implements TableModelListener, ListSelectionListener {893 /**894 * Constructs a new {@code AddSelectedBeforeSelection}.895 */896 AddSelectedBeforeSelection() {897 putValue(SHORT_DESCRIPTION,898 tr("Add all objects selected in the current dataset before the first selected member"));899 putValue(SMALL_ICON, ImageProvider.get("dialogs/conflict", "copybeforecurrentright"));900 refreshEnabled();901 }902 903 protected void refreshEnabled() {904 setEnabled(selectionTableModel.getRowCount() > 0905 && memberTableModel.getSelectionModel().getMinSelectionIndex() >= 0);906 }907 908 @Override909 public void actionPerformed(ActionEvent e) {910 try {911 List<OsmPrimitive> toAdd = filterConfirmedPrimitives(selectionTableModel.getSelection());912 memberTableModel.addMembersBeforeIdx(toAdd, memberTableModel913 .getSelectionModel().getMinSelectionIndex());914 } catch (AddAbortException ex) {915 // do nothing916 if (Main.isTraceEnabled()) {917 Main.trace(ex.getMessage());918 }919 }920 }921 922 @Override923 public void tableChanged(TableModelEvent e) {924 refreshEnabled();925 }926 927 @Override928 public void valueChanged(ListSelectionEvent e) {929 refreshEnabled();930 }931 }932 933 class AddSelectedAfterSelection extends AddFromSelectionAction implements TableModelListener, ListSelectionListener {934 AddSelectedAfterSelection() {935 putValue(SHORT_DESCRIPTION,936 tr("Add all objects selected in the current dataset after the last selected member"));937 putValue(SMALL_ICON, ImageProvider.get("dialogs/conflict", "copyaftercurrentright"));938 refreshEnabled();939 }940 941 protected void refreshEnabled() {942 setEnabled(selectionTableModel.getRowCount() > 0943 && memberTableModel.getSelectionModel().getMinSelectionIndex() >= 0);944 }945 946 @Override947 public void actionPerformed(ActionEvent e) {948 try {949 List<OsmPrimitive> toAdd = filterConfirmedPrimitives(selectionTableModel.getSelection());950 memberTableModel.addMembersAfterIdx(toAdd, memberTableModel951 .getSelectionModel().getMaxSelectionIndex());952 } catch (AddAbortException ex) {953 // do nothing954 if (Main.isTraceEnabled()) {955 Main.trace(ex.getMessage());956 }957 }958 }959 960 @Override961 public void tableChanged(TableModelEvent e) {962 refreshEnabled();963 }964 965 @Override966 public void valueChanged(ListSelectionEvent e) {967 refreshEnabled();968 }969 }970 971 class RemoveSelectedAction extends AbstractAction implements TableModelListener {972 /**973 * Constructs a new {@code RemoveSelectedAction}.974 */975 RemoveSelectedAction() {976 putValue(SHORT_DESCRIPTION, tr("Remove all members referring to one of the selected objects"));977 putValue(SMALL_ICON, ImageProvider.get("dialogs/relation", "deletemembers"));978 updateEnabledState();979 }980 981 protected void updateEnabledState() {982 DataSet ds = getLayer().data;983 if (ds == null || ds.getSelected().isEmpty()) {984 setEnabled(false);985 return;986 }987 // only enable the action if we have members referring to the988 // selected primitives989 //990 setEnabled(memberTableModel.hasMembersReferringTo(ds.getSelected()));991 }992 993 @Override994 public void actionPerformed(ActionEvent e) {995 memberTableModel.removeMembersReferringTo(selectionTableModel.getSelection());996 }997 998 @Override999 public void tableChanged(TableModelEvent e) {1000 updateEnabledState();1001 }1002 }1003 1004 /**1005 * Selects members in the relation editor which refer to primitives in the current1006 * selection of the context layer.1007 *1008 */1009 class SelectedMembersForSelectionAction extends AbstractAction implements TableModelListener {1010 SelectedMembersForSelectionAction() {1011 putValue(SHORT_DESCRIPTION, tr("Select relation members which refer to objects in the current selection"));1012 putValue(SMALL_ICON, ImageProvider.get("dialogs/relation", "selectmembers"));1013 updateEnabledState();1014 }1015 1016 protected void updateEnabledState() {1017 boolean enabled = selectionTableModel.getRowCount() > 01018 && !memberTableModel.getChildPrimitives(getLayer().data.getSelected()).isEmpty();1019 1020 if (enabled) {1021 putValue(SHORT_DESCRIPTION, tr("Select relation members which refer to {0} objects in the current selection",1022 memberTableModel.getChildPrimitives(getLayer().data.getSelected()).size()));1023 } else {1024 putValue(SHORT_DESCRIPTION, tr("Select relation members which refer to objects in the current selection"));1025 }1026 setEnabled(enabled);1027 }1028 1029 @Override1030 public void actionPerformed(ActionEvent e) {1031 memberTableModel.selectMembersReferringTo(getLayer().data.getSelected());1032 }1033 1034 @Override1035 public void tableChanged(TableModelEvent e) {1036 updateEnabledState();1037 }1038 }1039 1040 /**1041 * Selects primitives in the layer this editor belongs to. The selected primitives are1042 * equal to the set of primitives the currently selected relation members refer to.1043 *1044 */1045 class SelectPrimitivesForSelectedMembersAction extends AbstractAction implements ListSelectionListener {1046 SelectPrimitivesForSelectedMembersAction() {1047 putValue(SHORT_DESCRIPTION, tr("Select objects for selected relation members"));1048 putValue(SMALL_ICON, ImageProvider.get("dialogs/relation", "selectprimitives"));1049 updateEnabledState();1050 }1051 1052 protected void updateEnabledState() {1053 setEnabled(memberTable.getSelectedRowCount() > 0);1054 }1055 1056 @Override1057 public void actionPerformed(ActionEvent e) {1058 getLayer().data.setSelected(memberTableModel.getSelectedChildPrimitives());1059 }1060 1061 @Override1062 public void valueChanged(ListSelectionEvent e) {1063 updateEnabledState();1064 }1065 }1066 1067 class SortAction extends AbstractAction implements TableModelListener {1068 SortAction() {1069 String tooltip = tr("Sort the relation members");1070 putValue(SMALL_ICON, ImageProvider.get("dialogs", "sort"));1071 putValue(NAME, tr("Sort"));1072 Shortcut sc = Shortcut.registerShortcut("relationeditor:sort", tr("Relation Editor: Sort"),1073 KeyEvent.VK_END, Shortcut.ALT);1074 sc.setAccelerator(this);1075 putValue(SHORT_DESCRIPTION, Main.platform.makeTooltip(tooltip, sc));1076 updateEnabledState();1077 }1078 1079 @Override1080 public void actionPerformed(ActionEvent e) {1081 memberTableModel.sort();1082 }1083 1084 protected void updateEnabledState() {1085 setEnabled(memberTableModel.getRowCount() > 0);1086 }1087 1088 @Override1089 public void tableChanged(TableModelEvent e) {1090 updateEnabledState();1091 }1092 }1093 1094 class SortBelowAction extends AbstractAction implements TableModelListener, ListSelectionListener {1095 SortBelowAction() {1096 putValue(SMALL_ICON, ImageProvider.get("dialogs", "sort_below"));1097 putValue(NAME, tr("Sort below"));1098 putValue(SHORT_DESCRIPTION, tr("Sort the selected relation members and all members below"));1099 updateEnabledState();1100 }1101 1102 @Override1103 public void actionPerformed(ActionEvent e) {1104 memberTableModel.sortBelow();1105 }1106 1107 protected void updateEnabledState() {1108 setEnabled(memberTableModel.getRowCount() > 0 && !memberTableModel.getSelectionModel().isSelectionEmpty());1109 }1110 1111 @Override1112 public void tableChanged(TableModelEvent e) {1113 updateEnabledState();1114 }1115 1116 @Override1117 public void valueChanged(ListSelectionEvent e) {1118 updateEnabledState();1119 }1120 }1121 1122 class ReverseAction extends AbstractAction implements TableModelListener {1123 ReverseAction() {1124 putValue(SHORT_DESCRIPTION, tr("Reverse the order of the relation members"));1125 putValue(SMALL_ICON, ImageProvider.get("dialogs/relation", "reverse"));1126 putValue(NAME, tr("Reverse"));1127 // Shortcut.register Shortcut("relationeditor:reverse", tr("Relation Editor: Reverse"), KeyEvent.VK_END, Shortcut.ALT)1128 updateEnabledState();1129 }1130 1131 @Override1132 public void actionPerformed(ActionEvent e) {1133 memberTableModel.reverse();1134 }1135 1136 protected void updateEnabledState() {1137 setEnabled(memberTableModel.getRowCount() > 0);1138 }1139 1140 @Override1141 public void tableChanged(TableModelEvent e) {1142 updateEnabledState();1143 }1144 }1145 1146 class MoveUpAction extends AbstractAction implements ListSelectionListener {1147 MoveUpAction() {1148 String tooltip = tr("Move the currently selected members up");1149 putValue(SMALL_ICON, ImageProvider.get("dialogs", "moveup"));1150 Shortcut sc = Shortcut.registerShortcut("relationeditor:moveup", tr("Relation Editor: Move Up"),1151 KeyEvent.VK_UP, Shortcut.ALT);1152 sc.setAccelerator(this);1153 putValue(SHORT_DESCRIPTION, Main.platform.makeTooltip(tooltip, sc));1154 setEnabled(false);1155 }1156 1157 @Override1158 public void actionPerformed(ActionEvent e) {1159 memberTableModel.moveUp(memberTable.getSelectedRows());1160 }1161 1162 @Override1163 public void valueChanged(ListSelectionEvent e) {1164 setEnabled(memberTableModel.canMoveUp(memberTable.getSelectedRows()));1165 }1166 }1167 1168 class MoveDownAction extends AbstractAction implements ListSelectionListener {1169 MoveDownAction() {1170 String tooltip = tr("Move the currently selected members down");1171 putValue(SMALL_ICON, ImageProvider.get("dialogs", "movedown"));1172 Shortcut sc = Shortcut.registerShortcut("relationeditor:movedown", tr("Relation Editor: Move Down"),1173 KeyEvent.VK_DOWN, Shortcut.ALT);1174 sc.setAccelerator(this);1175 putValue(SHORT_DESCRIPTION, Main.platform.makeTooltip(tooltip, sc));1176 setEnabled(false);1177 }1178 1179 @Override1180 public void actionPerformed(ActionEvent e) {1181 memberTableModel.moveDown(memberTable.getSelectedRows());1182 }1183 1184 @Override1185 public void valueChanged(ListSelectionEvent e) {1186 setEnabled(memberTableModel.canMoveDown(memberTable.getSelectedRows()));1187 }1188 }1189 1190 class RemoveAction extends AbstractAction implements ListSelectionListener {1191 RemoveAction() {1192 String tooltip = tr("Remove the currently selected members from this relation");1193 putValue(SMALL_ICON, ImageProvider.get("dialogs", "delete"));1194 putValue(NAME, tr("Remove"));1195 Shortcut sc = Shortcut.registerShortcut("relationeditor:remove", tr("Relation Editor: Remove"),1196 KeyEvent.VK_DELETE, Shortcut.ALT);1197 sc.setAccelerator(this);1198 putValue(SHORT_DESCRIPTION, Main.platform.makeTooltip(tooltip, sc));1199 setEnabled(false);1200 }1201 1202 @Override1203 public void actionPerformed(ActionEvent e) {1204 memberTableModel.remove(memberTable.getSelectedRows());1205 }1206 1207 @Override1208 public void valueChanged(ListSelectionEvent e) {1209 setEnabled(memberTableModel.canRemove(memberTable.getSelectedRows()));1210 }1211 }1212 1213 class DeleteCurrentRelationAction extends AbstractAction implements PropertyChangeListener {1214 DeleteCurrentRelationAction() {1215 putValue(SHORT_DESCRIPTION, tr("Delete the currently edited relation"));1216 putValue(SMALL_ICON, ImageProvider.get("dialogs", "delete"));1217 putValue(NAME, tr("Delete"));1218 updateEnabledState();1219 }1220 1221 public void run() {1222 Relation toDelete = getRelation();1223 if (toDelete == null)1224 return;1225 org.openstreetmap.josm.actions.mapmode.DeleteAction.deleteRelation(1226 getLayer(),1227 toDelete1228 );1229 }1230 1231 @Override1232 public void actionPerformed(ActionEvent e) {1233 run();1234 }1235 1236 protected void updateEnabledState() {1237 setEnabled(getRelationSnapshot() != null);1238 }1239 1240 @Override1241 public void propertyChange(PropertyChangeEvent evt) {1242 if (evt.getPropertyName().equals(RELATION_SNAPSHOT_PROP)) {1243 updateEnabledState();1244 }1245 }1246 }1247 1248 abstract class SavingAction extends AbstractAction {1249 /**1250 * apply updates to a new relation1251 */1252 protected void applyNewRelation() {1253 final Relation newRelation = new Relation();1254 tagEditorPanel.getModel().applyToPrimitive(newRelation);1255 memberTableModel.applyToRelation(newRelation);1256 List<RelationMember> newMembers = new ArrayList<>();1257 for (RelationMember rm: newRelation.getMembers()) {1258 if (!rm.getMember().isDeleted()) {1259 newMembers.add(rm);1260 }1261 }1262 if (newRelation.getMembersCount() != newMembers.size()) {1263 newRelation.setMembers(newMembers);1264 String msg = tr("One or more members of this new relation have been deleted while the relation editor\n" +1265 "was open. They have been removed from the relation members list.");1266 JOptionPane.showMessageDialog(Main.parent, msg, tr("Warning"), JOptionPane.WARNING_MESSAGE);1267 }1268 // If the user wanted to create a new relation, but hasn't added any members or1269 // tags, don't add an empty relation1270 if (newRelation.getMembersCount() == 0 && !newRelation.hasKeys())1271 return;1272 Main.main.undoRedo.add(new AddCommand(getLayer(), newRelation));1273 1274 // make sure everybody is notified about the changes1275 //1276 getLayer().data.fireSelectionChanged();1277 GenericRelationEditor.this.setRelation(newRelation);1278 RelationDialogManager.getRelationDialogManager().updateContext(1279 getLayer(),1280 getRelation(),1281 GenericRelationEditor.this1282 );1283 SwingUtilities.invokeLater(new Runnable() {1284 @Override1285 public void run() {1286 // Relation list gets update in EDT so selecting my be postponed to following EDT run1287 Main.map.relationListDialog.selectRelation(newRelation);1288 }1289 });1290 }1291 1292 /**1293 * Apply the updates for an existing relation which has been changed1294 * outside of the relation editor.1295 *1296 */1297 protected void applyExistingConflictingRelation() {1298 Relation editedRelation = new Relation(getRelation());1299 tagEditorPanel.getModel().applyToPrimitive(editedRelation);1300 memberTableModel.applyToRelation(editedRelation);1301 Conflict<Relation> conflict = new Conflict<>(getRelation(), editedRelation);1302 Main.main.undoRedo.add(new ConflictAddCommand(getLayer(), conflict));1303 }1304 1305 /**1306 * Apply the updates for an existing relation which has not been changed1307 * outside of the relation editor.1308 *1309 */1310 protected void applyExistingNonConflictingRelation() {1311 Relation editedRelation = new Relation(getRelation());1312 tagEditorPanel.getModel().applyToPrimitive(editedRelation);1313 memberTableModel.applyToRelation(editedRelation);1314 Main.main.undoRedo.add(new ChangeCommand(getRelation(), editedRelation));1315 getLayer().data.fireSelectionChanged();1316 // this will refresh the snapshot and update the dialog title1317 //1318 setRelation(getRelation());1319 }1320 1321 protected boolean confirmClosingBecauseOfDirtyState() {1322 ButtonSpec[] options = new ButtonSpec[] {1323 new ButtonSpec(1324 tr("Yes, create a conflict and close"),1325 ImageProvider.get("ok"),1326 tr("Click to create a conflict and close this relation editor"),1327 null /* no specific help topic */1328 ),1329 new ButtonSpec(1330 tr("No, continue editing"),1331 ImageProvider.get("cancel"),1332 tr("Click to return to the relation editor and to resume relation editing"),1333 null /* no specific help topic */1334 )1335 };1336 1337 int ret = HelpAwareOptionPane.showOptionDialog(1338 Main.parent,1339 tr("<html>This relation has been changed outside of the editor.<br>"1340 + "You cannot apply your changes and continue editing.<br>"1341 + "<br>"1342 + "Do you want to create a conflict and close the editor?</html>"),1343 tr("Conflict in data"),1344 JOptionPane.WARNING_MESSAGE,1345 null,1346 options,1347 options[0], // OK is default1348 "/Dialog/RelationEditor#RelationChangedOutsideOfEditor"1349 );1350 return ret == 0;1351 }1352 1353 protected void warnDoubleConflict() {1354 JOptionPane.showMessageDialog(1355 Main.parent,1356 tr("<html>Layer ''{0}'' already has a conflict for object<br>"1357 + "''{1}''.<br>"1358 + "Please resolve this conflict first, then try again.</html>",1359 getLayer().getName(),1360 getRelation().getDisplayName(DefaultNameFormatter.getInstance())1361 ),1362 tr("Double conflict"),1363 JOptionPane.WARNING_MESSAGE1364 );1365 }1366 }1367 1368 class ApplyAction extends SavingAction {1369 ApplyAction() {1370 putValue(SHORT_DESCRIPTION, tr("Apply the current updates"));1371 putValue(SMALL_ICON, ImageProvider.get("save"));1372 putValue(NAME, tr("Apply"));1373 setEnabled(true);1374 }1375 1376 public void run() {1377 if (getRelation() == null) {1378 applyNewRelation();1379 } else if (!memberTableModel.hasSameMembersAs(getRelationSnapshot())1380 || tagEditorPanel.getModel().isDirty()) {1381 if (isDirtyRelation()) {1382 if (confirmClosingBecauseOfDirtyState()) {1383 if (getLayer().getConflicts().hasConflictForMy(getRelation())) {1384 warnDoubleConflict();1385 return;1386 }1387 applyExistingConflictingRelation();1388 setVisible(false);1389 }1390 } else {1391 applyExistingNonConflictingRelation();1392 }1393 }1394 }1395 1396 @Override1397 public void actionPerformed(ActionEvent e) {1398 run();1399 }1400 }1401 1402 class OKAction extends SavingAction {1403 OKAction() {1404 putValue(SHORT_DESCRIPTION, tr("Apply the updates and close the dialog"));1405 putValue(SMALL_ICON, ImageProvider.get("ok"));1406 putValue(NAME, tr("OK"));1407 setEnabled(true);1408 }1409 1410 public void run() {1411 Main.pref.put("relation.editor.generic.lastrole", tfRole.getText());1412 memberTable.stopHighlighting();1413 if (getRelation() == null) {1414 applyNewRelation();1415 } else if (!memberTableModel.hasSameMembersAs(getRelationSnapshot())1416 || tagEditorPanel.getModel().isDirty()) {1417 if (isDirtyRelation()) {1418 if (confirmClosingBecauseOfDirtyState()) {1419 if (getLayer().getConflicts().hasConflictForMy(getRelation())) {1420 warnDoubleConflict();1421 return;1422 }1423 applyExistingConflictingRelation();1424 } else1425 return;1426 } else {1427 applyExistingNonConflictingRelation();1428 }1429 }1430 setVisible(false);1431 }1432 1433 @Override1434 public void actionPerformed(ActionEvent e) {1435 run();1436 }1437 }1438 1439 class CancelAction extends SavingAction {1440 CancelAction() {1441 putValue(SHORT_DESCRIPTION, tr("Cancel the updates and close the dialog"));1442 putValue(SMALL_ICON, ImageProvider.get("cancel"));1443 putValue(NAME, tr("Cancel"));1444 1445 getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)1446 .put(KeyStroke.getKeyStroke("ESCAPE"), "ESCAPE");1447 getRootPane().getActionMap().put("ESCAPE", this);1448 setEnabled(true);1449 }1450 1451 @Override1452 public void actionPerformed(ActionEvent e) {1453 memberTable.stopHighlighting();1454 TagEditorModel tagModel = tagEditorPanel.getModel();1455 Relation snapshot = getRelationSnapshot();1456 if ((!memberTableModel.hasSameMembersAs(snapshot) || tagModel.isDirty())1457 && !(snapshot == null && tagModel.getTags().isEmpty())) {1458 //give the user a chance to save the changes1459 int ret = confirmClosingByCancel();1460 if (ret == 0) { //Yes, save the changes1461 //copied from OKAction.run()1462 Main.pref.put("relation.editor.generic.lastrole", tfRole.getText());1463 if (getRelation() == null) {1464 applyNewRelation();1465 } else if (!memberTableModel.hasSameMembersAs(snapshot) || tagModel.isDirty()) {1466 if (isDirtyRelation()) {1467 if (confirmClosingBecauseOfDirtyState()) {1468 if (getLayer().getConflicts().hasConflictForMy(getRelation())) {1469 warnDoubleConflict();1470 return;1471 }1472 applyExistingConflictingRelation();1473 } else1474 return;1475 } else {1476 applyExistingNonConflictingRelation();1477 }1478 }1479 } else if (ret == 2) //Cancel, continue editing1480 return;1481 //in case of "No, discard", there is no extra action to be performed here.1482 }1483 setVisible(false);1484 }1485 1486 protected int confirmClosingByCancel() {1487 ButtonSpec[] options = new ButtonSpec[] {1488 new ButtonSpec(1489 tr("Yes, save the changes and close"),1490 ImageProvider.get("ok"),1491 tr("Click to save the changes and close this relation editor"),1492 null /* no specific help topic */1493 ),1494 new ButtonSpec(1495 tr("No, discard the changes and close"),1496 ImageProvider.get("cancel"),1497 tr("Click to discard the changes and close this relation editor"),1498 null /* no specific help topic */1499 ),1500 new ButtonSpec(1501 tr("Cancel, continue editing"),1502 ImageProvider.get("cancel"),1503 tr("Click to return to the relation editor and to resume relation editing"),1504 null /* no specific help topic */1505 )1506 };1507 1508 return HelpAwareOptionPane.showOptionDialog(1509 Main.parent,1510 tr("<html>The relation has been changed.<br>"1511 + "<br>"1512 + "Do you want to save your changes?</html>"),1513 tr("Unsaved changes"),1514 JOptionPane.WARNING_MESSAGE,1515 null,1516 options,1517 options[0], // OK is default,1518 "/Dialog/RelationEditor#DiscardChanges"1519 );1520 }1521 }1522 1523 class AddTagAction extends AbstractAction {1524 AddTagAction() {1525 putValue(SHORT_DESCRIPTION, tr("Add an empty tag"));1526 putValue(SMALL_ICON, ImageProvider.get("dialogs", "add"));1527 setEnabled(true);1528 }1529 1530 @Override1531 public void actionPerformed(ActionEvent e) {1532 tagEditorPanel.getModel().appendNewTag();1533 }1534 }1535 1536 class DownloadIncompleteMembersAction extends AbstractAction implements TableModelListener {1537 DownloadIncompleteMembersAction() {1538 String tooltip = tr("Download all incomplete members");1539 putValue(SMALL_ICON, ImageProvider.get("dialogs/relation", "downloadincomplete"));1540 putValue(NAME, tr("Download Members"));1541 Shortcut sc = Shortcut.registerShortcut("relationeditor:downloadincomplete", tr("Relation Editor: Download Members"),1542 KeyEvent.VK_HOME, Shortcut.ALT);1543 sc.setAccelerator(this);1544 putValue(SHORT_DESCRIPTION, Main.platform.makeTooltip(tooltip, sc));1545 updateEnabledState();1546 }1547 1548 @Override1549 public void actionPerformed(ActionEvent e) {1550 if (!isEnabled())1551 return;1552 Main.worker.submit(new DownloadRelationMemberTask(1553 getRelation(),1554 memberTableModel.getIncompleteMemberPrimitives(),1555 getLayer(),1556 GenericRelationEditor.this)1557 );1558 }1559 1560 protected void updateEnabledState() {1561 setEnabled(memberTableModel.hasIncompleteMembers() && !Main.isOffline(OnlineResource.OSM_API));1562 }1563 1564 @Override1565 public void tableChanged(TableModelEvent e) {1566 updateEnabledState();1567 }1568 }1569 1570 class DownloadSelectedIncompleteMembersAction extends AbstractAction implements ListSelectionListener, TableModelListener {1571 DownloadSelectedIncompleteMembersAction() {1572 putValue(SHORT_DESCRIPTION, tr("Download selected incomplete members"));1573 putValue(SMALL_ICON, ImageProvider.get("dialogs/relation", "downloadincompleteselected"));1574 putValue(NAME, tr("Download Members"));1575 // Shortcut.register Shortcut("relationeditor:downloadincomplete", tr("Relation Editor: Download Members"), KeyEvent.VK_K, Shortcut.ALT)1576 updateEnabledState();1577 }1578 1579 @Override1580 public void actionPerformed(ActionEvent e) {1581 if (!isEnabled())1582 return;1583 Main.worker.submit(new DownloadRelationMemberTask(1584 getRelation(),1585 memberTableModel.getSelectedIncompleteMemberPrimitives(),1586 getLayer(),1587 GenericRelationEditor.this)1588 );1589 }1590 1591 protected void updateEnabledState() {1592 setEnabled(memberTableModel.hasIncompleteSelectedMembers() && !Main.isOffline(OnlineResource.OSM_API));1593 }1594 1595 @Override1596 public void valueChanged(ListSelectionEvent e) {1597 updateEnabledState();1598 }1599 1600 @Override1601 public void tableChanged(TableModelEvent e) {1602 updateEnabledState();1603 }1604 }1605 1606 class SetRoleAction extends AbstractAction implements ListSelectionListener, DocumentListener {1607 SetRoleAction() {1608 putValue(SHORT_DESCRIPTION, tr("Sets a role for the selected members"));1609 putValue(SMALL_ICON, ImageProvider.get("apply"));1610 putValue(NAME, tr("Apply Role"));1611 refreshEnabled();1612 }1613 1614 protected void refreshEnabled() {1615 setEnabled(memberTable.getSelectedRowCount() > 0);1616 }1617 1618 protected boolean isEmptyRole() {1619 return tfRole.getText() == null || tfRole.getText().trim().isEmpty();1620 }1621 1622 protected boolean confirmSettingEmptyRole(int onNumMembers) {1623 String message = "<html>"1624 + trn("You are setting an empty role on {0} object.",1625 "You are setting an empty role on {0} objects.", onNumMembers, onNumMembers)1626 + "<br>"1627 + tr("This is equal to deleting the roles of these objects.") +1628 "<br>"1629 + tr("Do you really want to apply the new role?") + "</html>";1630 String[] options = new String[] {1631 tr("Yes, apply it"),1632 tr("No, do not apply")1633 };1634 int ret = ConditionalOptionPaneUtil.showOptionDialog(1635 "relation_editor.confirm_applying_empty_role",1636 Main.parent,1637 message,1638 tr("Confirm empty role"),1639 JOptionPane.YES_NO_OPTION,1640 JOptionPane.WARNING_MESSAGE,1641 options,1642 options[0]1643 );1644 switch(ret) {1645 case JOptionPane.YES_OPTION:1646 case ConditionalOptionPaneUtil.DIALOG_DISABLED_OPTION:1647 return true;1648 default:1649 return false;1650 }1651 }1652 1653 @Override1654 public void actionPerformed(ActionEvent e) {1655 if (isEmptyRole()) {1656 if (!confirmSettingEmptyRole(memberTable.getSelectedRowCount()))1657 return;1658 }1659 memberTableModel.updateRole(memberTable.getSelectedRows(), tfRole.getText());1660 }1661 1662 @Override1663 public void valueChanged(ListSelectionEvent e) {1664 refreshEnabled();1665 }1666 1667 @Override1668 public void changedUpdate(DocumentEvent e) {1669 refreshEnabled();1670 }1671 1672 @Override1673 public void insertUpdate(DocumentEvent e) {1674 refreshEnabled();1675 }1676 1677 @Override1678 public void removeUpdate(DocumentEvent e) {1679 refreshEnabled();1680 }1681 }1682 1683 /**1684 * Creates a new relation with a copy of the current editor state.1685 */1686 class DuplicateRelationAction extends AbstractAction {1687 DuplicateRelationAction() {1688 putValue(SHORT_DESCRIPTION, tr("Create a copy of this relation and open it in another editor window"));1689 // FIXME provide an icon1690 putValue(SMALL_ICON, ImageProvider.get("duplicate"));1691 putValue(NAME, tr("Duplicate"));1692 setEnabled(true);1693 }1694 1695 @Override1696 public void actionPerformed(ActionEvent e) {1697 Relation copy = new Relation();1698 tagEditorPanel.getModel().applyToPrimitive(copy);1699 memberTableModel.applyToRelation(copy);1700 RelationEditor editor = RelationEditor.getEditor(getLayer(), copy, memberTableModel.getSelectedMembers());1701 editor.setVisible(true);1702 }1703 }1704 1705 /**1706 * Action for editing the currently selected relation.1707 */1708 class EditAction extends AbstractAction implements ListSelectionListener {1709 EditAction() {1710 putValue(SHORT_DESCRIPTION, tr("Edit the relation the currently selected relation member refers to"));1711 putValue(SMALL_ICON, ImageProvider.get("dialogs", "edit"));1712 refreshEnabled();1713 }1714 1715 protected void refreshEnabled() {1716 setEnabled(memberTable.getSelectedRowCount() == 11717 && memberTableModel.isEditableRelation(memberTable.getSelectedRow()));1718 }1719 1720 protected Collection<RelationMember> getMembersForCurrentSelection(Relation r) {1721 Collection<RelationMember> members = new HashSet<>();1722 Collection<OsmPrimitive> selection = getLayer().data.getSelected();1723 for (RelationMember member: r.getMembers()) {1724 if (selection.contains(member.getMember())) {1725 members.add(member);1726 }1727 }1728 return members;1729 }1730 1731 public void run() {1732 int idx = memberTable.getSelectedRow();1733 if (idx < 0)1734 return;1735 OsmPrimitive primitive = memberTableModel.getReferredPrimitive(idx);1736 if (!(primitive instanceof Relation))1737 return;1738 Relation r = (Relation) primitive;1739 if (r.isIncomplete())1740 return;1741 1742 RelationEditor editor = RelationEditor.getEditor(getLayer(), r, getMembersForCurrentSelection(r));1743 editor.setVisible(true);1744 }1745 1746 @Override1747 public void actionPerformed(ActionEvent e) {1748 if (!isEnabled())1749 return;1750 run();1751 }1752 1753 @Override1754 public void valueChanged(ListSelectionEvent e) {1755 refreshEnabled();1756 }1757 }1758 1759 class PasteMembersAction extends AddFromSelectionAction {1760 1761 @Override1762 public void actionPerformed(ActionEvent e) {1763 try {1764 List<PrimitiveData> primitives = Main.pasteBuffer.getDirectlyAdded();1765 DataSet ds = getLayer().data;1766 List<OsmPrimitive> toAdd = new ArrayList<>();1767 boolean hasNewInOtherLayer = false;1768 1769 for (PrimitiveData primitive: primitives) {1770 OsmPrimitive primitiveInDs = ds.getPrimitiveById(primitive);1771 if (primitiveInDs != null) {1772 toAdd.add(primitiveInDs);1773 } else if (!primitive.isNew()) {1774 OsmPrimitive p = primitive.getType().newInstance(primitive.getUniqueId(), true);1775 ds.addPrimitive(p);1776 toAdd.add(p);1777 } else {1778 hasNewInOtherLayer = true;1779 break;1780 }1781 }1782 1783 if (hasNewInOtherLayer) {1784 JOptionPane.showMessageDialog(Main.parent,1785 tr("Members from paste buffer cannot be added because they are not included in current layer"));1786 return;1787 }1788 1789 toAdd = filterConfirmedPrimitives(toAdd);1790 int index = memberTableModel.getSelectionModel().getMaxSelectionIndex();1791 if (index == -1) {1792 index = memberTableModel.getRowCount() - 1;1793 }1794 memberTableModel.addMembersAfterIdx(toAdd, index);1795 1796 tfRole.requestFocusInWindow();1797 1798 } catch (AddAbortException ex) {1799 // Do nothing1800 if (Main.isTraceEnabled()) {1801 Main.trace(ex.getMessage());1802 }1803 }1804 }1805 }1806 1807 class CopyMembersAction extends AbstractAction {1808 @Override1809 public void actionPerformed(ActionEvent e) {1810 Set<OsmPrimitive> primitives = new HashSet<>();1811 for (RelationMember rm: memberTableModel.getSelectedMembers()) {1812 primitives.add(rm.getMember());1813 }1814 if (!primitives.isEmpty()) {1815 CopyAction.copy(getLayer(), primitives);1816 }1817 }1818 }1819 1820 829 class MemberTableDblClickAdapter extends MouseAdapter { 1821 830 @Override 1822 831 public void mouseClicked(MouseEvent e) { 1823 832 if (e.getButton() == MouseEvent.BUTTON1 && e.getClickCount() == 2) { 1824 new EditAction( ).run();833 new EditAction(memberTable, memberTableModel, getLayer()).actionPerformed(null); 1825 834 } 1826 835 } -
trunk/src/org/openstreetmap/josm/gui/dialogs/relation/MemberTableModel.java
r9388 r9496 703 703 * Sort the selected relation members by the way they are linked. 704 704 */ 705 void sort() {705 public void sort() { 706 706 List<RelationMember> selectedMembers = new ArrayList<>(getSelectedMembers()); 707 List<RelationMember> sortedMembers = null;707 List<RelationMember> sortedMembers; 708 708 List<RelationMember> newMembers; 709 709 if (selectedMembers.size() <= 1) { … … 727 727 } 728 728 729 if (members.size() != newMembers.size()) throw new AssertionError(); 729 if (members.size() != newMembers.size()) 730 throw new AssertionError(); 730 731 731 732 members.clear(); … … 738 739 * Sort the selected relation members and all members below by the way they are linked. 739 740 */ 740 void sortBelow() {741 final List<RelationMember> subList = members.subList( getSelectionModel().getMinSelectionIndex(), members.size());741 public void sortBelow() { 742 final List<RelationMember> subList = members.subList(Math.max(0, getSelectionModel().getMinSelectionIndex()), members.size()); 742 743 final List<RelationMember> sorted = relationSorter.sortMembers(subList); 743 744 subList.clear(); … … 766 767 * Reverse the relation members. 767 768 */ 768 void reverse() {769 public void reverse() { 769 770 List<Integer> selectedIndices = getSelectedIndices(); 770 771 List<Integer> selectedIndicesReversed = getSelectedIndices(); -
trunk/src/org/openstreetmap/josm/gui/dialogs/relation/RelationEditor.java
r9078 r9496 19 19 import org.openstreetmap.josm.tools.CheckParameterUtil; 20 20 21 public abstract class RelationEditor extends ExtendedDialog { 21 /** 22 * Abstract relation editor. 23 * @since 1599 24 */ 25 public abstract class RelationEditor extends ExtendedDialog implements RelationAware { 26 22 27 /** the property name for the current relation. 23 28 * @see #setRelation(Relation) … … 34 39 private static List<Class<RelationEditor>> editors = new ArrayList<>(); 35 40 41 /** The relation that this editor is working on. */ 42 private transient Relation relation; 43 44 /** The version of the relation when editing is started. This is null if a new relation is created. */ 45 private transient Relation relationSnapshot; 46 47 /** The data layer the relation belongs to */ 48 private final transient OsmDataLayer layer; 49 50 private final PropertyChangeSupport support = new PropertyChangeSupport(this); 51 52 /** 53 * Creates a new relation editor 54 * 55 * @param layer the {@link OsmDataLayer} in whose context a relation is edited. Must not be null. 56 * @param relation the relation. Can be null if a new relation is to be edited. 57 * @throws IllegalArgumentException if layer is null 58 */ 59 protected RelationEditor(OsmDataLayer layer, Relation relation) { 60 super(Main.parent, 61 "", 62 new String[] {tr("Apply Changes"), tr("Cancel")}, 63 false, 64 false 65 ); 66 CheckParameterUtil.ensureParameterNotNull(layer, "layer"); 67 this.layer = layer; 68 setRelation(relation); 69 } 70 36 71 /** 37 72 * Registers a relation editor class. Depending on the type of relation to be edited … … 42 77 */ 43 78 public void registerRelationEditor(Class<RelationEditor> clazz) { 44 if (clazz == null) return; 45 if (!editors.contains(clazz)) { 79 if (clazz != null && !editors.contains(clazz)) { 46 80 editors.add(clazz); 47 81 } … … 49 83 50 84 /** 51 * The relation that this editor is working on. 52 */ 53 private transient Relation relation; 54 55 /** 56 * The version of the relation when editing is started. This is 57 * null if a new relation is created. */ 58 private transient Relation relationSnapshot; 59 60 /** the data layer the relation belongs to */ 61 private final transient OsmDataLayer layer; 62 63 /** 64 * This is a factory method that creates an appropriate RelationEditor 65 * instance suitable for editing the relation that was passed in as an 66 * argument. 85 * This is a factory method that creates an appropriate RelationEditor instance suitable for editing the relation 86 * that was passed in as an argument. 67 87 * 68 * This method is guaranteed to return a working RelationEditor. If no 69 * specific editor has been registered for the type of relation, then 70 * a generic editor will be returned. 88 * This method is guaranteed to return a working RelationEditor. If no specific editor has been registered for the 89 * type of relation, then a generic editor will be returned. 71 90 * 72 * Editors can be registered by adding their class to the static list "editors" 73 * in the RelationEditor class. When it comes to editing a relation, all 74 * registered editors are queried via their static "canEdit" method whether they 75 * feel responsible for that kind of relation, and if they return true 76 * then an instance of that class will be used. 91 * Editors can be registered by adding their class to the static list "editors" in the RelationEditor class. 92 * When it comes to editing a relation, all registered editors are queried via their static "canEdit" method whether 93 * they feel responsible for that kind of relation, and if they return true then an instance of that class will be used. 77 94 * 78 95 * @param layer the data layer the relation is a member of 79 96 * @param r the relation to be edited 80 * @param selectedMembers a collection of relation members which shall be selected when the 81 * editor is first launched 97 * @param selectedMembers a collection of relation members which shall be selected when the editor is first launched 82 98 * @return an instance of RelationEditor suitable for editing that kind of relation 83 99 */ … … 106 122 107 123 /** 108 * Creates a new relation editor109 *110 * @param layer the {@link OsmDataLayer} in whose context a relation is edited. Must not be null.111 * @param relation the relation. Can be null if a new relation is to be edited.112 * @param selectedMembers a collection of members in <code>relation</code> which the editor113 * should display selected when the editor is first displayed on screen114 * @throws IllegalArgumentException if layer is null115 */116 protected RelationEditor(OsmDataLayer layer, Relation relation, Collection<RelationMember> selectedMembers) {117 super(Main.parent,118 "",119 new String[] {tr("Apply Changes"), tr("Cancel")},120 false,121 false122 );123 CheckParameterUtil.ensureParameterNotNull(layer, "layer");124 this.layer = layer;125 setRelation(relation);126 }127 128 /**129 124 * updates the title of the relation editor 130 125 */ … … 139 134 } 140 135 141 /** 142 * Replies the currently edited relation 143 * 144 * @return the currently edited relation 145 */ 146 protected Relation getRelation() { 136 @Override 137 public final Relation getRelation() { 147 138 return relation; 148 139 } 149 140 150 /** 151 * Sets the currently edited relation. Creates a snapshot of the current 152 * state of the relation. See {@link #getRelationSnapshot()} 153 * 154 * @param relation the relation 155 */ 156 protected void setRelation(Relation relation) { 141 @Override 142 public final void setRelation(Relation relation) { 157 143 setRelationSnapshot((relation == null) ? null : new Relation(relation)); 158 144 Relation oldValue = this.relation; … … 165 151 166 152 /** 167 * Replies the {@link OsmDataLayer} in whose context this relation editor is 168 * open 153 * Replies the {@link OsmDataLayer} in whose context this relation editor is open 169 154 * 170 * @return the {@link OsmDataLayer} in whose context this relation editor is 171 * open 155 * @return the {@link OsmDataLayer} in whose context this relation editor is open 172 156 */ 173 protected OsmDataLayer getLayer() {157 protected final OsmDataLayer getLayer() { 174 158 return layer; 175 159 } 176 160 177 /** 178 * Replies the state of the edited relation when the editor has been launched 179 * 180 * @return the state of the edited relation when the editor has been launched 181 */ 182 protected Relation getRelationSnapshot() { 161 @Override 162 public final Relation getRelationSnapshot() { 183 163 return relationSnapshot; 184 164 } 185 165 186 protected void setRelationSnapshot(Relation snapshot) {166 protected final void setRelationSnapshot(Relation snapshot) { 187 167 Relation oldValue = relationSnapshot; 188 168 relationSnapshot = snapshot; … … 192 172 } 193 173 194 /** 195 * Replies true if the currently edited relation has been changed elsewhere. 196 * 197 * In this case a relation editor can't apply updates to the relation directly. Rather, 198 * it has to create a conflict. 199 * 200 * @return true if the currently edited relation has been changed elsewhere. 201 */ 202 protected boolean isDirtyRelation() { 174 @Override 175 public final boolean isDirtyRelation() { 203 176 return !relation.hasEqualSemanticAttributes(relationSnapshot); 204 177 } … … 207 180 /* property change support */ 208 181 /* ----------------------------------------------------------------------- */ 209 private final PropertyChangeSupport support = new PropertyChangeSupport(this);210 182 211 183 @Override 212 public void addPropertyChangeListener(PropertyChangeListener listener) {184 public final void addPropertyChangeListener(PropertyChangeListener listener) { 213 185 this.support.addPropertyChangeListener(listener); 214 186 } 215 187 216 188 @Override 217 public void removePropertyChangeListener(PropertyChangeListener listener) {189 public final void removePropertyChangeListener(PropertyChangeListener listener) { 218 190 this.support.removePropertyChangeListener(listener); 219 191 }
Note:
See TracChangeset
for help on using the changeset viewer.