921dcececf602a5443b227876f07d6275585146a
[scilab.git] / scilab / modules / xcos / src / java / org / scilab / modules / xcos / graph / model / XcosCell.java
1 /*
2  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  * Copyright (C) 2015-2015 - 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  *
14  */
15
16 package org.scilab.modules.xcos.graph.model;
17
18 import java.util.Collections;
19 import java.util.List;
20
21 import org.scilab.modules.xcos.JavaController;
22 import org.scilab.modules.xcos.Kind;
23 import org.scilab.modules.xcos.ObjectProperties;
24 import org.scilab.modules.xcos.PortKind;
25 import org.scilab.modules.xcos.VectorOfDouble;
26 import org.scilab.modules.xcos.VectorOfScicosID;
27
28 import com.mxgraph.model.mxCell;
29 import com.mxgraph.model.mxGeometry;
30 import com.mxgraph.model.mxICell;
31 import com.mxgraph.util.mxPoint;
32
33 public class XcosCell extends mxCell {
34     private static final long serialVersionUID = 1L;
35
36     private transient ScicosObjectOwner owner;
37
38     /**
39      * Construct an Xcos graphical object.
40      *
41      * This Java object owns the corresponding MVC object and thus will unrefererence it on GC.
42      *
43      * @param controller
44      *            the shared controller
45      * @param uid
46      *            the associated MVC identifier
47      * @param kind
48      *            the associated MVC kind
49      */
50     public XcosCell(final JavaController controller, long uid, Kind kind, Object value, mxGeometry geometry, String style, String id) {
51         super();
52
53         // defensive programming
54         if (uid == 0l) {
55             throw new IllegalArgumentException();
56         }
57
58         owner = new ScicosObjectOwner(controller, uid, kind);
59         setValue(controller, value);
60         setGeometry(controller, geometry);
61         setStyle(controller, style);
62         setId(controller, id);
63     }
64
65     /**
66      * @return the MVC unique identifier
67      */
68     public long getUID() {
69         return owner.getUID();
70     }
71
72     /**
73      * @return the MVC kind of object
74      */
75     public Kind getKind() {
76         return owner.getKind();
77     }
78
79     /*
80      * Override setters and hierarchy modifiers to propagate changes to the model
81      */
82
83     /*
84      * (non-Javadoc)
85      *
86      * @see com.mxgraph.model.mxCell#setValue(java.lang.Object)
87      */
88     @Override
89     public void setValue(Object value) {
90         setValue(new JavaController(), value);
91     }
92
93     public final void setValue(JavaController controller, Object value) {
94         super.setValue(value);
95         setMVCValue(controller, value);
96     }
97
98     private void setMVCValue(JavaController controller, Object value) {
99         if (value == null) {
100             return;
101         }
102
103         switch (getKind()) {
104             case ANNOTATION:
105                 controller.setObjectProperty(getUID(), getKind(), ObjectProperties.DESCRIPTION, String.valueOf(value));
106                 break;
107             case BLOCK:
108             case LINK:
109             case PORT:
110                 controller.setObjectProperty(getUID(), getKind(), ObjectProperties.LABEL, String.valueOf(value));
111                 break;
112             default:
113                 break;
114         }
115     }
116
117     /*
118      * (non-Javadoc)
119      *
120      * @see com.mxgraph.model.mxCell#setId(java.lang.String)
121      */
122     @Override
123     public void setId(String id) {
124         setId(new JavaController(), id);
125     }
126
127     public final void setId(JavaController controller, String id) {
128         super.setId(id);
129         setMVCId(controller, id);
130     }
131
132     private void setMVCId(JavaController controller, String id) {
133         if (id == null) {
134             return;
135         }
136
137         switch (getKind()) {
138             case ANNOTATION:
139             case BLOCK:
140             case LINK:
141             case PORT:
142                 controller.setObjectProperty(getUID(), getKind(), ObjectProperties.UID, id);
143                 break;
144             default:
145                 break;
146         }
147     }
148
149     /*
150      * (non-Javadoc)
151      *
152      * @see com.mxgraph.model.mxCell#setGeometry(com.mxgraph.model.mxGeometry)
153      */
154     @Override
155     public void setGeometry(mxGeometry geometry) {
156         setGeometry(new JavaController(), geometry);
157     }
158
159     public final void setGeometry(JavaController controller, mxGeometry geometry) {
160         super.setGeometry(geometry);
161         setMVCGeometry(controller, geometry);
162     }
163
164     private void setMVCGeometry(JavaController controller, mxGeometry geometry) {
165         if (geometry == null) {
166             return;
167         }
168
169         switch (getKind()) {
170             case ANNOTATION:
171             case BLOCK: {
172                 VectorOfDouble v = new VectorOfDouble(4);
173                 v.set(0, geometry.getX());
174                 v.set(1, geometry.getY());
175                 v.set(2, geometry.getWidth());
176                 v.set(3, geometry.getHeight());
177                 controller.setObjectProperty(getUID(), getKind(), ObjectProperties.GEOMETRY, v);
178                 break;
179             }
180             case LINK: {
181                 /*
182                  * try to find the origin of the source and target accordingly to the JGraphX implementation
183                  */
184                 mxPoint sourcePoint = null;
185                 mxPoint targetPoint = null;
186                 mxICell sourceCell = getSource();
187                 mxICell targetCell = getTarget();
188                 if (sourceCell != null && sourceCell.getGeometry() != null) {
189                     sourcePoint = new mxPoint(sourceCell.getGeometry().getCenterX(), sourceCell.getGeometry().getCenterY());
190                 }
191                 if (targetCell != null && targetCell.getGeometry() != null) {
192                     targetPoint = new mxPoint(targetCell.getGeometry().getCenterX(), targetCell.getGeometry().getCenterY());
193                 }
194                 if (sourcePoint == null) {
195                     sourcePoint = geometry.getSourcePoint();
196                 }
197                 if (targetPoint == null) {
198                     targetPoint = geometry.getTargetPoint();
199                 }
200                 if (sourcePoint == null) {
201                     sourcePoint = new mxPoint();
202                 }
203                 if (targetPoint == null) {
204                     targetPoint = new mxPoint();
205                 }
206                 List<mxPoint> points = geometry.getPoints();
207                 if (points == null) {
208                     points = Collections.emptyList();
209                 }
210
211                 /*
212                 * At that point, the sourcePoint, targetPoint and points are valid values (but may be unknown) encode them to the the CONTROL_POINTS
213                 */
214
215                 // Allocate some space to contains them all
216                 int nbOfPoints = 2 + points.size();
217                 VectorOfDouble v = new VectorOfDouble(2 * nbOfPoints);
218                 int i = 0;
219                 // then fill the allocation space
220                 v.set(2 * i, sourcePoint.getX());
221                 v.set(2 * i + 1, sourcePoint.getY());
222                 i++;
223                 for (; i < nbOfPoints - 1; i++) {
224                     v.set(2 * i, points.get(i - 1).getX());
225                     v.set(2 * i + 1, points.get(i - 1).getY());
226                 }
227                 v.set(2 * i, targetPoint.getX());
228                 v.set(2 * i + 1, targetPoint.getY());
229                 i++;
230                 /*
231                  * Finally push the values to the model
232                  */
233                 controller.setObjectProperty(getUID(), getKind(), ObjectProperties.CONTROL_POINTS, v);
234                 break;
235             }
236             default:
237                 break;
238         }
239     }
240
241     /*
242      * (non-Javadoc)
243      *
244      * @see com.mxgraph.model.mxCell#setStyle(java.lang.String)
245      */
246     @Override
247     public void setStyle(String style) {
248         setStyle(new JavaController(), style);
249     }
250
251     public final void setStyle(JavaController controller, String style) {
252         super.setStyle(style);
253         setMVCStyle(controller, style);
254     }
255
256     private void setMVCStyle(JavaController controller, String style) {
257         if (style == null) {
258             return;
259         }
260
261         switch (getKind()) {
262             case ANNOTATION:
263             case BLOCK:
264             case PORT:
265                 controller.setObjectProperty(getUID(), getKind(), ObjectProperties.STYLE, style);
266                 break;
267             default:
268                 break;
269         }
270     }
271
272     /*
273      * (non-Javadoc)
274      *
275      * @see com.mxgraph.model.mxCell#removeFromParent()
276      */
277     @Override
278     public void removeFromParent() {
279         super.removeFromParent();
280
281         // do not remove from parent on SUPER_f diagram creation : there is an MVC parent but no JGraphX one
282         if (parent == null) {
283             return;
284         }
285
286         JavaController controller = new JavaController();
287         switch (getKind()) {
288             case ANNOTATION:
289             case BLOCK:
290             case LINK: {
291                 /*
292                  * Retrieve the parent
293                  */
294                 long[] parent = new long[1];
295                 Kind parentKind = Kind.BLOCK;
296                 ObjectProperties prop = ObjectProperties.PARENT_BLOCK;
297                 controller.getObjectProperty(getUID(), getKind(), prop, parent);
298                 if (parent[0] == 0l) {
299                     parentKind = Kind.DIAGRAM;
300                     prop = ObjectProperties.PARENT_DIAGRAM;
301                     controller.getObjectProperty(getUID(), getKind(), prop, parent);
302                 }
303
304                 /*
305                  * If there is a parent, clear it
306                  */
307                 if (parent[0] != 0l) {
308                     VectorOfScicosID children = new VectorOfScicosID();
309                     controller.getObjectProperty(parent[0], parentKind, ObjectProperties.CHILDREN, children);
310                     children.remove(getUID());
311                     controller.setObjectProperty(parent[0], parentKind, ObjectProperties.CHILDREN, children);
312
313                     controller.setObjectProperty(getUID(), getKind(), prop, 0l);
314                 }
315                 break;
316             }
317             case PORT: {
318                 long[] parent = new long[1];
319                 Kind parentKind = Kind.BLOCK;
320                 controller.getObjectProperty(getUID(), getKind(), ObjectProperties.SOURCE_BLOCK, parent);
321
322                 int[] portKind = new int[1];
323                 controller.getObjectProperty(getUID(), getKind(), ObjectProperties.PORT_KIND, portKind);
324                 ObjectProperties property = relatedPortKindProperty(portKind[0]);
325
326                 VectorOfScicosID ports = new VectorOfScicosID();
327                 controller.getObjectProperty(parent[0], parentKind, property, ports);
328                 ports.remove(getUID());
329                 controller.setObjectProperty(parent[0], parentKind, property, ports);
330
331                 controller.setObjectProperty(getUID(), getKind(), ObjectProperties.SOURCE_BLOCK, 0l);
332                 break;
333             }
334             default:
335                 break;
336         }
337     }
338
339     private ObjectProperties relatedPortKindProperty(int portKind) {
340         ObjectProperties property;
341         switch (PortKind.values()[portKind]) {
342             case PORT_IN:
343                 property = ObjectProperties.INPUTS;
344                 break;
345             case PORT_OUT:
346                 property = ObjectProperties.OUTPUTS;
347                 break;
348             case PORT_EIN:
349                 property = ObjectProperties.EVENT_INPUTS;
350                 break;
351             case PORT_EOUT:
352                 property = ObjectProperties.EVENT_OUTPUTS;
353                 break;
354             default:
355                 property = null;
356                 break;
357         }
358         return property;
359     }
360
361     /*
362      * (non-Javadoc)
363      *
364      * @see com.mxgraph.model.mxCell#setParent(com.mxgraph.model.mxICell)
365      */
366     @Override
367     public void setParent(mxICell parent) {
368         super.setParent(parent);
369
370         if (parent instanceof XcosCell) {
371             XcosCell p = (XcosCell) parent;
372             JavaController controller = new JavaController();
373             switch (getKind()) {
374                 case ANNOTATION:
375                 case BLOCK:
376                 case LINK:
377                     if (p.getKind() == Kind.DIAGRAM) {
378                         controller.setObjectProperty(getUID(), getKind(), ObjectProperties.PARENT_DIAGRAM, p.getUID());
379                     } else {
380                         controller.setObjectProperty(getUID(), getKind(), ObjectProperties.PARENT_BLOCK, p.getUID());
381
382                         long[] root = new long[1];
383                         controller.getObjectProperty(p.getUID(), p.getKind(), ObjectProperties.PARENT_DIAGRAM, root);
384                         controller.setObjectProperty(getUID(), getKind(), ObjectProperties.PARENT_DIAGRAM, root[0]);
385                     }
386                     break;
387                 case PORT:
388                     controller.setObjectProperty(getUID(), getKind(), ObjectProperties.SOURCE_BLOCK, p.getUID());
389                     break;
390                 default:
391                     break;
392             }
393         }
394     }
395
396     @Override
397     public mxICell setTerminal(mxICell terminal, boolean isSource) {
398         mxICell cell = super.setTerminal(terminal, isSource);
399
400         final long uid;
401         if (cell == null) {
402             uid = 0l;
403         } else {
404             // a terminal of an XcosCell is always another XcosCell
405             uid = ((XcosCell) cell).getUID();
406         }
407
408         JavaController controller = new JavaController();
409         switch (getKind()) {
410             case LINK:
411                 if (isSource) {
412                     controller.setObjectProperty(getUID(), getKind(), ObjectProperties.SOURCE_PORT, uid);
413                 } else {
414                     controller.setObjectProperty(getUID(), getKind(), ObjectProperties.DESTINATION_PORT, uid);
415                 }
416                 if (uid != 0l) {
417                     controller.setObjectProperty(uid, Kind.PORT, ObjectProperties.CONNECTED_SIGNALS, getUID());
418                 }
419                 break;
420             default:
421                 break;
422         }
423
424         return cell;
425     }
426
427     /*
428      * (non-Javadoc)
429      *
430      * @see com.mxgraph.model.mxCell#insert(com.mxgraph.model.mxICell, int)
431      */
432     @Override
433     public mxICell insert(mxICell child, int index) {
434         mxICell inserted = super.insert(child, index);
435
436         // the child might not be an XcosCell but just an mxCell label
437         if (child instanceof XcosCell) {
438             XcosCell c = (XcosCell) child;
439             switch (getKind()) {
440                 case BLOCK:
441                     if (c.getKind() == Kind.PORT) {
442                         insertPort(c, index);
443                     } else {
444                         insertChild(c, index);
445                     }
446                     break;
447                 case DIAGRAM:
448                     insertChild(c, index);
449                     break;
450                 default:
451                     break;
452             }
453
454             JavaController controller = new JavaController();
455             controller.referenceObject(c.getUID());
456         }
457
458         return inserted;
459     }
460
461     private void insertPort(XcosCell c, int index) {
462         JavaController controller = new JavaController();
463         int[] v = new int[1];
464         controller.getObjectProperty(c.getUID(), c.getKind(), ObjectProperties.PORT_KIND, v);
465
466         VectorOfScicosID children = new VectorOfScicosID();
467         final ObjectProperties property = relatedPortKindProperty(v[0]);
468
469         if (property != null) {
470             controller.getObjectProperty(getUID(), getKind(), property, children);
471             // do no use the index argument as it is not possible to insert out of order on the MVC (as we have kind of port)
472             children.add(c.getUID());
473             controller.setObjectProperty(getUID(), getKind(), property, children);
474         }
475     }
476
477     private void insertChild(XcosCell c, int index) {
478         JavaController controller = new JavaController();
479         VectorOfScicosID children = new VectorOfScicosID();
480
481         controller.getObjectProperty(getUID(), getKind(), ObjectProperties.CHILDREN, children);
482         children.add(index, c.getUID());
483         controller.setObjectProperty(getUID(), getKind(), ObjectProperties.CHILDREN, children);
484     }
485
486     /*
487      * (non-Javadoc)
488      *
489      * @see com.mxgraph.model.mxCell#remove(com.mxgraph.model.mxICell)
490      */
491     @Override
492     public mxICell remove(mxICell child) {
493         mxICell removed = super.remove(child);
494
495         // the child might not be an XcosCell but just an mxCell label
496         if (child instanceof XcosCell) {
497             XcosCell c = (XcosCell) child;
498             switch (getKind()) {
499                 case BLOCK:
500                     if (c.getKind() == Kind.PORT) {
501                         removePort(c);
502                     } else {
503                         removeChild(c);
504                     }
505                     break;
506                 case DIAGRAM:
507                     removeChild(c);
508                     break;
509                 default:
510                     break;
511             }
512
513             JavaController controller = new JavaController();
514             controller.deleteObject(c.getUID());
515         }
516         return removed;
517     }
518
519     private void removePort(XcosCell c) {
520         JavaController controller = new JavaController();
521         int[] v = new int[1];
522         controller.getObjectProperty(c.getUID(), c.getKind(), ObjectProperties.PORT_KIND, v);
523
524         VectorOfScicosID children = new VectorOfScicosID();
525         final ObjectProperties property;
526         switch (PortKind.values()[v[0]]) {
527             case PORT_IN:
528                 property = ObjectProperties.INPUTS;
529                 break;
530             case PORT_OUT:
531                 property = ObjectProperties.OUTPUTS;
532                 break;
533             case PORT_EIN:
534                 property = ObjectProperties.EVENT_INPUTS;
535                 break;
536             case PORT_EOUT:
537                 property = ObjectProperties.EVENT_OUTPUTS;
538                 break;
539             default:
540                 property = null;
541                 break;
542         }
543
544         controller.getObjectProperty(getUID(), getKind(), property, children);
545         children.remove(c.getUID());
546         controller.setObjectProperty(getUID(), getKind(), property, children);
547     }
548
549     private void removeChild(XcosCell c) {
550         JavaController controller = new JavaController();
551         VectorOfScicosID children = new VectorOfScicosID();
552
553         controller.getObjectProperty(getUID(), getKind(), ObjectProperties.CHILDREN, children);
554         children.remove(c.getUID());
555         controller.setObjectProperty(getUID(), getKind(), ObjectProperties.CHILDREN, children);
556
557     }
558
559     /*
560      * Override methods from Object
561      */
562
563     @Override
564     public Object clone() throws CloneNotSupportedException {
565         JavaController controller = new JavaController();
566         XcosCell c = (XcosCell) super.clone();
567
568         c.owner = new ScicosObjectOwner(controller.cloneObject(getUID(), false, false), getKind());
569         return c;
570     }
571 }