updates for 0.9.4
[debian/openrocket] / src / net / sf / openrocket / gui / main / RocketActions.java
index b035228330a71aab3dbb62969aea43823ee65442..76f3c633b4fc3163f5e27f467ae72e521e4d8cf0 100644 (file)
@@ -4,18 +4,18 @@ package net.sf.openrocket.gui.main;
 import java.awt.event.ActionEvent;
 import java.awt.event.KeyEvent;
 import java.util.ArrayList;
-import java.util.List;
 
 import javax.swing.AbstractAction;
 import javax.swing.Action;
-import javax.swing.JFrame;
+import javax.swing.JCheckBox;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
 import javax.swing.KeyStroke;
-import javax.swing.event.TreeSelectionEvent;
-import javax.swing.event.TreeSelectionListener;
-import javax.swing.tree.TreePath;
-import javax.swing.tree.TreeSelectionModel;
 
+import net.miginfocom.swing.MigLayout;
 import net.sf.openrocket.document.OpenRocketDocument;
+import net.sf.openrocket.document.Simulation;
+import net.sf.openrocket.gui.components.StyledLabel;
 import net.sf.openrocket.gui.configdialog.ComponentConfigDialog;
 import net.sf.openrocket.rocketcomponent.ComponentChangeEvent;
 import net.sf.openrocket.rocketcomponent.ComponentChangeListener;
@@ -24,6 +24,7 @@ import net.sf.openrocket.rocketcomponent.RocketComponent;
 import net.sf.openrocket.rocketcomponent.Stage;
 import net.sf.openrocket.util.Icons;
 import net.sf.openrocket.util.Pair;
+import net.sf.openrocket.util.Prefs;
 
 
 
