* Bug #14659 fixed: number of I/O ports of the superblock was not updated when adding... 30/19030/4
Clément DAVID [Wed, 1 Feb 2017 10:23:20 +0000 (11:23 +0100)]
This commit fix the port synchronization between outer ports and inner diagram
when the user add / delete / update any I/O block. The tab title is also fixed
on save (previously the superblock diagram tab title was not updated)

Note: this fix required initial support for Undo/Redo but it is still not
shared for cross tab operation.

Change-Id: I13481bf7e0778a38ccf72cb460dcf04686d9a8df

12 files changed:
scilab/CHANGES.md
scilab/modules/graph/src/java/org/scilab/modules/graph/ScilabGraph.java
scilab/modules/xcos/src/java/org/scilab/modules/xcos/block/BasicBlock.java
scilab/modules/xcos/src/java/org/scilab/modules/xcos/block/actions/BlockParametersAction.java
scilab/modules/xcos/src/java/org/scilab/modules/xcos/block/actions/RegionToSuperblockAction.java
scilab/modules/xcos/src/java/org/scilab/modules/xcos/block/io/ContextUpdate.java
scilab/modules/xcos/src/java/org/scilab/modules/xcos/graph/XcosDiagram.java
scilab/modules/xcos/src/java/org/scilab/modules/xcos/graph/model/XcosCellFactory.java
scilab/modules/xcos/src/java/org/scilab/modules/xcos/graph/model/XcosGraphModel.java
scilab/modules/xcos/src/java/org/scilab/modules/xcos/utils/XcosConstants.java
scilab/modules/xcos/src/java/org/scilab/modules/xcos/utils/XcosEvent.java [new file with mode: 0644]
scilab/modules/xcos/src/java/org/scilab/modules/xcos/utils/XcosMessages.java

