View Javadoc
1   package org.opentrafficsim.editor;
2   
3   import java.util.List;
4   
5   import javax.swing.CellEditor;
6   import javax.swing.tree.TreePath;
7   
8   import org.opentrafficsim.editor.Undo.ActionType;
9   
10  import de.javagl.treetable.JTreeTable;
11  
12  /**
13   * This class houses actions that can be performed on tree nodes. The actions will always be executed. Any check on whether the
14   * state of a node is appropriate for an action, is up to the caller. Callers are typically mouse event or key listeners on the
15   * tree.
16   * <p>
17   * Copyright (c) 2023-2024 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
18   * BSD-style license. See <a href="https://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
19   * </p>
20   * @author <a href="https://github.com/wjschakel">Wouter Schakel</a>
21   */
22  public class NodeActions
23  {
24  
25      /** Editor. */
26      private final OtsEditor editor;
27  
28      /** Tree table. */
29      private final JTreeTable treeTable;
30  
31      /**
32       * Constructor.
33       * @param editor editor.
34       * @param treeTable tree table.
35       */
36      public NodeActions(final OtsEditor editor, final JTreeTable treeTable)
37      {
38          this.editor = editor;
39          this.treeTable = treeTable;
40      }
41  
42      /**
43       * Add node.
44       * @param node node.
45       */
46      public void add(final XsdTreeNode node)
47      {
48          this.editor.getUndo().startAction(ActionType.ADD, node, null);
49          XsdTreeNode added = node.add();
50          this.editor.getUndo().setPostActionShowNode(added);
51          this.editor.show(added, null);
52      }
53  
54      /**
55       * Duplicate node.
56       * @param node node.
57       */
58      public void duplicate(final XsdTreeNode node)
59      {
60          this.editor.getUndo().startAction(ActionType.DUPLICATE, node, null);
61          XsdTreeNode added = node.duplicate();
62          this.editor.getUndo().setPostActionShowNode(added);
63          this.editor.show(added, null);
64      }
65  
66      /**
67       * Remove node.
68       * @param node node.
69       */
70      public void remove(final XsdTreeNode node)
71      {
72          CellEditor editor = this.treeTable.getCellEditor();
73          if (editor != null)
74          {
75              editor.stopCellEditing();
76          }
77          this.editor.collapse(node);
78          this.editor.getUndo().startAction(ActionType.REMOVE, node, null);
79          XsdTreeNode parent = node.getParent();
80          int index = parent.getChildren().indexOf(node);
81          node.remove();
82          index = Math.min(index, parent.getChildren().size() - 1);
83          XsdTreeNode replaced = parent.getChild(index);
84          this.editor.getUndo().setPostActionShowNode(replaced);
85          this.editor.show(replaced, null);
86      }
87  
88      /**
89       * Copy node.
90       * @param node node.
91       */
92      public void copy(final XsdTreeNode node)
93      {
94          this.editor.setClipboard(node, false);
95      }
96  
97      /**
98       * Cut node.
99       * @param node node.
100      */
101     public void cut(final XsdTreeNode node)
102     {
103         this.editor.setClipboard(node, true);
104         this.editor.getUndo().startAction(ActionType.CUT, node, null);
105         node.setInactive();
106         this.editor.show(node, null);
107     }
108 
109     /**
110      * Insert node.
111      * @param node node.
112      */
113     public void insert(final XsdTreeNode node)
114     {
115         this.editor.getUndo().startAction(ActionType.INSERT, node, null);
116         XsdTreeNode newNode = node.emptyCopy();
117         newNode.getRoot().fireEvent(XsdTreeNodeRoot.NODE_CREATED,
118                 new Object[] {newNode, newNode.getParent(), newNode.getParent().getChildren().indexOf(newNode)});
119         newNode.move(-1);
120         this.editor.getClipboard().copyInto(newNode);
121         this.editor.removeClipboardWhenCut();
122         this.editor.getUndo().setPostActionShowNode(newNode);
123         this.editor.show(newNode, null);
124     }
125 
126     /**
127      * Paste node.
128      * @param node node.
129      */
130     public void paste(final XsdTreeNode node)
131     {
132         this.editor.getUndo().startAction(ActionType.PASTE, node, null);
133         XsdTreeNode newNode;
134         if (!node.isActive())
135         {
136             node.setActive();
137             newNode = node;
138         }
139         else
140         {
141             newNode = node.emptyCopy();
142             newNode.getRoot().fireEvent(XsdTreeNodeRoot.NODE_CREATED,
143                     new Object[] {newNode, newNode.getParent(), newNode.getParent().getChildren().indexOf(newNode)});
144         }
145         this.editor.getClipboard().copyInto(newNode);
146         if (!node.equals(newNode))
147         {
148             this.editor.removeClipboardWhenCut();
149         }
150         else
151         {
152             this.editor.setClipboard(null, false);
153         }
154         this.editor.getUndo().setPostActionShowNode(newNode);
155         this.editor.show(newNode, null);
156     }
157 
158     /**
159      * Revolve to the next option of the node.
160      * @param node node.
161      * @param options options of the node. These are obtainable from the node, but already gathered by the caller of this method
162      *            and therefore forwarded for efficieny.
163      */
164     public void revolveOption(final XsdTreeNode node, final List<XsdOption> options)
165     {
166         int optionIndex = 0;
167         for (int i = 0; i < options.size(); i++)
168         {
169             if (options.get(i).optionNode().equals(node))
170             {
171                 optionIndex = i + 1;
172                 break;
173             }
174         }
175         if (optionIndex >= options.size())
176         {
177             optionIndex = 0;
178         }
179         this.editor.getUndo().startAction(ActionType.OPTION, node, null);
180         XsdTreeNode next = options.get(optionIndex).optionNode();
181         node.setOption(next);
182         this.editor.show(next, null);
183     }
184 
185     /**
186      * Expand, or collapse, node.
187      * @param node node.
188      * @param path path in the tree of the node.
189      * @param expanded whether the node is currently expanded.
190      */
191     public void expand(final XsdTreeNode node, final TreePath path, final boolean expanded)
192     {
193         if (expanded)
194         {
195             this.treeTable.getTree().collapsePath(path);
196         }
197         else
198         {
199             if (!node.isActive())
200             {
201                 this.editor.getUndo().startAction(ActionType.ACTIVATE, node, null);
202                 node.setActive();
203             }
204             this.treeTable.getTree().expandPath(path);
205         }
206         this.editor.show(node, null);
207     }
208 
209     /**
210      * Move node.
211      * @param node node.
212      * @param down number of rows to move the node down.
213      */
214     public void move(final XsdTreeNode node, final int down)
215     {
216         this.editor.getUndo().startAction(ActionType.MOVE, node, null);
217         node.move(down);
218         this.editor.show(node, null);
219     }
220 
221 }