001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.actions; 003 004import static org.openstreetmap.josm.gui.help.HelpUtil.ht; 005import static org.openstreetmap.josm.tools.I18n.tr; 006import static org.openstreetmap.josm.tools.I18n.trn; 007 008import java.awt.GridBagLayout; 009import java.awt.event.ActionEvent; 010import java.awt.event.KeyEvent; 011import java.util.Collection; 012 013import javax.swing.JOptionPane; 014import javax.swing.JPanel; 015 016import org.openstreetmap.josm.Main; 017import org.openstreetmap.josm.command.DeleteCommand.DeletionCallback; 018import org.openstreetmap.josm.data.osm.DefaultNameFormatter; 019import org.openstreetmap.josm.data.osm.OsmPrimitive; 020import org.openstreetmap.josm.data.osm.Relation; 021import org.openstreetmap.josm.data.osm.RelationToChildReference; 022import org.openstreetmap.josm.gui.ConditionalOptionPaneUtil; 023import org.openstreetmap.josm.gui.MainApplication; 024import org.openstreetmap.josm.gui.MapFrame; 025import org.openstreetmap.josm.gui.dialogs.DeleteFromRelationConfirmationDialog; 026import org.openstreetmap.josm.gui.widgets.JMultilineLabel; 027import org.openstreetmap.josm.tools.Shortcut; 028 029/** 030 * Action that deletes selected objects. 031 * @since 770 032 */ 033public final class DeleteAction extends JosmAction { 034 035 /** 036 * The default {@link DeletionCallback} for {@code DeleteCommand}. 037 * @since 12760 038 */ 039 public static final DeletionCallback defaultDeletionCallback = new DeletionCallback() { 040 @Override 041 public boolean checkAndConfirmOutlyingDelete(Collection<? extends OsmPrimitive> primitives, 042 Collection<? extends OsmPrimitive> ignore) { 043 return DeleteAction.checkAndConfirmOutlyingDelete(primitives, ignore); 044 } 045 046 @Override 047 public boolean confirmRelationDeletion(Collection<Relation> relations) { 048 return DeleteAction.confirmRelationDeletion(relations); 049 } 050 051 @Override 052 public boolean confirmDeletionFromRelation(Collection<RelationToChildReference> references) { 053 DeleteFromRelationConfirmationDialog dialog = DeleteFromRelationConfirmationDialog.getInstance(); 054 dialog.getModel().populate(references); 055 dialog.setVisible(true); 056 return !dialog.isCanceled(); 057 } 058 }; 059 060 /** 061 * Constructs a new {@code DeleteAction}. 062 */ 063 public DeleteAction() { 064 super(tr("Delete"), "dialogs/delete", tr("Delete selected objects."), 065 Shortcut.registerShortcut("system:delete", tr("Edit: {0}", tr("Delete")), KeyEvent.VK_DELETE, Shortcut.DIRECT), true); 066 putValue("help", ht("/Action/Delete")); 067 } 068 069 @Override 070 public void actionPerformed(ActionEvent e) { 071 MapFrame map = MainApplication.getMap(); 072 if (!isEnabled() || !map.mapView.isActiveLayerVisible()) 073 return; 074 map.mapModeDelete.doActionPerformed(e); 075 } 076 077 @Override 078 protected void updateEnabledState() { 079 updateEnabledStateOnCurrentSelection(); 080 } 081 082 @Override 083 protected void updateEnabledState(Collection<? extends OsmPrimitive> selection) { 084 updateEnabledStateOnModifiableSelection(selection); 085 } 086 087 /** 088 * Check whether user is about to delete data outside of the download area. 089 * Request confirmation if he is. 090 * @param primitives the primitives to operate on 091 * @param ignore {@code null} or a primitive to be ignored 092 * @return true, if operating on outlying primitives is OK; false, otherwise 093 * @since 12749 (moved from DeleteCommand) 094 */ 095 public static boolean checkAndConfirmOutlyingDelete(Collection<? extends OsmPrimitive> primitives, 096 Collection<? extends OsmPrimitive> ignore) { 097 return checkAndConfirmOutlyingOperation("delete", 098 tr("Delete confirmation"), 099 tr("You are about to delete nodes outside of the area you have downloaded." 100 + "<br>" 101 + "This can cause problems because other objects (that you do not see) might use them." 102 + "<br>" 103 + "Do you really want to delete?"), 104 tr("You are about to delete incomplete objects." 105 + "<br>" 106 + "This will cause problems because you don''t see the real object." 107 + "<br>" + "Do you really want to delete?"), 108 primitives, ignore); 109 } 110 111 /** 112 * Confirm before deleting a relation, as it is a common newbie error. 113 * @param relations relation to check for deletion 114 * @return {@code true} if user confirms the deletion 115 * @since 12760 116 */ 117 public static boolean confirmRelationDeletion(Collection<Relation> relations) { 118 JPanel msg = new JPanel(new GridBagLayout()); 119 msg.add(new JMultilineLabel("<html>" + trn( 120 "You are about to delete {0} relation: {1}" 121 + "<br/>" 122 + "This step is rarely necessary and cannot be undone easily after being uploaded to the server." 123 + "<br/>" 124 + "Do you really want to delete?", 125 "You are about to delete {0} relations: {1}" 126 + "<br/>" 127 + "This step is rarely necessary and cannot be undone easily after being uploaded to the server." 128 + "<br/>" 129 + "Do you really want to delete?", 130 relations.size(), relations.size(), DefaultNameFormatter.getInstance().formatAsHtmlUnorderedList(relations, 20)) 131 + "</html>")); 132 return ConditionalOptionPaneUtil.showConfirmationDialog( 133 "delete_relations", 134 Main.parent, 135 msg, 136 tr("Delete relation?"), 137 JOptionPane.YES_NO_OPTION, 138 JOptionPane.QUESTION_MESSAGE, 139 JOptionPane.YES_OPTION); 140 } 141}