index 9ad842d..2d92f91 100644 (file)
@@ -432,6 +432,7 @@ Bug Fixes
 * [#14648](http://bugzilla.scilab.org/show_bug.cgi?id=14648): `isinf` returned `%F` for complex numbers with both real and imag infinite parts.
 * [#14649](http://bugzilla.scilab.org/show_bug.cgi?id=14649): `isnan(complex(%inf, %inf))` returned `%F` while the phase is `NaN`.
 * [#14654](http://bugzilla.scilab.org/show_bug.cgi?id=14654): `bitor`, `bitxor` and `bitand` did not accept positive inputs of type `int8`, `int16`, `int32`, `int64` or `uint64`
+* [#14659](http://bugzilla.scilab.org/show_bug.cgi?id=14659): number of I/O ports of the superblock was not updated when adding or deleting I/O blocks inside a superblock.
 * [#14662](http://bugzilla.scilab.org/show_bug.cgi?id=14662): Matrix of strings concatenation with single quote led to a parser error.
 * [#14667](http://bugzilla.scilab.org/show_bug.cgi?id=14667): Multi line string without final quote generated a non terminal parser state.
 * [#14681](http://bugzilla.scilab.org/show_bug.cgi?id=14681): Short-circuited AND operation was not possible with double matrices in if and while clauses
index bea1be3..f131b63 100644 (file)
@@ -67,7 +67,7 @@ public class ScilabGraph extends mxGraph {
 
     private String title = null;
     private File savedFile;
-    private boolean modified;
+    private boolean modified = false;
     private boolean readOnly;
 
     private transient mxRubberband rubberBand;
index 7c4751c..eadc672 100644 (file)
@@ -82,6 +82,7 @@ import org.scilab.modules.xcos.utils.XcosMessages;
 
 import com.mxgraph.model.mxGeometry;
 import com.mxgraph.model.mxICell;
+import java.util.TreeMap;
 
 /**
  * A block on the diagram
@@ -287,79 +288,93 @@ public class BasicBlock extends XcosCell implements Serializable {
             return;
         }
 
-        // TODO these copies are not managed by undo/redo ; fix that
+        Map<ObjectProperties, Object> props = new TreeMap<>();
 
-        int[] integer = new int[1];
+        int[] integer;
 
+        integer = new int[1];
         controller.getObjectProperty(modifiedBlock.getUID(), modifiedBlock.getKind(), ObjectProperties.SIM_FUNCTION_API, integer);
-        controller.setObjectProperty(getUID(), getKind(), ObjectProperties.SIM_FUNCTION_API, integer[0]);
+        props.put(ObjectProperties.SIM_FUNCTION_API, integer);
 
-        String[] str = new String[1];
+        String[] str;
 
+        str = new String[1];
         controller.getObjectProperty(modifiedBlock.getUID(), modifiedBlock.getKind(), ObjectProperties.INTERFACE_FUNCTION, str);
-        controller.setObjectProperty(getUID(), getKind(), ObjectProperties.INTERFACE_FUNCTION, str[0]);
+        props.put(ObjectProperties.INTERFACE_FUNCTION, str);
 
+        str = new String[1];
         controller.getObjectProperty(modifiedBlock.getUID(), modifiedBlock.getKind(), ObjectProperties.SIM_FUNCTION_NAME, str);
-        controller.setObjectProperty(getUID(), getKind(), ObjectProperties.SIM_FUNCTION_NAME, str[0]);
+        props.put(ObjectProperties.SIM_FUNCTION_NAME, str);
 
+        str = new String[1];
         controller.getObjectProperty(modifiedBlock.getUID(), modifiedBlock.getKind(), ObjectProperties.SIM_BLOCKTYPE, str);
-        controller.setObjectProperty(getUID(), getKind(), ObjectProperties.SIM_BLOCKTYPE, str[0]);
+        props.put(ObjectProperties.SIM_BLOCKTYPE, str);
 
-        VectorOfDouble vDouble = new VectorOfDouble();
+        VectorOfDouble vDouble;
 
+        vDouble = new VectorOfDouble();
         controller.getObjectProperty(modifiedBlock.getUID(), modifiedBlock.getKind(), ObjectProperties.EXPRS, vDouble);
-        controller.setObjectProperty(getUID(), getKind(), ObjectProperties.EXPRS, vDouble);
+        props.put(ObjectProperties.EXPRS, vDouble);
 
+        vDouble = new VectorOfDouble();
         controller.getObjectProperty(modifiedBlock.getUID(), modifiedBlock.getKind(), ObjectProperties.STATE, vDouble);
-        controller.setObjectProperty(getUID(), getKind(), ObjectProperties.STATE, vDouble);
+        props.put(ObjectProperties.STATE, vDouble);
 
+        vDouble = new VectorOfDouble();
         controller.getObjectProperty(modifiedBlock.getUID(), modifiedBlock.getKind(), ObjectProperties.DSTATE, vDouble);
-        controller.setObjectProperty(getUID(), getKind(), ObjectProperties.DSTATE, vDouble);
+        props.put(ObjectProperties.DSTATE, vDouble);
 
+        vDouble = new VectorOfDouble();
         controller.getObjectProperty(modifiedBlock.getUID(), modifiedBlock.getKind(), ObjectProperties.ODSTATE, vDouble);
-        controller.setObjectProperty(getUID(), getKind(), ObjectProperties.ODSTATE, vDouble);
+        props.put(ObjectProperties.ODSTATE, vDouble);
 
+        vDouble = new VectorOfDouble();
         controller.getObjectProperty(modifiedBlock.getUID(), modifiedBlock.getKind(), ObjectProperties.RPAR, vDouble);
-        controller.setObjectProperty(getUID(), getKind(), ObjectProperties.RPAR, vDouble);
+        props.put(ObjectProperties.RPAR, vDouble);
 
+        vDouble = new VectorOfDouble();
         controller.getObjectProperty(modifiedBlock.getUID(), modifiedBlock.getKind(), ObjectProperties.OPAR, vDouble);
-        controller.setObjectProperty(getUID(), getKind(), ObjectProperties.OPAR, vDouble);
+        props.put(ObjectProperties.OPAR, vDouble);
 
+        vDouble = new VectorOfDouble();
         controller.getObjectProperty(modifiedBlock.getUID(), modifiedBlock.getKind(), ObjectProperties.EQUATIONS, vDouble);
-        controller.setObjectProperty(getUID(), getKind(), ObjectProperties.EQUATIONS, vDouble);
+        props.put(ObjectProperties.EQUATIONS, vDouble);
 
-        VectorOfInt vInt = new VectorOfInt();
+        VectorOfInt vInt;
 
+        vInt = new VectorOfInt();
         controller.getObjectProperty(modifiedBlock.getUID(), modifiedBlock.getKind(), ObjectProperties.SIM_DEP_UT, vInt);
-        controller.setObjectProperty(getUID(), getKind(), ObjectProperties.SIM_DEP_UT, vInt);
+        props.put(ObjectProperties.SIM_DEP_UT, vInt);
 
+        vInt = new VectorOfInt();
         controller.getObjectProperty(modifiedBlock.getUID(), modifiedBlock.getKind(), ObjectProperties.NZCROSS, vInt);
-        controller.setObjectProperty(getUID(), getKind(), ObjectProperties.NZCROSS, vInt);
+        props.put(ObjectProperties.NZCROSS, vInt);
 
+        vInt = new VectorOfInt();
         controller.getObjectProperty(modifiedBlock.getUID(), modifiedBlock.getKind(), ObjectProperties.NMODE, vInt);
-        controller.setObjectProperty(getUID(), getKind(), ObjectProperties.NMODE, vInt);
+        props.put(ObjectProperties.NMODE, vInt);
 
+        vInt = new VectorOfInt();
         controller.getObjectProperty(modifiedBlock.getUID(), modifiedBlock.getKind(), ObjectProperties.IPAR, vInt);
-        controller.setObjectProperty(getUID(), getKind(), ObjectProperties.IPAR, vInt);
+        props.put(ObjectProperties.IPAR, vInt);
 
+        vInt = new VectorOfInt();
         controller.getObjectProperty(modifiedBlock.getUID(), modifiedBlock.getKind(), ObjectProperties.COLOR, vInt);
         controller.setObjectProperty(getUID(), getKind(), ObjectProperties.COLOR, vInt);
+        props.put(ObjectProperties.COLOR, vInt);
 
-        VectorOfString vStr = new VectorOfString();
+        VectorOfString vStr;
 
+        vStr = new VectorOfString();
         controller.getObjectProperty(modifiedBlock.getUID(), modifiedBlock.getKind(), ObjectProperties.DIAGRAM_CONTEXT, vStr);
-        controller.setObjectProperty(getUID(), getKind(), ObjectProperties.DIAGRAM_CONTEXT, vStr);
+        props.put(ObjectProperties.DIAGRAM_CONTEXT, vStr);
 
-        // move the children to the parent
         VectorOfScicosID localChildren = new VectorOfScicosID();
         controller.getObjectProperty(modifiedBlock.getUID(), modifiedBlock.getKind(), ObjectProperties.CHILDREN, localChildren);
-        final int size = localChildren.size();
-        for (int i = 0; i < size; i++) {
-            long child = localChildren.get(i);
-            controller.referenceObject(child);
-            controller.setObjectProperty(child, controller.getKind(child), ObjectProperties.PARENT_BLOCK, getUID());
-        }
-        controller.setObjectProperty(getUID(), getKind(), ObjectProperties.CHILDREN, localChildren);
+        props.put(ObjectProperties.CHILDREN, localChildren);
+
+        // apply changes
+        parent.updateBlock(this, props);
 
         /*
          * JGraphX mapped properties
index c6a2881..b1fb45b 100644 (file)
@@ -115,9 +115,15 @@ public class BlockParametersAction extends VertexSelectionDependantAction {
                 ScicosObjectOwner root = Xcos.findRoot(graph);
                 Xcos.getInstance().addDiagram(root, sub);
 
-                // propagate the modified status
+                // propagate the modified status after discarding modification
+                // done on children insertion
+                sub.setModified(false);
                 sub.setModified(Xcos.getInstance().isModified(root));
 
+                // setup graphical interface
+                sub.getUndoManager().clear();
+                sub.installListeners();
+
                 XcosTab.restore(sub, true);
             } else {
                 BasicBlock block = (BasicBlock) cell;
index 9b28084..8528524 100644 (file)
@@ -48,7 +48,9 @@ import com.mxgraph.util.mxRectangle;
 import java.nio.LongBuffer;
 import java.rmi.server.UID;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.logging.Level;
 import static java.util.stream.Collectors.toList;
 import org.scilab.modules.action_binding.highlevel.ScilabInterpreterManagement;
@@ -60,6 +62,11 @@ import org.scilab.modules.xcos.ObjectProperties;
 import org.scilab.modules.xcos.VectorOfDouble;
 import org.scilab.modules.xcos.VectorOfInt;
 import org.scilab.modules.xcos.VectorOfScicosID;
+import static org.scilab.modules.xcos.graph.XcosDiagram.EIN;
+import static org.scilab.modules.xcos.graph.XcosDiagram.EOUT;
+import static org.scilab.modules.xcos.graph.XcosDiagram.IN;
+import static org.scilab.modules.xcos.graph.XcosDiagram.OUT;
+import static org.scilab.modules.xcos.graph.XcosDiagram.UpdateSuperblockPortsTracker.syncPorts;
 import org.scilab.modules.xcos.graph.model.XcosCell;
 import org.scilab.modules.xcos.graph.model.XcosCellFactory;
 import org.scilab.modules.xcos.io.ScilabTypeCoder;
@@ -409,6 +416,11 @@ public class RegionToSuperblockAction extends VertexSelectionDependantAction {
              */
             moveToChild(controller, parentGraph, superBlock, brokenLinks, toBeMoved);
 
+            /*
+             * Append the port to the superblock (in case of IN_f / OUT_f selected)
+             */
+            updateIO(controller, parentGraph, superBlock, toBeMoved);
+
             BlockPositioning.updateBlockView(parentGraph, superBlock);
         } catch (ScilabInterpreterManagement.InterpreterException ex) {
             // Scilab seems to be blocked, just consume the exception at this point
@@ -747,5 +759,22 @@ public class RegionToSuperblockAction extends VertexSelectionDependantAction {
 
         controller.setObjectProperty(superBlock.getUID(), superBlock.getKind(), ObjectProperties.CHILDREN, children);
     }
+
+    /**
+     * Update the ports according to the IOBlocks moved
+     * @param controller the shared controller
+     * @param parent the parent diagram
+     * @param superblock the superblock cell
+     * @param toBeMoved the moved blocks
+     */
+    private void updateIO(JavaController controller, XcosDiagram parent, SuperBlock superblock, List<XcosCell> toBeMoved) {
+        Map<Object, Object> context = new HashMap<>();
+        XcosDiagram.UpdateSuperblockPortsTracker.updateContext(context, toBeMoved, controller);
+
+        syncPorts(controller, superblock, ObjectProperties.INPUTS, (List<ContextUpdate>) context.get(IN), parent);
+        syncPorts(controller, superblock, ObjectProperties.OUTPUTS, (List<ContextUpdate>) context.get(OUT), parent);
+        syncPorts(controller, superblock, ObjectProperties.EVENT_INPUTS, (List<ContextUpdate>) context.get(EIN), parent);
+        syncPorts(controller, superblock, ObjectProperties.EVENT_OUTPUTS, (List<ContextUpdate>) context.get(EOUT), parent);
+    }
 }
 // CSON: ClassFanOutComplexity
index 652da6d..7606fd3 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
  * Copyright (C) 2009 - DIGITEO - Clement DAVID
- * Copyright (C) 2011-2015 - Scilab Enterprises - Clement DAVID
+ * Copyright (C) 2011-2017 - Scilab Enterprises - Clement DAVID
  *
  * Copyright (C) 2012 - 2016 - Scilab Enterprises
  *
@@ -46,7 +46,9 @@ import org.scilab.modules.xcos.port.output.ImplicitOutputPort;
 import org.scilab.modules.xcos.port.output.OutputPort;
 
 import com.mxgraph.model.mxICell;
+import java.lang.reflect.InvocationTargetException;
 import java.rmi.server.UID;
+import java.util.logging.Level;
 import org.scilab.modules.xcos.ObjectProperties;
 
 /**
@@ -287,6 +289,22 @@ public abstract class ContextUpdate extends BasicBlock {
         }
 
         /**
+         * Return the assignement compatible port class of the block
+         *
+         * @param klass
+         *            the klass
+         * @return the klass of the port
+         */
+        public static Class<? extends BasicPort> getPort(Class<? extends ContextUpdate> klass) {
+            for (IOBlocks b : IOBlocks.values()) {
+                if (b.getReferencedClass() == klass) {
+                    return b.getReferencedPortClass();
+                }
+            }
+            return null;
+        }
+
+        /**
          * Create a corresponding I/O block
          *
          * @param port
@@ -323,6 +341,26 @@ public abstract class ContextUpdate extends BasicBlock {
         }
 
         /**
+         * Create a corresponding port
+         * @param controller the shared controller
+         * @param block the block used on the superblock level
+         * @return port of the superblock
+         */
+        public static BasicPort createPort(JavaController controller, ContextUpdate block) {
+            Class<? extends BasicPort> p = ContextUpdate.IOBlocks.getPort(block.getClass());
+
+            BasicPort port;
+            try {
+                port = p.getConstructor(JavaController.class, Long.TYPE, Kind.class, Object.class, String.class, String.class).
+                       newInstance(controller, controller.createObject(Kind.PORT), Kind.PORT, null, null, new UID().toString());
+                return port;
+            } catch (NoSuchMethodException | SecurityException | InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
+                Logger.getLogger(ContextUpdate.class.getName()).log(Level.SEVERE, null, ex);
+            }
+            return null;
+        }
+
+        /**
          * @return referenced class
          */
         public Class<? extends ContextUpdate> getReferencedClass() {
index 4851b90..bb88456 100644 (file)
@@ -108,8 +108,6 @@ import com.mxgraph.model.mxICell;
 import com.mxgraph.util.mxEvent;
 import com.mxgraph.util.mxEventObject;
 import com.mxgraph.util.mxPoint;
-import com.mxgraph.util.mxUndoableEdit;
-import com.mxgraph.util.mxUndoableEdit.mxUndoableChange;
 import com.mxgraph.view.mxGraphSelectionModel;
 import com.mxgraph.view.mxMultiplicity;
 import java.lang.reflect.Constructor;
@@ -117,7 +115,13 @@ import java.rmi.server.UID;
 import java.util.HashMap;
 import java.util.Hashtable;
 import java.util.Optional;
+import java.util.stream.Collectors;
+import org.scilab.modules.xcos.VectorOfBool;
+import org.scilab.modules.xcos.VectorOfScicosID;
+import org.scilab.modules.xcos.block.SuperBlock;
+import org.scilab.modules.xcos.block.io.ContextUpdate;
 import org.scilab.modules.xcos.io.ScilabTypeCoder;
+import org.scilab.modules.xcos.utils.XcosEvent;
 
 /**
  * The base class for a diagram. This class contains jgraphx + Scicos data.
@@ -257,14 +261,14 @@ public class XcosDiagram extends ScilabGraph {
      * Sort the blocks per first integer parameter value
      *
      * @param blocks the block list
+     * @param the shared controller
      * @return the sorted block list (same instance)
      */
-    public List<? extends BasicBlock> iparSort(final List<? extends BasicBlock> blocks) {
+    public static List<? extends BasicBlock> iparSort(final List<? extends BasicBlock> blocks, final JavaController controller) {
         Collections.sort(blocks, new Comparator<BasicBlock>() {
             @Override
             public int compare(BasicBlock o1, BasicBlock o2) {
 
-                JavaController controller = new JavaController();
 
                 final VectorOfInt data1 = new VectorOfInt();
                 final VectorOfInt data2 = new VectorOfInt();
@@ -332,21 +336,25 @@ public class XcosDiagram extends ScilabGraph {
      * Fill the context with I/O port
      *
      * @param context the context to fill
+     * @param controller the shared controller
+     * @return the context
      */
     @SuppressWarnings("unchecked")
-    protected void fillContext(final Hashtable<Object, Object> context) {
+    public final Map<Object, Object> fillContext(final Map<Object, Object> context, final JavaController controller) {
         if (!context.containsKey(IN)) {
-            context.put(IN, iparSort(getAllTypedBlock(new Class[] {ExplicitInBlock.class, ImplicitInBlock.class})));
+            context.put(IN, iparSort(getAllTypedBlock(new Class[] {ExplicitInBlock.class, ImplicitInBlock.class}), controller));
         }
         if (!context.containsKey(OUT)) {
-            context.put(OUT, iparSort(getAllTypedBlock(new Class[] {ExplicitOutBlock.class, ImplicitOutBlock.class})));
+            context.put(OUT, iparSort(getAllTypedBlock(new Class[] {ExplicitOutBlock.class, ImplicitOutBlock.class}), controller));
         }
         if (!context.containsKey(EIN)) {
-            context.put(EIN, iparSort(getAllTypedBlock(new Class[] {EventInBlock.class})));
+            context.put(EIN, iparSort(getAllTypedBlock(new Class[] {EventInBlock.class}), controller));
         }
         if (!context.containsKey(EOUT)) {
-            context.put(EOUT, iparSort(getAllTypedBlock(new Class[] {EventOutBlock.class})));
+            context.put(EOUT, iparSort(getAllTypedBlock(new Class[] {EventOutBlock.class}), controller));
         }
+
+        return context;
     }
 
     @Override
@@ -367,8 +375,9 @@ public class XcosDiagram extends ScilabGraph {
      *
      * @param cell Cell that represents the cell to validate.
      * @param context Hashtable that represents the global validation state.
+     * @return the error message or null
      */
-    public String validateChildDiagram(final Object cell, final Hashtable<Object, Object> context) {
+    public String validateChildDiagram(final Object cell, final Map<Object, Object> context) {
         String err = null;
 
         /*
@@ -388,12 +397,13 @@ public class XcosDiagram extends ScilabGraph {
             return null;
         }
         final BasicBlock block = (BasicBlock) cell;
+        final JavaController controller = new JavaController();
 
         /*
          * Prepare validation
          */
         // fill the context once
-        fillContext(context);
+        fillContext(context, controller);
 
         /*
          * Validate with ipar
@@ -403,7 +413,6 @@ public class XcosDiagram extends ScilabGraph {
         final int realIndex = blocks.indexOf(block) + 1;
 
         // get the user index
-        JavaController controller = new JavaController();
         VectorOfInt ipar = new VectorOfInt();
         controller.getObjectProperty(block.getUID(), Kind.BLOCK, ObjectProperties.IPAR, ipar);
         if (ipar.size() < 1) {
@@ -417,7 +426,7 @@ public class XcosDiagram extends ScilabGraph {
             str.append("<html><body><em>");
             str.append(XcosMessages.WRONG_PORT_NUMBER);
             str.append("</em><br/>");
-            str.append(String.format(XcosMessages.EXPECTING_NUMBER, realIndex));
+            str.append(String.format(XcosMessages.EXPECTING_NUMBER, realIndex, userIndex));
             str.append("</body></html>    ");
 
             err = str.toString();
@@ -426,6 +435,53 @@ public class XcosDiagram extends ScilabGraph {
         return err;
     }
 
+    /**
+     * Set a model property and track undo/redo operation
+     * @param cell the cell
+     * @param values the value to set
+     */
+    public void updateBlock(BasicBlock cell, Map<ObjectProperties, Object> values) {
+        model.beginUpdate();
+        try {
+            blockUpdated(cell, values);
+            fireEvent(new mxEventObject(XcosEvent.UPDATE_BLOCK, XcosEvent.BLOCK, cell));
+        } finally {
+            model.endUpdate();
+        }
+    }
+
+    private void blockUpdated(BasicBlock cell, Map<ObjectProperties, Object> values) {
+        model.beginUpdate();
+        try {
+            for (Map.Entry<ObjectProperties, Object> e : values.entrySet()) {
+                if (e.getValue() instanceof double[]) {
+                    ((XcosGraphModel) model).setProperty(cell, e.getKey(), (double[]) e.getValue());
+                } else if (e.getValue() instanceof int[]) {
+                    ((XcosGraphModel) model).setProperty(cell, e.getKey(), (int[]) e.getValue());
+                } else if (e.getValue() instanceof boolean[]) {
+                    ((XcosGraphModel) model).setProperty(cell, e.getKey(), (boolean[]) e.getValue());
+                } else if (e.getValue() instanceof String[]) {
+                    ((XcosGraphModel) model).setProperty(cell, e.getKey(), (String[]) e.getValue());
+                } else if (e.getValue() instanceof long[]) {
+                    ((XcosGraphModel) model).setProperty(cell, e.getKey(), (long[]) e.getValue());
+                } else if (e.getValue() instanceof VectorOfDouble) {
+                    ((XcosGraphModel) model).setProperty(cell, e.getKey(), (VectorOfDouble) e.getValue());
+                } else if (e.getValue() instanceof VectorOfInt) {
+                    ((XcosGraphModel) model).setProperty(cell, e.getKey(), (VectorOfInt) e.getValue());
+                } else if (e.getValue() instanceof VectorOfBool) {
+                    ((XcosGraphModel) model).setProperty(cell, e.getKey(), (VectorOfBool) e.getValue());
+                } else if (e.getValue() instanceof VectorOfString) {
+                    ((XcosGraphModel) model).setProperty(cell, e.getKey(), (VectorOfString) e.getValue());
+                } else if (e.getValue() instanceof VectorOfScicosID) {
+                    ((XcosGraphModel) model).setProperty(cell, e.getKey(), (VectorOfScicosID) e.getValue());
+                }
+            }
+        } finally {
+            model.endUpdate();
+        }
+
+    }
+
     /*
      * Static diagram listeners
      */
@@ -480,101 +536,10 @@ public class XcosDiagram extends ScilabGraph {
     }
 
     /**
-     * Update the modified block on undo/redo
-     */
-    private static final class UndoUpdateTracker implements mxIEventListener {
-
-        private static UndoUpdateTracker instance;
-
-        /**
-         * Constructor
-         */
-        public UndoUpdateTracker() {
-        }
-
-        /**
-         * @return the instance
-         */
-        public static UndoUpdateTracker getInstance() {
-            if (instance == null) {
-                instance = new UndoUpdateTracker();
-            }
-            return instance;
-        }
-
-        /**
-         * Update the block and style on undo
-         *
-         * @param source the source instance
-         * @param evt the event data
-         * @see
-         * com.mxgraph.util.mxEventSource.mxIEventListener#invoke(java.lang.Object,
-         * com.mxgraph.util.mxEventObject)
-         */
-        @Override
-        public void invoke(final Object source, final mxEventObject evt) {
-            final mxUndoableEdit edit = (mxUndoableEdit) evt.getProperty(ScilabGraphConstants.EVENT_CHANGE_EDIT);
-
-            final mxGraphModel model = (mxGraphModel) edit.getSource();
-            final List<mxUndoableChange> changes = edit.getChanges();
-
-            final Object[] changedCells = getSelectionCellsForChanges(changes, model);
-            model.beginUpdate();
-            try {
-                // FIXME manage that for the MVC
-                // for (final Object object : changedCells) {
-                // if (object instanceof BasicBlock) {
-                // final BasicBlock current = (BasicBlock) object;
-                // final XcosDiagram graph = current.getParentDiagram();
-                //
-                // // When we change the style property we have to update
-                // // some BasiBlock fields
-                // if (changes.get(0) instanceof mxStyleChange) {
-                // current.updateFieldsFromStyle();
-                // }
-                //
-                // // update the superblock container ports if the block is
-                // // inside a superblock diagram
-                // if (graph instanceof SuperBlockDiagram) {
-                // SuperBlockDiagram superdiagram = (SuperBlockDiagram) current.getParentDiagram();
-                // SuperBlock superblock = superdiagram.getContainer();
-                // superblock.updateExportedPort();
-                // }
-                //
-                // // Update the block position
-                // BlockPositioning.updateBlockView(current);
-                //
-                // // force a refresh of the block ports and links
-                // // connected to these ports
-                // final int childCount = model.getChildCount(current);
-                // for (int i = 0; i < childCount; i++) {
-                // final Object port = model.getChildAt(current, i);
-                // graph.getView().clear(port, true, true);
-                // final int edgeCount = model.getEdgeCount(port);
-                // for (int j = 0; j < edgeCount; j++) {
-                // final Object edge = model.getEdgeAt(port, j);
-                // graph.getView().clear(edge, true, true);
-                // }
-                // }
-                // // force a refresh of the block
-                // graph.getView().clear(current, true, true);
-                //
-                // graph.getView().validate();
-                // graph.repaint();
-                // }
-                // }
-            } finally {
-                model.endUpdate();
-            }
-        }
-    }
-
-    /**
      * Refresh each block on modification (update port position, etc...)
      */
     private static final class RefreshBlockTracker implements mxIEventListener {
-
-        private static RefreshBlockTracker instance;
+        private static RefreshBlockTracker instance = new RefreshBlockTracker();
 
         /**
          * Default constructor
@@ -586,9 +551,6 @@ public class XcosDiagram extends ScilabGraph {
          * @return the instance
          */
         public static RefreshBlockTracker getInstance() {
-            if (instance == null) {
-                instance = new RefreshBlockTracker();
-            }
             return instance;
         }
 
@@ -605,9 +567,13 @@ public class XcosDiagram extends ScilabGraph {
         public void invoke(Object sender, mxEventObject evt) {
             final XcosDiagram diagram = (XcosDiagram) sender;
 
+            if (diagram.isReadonly()) {
+                return;
+            }
+
             diagram.getModel().beginUpdate();
             try {
-                final BasicBlock updatedBlock = (BasicBlock) evt.getProperty(XcosConstants.EVENT_BLOCK_UPDATED);
+                final BasicBlock updatedBlock = (BasicBlock) evt.getProperty(XcosEvent.BLOCK);
                 BlockPositioning.updateBlockView(diagram, updatedBlock);
 
                 diagram.getView().clear(updatedBlock, true, true);
@@ -645,8 +611,154 @@ public class XcosDiagram extends ScilabGraph {
                 diagrams.stream().forEach(d -> d.updateTabTitle());
             }
         }
+    }
+
+    /**
+     * Update the number and position of ports for a Superblock
+     */
+    public static final class UpdateSuperblockPortsTracker implements mxIEventListener {
+
+        private static UpdateSuperblockPortsTracker instance = new UpdateSuperblockPortsTracker();
+
+        public static UpdateSuperblockPortsTracker getInstance() {
+            return instance;
+        }
+
+        @Override
+        public void invoke(Object sender, mxEventObject evt) {
+            final XcosDiagram diagram = (XcosDiagram) sender;
+
+            if (diagram.isReadonly()) {
+                return;
+            }
+
+            // common behavior for both block adding/removing and block update
+            List<Object> updatedIOBlocks;
+            if (XcosEvent.UPDATE_BLOCK.equals(evt.getName())) {
+                updatedIOBlocks = new ArrayList<>();
+                Object b = evt.getProperty(XcosEvent.BLOCK);
+                if  (b instanceof ContextUpdate) {
+                    updatedIOBlocks.add(b);
+                }
+            } else { // ADD_CELLS or REMOVE_CELLS
+                Object[] cells = (Object[]) evt.getProperty("cells");
+                updatedIOBlocks = Arrays.stream(cells).filter(b -> b instanceof ContextUpdate).collect(Collectors.toList());
+            }
+            if (updatedIOBlocks.isEmpty()) {
+                return;
+            }
+
+            final JavaController controller = new JavaController();
+
+            String[] superBlockUID = {""};
+            controller.getObjectProperty(diagram.getUID(), diagram.getKind(), ObjectProperties.UID, superBlockUID);
+
+            List<XcosDiagram> diagrams = Xcos.getInstance().openedDiagrams(Xcos.findRoot(controller, diagram));
+            for (XcosDiagram parent : diagrams) {
+                final XcosGraphModel model = (XcosGraphModel) parent.getModel();
+                Object cell = model.getCell(superBlockUID[0]);
+                if (cell != null) {
+                    // associated parent superblock when visible
+                    SuperBlock superblock = (SuperBlock) cell;
+
+                    // create a full context
+                    Map<Object, Object> context = new HashMap<>();
+                    diagram.fillContext(context, controller);
+
+                    // only update the superblock ports if all of them are valids
+                    diagram.getAsComponent().clearCellOverlays();
+                    String status = diagram.getAsComponent().validateGraph();
+                    if (status != null) {
+                        return;
+                    }
+
+                    model.beginUpdate();
+                    try {
+                        syncPorts(controller, superblock, ObjectProperties.INPUTS, (List<ContextUpdate>) context.get(IN), parent);
+                        syncPorts(controller, superblock, ObjectProperties.OUTPUTS, (List<ContextUpdate>) context.get(OUT), parent);
+                        syncPorts(controller, superblock, ObjectProperties.EVENT_INPUTS, (List<ContextUpdate>) context.get(EIN), parent);
+                        syncPorts(controller, superblock, ObjectProperties.EVENT_OUTPUTS, (List<ContextUpdate>) context.get(EOUT), parent);
+                    } finally {
+                        model.endUpdate();
+                    }
+                    break;
+                }
+            }
+        }
 
+        /**
+         * Synchronize ports on the parent diagram accordingly to the updated IOBlocks
+         * @param controller shared controller;
+         * @param superblock the superblock to update
+         * @param p port kind
+         * @param updated the updated IOBlocks (ipar sorted)
+         * @param parent diagram containing the superblock
+         */
+        public static void syncPorts(final JavaController controller, SuperBlock superblock, ObjectProperties p, List<ContextUpdate> updated, XcosDiagram parent) {
+            VectorOfScicosID ports = new VectorOfScicosID();
+            controller.getObjectProperty(superblock.getUID(), superblock.getKind(), p, ports);
+
+            int added = updated.size() - ports.size();
+            if (added > 0) {
+                for (int i = 0; i < added; i++) {
+                    // adding port
+                    BasicPort port = ContextUpdate.IOBlocks.createPort(controller, updated.get(ports.size() + i));
+                    parent.addCell(port, superblock);
+                }
+            } else if (added < 0) {
+                for (int i = 0; i < -added; i++) {
+                    // removing port
+                    String portUID[] = {""};
+                    controller.getObjectProperty(ports.get(updated.size() + i), Kind.PORT, ObjectProperties.UID, portUID);
+                    parent.removeCells(new Object[] {((XcosGraphModel) parent.getModel()).getCell(portUID[0])});
+                }
+            }
+        }
 
+        /**
+         * Append the modified blocks to an existing context
+         * @param context the validation context
+         * @param updatedIOBlocks the blocks to add
+         * @param controller shared controller
+         */
+        public static void updateContext(Map<Object, Object> context, List<XcosCell> updatedIOBlocks, final JavaController controller) {
+            {
+                List<BasicBlock> l = (List<BasicBlock>) context.getOrDefault(IN, new ArrayList<>());
+                updatedIOBlocks.stream()
+                .filter(b -> b instanceof ExplicitInBlock || b instanceof ImplicitInBlock)
+                .map(b -> (ContextUpdate) b)
+                .collect(Collectors.toCollection(() -> l));
+                iparSort(l, controller);
+                context.putIfAbsent(IN, l);
+            }
+            {
+                List<BasicBlock> l = (List<BasicBlock>) context.getOrDefault(OUT, new ArrayList<>());
+                updatedIOBlocks.stream()
+                .filter(b -> b instanceof ExplicitOutBlock || b instanceof ImplicitOutBlock)
+                .map(b -> (ContextUpdate) b)
+                .collect(Collectors.toCollection(() -> l));
+                iparSort(l, controller);
+                context.putIfAbsent(OUT, l);
+            }
+            {
+                List<BasicBlock> l = (List<BasicBlock>) context.getOrDefault(EIN, new ArrayList<>());
+                updatedIOBlocks.stream()
+                .filter(b -> b instanceof EventInBlock)
+                .map(b -> (ContextUpdate) b)
+                .collect(Collectors.toCollection(() -> l));
+                iparSort(l, controller);
+                context.putIfAbsent(EIN, l);
+            }
+            {
+                List<BasicBlock> l = (List<BasicBlock>) context.getOrDefault(EOUT, new ArrayList<>());
+                updatedIOBlocks.stream()
+                .filter(b -> b instanceof EventOutBlock)
+                .map(b -> (ContextUpdate) b)
+                .collect(Collectors.toCollection(() -> l));
+                iparSort(l, controller);
+                context.putIfAbsent(EOUT, l);
+            }
+        }
     }
 
     /**
@@ -1116,22 +1228,29 @@ public class XcosDiagram extends ScilabGraph {
         /*
          * First remove all listeners if present
          */
-        removeListener(RepositionTracker.getInstance());
-        getUndoManager().removeListener(UndoUpdateTracker.getInstance());
-        removeListener(RefreshBlockTracker.getInstance());
         getModel().removeListener(SavedStatusTracker.getInstance(this));
-
-        // Update the saved status rendering on modification
-        getModel().addListener(mxEvent.CHANGE, SavedStatusTracker.getInstance(this));
+        removeListener(UpdateSuperblockPortsTracker.getInstance());
+        removeListener(RefreshBlockTracker.getInstance());
+        removeListener(RepositionTracker.getInstance());
 
         // Track when resizing or moving (droping) a cell.
         addListener(mxEvent.CELLS_RESIZED, RepositionTracker.getInstance());
         addListener(mxEvent.CELLS_MOVED, RepositionTracker.getInstance());
 
-        // Update the blocks view on undo/redo
-        getUndoManager().addListener(mxEvent.UNDO, UndoUpdateTracker.getInstance());
-        getUndoManager().addListener(mxEvent.REDO, UndoUpdateTracker.getInstance());
+        // Refresh block rendering on update
+        addListener(XcosEvent.UPDATE_BLOCK, RefreshBlockTracker.getInstance());
 
+        // on Superblock diagram, refresh port interface on the parent diagram
+        if (getKind() == Kind.BLOCK) {
+            addListener(XcosEvent.UPDATE_BLOCK, UpdateSuperblockPortsTracker.getInstance());
+
+            addListener(mxEvent.ADD_CELLS, UpdateSuperblockPortsTracker.getInstance());
+            addListener(mxEvent.REMOVE_CELLS, UpdateSuperblockPortsTracker.getInstance());
+            addListener(mxEvent.MOVE_CELLS, UpdateSuperblockPortsTracker.getInstance());
+        }
+
+        // Update the saved status rendering on modification
+        getModel().addListener(mxEvent.CHANGE, SavedStatusTracker.getInstance(this));
     }
 
     /**
@@ -1762,7 +1881,12 @@ public class XcosDiagram extends ScilabGraph {
 
             setTitle(writeFile.getName().substring(0, writeFile.getName().lastIndexOf('.')));
             ConfigurationManager.getInstance().addToRecentFiles(writeFile);
-            Xcos.getInstance().setModified(Xcos.findRoot(this), false);
+
+            ScicosObjectOwner root = Xcos.findRoot(this);
+            Xcos.getInstance().setModified(root, false);
+            Xcos.getInstance().openedDiagrams(root).stream()
+            .forEach(d -> d.updateTabTitle());
+
             isSuccess = true;
         } catch (final Exception e) {
             LOG.severe(e.toString());
index 97ab13e..972f6be 100644 (file)
@@ -542,6 +542,7 @@ public final class XcosCellFactory {
      *            <LI>{@link ObjectProperties#OUTPUTS}
      *            <LI>{@link ObjectProperties#EVENT_INPUTS}
      *            <LI>{@link ObjectProperties#EVENT_OUTPUTS}
+     *            </UL>
      * @param parent
      *            is the parent {@link mxCell} to modify
      * @return the number of inserted children
index 3b3e23b..7432e18 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
- * Copyright (C) 2011-2016 - Scilab Enterprises - Clement DAVID
+ * Copyright (C) 2011-2017 - Scilab Enterprises - Clement DAVID
  *
  * Copyright (C) 2012 - 2016 - Scilab Enterprises
  *
@@ -12,7 +12,6 @@
  * along with this program.
  *
  */
-
 package org.scilab.modules.xcos.graph.model;
 
 import com.mxgraph.model.mxCell;
@@ -20,20 +19,373 @@ import com.mxgraph.model.mxGraphModel;
 import java.rmi.server.UID;
 import org.scilab.modules.xcos.JavaController;
 import org.scilab.modules.xcos.Kind;
+import org.scilab.modules.xcos.ObjectProperties;
+import org.scilab.modules.xcos.VectorOfBool;
+import org.scilab.modules.xcos.VectorOfDouble;
+import org.scilab.modules.xcos.VectorOfInt;
+import org.scilab.modules.xcos.VectorOfScicosID;
+import org.scilab.modules.xcos.VectorOfString;
+import org.scilab.modules.xcos.block.BasicBlock;
 
 /**
  * Implement a custom model for Xcos
  */
 public class XcosGraphModel extends mxGraphModel {
+
     public XcosGraphModel(JavaController controller, long diagramId, Kind kind, String uid) {
         super(new mxCell());
 
         XcosCell parent = new XcosCell(controller, diagramId, kind, null, null, null, uid);
-        ((mxCell) getRoot()).insert(parent);
+        ((mxCell) root).insert(parent);
     }
 
     @Override
     public final String createId(Object cell) {
         return new UID().toString();
     }
+
+    /**
+     * Common property change support for a generic type
+     *
+     * @param <T> the type
+     */
+    private static abstract class PropertyChange<T> extends mxAtomicGraphModelChange {
+
+        private final long uid;
+        private final ObjectProperties key;
+
+        private T previous;
+
+        public PropertyChange(XcosGraphModel model, BasicBlock cell, ObjectProperties key, T value) {
+            super(model);
+
+            this.uid = cell.getUID();
+            this.key = key;
+            this.previous = value;
+        }
+
+        protected abstract T getProperty(JavaController controller, long uid, Kind kind, ObjectProperties p);
+
+        protected abstract void setProperty(JavaController controller, long uid, Kind kind, ObjectProperties p, T value);
+
+        @Override
+        public void execute() {
+            JavaController controller = new JavaController();
+
+            T temp = getProperty(controller, uid, Kind.BLOCK, key);
+            setProperty(controller, uid, Kind.LINK, key, previous);
+            previous = temp;
+        }
+    }
+
+    /**
+     * Set a block property
+     *
+     * @param cell the block
+     * @param key the property
+     * @param value the value to assign
+     */
+    public void setProperty(BasicBlock cell, ObjectProperties key, double[] value) {
+        execute(new DoublePropertyChange(this, cell, key, value));
+    }
+
+    private static final class DoublePropertyChange extends PropertyChange<double[]> {
+
+        public DoublePropertyChange(XcosGraphModel model, BasicBlock cell, ObjectProperties key, double[] value) {
+            super(model, cell, key, value);
+        }
+
+        @Override
+        protected double[] getProperty(JavaController controller, long uid, Kind kind, ObjectProperties p) {
+            double[] v = {0};
+            controller.getObjectProperty(uid, kind, p, v);
+            return v;
+        }
+
+        @Override
+        protected void setProperty(JavaController controller, long uid, Kind kind, ObjectProperties p, double[] value) {
+            controller.setObjectProperty(uid, kind, p, value[0]);
+        }
+    }
+
+    /**
+     * Set a block property
+     *
+     * @param cell the block
+     * @param key the property
+     * @param value the value to assign
+     */
+    public void setProperty(BasicBlock cell, ObjectProperties key, int[] value) {
+        execute(new IntPropertyChange(this, cell, key, value));
+    }
+
+    private static class IntPropertyChange extends PropertyChange<int[]> {
+
+        public IntPropertyChange(XcosGraphModel model, BasicBlock cell, ObjectProperties key, int[] value) {
+            super(model, cell, key, value);
+        }
+
+        @Override
+        protected int[] getProperty(JavaController controller, long uid, Kind kind, ObjectProperties p) {
+            int[] v = {0};
+            controller.getObjectProperty(uid, kind, p, v);
+            return v;
+        }
+
+        @Override
+        protected void setProperty(JavaController controller, long uid, Kind kind, ObjectProperties p, int[] value) {
+            controller.setObjectProperty(uid, kind, p, value[0]);
+        }
+    }
+
+    /**
+     * Set a block property
+     *
+     * @param cell the block
+     * @param key the property
+     * @param value the value to assign
+     */
+    public void setProperty(BasicBlock cell, ObjectProperties key, boolean[] value) {
+        execute(new BoolPropertyChange(this, cell, key, value));
+    }
+
+    private static class BoolPropertyChange extends PropertyChange<boolean[]> {
+
+        public BoolPropertyChange(XcosGraphModel model, BasicBlock cell, ObjectProperties key, boolean[] value) {
+            super(model, cell, key, value);
+        }
+
+        @Override
+        protected boolean[] getProperty(JavaController controller, long uid, Kind kind, ObjectProperties p) {
+            boolean[] v = {false};
+            controller.getObjectProperty(uid, kind, p, v);
+            return v;
+        }
+
+        @Override
+        protected void setProperty(JavaController controller, long uid, Kind kind, ObjectProperties p, boolean[] value) {
+            controller.setObjectProperty(uid, kind, p, value[0]);
+        }
+    }
+
+    /**
+     * Set a block property
+     *
+     * @param cell the block
+     * @param key the property
+     * @param value the value to assign
+     */
+    public void setProperty(BasicBlock cell, ObjectProperties key, String[] value) {
+        execute(new StringPropertyChange(this, cell, key, value));
+    }
+
+    private static class StringPropertyChange extends PropertyChange<String[]> {
+
+        public StringPropertyChange(XcosGraphModel model, BasicBlock cell, ObjectProperties key, String[] value) {
+            super(model, cell, key, value);
+        }
+
+        @Override
+        protected String[] getProperty(JavaController controller, long uid, Kind kind, ObjectProperties p) {
+            String[] v = {""};
+            controller.getObjectProperty(uid, kind, p, v);
+            return v;
+        }
+
+        @Override
+        protected void setProperty(JavaController controller, long uid, Kind kind, ObjectProperties p, String[] value) {
+            controller.setObjectProperty(uid, kind, p, value[0]);
+        }
+    }
+
+    /**
+     * Set a block property
+     *
+     * @param cell the block
+     * @param key the property
+     * @param value the value to assign
+     */
+    public void setProperty(BasicBlock cell, ObjectProperties key, long[] value) {
+        execute(new LongPropertyChange(this, cell, key, value));
+    }
+
+    private static class LongPropertyChange extends PropertyChange<long[]> {
+
+        public LongPropertyChange(XcosGraphModel model, BasicBlock cell, ObjectProperties key, long[] value) {
+            super(model, cell, key, value);
+        }
+
+        @Override
+        protected long[] getProperty(JavaController controller, long uid, Kind kind, ObjectProperties p) {
+            long[] v = {0};
+            controller.getObjectProperty(uid, kind, p, v);
+            return v;
+        }
+
+        @Override
+        protected void setProperty(JavaController controller, long uid, Kind kind, ObjectProperties p, long[] value) {
+            controller.setObjectProperty(uid, kind, p, value[0]);
+        }
+    }
+
+    /**
+     * Set a block property
+     *
+     * @param cell the block
+     * @param key the property
+     * @param value the value to assign
+     */
+    public void setProperty(BasicBlock cell, ObjectProperties key, VectorOfDouble value) {
+        execute(new VectorOfDoublePropertyChange(this, cell, key, value));
+    }
+
+    private static class VectorOfDoublePropertyChange extends PropertyChange<VectorOfDouble> {
+
+        public VectorOfDoublePropertyChange(XcosGraphModel model, BasicBlock cell, ObjectProperties key, VectorOfDouble value) {
+            super(model, cell, key, value);
+        }
+
+        @Override
+        protected VectorOfDouble getProperty(JavaController controller, long uid, Kind kind, ObjectProperties p) {
+            VectorOfDouble v = new VectorOfDouble();
+            controller.getObjectProperty(uid, kind, p, v);
+            return v;
+        }
+
+        @Override
+        protected void setProperty(JavaController controller, long uid, Kind kind, ObjectProperties p, VectorOfDouble value) {
+            controller.setObjectProperty(uid, kind, p, value);
+        }
+    }
+
+    /**
+     * Set a block property
+     *
+     * @param cell the block
+     * @param key the property
+     * @param value the value to assign
+     */
+    public void setProperty(BasicBlock cell, ObjectProperties key, VectorOfInt value) {
+        execute(new VectorOfIntPropertyChange(this, cell, key, value));
+    }
+
+    private static class VectorOfIntPropertyChange extends PropertyChange<VectorOfInt> {
+
+        public VectorOfIntPropertyChange(XcosGraphModel model, BasicBlock cell, ObjectProperties key, VectorOfInt value) {
+            super(model, cell, key, value);
+        }
+
+        @Override
+        protected VectorOfInt getProperty(JavaController controller, long uid, Kind kind, ObjectProperties p) {
+            VectorOfInt v = new VectorOfInt();
+            controller.getObjectProperty(uid, kind, p, v);
+            return v;
+        }
+
+        @Override
+        protected void setProperty(JavaController controller, long uid, Kind kind, ObjectProperties p, VectorOfInt value) {
+            controller.setObjectProperty(uid, kind, p, value);
+        }
+    }
+
+    /**
+     * Set a block property
+     *
+     * @param cell the block
+     * @param key the property
+     * @param value the value to assign
+     */
+    public void setProperty(BasicBlock cell, ObjectProperties key, VectorOfBool value) {
+        execute(new VectorOfBoolPropertyChange(this, cell, key, value));
+    }
+
+    private static class VectorOfBoolPropertyChange extends PropertyChange<VectorOfBool> {
+
+        public VectorOfBoolPropertyChange(XcosGraphModel model, BasicBlock cell, ObjectProperties key, VectorOfBool value) {
+            super(model, cell, key, value);
+        }
+
+        @Override
+        protected VectorOfBool getProperty(JavaController controller, long uid, Kind kind, ObjectProperties p) {
+            VectorOfBool v = new VectorOfBool();
+            controller.getObjectProperty(uid, kind, p, v);
+            return v;
+        }
+
+        @Override
+        protected void setProperty(JavaController controller, long uid, Kind kind, ObjectProperties p, VectorOfBool value) {
+            controller.setObjectProperty(uid, kind, p, value);
+        }
+    }
+
+    /**
+     * Set a block property
+     *
+     * @param cell the block
+     * @param key the property
+     * @param value the value to assign
+     */
+    public void setProperty(BasicBlock cell, ObjectProperties key, VectorOfString value) {
+        execute(new VectorOfStringPropertyChange(this, cell, key, value));
+    }
+
+    private static class VectorOfStringPropertyChange extends PropertyChange<VectorOfString> {
+
+        public VectorOfStringPropertyChange(XcosGraphModel model, BasicBlock cell, ObjectProperties key, VectorOfString value) {
+            super(model, cell, key, value);
+        }
+
+        @Override
+        protected VectorOfString getProperty(JavaController controller, long uid, Kind kind, ObjectProperties p) {
+            VectorOfString v = new VectorOfString();
+            controller.getObjectProperty(uid, kind, p, v);
+            return v;
+        }
+
+        @Override
+        protected void setProperty(JavaController controller, long uid, Kind kind, ObjectProperties p, VectorOfString value) {
+            controller.setObjectProperty(uid, kind, p, value);
+        }
+    }
+
+    /**
+     * Set a block property
+     *
+     * @param cell the block
+     * @param key the property
+     * @param value the value to assign
+     */
+    public void setProperty(BasicBlock cell, ObjectProperties key, VectorOfScicosID value) {
+        execute(new VectorOfScicosIDPropertyChange(this, cell, key, value));
+    }
+
+    private static class VectorOfScicosIDPropertyChange extends PropertyChange<VectorOfScicosID> {
+
+        public VectorOfScicosIDPropertyChange(XcosGraphModel model, BasicBlock cell, ObjectProperties key, VectorOfScicosID value) {
+            super(model, cell, key, value);
+        }
+
+        @Override
+        protected VectorOfScicosID getProperty(JavaController controller, long uid, Kind kind, ObjectProperties p) {
+            VectorOfScicosID v = new VectorOfScicosID();
+            controller.getObjectProperty(uid, kind, p, v);
+            return v;
+        }
+
+        @Override
+        protected void setProperty(JavaController controller, long uid, Kind kind, ObjectProperties p, VectorOfScicosID value) {
+
+            // move the children to the parent
+            if (ObjectProperties.CHILDREN == p) {
+                final int size = value.size();
+                for (int i = 0; i < size; i++) {
+                    long child = value.get(i);
+                    controller.referenceObject(child);
+                    controller.setObjectProperty(child, controller.getKind(child), ObjectProperties.PARENT_BLOCK, uid);
+                }
+            }
+
+            controller.setObjectProperty(uid, kind, p, value);
+        }
+    }
 }
index aed4573..efb8bbb 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
  * Copyright (C) 2010 - DIGITEO - Clement David
- * Copyright (C) 2011-2015 - Scilab Enterprises - Clement DAVID
+ * Copyright (C) 2011-2017 - Scilab Enterprises - Clement DAVID
  * Copyright (C) 2015 - Marcos CARDINOT
  *
  * Copyright (C) 2012 - 2016 - Scilab Enterprises
@@ -141,16 +141,6 @@ public final class XcosConstants extends ScilabGraphConstants {
         }
     }
 
-    /* Events */
-    /**
-     * When a block changed
-     */
-    public static final String EVENT_BLOCK_UPDATED = "block";
-    /** Change event old name */
-    public static final String EVENT_CHANGE_OLD = "old";
-    /** Change event new name */
-    public static final String EVENT_CHANGE_NEW = "new";
-
     /* SCI environment */
     /** Path from SCI or SCIHOME to the Xcos configuration directory */
     public static final String XCOS_ETC = "/modules/xcos/etc";
diff --git a/scilab/modules/xcos/src/java/org/scilab/modules/xcos/utils/XcosEvent.java b/scilab/modules/xcos/src/java/org/scilab/modules/xcos/utils/XcosEvent.java
new file mode 100644 (file)
index 0000000..cf04a42
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2017 - Scilab Enterprises - Clement DAVID
+ *
+ * Copyright (C) 2012 - 2016 - Scilab Enterprises
+ *
+ * This file is hereby licensed under the terms of the GNU GPL v2.0,
+ * pursuant to article 5.3.4 of the CeCILL v.2.1.
+ * This file was originally licensed under the terms of the CeCILL v2.1,
+ * and continues to be available under such terms.
+ * For more information, see the COPYING file which you should have received
+ * along with this program.
+ *
+ */
+
+package org.scilab.modules.xcos.utils;
+
+/**
+ * All global event related constants
+ */
+public final class XcosEvent {
+
+    /**
+     * trigerred on block change at the diagram level
+     */
+    public static final String UPDATE_BLOCK = "updateBlock";
+
+    /**
+     * On block update, this property is used to retrieve the current block
+     */
+    public static final String BLOCK = "block";
+}
index a761846..5ba2897 100644 (file)
@@ -2,7 +2,7 @@
  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
  * Copyright (C) 2009 - DIGITEO - Vincent COUVERT
  * Copyright (C) 2009 - DIGITEO - Clement DAVID
- * Copyright (C) 2011-2015 - Scilab Enterprises - Clement DAVID
+ * Copyright (C) 2011-2017 - Scilab Enterprises - Clement DAVID
  * Copyright (C) 2015 - Marcos CARDINOT
  *
  * Copyright (C) 2012 - 2016 - Scilab Enterprises
@@ -306,7 +306,7 @@ public final class XcosMessages {
     /* Errors */
     public static final String ERROR_UNABLE_TO_COMPILE_THIS_SUPER_BLOCK = Messages.gettext("Error: unable to compile this SuperBlock");
     public static final String WRONG_PORT_NUMBER = Messages.gettext("Evaluation problem: wrong port number.");
-    public static final String EXPECTING_NUMBER = Messages.gettext("Expecting '%d'.");
+    public static final String EXPECTING_NUMBER = Messages.gettext("Expecting <code>%d</code> but got <code>%d</code>.");
     public static final String LINK_NOT_CONNECTED = Messages
             .gettext("<html><body>Compilation error: link ignored because it is not connected. <br/>Please reconnect it.</body></html>");