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 cellEditor = this.treeTable.getCellEditor();
73          if (cellEditor != null)
74          {
75              cellEditor.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 
106         XsdTreeNode parent = node.getParent();
107         int childIndex = parent.getChildren().indexOf(node);
108 
109         node.remove();
110 
111         childIndex = Math.min(childIndex, parent.getChildCount() - 1);
112         List<XsdTreeNode> nodePath = childIndex < 0 ? parent.getPath() : parent.getChild(childIndex).getPath();
113         TreePath path = new TreePath(nodePath.toArray());
114         this.treeTable.getTree().setSelectionPath(path);
115         this.editor.getUndo().setPostActionShowNode(parent.getChild(childIndex));
116 
117         this.treeTable.updateUI();
118     }
119 
120     /**
121      * Insert node.
122      * @param node node.
123      */
124     public void insert(final XsdTreeNode node)
125     {
126         this.editor.getUndo().startAction(ActionType.INSERT, node, null);
127         XsdTreeNode newNode = node.emptyCopy();
128         newNode.getRoot().fireEvent(XsdTreeNodeRoot.NODE_CREATED,
129                 new Object[] {newNode, newNode.getParent(), newNode.getParent().getChildren().indexOf(newNode)});
130         newNode.move(-1);
131         this.editor.getClipboard().copyInto(newNode);
132         this.editor.removeClipboardWhenCut();
133         this.editor.getUndo().setPostActionShowNode(newNode);
134         this.editor.show(newNode, null);
135     }
136 
137     /**
138      * Paste node.
139      * @param node node.
140      */
141     public void paste(final XsdTreeNode node)
142     {
143         this.editor.getUndo().startAction(ActionType.PASTE, node, null);
144         XsdTreeNode newNode;
145         if (!node.isActive())
146         {
147             node.setActive();
148             newNode = node;
149         }
150         else
151         {
152             newNode = node.emptyCopy();
153             newNode.getRoot().fireEvent(XsdTreeNodeRoot.NODE_CREATED,
154                     new Object[] {newNode, newNode.getParent(), newNode.getParent().getChildren().indexOf(newNode)});
155         }
156         this.editor.getClipboard().copyInto(newNode);
157         if (!node.equals(newNode))
158         {
159             this.editor.removeClipboardWhenCut();
160         }
161         else
162         {
163             this.editor.setClipboard(null, false);
164         }
165         this.editor.getUndo().setPostActionShowNode(newNode);
166         this.editor.show(newNode, null);
167     }
168 
169     /**
170      * Revolve to the next option of the node.
171      * @param node node.
172      * @param options options of the node. These are obtainable from the node, but already gathered by the caller of this method
173      *            and therefore forwarded for efficiency.
174      */
175     public void revolveOption(final XsdTreeNode node, final List<XsdOption> options)
176     {
177         int optionIndex = 0;
178         for (int i = 0; i < options.size(); i++)
179         {
180             if (options.get(i).optionNode().equals(node))
181             {
182                 optionIndex = i + 1;
183                 break;
184             }
185         }
186         if (optionIndex >= options.size())
187         {
188             optionIndex = 0;
189         }
190         this.editor.getUndo().startAction(ActionType.OPTION, node, null);
191         XsdTreeNode next = options.get(optionIndex).optionNode();
192         node.setOption(next);
193         this.editor.getUndo().setPostActionShowNode(next);
194         this.editor.show(next, null);
195     }
196 
197     /**
198      * Set node as selected in its choice.
199      * @param selected selected node
200      */
201     public void setOption(final XsdTreeNode selected)
202     {
203         this.editor.getUndo().startAction(ActionType.OPTION, selected.getOption(), null);
204         selected.setOption(selected);
205         this.editor.getUndo().setPostActionShowNode(selected);
206         this.editor.show(selected, null);
207     }
208 
209     /**
210      * Expand, or collapse, node.
211      * @param node node.
212      * @param path path in the tree of the node.
213      * @param expanded whether the node is currently expanded.
214      */
215     public void expand(final XsdTreeNode node, final TreePath path, final boolean expanded)
216     {
217         if (expanded)
218         {
219             this.treeTable.getTree().collapsePath(path);
220         }
221         else
222         {
223             if (!node.isActive())
224             {
225                 this.editor.getUndo().startAction(ActionType.ACTIVATE, node, null);
226                 node.setActive();
227             }
228             this.treeTable.getTree().expandPath(path);
229         }
230         this.editor.show(node, null);
231     }
232 
233     /**
234      * Move node.
235      * @param node node.
236      * @param down number of rows to move the node down.
237      */
238     public void move(final XsdTreeNode node, final int down)
239     {
240         this.editor.getUndo().startAction(ActionType.MOVE, node, null);
241         node.move(down);
242         this.editor.show(node, null);
243     }
244 
245 }