GPL + CeCILL Header change
[scilab.git] / scilab / modules / xcos / src / java / org / scilab / modules / xcos / BrowserView.java
1 /*
2  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  * Copyright (C) 2014 - Scilab Enterprises - Clement DAVID
4  *
5  * Copyright (C) 2012 - 2016 - Scilab Enterprises
6  *
7  * This file is hereby licensed under the terms of the GNU GPL v2.0,
8  * pursuant to article 5.3.4 of the CeCILL v.2.1.
9  * This file was originally licensed under the terms of the CeCILL v2.1,
10  * and continues to be available under such terms.
11  * For more information, see the COPYING file which you should have received
12  * along with this program.
13  * === LICENSE_END ===
14  *
15  */
16
17 package org.scilab.modules.xcos;
18
19 import java.util.Enumeration;
20 import java.util.LinkedList;
21
22 import javax.swing.SwingUtilities;
23 import javax.swing.tree.DefaultMutableTreeNode;
24 import javax.swing.tree.DefaultTreeModel;
25
26 import org.scilab.modules.xcos.explorer.BrowserTreeNodeData;
27
28
29 /**
30  * Implement a basic model explorer using a tree view
31  */
32 public class BrowserView extends View {
33     private final DefaultTreeModel model;
34
35     /**
36      * Default constructor
37      */
38     public BrowserView() {
39         DefaultMutableTreeNode root = new DefaultMutableTreeNode(new BrowserTreeNodeData(), true);
40
41         model = new DefaultTreeModel(root);
42
43         /*
44          * retrieve all the existing objects and append them to the model.
45          */
46         fillModel();
47         model.reload();
48     }
49
50     private void fillModel() {
51         Controller controller = new Controller();
52         DefaultMutableTreeNode root = (DefaultMutableTreeNode) model.getRoot();
53
54         // first create all the diagrams
55         VectorOfScicosID o = controller.getAll(Kind.DIAGRAM);
56         int length = o.size();
57         for (int i = 0; i < length; i++) {
58             long uid = o.get(i);
59
60             controller.referenceObject(uid);
61             DefaultMutableTreeNode current = new DefaultMutableTreeNode(new BrowserTreeNodeData(uid, Kind.DIAGRAM));
62             root.add(current);
63         }
64
65         // fill each diagram node with its block hierarchy
66         LinkedList<DefaultMutableTreeNode> stash = new LinkedList<DefaultMutableTreeNode>();
67         for (int i = 0; i < root.getChildCount(); i++) {
68             DefaultMutableTreeNode node = (DefaultMutableTreeNode) root.getChildAt(i);
69             stash.add(node);
70         }
71
72         VectorOfScicosID children = new VectorOfScicosID(256);
73         while (!stash.isEmpty()) {
74             DefaultMutableTreeNode node = stash.pop();
75             BrowserTreeNodeData data = (BrowserTreeNodeData) node.getUserObject();
76
77             controller.getObjectProperty(data.getId(), data.getKind(), ObjectProperties.CHILDREN, children);
78             int childrenLen = children.size();
79             for (int j = 0 ; j < childrenLen; j++) {
80                 long childUID = children.get(j);
81                 Kind childKind = controller.getKind(childUID);
82
83                 controller.referenceObject(childUID);
84                 DefaultMutableTreeNode child = new DefaultMutableTreeNode(new BrowserTreeNodeData(childUID, childKind));
85
86                 node.add(child);
87                 // manage the children only if this is a block
88                 if (childKind == Kind.BLOCK) {
89                     stash.add(child);
90                 }
91             }
92         }
93     }
94
95     public DefaultTreeModel getModel() {
96         return model;
97     }
98
99     /*
100      * Implement some View methods on the Event Dispatch Thread
101      */
102
103     @Override
104     public void objectCreated(final long uid, final Kind kind) {
105         if (model == null) {
106             return;
107         }
108         if (kind == Kind.PORT) {
109             return;
110         }
111
112         SwingUtilities.invokeLater(new Runnable() {
113             @Override
114             public void run() {
115                 objectCreatedOnEDT(uid, kind);
116             }
117         });
118
119         // reference on the caller Thread to avoid synchronization later
120         new Controller().referenceObject(uid);
121     }
122
123     @Override
124     public void objectReferenced(final long uid, final Kind kind, long refCount) {
125         if (model == null) {
126             return;
127         }
128         if (kind == Kind.PORT) {
129             return;
130         }
131
132         SwingUtilities.invokeLater(new Runnable() {
133             @Override
134             public void run() {
135                 objectReferencedOnEDT(uid, kind, refCount);
136             }
137         });
138     }
139
140     @Override
141     public void objectUnreferenced(final long uid, final Kind kind, long refCount) {
142         if (model == null) {
143             return;
144         }
145         if (kind == Kind.PORT) {
146             return;
147         }
148
149         SwingUtilities.invokeLater(new Runnable() {
150             @Override
151             public void run() {
152                 objectUnreferencedOnEDT(uid, kind, refCount);
153             }
154         });
155     };
156
157     @Override
158     public void objectDeleted(final long uid, final Kind kind) {
159     }
160
161     @Override
162     public void propertyUpdated(final long uid, final Kind kind, final ObjectProperties property, final UpdateStatus status) {
163         if (model == null) {
164             return;
165         }
166         if (status != UpdateStatus.SUCCESS) {
167             return;
168         }
169
170         SwingUtilities.invokeLater(new Runnable() {
171             @Override
172             public void run() {
173                 propertyUpdatedOnEDT(uid, kind, property, status);
174             }
175         });
176     }
177
178     public void objectCreatedOnEDT(final long uid, final Kind kind) {
179         DefaultMutableTreeNode root = (DefaultMutableTreeNode) model.getRoot();
180         int position = model.getChildCount(root);
181
182         final DefaultMutableTreeNode node = new DefaultMutableTreeNode(new BrowserTreeNodeData(uid, kind), true);
183         model.insertNodeInto(node, root, position);
184     }
185
186     public void objectReferencedOnEDT(final long uid, final Kind kind, long refCount) {
187         DefaultMutableTreeNode node = lookupForUID(uid);
188         BrowserTreeNodeData data = (BrowserTreeNodeData) node.getUserObject();
189
190         data.incRefCount();
191     }
192
193     public void objectUnreferencedOnEDT(final long uid, final Kind kind, long refCount) {
194         DefaultMutableTreeNode node = lookupForUID(uid);
195         if (node == null) {
196             return;
197         }
198         BrowserTreeNodeData data = (BrowserTreeNodeData) node.getUserObject();
199
200         if (data.decRefCount() < 1) {
201             model.removeNodeFromParent(node);
202
203             // This is a deletion request, other views synchronization will be done on another event
204             new Controller().deleteObject(uid);
205         }
206     }
207
208     public void propertyUpdatedOnEDT(final long uid, final Kind kind, final ObjectProperties property, final UpdateStatus status) {
209
210         /* Manage the children case to append them to associated diagram */
211         if (property == ObjectProperties.PARENT_DIAGRAM || property == ObjectProperties.PARENT_BLOCK) {
212             switch (kind) {
213                 case ANNOTATION:
214                 case BLOCK:
215                 case LINK: {
216                     final Controller controller = new Controller();
217                     long[] v = { 0 };
218                     if (!controller.getObjectProperty(uid, kind, property, v)) {
219                         return;
220                     }
221
222                     final DefaultMutableTreeNode parent = lookupForUID(v[0]);
223                     final DefaultMutableTreeNode current = lookupForUID(uid);
224                     if (current == null || current.getParent() == parent) {
225                         return;
226                     }
227
228                     model.removeNodeFromParent(current);
229
230                     // current parent is re-set'ed and its old parent is also
231                     // updated
232                     int position = parent.getChildCount();
233                     model.insertNodeInto(current, parent, position);
234                 }
235                 break;
236
237                 default:
238                     break;
239             }
240         }
241
242     }
243
244     /*
245      * Utilities
246      */
247
248     /**
249      * Lookup for the UID in the TreeModel and return the result or null if not found
250      * @param uid the uid to look for
251      * @return the found {@link DefaultMutableTreeNode} or <code>null</code> if not found
252      */
253     private DefaultMutableTreeNode lookupForUID(final long uid) {
254         final DefaultMutableTreeNode root = (DefaultMutableTreeNode) model.getRoot();
255
256         DefaultMutableTreeNode node;
257         for (Enumeration<DefaultMutableTreeNode> e = root.depthFirstEnumeration(); e.hasMoreElements();) {
258             node = e.nextElement();
259             BrowserTreeNodeData data = (BrowserTreeNodeData) node.getUserObject();
260             if (data.getId() == uid) {
261                 return node;
262             }
263         }
264
265         return null;
266     }
267
268 }