9455066bdb2bd4bd71ae67de792663fd1fddd71b
[scilab.git] / scilab / modules / xcos / src / java / org / scilab / modules / xcos / graph / model / XcosCellFactory.java
1 /*
2  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  * Copyright (C) 2015-2017 - Scilab Enterprises - Clement DAVID
4  * Copyright (C) 2017 - ESI Group - Clement DAVID
5  *
6  * Copyright (C) 2012 - 2016 - Scilab Enterprises
7  *
8  * This file is hereby licensed under the terms of the GNU GPL v2.0,
9  * pursuant to article 5.3.4 of the CeCILL v.2.1.
10  * This file was originally licensed under the terms of the CeCILL v2.1,
11  * and continues to be available under such terms.
12  * For more information, see the COPYING file which you should have received
13  * along with this program.
14  *
15  */
16
17 package org.scilab.modules.xcos.graph.model;
18
19 import static org.scilab.modules.action_binding.highlevel.ScilabInterpreterManagement.buildCall;
20 import static org.scilab.modules.action_binding.highlevel.ScilabInterpreterManagement.synchronousScilabExec;
21
22 import java.lang.reflect.InvocationTargetException;
23 import java.util.ArrayList;
24 import java.util.Arrays;
25 import java.util.EnumSet;
26 import java.util.HashMap;
27 import java.util.Optional;
28 import java.util.logging.Logger;
29
30 import javax.swing.SwingUtilities;
31
32 import org.scilab.modules.action_binding.highlevel.ScilabInterpreterManagement.InterpreterException;
33 import org.scilab.modules.graph.utils.ScilabExported;
34 import org.scilab.modules.xcos.JavaController;
35 import org.scilab.modules.xcos.Kind;
36 import org.scilab.modules.xcos.ObjectProperties;
37 import org.scilab.modules.xcos.VectorOfDouble;
38 import org.scilab.modules.xcos.VectorOfScicosID;
39 import org.scilab.modules.xcos.Xcos;
40 import org.scilab.modules.xcos.XcosView;
41 import org.scilab.modules.xcos.block.BasicBlock;
42 import org.scilab.modules.xcos.graph.XcosDiagram;
43 import org.scilab.modules.xcos.link.BasicLink;
44 import org.scilab.modules.xcos.link.CommandControlLink;
45 import org.scilab.modules.xcos.link.ExplicitLink;
46 import org.scilab.modules.xcos.link.ImplicitLink;
47 import org.scilab.modules.xcos.port.BasicPort;
48 import org.scilab.modules.xcos.port.command.CommandPort;
49 import org.scilab.modules.xcos.port.control.ControlPort;
50 import org.scilab.modules.xcos.port.input.ExplicitInputPort;
51 import org.scilab.modules.xcos.port.input.ImplicitInputPort;
52 import org.scilab.modules.xcos.port.output.ExplicitOutputPort;
53 import org.scilab.modules.xcos.port.output.ImplicitOutputPort;
54 import org.scilab.modules.xcos.utils.BlockPositioning;
55
56 import com.mxgraph.model.mxCell;
57 import com.mxgraph.model.mxGeometry;
58 import com.mxgraph.util.mxPoint;
59 import java.lang.reflect.Constructor;
60 import java.util.EnumMap;
61 import org.scilab.modules.xcos.block.SplitBlock;
62 import org.scilab.modules.xcos.block.custom.RoundBlock;
63 ;
64
65 /**
66  * Ease the creation of any {@link Kind} of graphical object
67  */
68 public final class XcosCellFactory {
69
70     /** Size compatibility for user defined blocks */
71     private static final double DEFAULT_SIZE_FACTOR = 20.0;
72     private static final Logger LOG = Logger.getLogger(XcosCellFactory.class.getName());
73
74     /** Default singleton constructor */
75     private XcosCellFactory() {
76         // This class is a static singleton
77     }
78
79     /**
80      * This is a notify method mapped as a Scilab gateway used to alert with the loaded UID
81      *
82      * @param uid
83      *            the loaded UID
84      * @param kind
85      *            the kind of the created object (as an int)
86      */
87     @ScilabExported(module = "xcos", filename = "XcosCellFactory.giws.xml")
88     public static synchronized void created(long uid, int kind) {
89         lastCreated = new ScicosObjectOwner(uid, Kind.values()[kind]);
90
91     }
92
93     /**
94      * This is a notify method mapped as a Scilab gateway used to update an UID
95      *
96      * @param uid
97      *            the loaded UID
98      * @param kind
99      *            the kind of the created object (as an int)
100      */
101     @ScilabExported(module = "xcos", filename = "XcosCellFactory.giws.xml")
102     public static synchronized void update(long uid, int kind) {
103         lastCreated = new ScicosObjectOwner(uid, Kind.values()[kind]);
104
105         try {
106             SwingUtilities.invokeAndWait(() -> {
107                 if (kind == Kind.BLOCK.ordinal()) {
108                     JavaController controller = new JavaController();
109
110                     XcosDiagram graph = previousDiagram;
111                     graph.getModel().beginUpdate();
112                     try {
113                         BasicBlock block = createBlock(controller, lastCreated);
114                         previousBlock.updateBlockSettings(controller, graph, block);
115                         BlockPositioning.updateBlockView(graph, block);
116                     } finally {
117                         graph.getModel().beginUpdate();
118                     }
119                 }
120             });
121         } catch (InvocationTargetException | InterruptedException e) {
122             e.printStackTrace();
123         }
124     }
125
126     private static ScicosObjectOwner lastCreated = null;
127     private static BasicBlock previousBlock = null;
128     private static XcosDiagram previousDiagram = null;
129
130     /**
131      * Retrieve and clear the last created object (<pre>xcosCellCreated</pre> call)
132      * @return the last created object
133      */
134     public static synchronized ScicosObjectOwner getLastCreated() {
135         ScicosObjectOwner last = lastCreated;
136         lastCreated = null;
137         return last;
138     }
139
140     /**
141      * Set an object available for update (<pre>xcosUpdateBlock</pre> call)
142      * @param previous the object to track for update
143      */
144     public static synchronized void setPrevious(BasicBlock block, XcosDiagram diagram) {
145         previousBlock = block;
146         previousDiagram = diagram;
147     }
148
149     /*
150      * Diagram management
151      */
152
153     /**
154      * Allocate a Java XcosDiagram from a COSF file.
155      *
156      * This method execute the file and register a
157      *
158      * @param controller
159      *            the controller
160      * @param filename
161      *            the file to execute
162      * @return an allocated XcosDiagram
163      */
164     public static XcosDiagram createDiagramFromCOSF(final JavaController controller, String filename) {
165         XcosView view = (XcosView) JavaController.lookup_view(Xcos.class.getName());
166         JavaController.unregister_view(view);
167
168         XcosDiagram diagram;
169         try {
170             synchronousScilabExec(
171                 "function f(), " + buildCall("exec", filename, -1) + "; " + buildCall("xcosCellCreated", "scs_m".toCharArray()) + "endfunction; f();");
172
173             ScicosObjectOwner last = getLastCreated();
174             if (last.getKind() == Kind.DIAGRAM) {
175                 String[] strUID = new String[1];
176                 controller.getObjectProperty(last.getUID(), last.getKind(), ObjectProperties.UID, strUID);
177
178                 diagram = new XcosDiagram(controller, last.getUID(), last.getKind(), strUID[0]);
179                 insertChildren(controller, diagram);
180             } else {
181                 diagram = null;
182             }
183         } catch (InterpreterException e) {
184             diagram = null;
185         } finally {
186             JavaController.register_view(Xcos.class.getName(), view);
187         }
188
189         return diagram;
190     }
191
192     /**
193      * Insert the diagram MVC children into the JGraphX model
194      *
195      * @param controller
196      *            the shared controller
197      * @param diagram
198      *            the current diagram instance
199      */
200     public static void insertChildren(JavaController controller, XcosDiagram diagram) {
201         /*
202          * Retrieve the children
203          */
204         VectorOfScicosID children = new VectorOfScicosID();
205         controller.getObjectProperty(diagram.getUID(), diagram.getKind(), ObjectProperties.CHILDREN, children);
206         final int childrenLen = children.size();
207
208         /*
209          * Allocation some pre-sized stash data
210          */
211         final ArrayList<BasicLink> links = new ArrayList<>(childrenLen / 2);
212         final HashMap<Long, BasicPort> ports = new HashMap<>(childrenLen);
213
214         /*
215          * Create the XcosCell objects and store some of them for later use
216          */
217         XcosCell[] cells = new XcosCell[childrenLen];
218         for (int i = 0; i < childrenLen; i++) {
219             final long uid = children.get(i);
220             final Kind kind = controller.getKind(uid);
221
222             switch (kind) {
223                 case ANNOTATION:
224                 case BLOCK:
225                     BasicBlock b = createBlock(controller, uid, kind);
226                     cells[i] = b;
227                     BlockPositioning.updatePortsPosition(diagram, b);
228                     b.getTypedChildrenIndexes(BasicPort.class).stream()
229                     .map(index -> b.getChildAt(index))
230                     .filter(c -> c instanceof BasicPort)
231                     .map(c -> (BasicPort) c)
232                     .forEach(c -> ports.put(c.getUID(), c));
233                     break;
234                 case LINK:
235                     BasicLink l = createLink(controller, uid, kind);
236                     cells[i] = l;
237                     links.add(l);
238                     break;
239                 default:
240                     break;
241             }
242
243             // add the optionnal label
244             long[] label = { 0 };
245             controller.getObjectProperty(uid, kind, ObjectProperties.LABEL, label);
246             if (label[0] != 0) {
247                 cells[i].insert(createAnnotation(controller, label[0], Kind.ANNOTATION));
248             }
249         }
250
251         /*
252          * Relink the links on the XcosCell part
253          */
254         for (BasicLink l : links) {
255             long[] src = new long[1];
256             controller.getObjectProperty(l.getUID(), l.getKind(), ObjectProperties.SOURCE_PORT, src);
257
258             long[] dest = new long[1];
259             controller.getObjectProperty(l.getUID(), l.getKind(), ObjectProperties.DESTINATION_PORT, dest);
260
261             BasicPort srcPort = ports.get(src[0]);
262             if (srcPort != null) {
263                 l.setSource(srcPort);
264             } else {
265                 LOG.severe("Unable to connect link " + l.getId() + " : invalid source " + src[0]);
266                 int index = Arrays.asList(cells).indexOf(l);
267                 if (index >= 0) {
268                     cells[index] = null;
269                 }
270             }
271
272             BasicPort destPort = ports.get(dest[0]);
273             if (destPort != null) {
274                 l.setTarget(destPort);
275             } else {
276                 LOG.severe("Unable to connect link " + l.getId() + " : invalid target " + dest[0]);
277                 int index = Arrays.asList(cells).indexOf(l);
278                 if (index >= 0) {
279                     cells[index] = null;
280                 }
281             }
282         }
283
284         // re-add the children cells without duplicating them
285         children.clear();
286         controller.setObjectProperty(diagram.getUID(), diagram.getKind(), ObjectProperties.CHILDREN, children);
287
288         // add all the children using the diagram modification tracking features
289         diagram.addCells(cells);
290     }
291
292     /*
293      * Block and Annotation management
294      */
295
296     /**
297      * Instantiate a new block with the specified interface function.
298      *
299      * @param func
300      *            the interface function
301      * @return A new instance of a block.
302      */
303     public static BasicBlock createBlock(BlockInterFunction func) throws InterpreterException {
304         return createBlock(func, func.name());
305     }
306
307     /**
308      * Instantiate a new block with the specified UID value and interface function
309      *
310      * @param uid
311      *            The associated UID value
312      * @param interfaceFunction
313      *            the interface function
314      * @return A new instance of a block.
315      */
316     public static BasicBlock createBlock(String interfaceFunction) throws InterpreterException {
317         Optional<BlockInterFunction> func = EnumSet.allOf(BlockInterFunction.class).stream().filter(f -> f.name().equals(interfaceFunction)).findFirst();
318
319         final BasicBlock block;
320         if (func.isPresent()) {
321             block = createBlock(func.get());
322         } else {
323             block = createBlock(BlockInterFunction.BASIC_BLOCK, interfaceFunction);
324         }
325         block.setStyle(interfaceFunction);
326
327         return block;
328     }
329
330     private static BasicBlock createBlock(BlockInterFunction func, String interfaceFunction) throws InterpreterException {
331         return createBlock(new JavaController(), func, interfaceFunction);
332     }
333
334     private static BasicBlock createBlock(final JavaController controller, BlockInterFunction func, String interfaceFunction) throws InterpreterException {
335         BasicBlock block;
336         ScicosObjectOwner last;
337
338         if (BlockInterFunction.BASIC_BLOCK.name().equals(interfaceFunction)) {
339             // deliver all the MVC speed for the casual case
340             last = new ScicosObjectOwner(controller.createObject(Kind.BLOCK), Kind.BLOCK);
341         } else {
342             // allocate an empty block that will be filled later
343             synchronousScilabExec("xcosCellCreated(" + interfaceFunction + "(\"define\")); ");
344             last = getLastCreated();
345         }
346
347         // defensive programming
348         if (last == null) {
349             throw new InterpreterException("XcosCellFactory#createBlock : unable to allocate " + interfaceFunction);
350         }
351
352         if (EnumSet.of(Kind.BLOCK, Kind.ANNOTATION).contains(last.getKind())) {
353             block = createBlock(controller, func, interfaceFunction, last.getUID(), last.getKind());
354         } else {
355             block = null;
356         }
357
358         return block;
359     }
360
361     public static BasicBlock createBlock(final JavaController controller, long uid, Kind kind) {
362         String[] interfaceFunction = new String[1];
363         if (kind == Kind.BLOCK) {
364             controller.getObjectProperty(uid, kind, ObjectProperties.INTERFACE_FUNCTION, interfaceFunction);
365         } else { // ANNOTATION
366             interfaceFunction[0] = "TEXT_f";
367         }
368
369         final BlockInterFunction func = lookForInterfunction(interfaceFunction[0]);
370
371         return createBlock(controller, func, interfaceFunction[0], uid, kind);
372     }
373
374     public static BlockInterFunction lookForInterfunction(String interfaceFunction) {
375         Optional<BlockInterFunction> optFunc = EnumSet.allOf(BlockInterFunction.class).stream().filter(f -> f.name().equals(interfaceFunction)).findFirst();
376
377         final BlockInterFunction func;
378         if (optFunc.isPresent()) {
379             func = optFunc.get();
380         } else {
381             func = BlockInterFunction.BASIC_BLOCK;
382         }
383         return func;
384     }
385
386     /**
387      * Instantiate a new block with the specified interface function and uid.
388      *
389      * @param controller
390      *            the Java controller to use
391      * @param func
392      *            the interface function as an enum
393      * @param interfaceFunction
394      *            the interface function name
395      * @param uid
396      *            the allocated uid
397      * @return A new instance of a block.
398      */
399     public static BasicBlock createBlock(final JavaController controller, BlockInterFunction func, String interfaceFunction, long uid, Kind kind) {
400
401         final EnumMap<ObjectProperties, Integer> properties = new EnumMap<>(ObjectProperties.class);
402         properties.put(ObjectProperties.INPUTS, 0);
403         properties.put(ObjectProperties.OUTPUTS, 0);
404         properties.put(ObjectProperties.EVENT_INPUTS, 0);
405         properties.put(ObjectProperties.EVENT_OUTPUTS, 0);
406
407
408         /*
409          * Retrieve the JGraphX data before cell creation
410          */
411         String[] strUID = new String[1];
412         controller.getObjectProperty(uid, kind, ObjectProperties.UID, strUID);
413
414         String[] style = new String[1];
415         controller.getObjectProperty(uid, kind, ObjectProperties.STYLE, style);
416         if (style[0].isEmpty()) {
417             style[0] = interfaceFunction;
418         }
419
420         String value;
421         String[] description = { null };
422         controller.getObjectProperty(uid, kind, ObjectProperties.DESCRIPTION, description);
423         value = description[0];
424
425         VectorOfDouble geom = new VectorOfDouble(4);
426         controller.getObjectProperty(uid, kind, ObjectProperties.GEOMETRY, geom);
427
428         double x = geom.get(0);
429         double y = geom.get(1);
430         double w = geom.get(2);
431         double h = geom.get(3);
432         mxGeometry geometry = new mxGeometry(x, y, w, h);
433
434         /*
435          * Instanciate the block
436          */
437         BasicBlock block = null;
438         try {
439             Constructor<? extends BasicBlock> cstr = func.getKlass().getConstructor(JavaController.class, Long.TYPE, Kind.class, Object.class, mxGeometry.class, String.class, String.class);
440             block = cstr.newInstance(controller, uid, kind, value, geometry, style[0], strUID[0]);
441         } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException
442                      | SecurityException e) {
443             // Something goes wrong, print it.
444             e.printStackTrace();
445             return block;
446         }
447
448         /*
449          * Synchronize model information back to the JGraphX data
450          *
451          * Annotations have no inputs/outputs
452          */
453
454         if (block.getKind() == Kind.BLOCK) {
455             insertPortChildren(controller, properties, block);
456         }
457
458
459         /*
460          * Compatibility to ease user definition :
461          *   * split are not updated as they have an hard-coded fixed-size
462          *   * round blocks : ports globally layout around the block
463          *   * generic case : layout the ports per kind per block-side
464          */
465         boolean convertGeometry;
466         if (block instanceof SplitBlock) {
467             convertGeometry = false;
468         } else if (block instanceof RoundBlock) {
469             int numberOfPorts = properties.get(ObjectProperties.INPUTS) + 1 +
470                                 properties.get(ObjectProperties.OUTPUTS) + 1 +
471                                 properties.get(ObjectProperties.EVENT_INPUTS) + 1 +
472                                 properties.get(ObjectProperties.EVENT_OUTPUTS) + 1;
473             convertGeometry = (2 * w + 2 * h) < (numberOfPorts * BasicPort.DEFAULT_PORTSIZE);
474         } else {
475             double minimalHeight = Math.max((properties.get(ObjectProperties.INPUTS) + 1) * BasicPort.DEFAULT_PORTSIZE, (properties.get(ObjectProperties.OUTPUTS) + 1) * BasicPort.DEFAULT_PORTSIZE);
476             double minimalWidth = Math.max((properties.get(ObjectProperties.EVENT_INPUTS) + 1) * BasicPort.DEFAULT_PORTSIZE, (properties.get(ObjectProperties.EVENT_OUTPUTS) + 1) * BasicPort.DEFAULT_PORTSIZE);
477
478             convertGeometry = h < minimalHeight | w < minimalWidth;
479             convertGeometry |= h * w < minimalHeight * minimalWidth;
480         }
481
482         if (convertGeometry) {
483             w = w * DEFAULT_SIZE_FACTOR;
484             h = h * DEFAULT_SIZE_FACTOR;
485
486             /*
487              * Invert the y-axis value and translate it.
488              */
489             y = -y - h;
490
491             block.setGeometry(new mxGeometry(x, y, w, h));
492         }
493
494         return block;
495     }
496
497     /**
498      * Instantiate a new block for an already created MVC object
499      *
500      * @param lastCreated the owned MVC object
501      * @return a block or null
502      */
503     public static BasicBlock createBlock(final JavaController controller, ScicosObjectOwner lastCreated) {
504         // pre-condition
505         if (lastCreated.getKind() != Kind.ANNOTATION && lastCreated.getKind() != Kind.BLOCK) {
506             return null;
507         }
508
509         String[] interfaceFunction = new String[1];
510         BlockInterFunction func = lookForInterfunction(interfaceFunction[0]);
511
512         return createBlock(controller, func, interfaceFunction[0], lastCreated.getUID(), lastCreated.getKind());
513     }
514
515     /*
516      * Port management
517      */
518
519     /**
520      * Helper used to create port children on a parent block.
521      *
522      * This method does not manage the model transaction and should be used to preset the children of a block out of an {@link XcosDiagram}.
523      *
524      * @param controller
525      *            is the shared controller instance
526      * @param properties
527      *            specify the kind of port to insert and should be some of :
528      *            <UL>
529      *            <LI>{@link ObjectProperties#INPUTS}
530      *            <LI>{@link ObjectProperties#OUTPUTS}
531      *            <LI>{@link ObjectProperties#EVENT_INPUTS}
532      *            <LI>{@link ObjectProperties#EVENT_OUTPUTS}
533      *            </UL>
534      *            This method will fill the value with the number of added ports
535      * @param parent
536      *            is the parent {@link mxCell} to modify
537      */
538     private static void insertPortChildren(final JavaController controller, final EnumMap<ObjectProperties, Integer> properties, final XcosCell parent) {
539         for (ObjectProperties property : properties.keySet()) {
540             properties.put(property, insertPortChildren(controller, property, parent));
541         }
542     }
543
544     /**
545      * Helper used to create port children on a parent block.
546      *
547      * This method does not manage the model transaction and should be used to preset the children of a block out of an {@link XcosDiagram}.
548      *
549      * @param controller
550      *            is the shared controller instance
551      * @param property
552      *            specify the kind of port to insert and should be one of :
553      *            <UL>
554      *            <LI>{@link ObjectProperties#INPUTS}
555      *            <LI>{@link ObjectProperties#OUTPUTS}
556      *            <LI>{@link ObjectProperties#EVENT_INPUTS}
557      *            <LI>{@link ObjectProperties#EVENT_OUTPUTS}
558      *            </UL>
559      * @param parent
560      *            is the parent {@link mxCell} to modify
561      * @return the number of inserted children
562      */
563     private static int insertPortChildren(final JavaController controller, final ObjectProperties property, final XcosCell parent) {
564         VectorOfScicosID modelChildren = new VectorOfScicosID();
565         controller.getObjectProperty(parent.getUID(), parent.getKind(), property, modelChildren);
566
567         XcosCell[] children = new XcosCell[modelChildren.size()];
568         for (int i = 0; i < children.length; i++) {
569             XcosCell child = createPort(controller, modelChildren.get(i), property);
570             children[i] = child;
571         }
572
573         modelChildren.clear();
574         controller.setObjectProperty(parent.getUID(), parent.getKind(), property, modelChildren);
575
576         Arrays.stream(children).forEach(c -> {
577             parent.insert(c);
578         });
579
580         return children.length;
581     }
582
583     /**
584      * Create a port for a specific uid
585      *
586      * @param controller
587      *            is the shared controller instance
588      * @param uid
589      *            represent the allocated UID on the MVC
590      * @param property
591      *            specify the kind of port to create and should be one of :
592      *            <UL>
593      *            <LI>{@link ObjectProperties#INPUTS}
594      *            <LI>{@link ObjectProperties#OUTPUTS}
595      *            <LI>{@link ObjectProperties#EVENT_INPUTS}
596      *            <LI>{@link ObjectProperties#EVENT_OUTPUTS}
597      * @return a newly allocated port
598      */
599     private static final BasicPort createPort(final JavaController controller, long uid, final ObjectProperties property) {
600         BasicPort port;
601         boolean[] isImplicit = { false };
602
603         String[] strUID = new String[] { "" };
604         controller.getObjectProperty(uid, Kind.PORT, ObjectProperties.UID, strUID);
605
606         String[] style = new String[] { "" };
607         controller.getObjectProperty(uid, Kind.PORT, ObjectProperties.STYLE, style);
608
609         String[] value = new String[] { "" };
610         controller.getObjectProperty(uid, Kind.PORT, ObjectProperties.LABEL, value);
611
612         switch (property) {
613             case INPUTS:
614                 controller.getObjectProperty(uid, Kind.PORT, ObjectProperties.IMPLICIT, isImplicit);
615                 if (isImplicit[0]) {
616                     port = new ImplicitInputPort(controller, uid, Kind.PORT, value[0], style[0], strUID[0]);
617                 } else {
618                     port = new ExplicitInputPort(controller, uid, Kind.PORT, value[0], style[0], strUID[0]);
619                 }
620                 break;
621             case OUTPUTS:
622                 controller.getObjectProperty(uid, Kind.PORT, ObjectProperties.IMPLICIT, isImplicit);
623                 if (isImplicit[0]) {
624                     port = new ImplicitOutputPort(controller, uid, Kind.PORT, value[0], style[0], strUID[0]);
625                 } else {
626                     port = new ExplicitOutputPort(controller, uid, Kind.PORT, value[0], style[0], strUID[0]);
627                 }
628                 break;
629             case EVENT_INPUTS:
630                 port = new ControlPort(controller, uid, Kind.PORT, value[0], style[0], strUID[0]);
631                 break;
632             case EVENT_OUTPUTS:
633                 port = new CommandPort(controller, uid, Kind.PORT, value[0], style[0], strUID[0]);
634                 break;
635             default:
636                 return null;
637         }
638
639         /*
640          * Setup JGraphX properties
641          */
642
643         return port;
644     }
645
646     /*
647      * Link management
648      */
649
650     private static BasicLink createLink(JavaController controller, long uid, Kind kind) {
651         int[] type = new int[1];
652         controller.getObjectProperty(uid, kind, ObjectProperties.KIND, type);
653
654         /*
655          * Synchronize model information back to the JGraphX data
656          */
657
658         String value;
659         String[] description = { null };
660         controller.getObjectProperty(uid, kind, ObjectProperties.DESCRIPTION, description);
661         value = description[0];
662
663         String[] style = new String[] { "" };
664         controller.getObjectProperty(uid, kind, ObjectProperties.STYLE, style);
665
666         String[] strUID = new String[] { "" };
667         controller.getObjectProperty(uid, kind, ObjectProperties.UID, strUID);
668
669         VectorOfDouble controlPoints = new VectorOfDouble();
670         controller.getObjectProperty(uid, kind, ObjectProperties.CONTROL_POINTS, controlPoints);
671         final int pointsLen = controlPoints.size() / 2;
672
673         mxGeometry geom = new mxGeometry();
674
675         // as the link is supposed to be connected and accordingly to the JGraphX rules : do not add the origin and destination point
676         ArrayList<mxPoint> points = new ArrayList<>();
677         int i = 0;
678         // ignore origin
679         i++;
680         // loop for points
681         for (; i < pointsLen - 1; i++) {
682             points.add(new mxPoint(controlPoints.get(2 * i), controlPoints.get(2 * i + 1)));
683         }
684         // ignore destination
685         i++;
686
687         geom.setPoints(points);
688
689         /*
690          * Allocate the link
691          */
692         BasicLink link;
693         switch (type[0]) {
694             case -1:
695                 link = new CommandControlLink(controller, uid, kind, value, geom, style[0], strUID[0]);
696                 break;
697             case 1:
698                 link = new ExplicitLink(controller, uid, kind, value, geom, style[0], strUID[0]);
699                 break;
700             case 2:
701                 link = new ImplicitLink(controller, uid, kind, value, geom, style[0], strUID[0]);
702                 break;
703             default:
704                 return null;
705         }
706
707         return link;
708     }
709
710     /*
711      * Annotation management
712      */
713
714     private static XcosCell createAnnotation(JavaController controller, long uid, Kind kind) {
715         String[] description = new String[] { "" };
716         controller.getObjectProperty(uid, kind, ObjectProperties.DESCRIPTION, description);
717
718         VectorOfDouble geom = new VectorOfDouble(4);
719         controller.getObjectProperty(uid, kind, ObjectProperties.GEOMETRY, geom);
720
721         double x = geom.get(0);
722         double y = geom.get(1);
723         double w = geom.get(2);
724         double h = geom.get(3);
725         mxGeometry geometry = new mxGeometry(x, y, w, h);
726
727         String[] strUID = new String[1];
728         controller.getObjectProperty(uid, kind, ObjectProperties.UID, strUID);
729
730         String[] style = new String[1];
731         controller.getObjectProperty(uid, kind, ObjectProperties.STYLE, style);
732
733         XcosCell label = new XcosCell(controller, uid, kind, description[0], geometry, style[0], strUID[0]);
734         label.setConnectable(false);
735         label.setVertex(true);
736
737         return label;
738     }
739 }