@@ -35,15 +36,21 @@ import net.sf.openrocket.util.Pair;
  */
 public class RocketActions {
 
-       private static RocketComponent clipboard = null;
-       private static List<RocketAction> clipboardListeners = new ArrayList<RocketAction>();
-
+       public static final KeyStroke CUT_KEY_STROKE = KeyStroke.getKeyStroke(KeyEvent.VK_X,
+                       ActionEvent.CTRL_MASK);
+       public static final KeyStroke COPY_KEY_STROKE = KeyStroke.getKeyStroke(KeyEvent.VK_C,
+                       ActionEvent.CTRL_MASK);
+       public static final KeyStroke PASTE_KEY_STROKE = KeyStroke.getKeyStroke(KeyEvent.VK_V,
+                       ActionEvent.CTRL_MASK);
+       
        private final OpenRocketDocument document;
        private final Rocket rocket;
-       private final JFrame parentFrame;
-       private final TreeSelectionModel selectionModel;
+       private final BasicFrame parentFrame;
+       private final DocumentSelectionModel selectionModel;
 
 
+       private final RocketAction deleteComponentAction;
+       private final RocketAction deleteSimulationAction;
        private final RocketAction deleteAction;
        private final RocketAction cutAction;
        private final RocketAction copyAction;
@@ -54,8 +61,8 @@ public class RocketActions {
        private final RocketAction moveDownAction;
        
 
-       public RocketActions(OpenRocketDocument document, TreeSelectionModel selectionModel,
-                       JFrame parentFrame) {
+       public RocketActions(OpenRocketDocument document, DocumentSelectionModel selectionModel,
+                       BasicFrame parentFrame) {
                this.document = document;
                this.rocket = document.getRocket();
                this.selectionModel = selectionModel;
@@ -63,6 +70,8 @@ public class RocketActions {
 
                // Add action also to updateActions()
                this.deleteAction = new DeleteAction();
+               this.deleteComponentAction = new DeleteComponentAction();
+               this.deleteSimulationAction = new DeleteSimulationAction();
                this.cutAction = new CutAction();
                this.copyAction = new CopyAction();
                this.pasteAction = new PasteAction();
@@ -71,13 +80,14 @@ public class RocketActions {
                this.moveUpAction = new MoveUpAction();
                this.moveDownAction = new MoveDownAction();
 
+               OpenRocketClipboard.addClipboardListener(this.pasteAction);
                updateActions();
 
                // Update all actions when tree selection or rocket changes
 
-               selectionModel.addTreeSelectionListener(new TreeSelectionListener() {
+               selectionModel.addDocumentSelectionListener(new DocumentSelectionListener() {
                        @Override
-                       public void valueChanged(TreeSelectionEvent e) {
+                       public void valueChanged(int changeType) {
                                updateActions();
                        }
                });
@@ -93,28 +103,26 @@ public class RocketActions {
         * Update the state of all of the actions.
         */
        private void updateActions() {
-               deleteAction.update();
-               cutAction.update();
-               copyAction.update();
-               pasteAction.update();
-               editAction.update();
-               newStageAction.update();
-               moveUpAction.update();
-               moveDownAction.update();
+               deleteAction.clipboardChanged();
+               cutAction.clipboardChanged();
+               copyAction.clipboardChanged();
+               pasteAction.clipboardChanged();
+               editAction.clipboardChanged();
+               newStageAction.clipboardChanged();
+               moveUpAction.clipboardChanged();
+               moveDownAction.clipboardChanged();
        }
        
        
-       /**
-        * Update the state of all actions that depend on the clipboard.
-        */
-       private void updateClipboardActions() {
-               RocketAction[] array = clipboardListeners.toArray(new RocketAction[0]);
-               for (RocketAction a: array) {
-                       a.update();
-               }
+       
+
+       public Action getDeleteComponentAction() {
+               return deleteAction;
        }
 
-       
+       public Action getDeleteSimulationAction() {
+               return deleteAction;
+       }
 
        public Action getDeleteAction() {
                return deleteAction;
@@ -152,30 +160,6 @@ public class RocketActions {
        
        ////////  Helper methods for the actions
 
-       /**
-        * Return the currently selected rocket component, or null if none selected.
-        * 
-        * @return      the currently selected component.
-        */
-       private RocketComponent getSelectedComponent() {
-               RocketComponent c = null;
-               TreePath p = selectionModel.getSelectionPath();
-               if (p != null)
-                       c = (RocketComponent) p.getLastPathComponent();
-
-               if (c != null && c.getRocket() != rocket) {
-                       throw new IllegalStateException("Selection not same as document rocket, "
-                                       + "report bug!");
-               }
-               return c;
-       }
-       
-       private void setSelectedComponent(RocketComponent component) {
-               TreePath path = ComponentTreeModel.makeTreePath(component);
-               selectionModel.setSelectionPath(path);
-       }
-
-
        private boolean isDeletable(RocketComponent c) {
                // Sanity check
                if (c == null || c.getParent() == null)
@@ -195,7 +179,8 @@ public class RocketActions {
 
        private void delete(RocketComponent c) {
                if (!isDeletable(c)) {
-                       throw new IllegalArgumentException("Report bug!  Component " + c + " not deletable.");
+                       throw new IllegalArgumentException("Report bug!  Component " + c + 
+                                       " not deletable.");
                }
 
                RocketComponent parent = c.getParent();
@@ -211,6 +196,42 @@ public class RocketActions {
        }
 
        
+       private boolean isSimulationSelected() {
+               Simulation[] selection = selectionModel.getSelectedSimulations();
+               return (selection != null  &&  selection.length > 0);
+       }
+       
+       
+       
+       private boolean verifyDeleteSimulation() {
+               boolean verify = Prefs.NODE.getBoolean(Prefs.CONFIRM_DELETE_SIMULATION, true);
+               if (verify) {
+                       JPanel panel = new JPanel(new MigLayout());
+                       JCheckBox dontAsk = new JCheckBox("Do not ask me again");
+                       panel.add(dontAsk,"wrap");
+                       panel.add(new StyledLabel("You can change the default operation in the " +
+                                       "preferences.",-2));
+
+                       int ret = JOptionPane.showConfirmDialog(
+                                       parentFrame,
+                                       new Object[] {
+                                       "Delete the selected simulations?",
+                                       "<html><i>This operation cannot be undone.</i>",
+                                       "",
+                                       panel },
+                                       "Delete simulations",
+                                       JOptionPane.OK_CANCEL_OPTION,
+                                       JOptionPane.WARNING_MESSAGE);
+                       if (ret != JOptionPane.OK_OPTION)
+                               return false;
+
+                       if (dontAsk.isSelected()) {
+                               Prefs.NODE.putBoolean(Prefs.CONFIRM_DELETE_SIMULATION, false);
+                       }
+               }
+
+               return true;
+       }
 
 
        /**
@@ -218,10 +239,11 @@ public class RocketActions {
         * should be pasted.  Returns null if the clipboard is empty or if the
         * clipboard cannot be pasted to the current selection.
         * 
+        * @param   clipboard   the component on the clipboard.
         * @return  a Pair with both components defined, or null.
         */
-       private Pair<RocketComponent, Integer> getPastePosition() {
-               RocketComponent selected = getSelectedComponent();
+       private Pair<RocketComponent, Integer> getPastePosition(RocketComponent clipboard) {
+               RocketComponent selected = selectionModel.getSelectedComponent();
                if (selected == null)
                        return null;
 
@@ -246,39 +268,105 @@ public class RocketActions {
 
        ///////  Action classes
 
-       private abstract class RocketAction extends AbstractAction {
-               public abstract void update();
+       private abstract class RocketAction extends AbstractAction implements ClipboardListener {
+               public abstract void clipboardChanged();
+       }
+
+
+       /**
+        * Action that deletes the selected component.
+        */
+       private class DeleteComponentAction extends RocketAction {
+               public DeleteComponentAction() {
+                       this.putValue(NAME, "Delete");
+                       this.putValue(SHORT_DESCRIPTION, "Delete the selected component.");
+                       this.putValue(MNEMONIC_KEY, KeyEvent.VK_D);
+//                     this.putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0));
+                       this.putValue(SMALL_ICON, Icons.EDIT_DELETE);
+                       clipboardChanged();
+               }
+
+               @Override
+               public void actionPerformed(ActionEvent e) {
+                       RocketComponent c = selectionModel.getSelectedComponent();
+
+                       if (isDeletable(c)) {
+                               ComponentConfigDialog.hideDialog();
+
+                               document.addUndoPosition("Delete " + c.getComponentName());
+                               delete(c);
+                       }
+               }
+
+               @Override
+               public void clipboardChanged() {
+                       this.setEnabled(isDeletable(selectionModel.getSelectedComponent()));
+               }
+       }
+
+
+       
+       /**
+        * Action that deletes the selected component.
+        */
+       private class DeleteSimulationAction extends RocketAction {
+               public DeleteSimulationAction() {
+                       this.putValue(NAME, "Delete");
+                       this.putValue(SHORT_DESCRIPTION, "Delete the selected simulation.");
+                       this.putValue(MNEMONIC_KEY, KeyEvent.VK_D);
+//                     this.putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0));
+                       this.putValue(SMALL_ICON, Icons.EDIT_DELETE);
+                       clipboardChanged();
+               }
+
+               @Override
+               public void actionPerformed(ActionEvent e) {
+                       Simulation[] sims = selectionModel.getSelectedSimulations();
+                       if (sims.length > 0) {
+                               if (verifyDeleteSimulation()) {
+                                       for (Simulation s: sims) {
+                                               document.removeSimulation(s);
+                                       }
+                               }
+                       }
+               }
+
+               @Override
+               public void clipboardChanged() {
+                       this.setEnabled(isSimulationSelected());
+               }
        }
 
 
+       
        /**
         * Action that deletes the selected component.
         */
        private class DeleteAction extends RocketAction {
                public DeleteAction() {
                        this.putValue(NAME, "Delete");
-                       this.putValue(SHORT_DESCRIPTION, "Delete the selected component and subcomponents.");
+                       this.putValue(SHORT_DESCRIPTION, "Delete the selected component or simulation.");
                        this.putValue(MNEMONIC_KEY, KeyEvent.VK_D);
                        this.putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0));
                        this.putValue(SMALL_ICON, Icons.EDIT_DELETE);
-                       update();
+                       clipboardChanged();
                }
 
                @Override
                public void actionPerformed(ActionEvent e) {
-                       RocketComponent c = getSelectedComponent();
-                       if (!isDeletable(c))
-                               return;
-
-                       ComponentConfigDialog.hideDialog();
-
-                       document.addUndoPosition("Delete " + c.getComponentName());
-                       delete(c);
+                       if (isSimulationSelected()) {
+                               deleteSimulationAction.actionPerformed(e);
+                               parentFrame.selectTab(BasicFrame.SIMULATION_TAB);
+                       } else {
+                               deleteComponentAction.actionPerformed(e);
+                               parentFrame.selectTab(BasicFrame.COMPONENT_TAB);
+                       }
                }
 
                @Override
-               public void update() {
-                       this.setEnabled(isDeletable(getSelectedComponent()));
+               public void clipboardChanged() {
+                       this.setEnabled(isDeletable(selectionModel.getSelectedComponent()) ||
+                                       isSimulationSelected());
                }
        }
 
@@ -291,32 +379,44 @@ public class RocketActions {
                public CutAction() {
                        this.putValue(NAME, "Cut");
                        this.putValue(MNEMONIC_KEY, KeyEvent.VK_T);
-                       this.putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_X,
-                                       ActionEvent.CTRL_MASK));
-                       this.putValue(SHORT_DESCRIPTION, "Cut this component (and subcomponents) to "
+                       this.putValue(ACCELERATOR_KEY, CUT_KEY_STROKE);
+                       this.putValue(SHORT_DESCRIPTION, "Cut this component or simulation to "
                                        + "the clipboard and remove from this design");
                        this.putValue(SMALL_ICON, Icons.EDIT_CUT);
-                       update();
+                       clipboardChanged();
                }
 
                @Override
                public void actionPerformed(ActionEvent e) {
-                       RocketComponent c = getSelectedComponent();
-                       if (!isDeletable(c) || !isCopyable(c))
-                               return;
-
-                       ComponentConfigDialog.hideDialog();
-
-                       document.addUndoPosition("Cut " + c.getComponentName());
-                       clipboard = c.copy();
-                       delete(c);
-                       updateClipboardActions();
+                       RocketComponent c = selectionModel.getSelectedComponent();
+                       Simulation[] sims = selectionModel.getSelectedSimulations();
+
+                       if (isDeletable(c) && isCopyable(c)) {
+                               ComponentConfigDialog.hideDialog();
+                               
+                               document.addUndoPosition("Cut " + c.getComponentName());
+                               OpenRocketClipboard.setClipboard(c.copy());
+                               delete(c);
+                               parentFrame.selectTab(BasicFrame.COMPONENT_TAB);
+                       } else if (isSimulationSelected()) {
+
+                               Simulation[] simsCopy = new Simulation[sims.length];
+                               for (int i=0; i < sims.length; i++) {
+                                       simsCopy[i] = sims[i].copy();
+                               }
+                               OpenRocketClipboard.setClipboard(simsCopy);
+
+                               for (Simulation s: sims) {
+                                       document.removeSimulation(s);
+                               }
+                               parentFrame.selectTab(BasicFrame.SIMULATION_TAB);
+                       }
                }
 
                @Override
-               public void update() {
-                       RocketComponent c = getSelectedComponent();
-                       this.setEnabled(isDeletable(c) && isCopyable(c));
+               public void clipboardChanged() {
+                       RocketComponent c = selectionModel.getSelectedComponent();
+                       this.setEnabled((isDeletable(c) && isCopyable(c)) || isSimulationSelected());
                }
        }
 
@@ -329,27 +429,36 @@ public class RocketActions {
                public CopyAction() {
                        this.putValue(NAME, "Copy");
                        this.putValue(MNEMONIC_KEY, KeyEvent.VK_C);
-                       this.putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_C,
-                                       ActionEvent.CTRL_MASK));
+                       this.putValue(ACCELERATOR_KEY, COPY_KEY_STROKE);
                        this.putValue(SHORT_DESCRIPTION, "Copy this component (and subcomponents) to "
                                        + "the clipboard.");
                        this.putValue(SMALL_ICON, Icons.EDIT_COPY);
-                       update();
+                       clipboardChanged();
                }
 
                @Override
                public void actionPerformed(ActionEvent e) {
-                       RocketComponent c = getSelectedComponent();
-                       if (!isCopyable(c))
-                               return;
-
-                       clipboard = c.copy();
-                       updateClipboardActions();
+                       RocketComponent c = selectionModel.getSelectedComponent();
+                       Simulation[] sims = selectionModel.getSelectedSimulations();
+
+                       if (isCopyable(c)) {
+                               OpenRocketClipboard.setClipboard(c.copy());
+                               parentFrame.selectTab(BasicFrame.COMPONENT_TAB);
+                       } else if (sims.length >= 0) {
+
+                               Simulation[] simsCopy = new Simulation[sims.length];
+                               for (int i=0; i < sims.length; i++) {
+                                       simsCopy[i] = sims[i].copy();
+                               }
+                               OpenRocketClipboard.setClipboard(simsCopy);
+                               parentFrame.selectTab(BasicFrame.SIMULATION_TAB);
+                       }
                }
 
                @Override
-               public void update() {
-                       this.setEnabled(isCopyable(getSelectedComponent()));
+               public void clipboardChanged() {
+                       this.setEnabled(isCopyable(selectionModel.getSelectedComponent()) ||
+                                       isSimulationSelected());
                }
                
        }
@@ -365,34 +474,53 @@ public class RocketActions {
                public PasteAction() {
                        this.putValue(NAME, "Paste");
                        this.putValue(MNEMONIC_KEY, KeyEvent.VK_P);
-                       this.putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_V,
-                                       ActionEvent.CTRL_MASK));
-                       this.putValue(SHORT_DESCRIPTION, "Paste the component (and subcomponents) on "
+                       this.putValue(ACCELERATOR_KEY, PASTE_KEY_STROKE);
+                       this.putValue(SHORT_DESCRIPTION, "Paste the component or simulation on "
                                        + "the clipboard to the design.");
                        this.putValue(SMALL_ICON, Icons.EDIT_PASTE);
-                       update();
-                       
-                       // Listen to when the clipboard changes
-                       clipboardListeners.add(this);
+                       clipboardChanged();
                }
 
                @Override
                public void actionPerformed(ActionEvent e) {
-                       Pair<RocketComponent, Integer> position = getPastePosition();
-                       if (position == null)
-                               return;
-
-                       ComponentConfigDialog.hideDialog();
-
-                       RocketComponent pasted = clipboard.copy();
-                       document.addUndoPosition("Paste " + pasted.getComponentName());
-                       position.getU().addChild(pasted, position.getV());
-                       setSelectedComponent(pasted);
+                       RocketComponent clipboard = OpenRocketClipboard.getClipboardComponent();
+                       Simulation[] sims = OpenRocketClipboard.getClipboardSimulations();
+                       
+                       Pair<RocketComponent, Integer> position = getPastePosition(clipboard);
+                       if (position != null) {
+                               ComponentConfigDialog.hideDialog();
+                               
+                               RocketComponent pasted = clipboard.copy();
+                               document.addUndoPosition("Paste " + pasted.getComponentName());
+                               position.getU().addChild(pasted, position.getV());
+                               selectionModel.setSelectedComponent(pasted);
+                               
+                               parentFrame.selectTab(BasicFrame.COMPONENT_TAB);
+                               
+                       } else if (sims != null) {
+                               
+                               ArrayList<Simulation> copySims = new ArrayList<Simulation>();
+
+                               for (Simulation s: sims) {
+                                       Simulation copy = s.duplicateSimulation(rocket);
+                                       String name = copy.getName();
+                                       if (name.matches(OpenRocketDocument.SIMULATION_NAME_PREFIX + "[0-9]+ *")) {
+                                               copy.setName(document.getNextSimulationName());
+                                       }
+                                       document.addSimulation(copy);
+                                       copySims.add(copy);
+                               }
+                               selectionModel.setSelectedSimulations(copySims.toArray(new Simulation[0]));
+                               
+                               parentFrame.selectTab(BasicFrame.SIMULATION_TAB);
+                       }
                }
 
                @Override
-               public void update() {
-                       this.setEnabled(getPastePosition() != null);
+               public void clipboardChanged() {
+                       this.setEnabled(
+                                       (getPastePosition(OpenRocketClipboard.getClipboardComponent()) != null) ||
+                                       (OpenRocketClipboard.getClipboardSimulations() != null));
                }
        }
        
@@ -408,12 +536,12 @@ public class RocketActions {
                public EditAction() {
                        this.putValue(NAME, "Edit");
                        this.putValue(SHORT_DESCRIPTION, "Edit the selected component.");
-                       update();
+                       clipboardChanged();
                }
 
                @Override
                public void actionPerformed(ActionEvent e) {
-                       RocketComponent c = getSelectedComponent();
+                       RocketComponent c = selectionModel.getSelectedComponent();
                        if (c == null)
                                return;
                        
@@ -421,8 +549,8 @@ public class RocketActions {
                }
 
                @Override
-               public void update() {
-                       this.setEnabled(getSelectedComponent() != null);
+               public void clipboardChanged() {
+                       this.setEnabled(selectionModel.getSelectedComponent() != null);
                }
        }
 
@@ -439,7 +567,7 @@ public class RocketActions {
                public NewStageAction() {
                        this.putValue(NAME, "New stage");
                        this.putValue(SHORT_DESCRIPTION, "Add a new stage to the rocket design.");
-                       update();
+                       clipboardChanged();
                }
 
                @Override
@@ -452,13 +580,13 @@ public class RocketActions {
                        document.addUndoPosition("Add stage");
                        rocket.addChild(stage);
                        rocket.getDefaultConfiguration().setAllStages();
-                       setSelectedComponent(stage);
+                       selectionModel.setSelectedComponent(stage);
                        ComponentConfigDialog.showDialog(parentFrame, document, stage);
                        
                }
 
                @Override
-               public void update() {
+               public void clipboardChanged() {
                        this.setEnabled(true);
                }
        }
@@ -473,12 +601,12 @@ public class RocketActions {
                public MoveUpAction() {
                        this.putValue(NAME, "Move up");
                        this.putValue(SHORT_DESCRIPTION, "Move this component upwards.");
-                       update();
+                       clipboardChanged();
                }
 
                @Override
                public void actionPerformed(ActionEvent e) {
-                       RocketComponent selected = getSelectedComponent();
+                       RocketComponent selected = selectionModel.getSelectedComponent();
                        if (!canMove(selected))
                                return;
                        
@@ -487,12 +615,12 @@ public class RocketActions {
                        RocketComponent parent = selected.getParent();
                        document.addUndoPosition("Move "+selected.getComponentName());
                        parent.moveChild(selected, parent.getChildPosition(selected)-1);
-                       setSelectedComponent(selected);
+                       selectionModel.setSelectedComponent(selected);
                }
 
                @Override
-               public void update() {
-                       this.setEnabled(canMove(getSelectedComponent()));
+               public void clipboardChanged() {
+                       this.setEnabled(canMove(selectionModel.getSelectedComponent()));
                }
                
                private boolean canMove(RocketComponent c) {
@@ -514,12 +642,12 @@ public class RocketActions {
                public MoveDownAction() {
                        this.putValue(NAME, "Move down");
                        this.putValue(SHORT_DESCRIPTION, "Move this component downwards.");
-                       update();
+                       clipboardChanged();
                }
 
                @Override
                public void actionPerformed(ActionEvent e) {
-                       RocketComponent selected = getSelectedComponent();
+                       RocketComponent selected = selectionModel.getSelectedComponent();
                        if (!canMove(selected))
                                return;
                        
@@ -528,12 +656,12 @@ public class RocketActions {
                        RocketComponent parent = selected.getParent();
                        document.addUndoPosition("Move "+selected.getComponentName());
                        parent.moveChild(selected, parent.getChildPosition(selected)+1);
-                       setSelectedComponent(selected);
+                       selectionModel.setSelectedComponent(selected);
                }
 
                @Override
-               public void update() {
-                       this.setEnabled(canMove(getSelectedComponent()));
+               public void clipboardChanged() {
+                       this.setEnabled(canMove(selectionModel.getSelectedComponent()));
                }
                
                private boolean canMove(RocketComponent c) {