Xcos: fix update of empty value for IOBlocks
[scilab.git] / scilab / modules / xcos / src / java / org / scilab / modules / xcos / block / BasicBlock.java
1 /*
2  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  * Copyright (C) 2009 - DIGITEO - Bruno JOFRET
4  * 
5  * This file must be used under the terms of the CeCILL.
6  * This source file is licensed as described in the file COPYING, which
7  * you should have received as part of this distribution.  The terms
8  * are also available at    
9  * http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt
10  *
11  */
12
13 package org.scilab.modules.xcos.block;
14
15 import static org.scilab.modules.xcos.utils.FileUtils.delete;
16
17 import java.awt.MouseInfo;
18 import java.awt.event.ActionEvent;
19 import java.awt.event.ActionListener;
20 import java.beans.PropertyChangeEvent;
21 import java.beans.PropertyChangeListener;
22 import java.beans.PropertyChangeSupport;
23 import java.io.File;
24 import java.io.IOException;
25 import java.io.Serializable;
26 import java.util.HashMap;
27 import java.util.List;
28 import java.util.Map;
29
30 import ncsa.hdf.hdf5lib.exceptions.HDF5Exception;
31
32 import org.apache.commons.logging.Log;
33 import org.apache.commons.logging.LogFactory;
34 import org.scilab.modules.action_binding.highlevel.ScilabInterpreterManagement;
35 import org.scilab.modules.action_binding.highlevel.ScilabInterpreterManagement.InterpreterException;
36 import org.scilab.modules.graph.ScilabGraph;
37 import org.scilab.modules.graph.ScilabGraphUniqueObject;
38 import org.scilab.modules.graph.actions.CopyAction;
39 import org.scilab.modules.graph.actions.CutAction;
40 import org.scilab.modules.graph.actions.DeleteAction;
41 import org.scilab.modules.graph.actions.base.DefaultAction;
42 import org.scilab.modules.graph.utils.StyleMap;
43 import org.scilab.modules.gui.bridge.contextmenu.SwingScilabContextMenu;
44 import org.scilab.modules.gui.contextmenu.ContextMenu;
45 import org.scilab.modules.gui.contextmenu.ScilabContextMenu;
46 import org.scilab.modules.gui.events.callback.CallBack;
47 import org.scilab.modules.gui.menu.Menu;
48 import org.scilab.modules.gui.menu.ScilabMenu;
49 import org.scilab.modules.gui.menuitem.MenuItem;
50 import org.scilab.modules.gui.menuitem.ScilabMenuItem;
51 import org.scilab.modules.hdf5.write.H5Write;
52 import org.scilab.modules.types.scilabTypes.ScilabDouble;
53 import org.scilab.modules.types.scilabTypes.ScilabList;
54 import org.scilab.modules.types.scilabTypes.ScilabString;
55 import org.scilab.modules.types.scilabTypes.ScilabType;
56 import org.scilab.modules.xcos.Xcos;
57 import org.scilab.modules.xcos.XcosTab;
58 import org.scilab.modules.xcos.actions.ShowHideShadowAction;
59 import org.scilab.modules.xcos.block.actions.BlockDocumentationAction;
60 import org.scilab.modules.xcos.block.actions.BlockParametersAction;
61 import org.scilab.modules.xcos.block.actions.BorderColorAction;
62 import org.scilab.modules.xcos.block.actions.EditBlockFormatAction;
63 import org.scilab.modules.xcos.block.actions.FilledColorAction;
64 import org.scilab.modules.xcos.block.actions.FlipAction;
65 import org.scilab.modules.xcos.block.actions.MirrorAction;
66 import org.scilab.modules.xcos.block.actions.RegionToSuperblockAction;
67 import org.scilab.modules.xcos.block.actions.RotateAction;
68 import org.scilab.modules.xcos.block.actions.ViewDetailsAction;
69 import org.scilab.modules.xcos.block.actions.alignement.AlignBlockAction;
70 import org.scilab.modules.xcos.block.actions.alignement.AlignBlockActionBottom;
71 import org.scilab.modules.xcos.block.actions.alignement.AlignBlockActionCenter;
72 import org.scilab.modules.xcos.block.actions.alignement.AlignBlockActionLeft;
73 import org.scilab.modules.xcos.block.actions.alignement.AlignBlockActionMiddle;
74 import org.scilab.modules.xcos.block.actions.alignement.AlignBlockActionRight;
75 import org.scilab.modules.xcos.block.actions.alignement.AlignBlockActionTop;
76 import org.scilab.modules.xcos.graph.PaletteDiagram;
77 import org.scilab.modules.xcos.graph.SuperBlockDiagram;
78 import org.scilab.modules.xcos.graph.XcosDiagram;
79 import org.scilab.modules.xcos.io.scicos.BasicBlockInfo;
80 import org.scilab.modules.xcos.io.scicos.H5RWHandler;
81 import org.scilab.modules.xcos.port.BasicPort;
82 import org.scilab.modules.xcos.port.command.CommandPort;
83 import org.scilab.modules.xcos.port.control.ControlPort;
84 import org.scilab.modules.xcos.port.input.InputPort;
85 import org.scilab.modules.xcos.port.output.OutputPort;
86 import org.scilab.modules.xcos.utils.BlockPositioning;
87 import org.scilab.modules.xcos.utils.FileUtils;
88 import org.scilab.modules.xcos.utils.XcosConstants;
89 import org.scilab.modules.xcos.utils.XcosEvent;
90 import org.scilab.modules.xcos.utils.XcosMessages;
91
92 import com.mxgraph.model.mxGeometry;
93 import com.mxgraph.model.mxICell;
94 import com.mxgraph.util.mxEventObject;
95 import com.mxgraph.util.mxUtils;
96
97 public class BasicBlock extends ScilabGraphUniqueObject implements Serializable {
98         private static final double DEFAULT_POSITION_X = 10.0;
99         private static final double DEFAULT_POSITION_Y = 10.0;
100         private static final double DEFAULT_WIDTH = 40.0;
101         private static final double DEFAULT_HEIGHT = 40.0;
102         
103         private static final PropertyChangeListener styleUpdater = new UpdateStyleFromInterfunction();
104         private static final Log LOG = LogFactory.getLog(BasicBlock.class);
105         
106         /**
107          * Manage events for block parameters.
108          * 
109          * The property name is the field name, is one of:
110          *     - "interfaceFunctionName"
111          *     - "simulationFunctionName"
112          *     - "simulationFunctionType"
113          *     - "exprs"
114          *     - "realParameters"
115          *     - "integerParameters"
116          *     - "objectsParameters"
117          *     - "nbZerosCrossing"
118          *     - "nmode"
119          *     - "state"
120          *     - "dState"
121          *     - "oDState"
122          *     - "equations"
123          *     - "dependsOnU"
124          *     - "dependsOnT"
125          *     - "blockType"
126          *     - "ordering"
127          */
128         protected PropertyChangeSupport parametersPCS = new PropertyChangeSupport(this);
129         
130     private String interfaceFunctionName = "xcos_block";
131     private String simulationFunctionName = "xcos_simulate";
132     private SimulationFunctionType simulationFunctionType = SimulationFunctionType.DEFAULT;
133     private transient XcosDiagram parentDiagram;   
134     
135     private int angle;
136     private boolean isFlipped;
137     private boolean isMirrored;
138     
139
140     // TODO : Must make this types evolve, but for now keep a strong link to Scilab
141     // !! WARNING !!
142     // exprs = [] ; rpar = [] ; ipar = [] ; opar = list()
143
144     //private List<String> exprs = new ArrayList<String>();
145     private ScilabType exprs;
146     //private List<Double> realParameters = new ArrayList<Double>();
147     private ScilabType realParameters;
148     //private List<Integer> integerParameters = new ArrayList<Integer>();
149     private ScilabType integerParameters;
150     //private List objectsParameters = new ArrayList();
151     private ScilabType objectsParameters;
152
153     private ScilabType nbZerosCrossing = new ScilabDouble();
154
155     private ScilabType nmode = new ScilabDouble();
156
157     private ScilabType state = new ScilabDouble();
158     private ScilabType dState = new ScilabDouble();
159     private ScilabType oDState = new ScilabDouble();
160
161     private ScilabType equations;
162
163     private boolean dependsOnU;
164     private boolean dependsOnT;
165
166     private String blockType = "c";
167
168     private int ordering;
169     private boolean locked;
170
171         /**
172          * Represent a simulation function type compatible with Scilab/Scicos
173          * function type descriptors.
174          */
175         public static enum SimulationFunctionType {
176                 ESELECT(-2.0), IFTHENELSE(-1.0), DEFAULT(0.0), TYPE_1(1.0), TYPE_2(2.0),
177                     TYPE_3(3.0), C_OR_FORTRAN(4.0), SCILAB(5.0), MODELICA(30004.0), UNKNOWN(5.0), OLDBLOCKS(10001.0), IMPLICIT_C_OR_FORTRAN(10004.0);
178
179                 private double value;
180
181                 /**
182                  * Default constructor
183                  * 
184                  * @param scilabValue
185                  *            Scilab/Scicos function type descriptor
186                  */
187                 private SimulationFunctionType(double scilabValue) {
188                         value = scilabValue;
189                 }
190
191                 /**
192                  * Get the Java descriptor from the Scilab descriptor.
193                  * 
194                  * @param scilabValue
195                  *            Scilab/Scicos function type descriptor
196                  * @return The corresponding java descriptor
197                  */
198                 public static SimulationFunctionType convertScilabValue(int scilabValue) {
199                         for (SimulationFunctionType iter : SimulationFunctionType.values()) {
200                                 if (iter.getAsDouble() == scilabValue) {
201                                         return iter;
202                                 }
203                         }
204                         return UNKNOWN;
205                 }
206
207                 /**
208                  * Get the Scilab Descriptor from the Java Descriptor
209                  * 
210                  * @return The corresponding Scilab/Scicos descriptor
211                  */
212                 public double getAsDouble() {
213                         return this.value;
214                 }
215         };
216
217         /**
218          * Update the source block when the interfunction change. 
219          */
220         private static class UpdateStyleFromInterfunction implements PropertyChangeListener, Serializable {
221
222                 /**
223                  * Update the label on interfunction change.
224                  * 
225                  * @param evt the property change event.
226                  * @see java.beans.PropertyChangeListener#propertyChange(java.beans.PropertyChangeEvent)
227                  */
228                 @Override
229                 public void propertyChange(PropertyChangeEvent evt) {
230                         BasicBlock source = (BasicBlock) evt.getSource();
231                         
232                         StyleMap style = new StyleMap(source.getStyle());
233                         style.remove((String) evt.getOldValue());
234                         style.put((String) evt.getNewValue(), null);
235                         source.setStyle(style.toString());
236                 }
237                 
238         }
239         
240         private static class TraceParametersListener implements PropertyChangeListener, Serializable {
241                 private static TraceParametersListener instance;
242                 
243                 private TraceParametersListener() {
244                         super();
245                 }
246                 
247                 /**
248                  * @return the instance
249                  */
250                 public static TraceParametersListener getInstance() {
251                         if (instance == null) {
252                                 instance = new TraceParametersListener();
253                         }
254                         return instance;
255                 }
256                 
257                 @Override
258                 public void propertyChange(PropertyChangeEvent evt) {
259                         LOG.trace(evt.getPropertyName() + ": " + evt.getOldValue() + ", " + evt.getNewValue());
260                 }
261         }
262         
263         /**
264          * 
265          */
266         public BasicBlock() {
267                 super();
268                 setDefaultValues();
269                 setVisible(true);
270                 setVertex(true);
271                 
272                 if (getStyle().isEmpty() && !getInterfaceFunctionName().isEmpty()) {
273                         setStyle(getInterfaceFunctionName());
274                 }
275                 
276                 parametersPCS.addPropertyChangeListener("interfaceFunctionName",
277                                 styleUpdater);
278                 
279                 /*
280                  * Trace block parameters change if applicable.
281                  */
282                 if (LOG.isTraceEnabled()) {
283                         parametersPCS.addPropertyChangeListener(TraceParametersListener.getInstance());
284                 }
285         }
286
287         /**
288          * @param label block label
289          */
290         protected BasicBlock(String label) {
291                 this();
292                 setDefaultValues();
293                 setValue(label);
294         }
295
296         /**
297          * @param label block label
298          * @param style initial style
299          */
300         protected BasicBlock(String label, String style) {
301                 this(label);
302                 setStyle(style);
303         }
304
305         /**
306          * Initialize the block with the default values
307          */
308         protected void setDefaultValues() {
309                 setVisible(true);
310                 setVertex(true);
311                 setConnectable(false);
312                 setGeometry(new mxGeometry(DEFAULT_POSITION_X, DEFAULT_POSITION_Y,
313                                 DEFAULT_WIDTH, DEFAULT_HEIGHT));
314                 setValue("");
315                 setStyle("");
316         }
317
318     /**
319      * @return parent diagram
320      */
321     public XcosDiagram getParentDiagram() {
322         return parentDiagram;
323     }
324
325     /**
326      * @param parentDiagram parent diagram
327      */
328     public void setParentDiagram(XcosDiagram parentDiagram) {
329         this.parentDiagram = parentDiagram;
330     }
331
332     
333     /**
334      * @return interface function name
335      */
336     public String getInterfaceFunctionName() {
337         return interfaceFunctionName;
338     }
339
340     /**
341      * @param interfaceFunctionName interface function name
342      */
343     public void setInterfaceFunctionName(String interfaceFunctionName) {
344                 if ((this.interfaceFunctionName == null && interfaceFunctionName != null)
345                                 || !this.interfaceFunctionName.equals(interfaceFunctionName)) {
346                         
347                         final String oldValue = this.interfaceFunctionName;
348                         this.interfaceFunctionName = interfaceFunctionName;
349                         parametersPCS.firePropertyChange("interfaceFunctionName", oldValue,
350                                         interfaceFunctionName);
351                 }
352     }
353
354     /**
355      * @param simulationFunctionName sumulation function name
356      */
357     public void setSimulationFunctionName(String simulationFunctionName) {
358                 if ((this.simulationFunctionName == null && simulationFunctionName != null)
359                                 || !this.simulationFunctionName.equals(simulationFunctionName)) {
360                         
361                 final String oldValue = this.simulationFunctionName;
362                 this.simulationFunctionName = simulationFunctionName;
363                 parametersPCS.firePropertyChange("simulationFunctionName", oldValue, simulationFunctionName);
364         }
365     }
366
367     /**
368      * @return sumulation function name
369      */
370     public String getSimulationFunctionName() {
371         return simulationFunctionName;
372     }
373
374     /**
375      * @param scilabValue simulation function type
376      */
377     public void setSimulationFunctionType(int scilabValue) {
378                 SimulationFunctionType simulationFunctionType = SimulationFunctionType.convertScilabValue(scilabValue);
379                 setSimulationFunctionType(simulationFunctionType);
380     }
381
382     /**
383      * @param simulationFunctionType simulation function type
384      */
385         public void setSimulationFunctionType(SimulationFunctionType simulationFunctionType) {
386                 if ((this.simulationFunctionType == null && simulationFunctionType != null)
387                                 || !this.simulationFunctionType.equals(simulationFunctionType)) {
388                         
389                         final SimulationFunctionType oldValue = this.simulationFunctionType;
390                         this.simulationFunctionType = simulationFunctionType;
391                         parametersPCS.firePropertyChange("simulationFunctionType", oldValue,
392                                         simulationFunctionType);
393                 }
394         }
395
396     /**
397      * @return simulation function type
398      */
399     public SimulationFunctionType getSimulationFunctionType() {
400         return simulationFunctionType;
401     }
402
403     /**
404      * @return real parameter ( rpar )
405      */
406     public ScilabType getRealParameters() {
407         return realParameters;
408     }
409
410     /**
411      * @param realParameters reaL parameter ( rpar )
412      */
413     public void setRealParameters(ScilabType realParameters) {
414                 if ((this.realParameters == null && realParameters != null)
415                                 || !this.realParameters.equals(realParameters)) {
416                         
417                         final ScilabType oldValue = this.realParameters;
418                         this.realParameters = realParameters;
419                         parametersPCS.firePropertyChange("realParameters", oldValue, realParameters);
420                 }
421     } 
422
423     /**
424      * @return integer parameter ( ipar )
425      */
426     public ScilabType getIntegerParameters() {
427         return integerParameters;
428     }
429
430     /**
431      * @param integerParameters integer parameter ( ipar )
432      */
433     public void setIntegerParameters(ScilabType integerParameters) {
434                 if ((this.integerParameters == null && integerParameters != null)
435                                 || !this.integerParameters.equals(integerParameters)) {
436                         
437                         final ScilabType oldValue = this.integerParameters;
438                         this.integerParameters = integerParameters;
439                         parametersPCS.firePropertyChange("integerParameters", oldValue, integerParameters);
440                 }
441     }
442
443     /**
444      * @return object parameter ( opar )
445      */
446     public ScilabType getObjectsParameters() {
447         return objectsParameters;
448     }
449
450     /**
451      * @param objectsParameters object parameter ( opar )
452      */
453     public void setObjectsParameters(ScilabType objectsParameters) {
454                 if ((this.objectsParameters == null && objectsParameters != null)
455                                 || !this.objectsParameters.equals(objectsParameters)) {
456                         
457                         final ScilabType oldValue = this.objectsParameters;
458                         this.objectsParameters = objectsParameters;
459                         parametersPCS.firePropertyChange("objectsParameters", oldValue, objectsParameters);
460                 }
461     }
462
463     /**
464      * @param dependsOnU ?
465      */
466     public void setDependsOnU(boolean dependsOnU) {
467                 if (this.dependsOnU != dependsOnU) {
468                         
469                         final boolean oldValue = this.dependsOnU;
470                         this.dependsOnU = dependsOnU;
471                         parametersPCS.firePropertyChange("dependsOnU", oldValue, dependsOnU);
472                 }
473     }
474
475     /**
476      * @return ?
477      */
478     public boolean isDependsOnU() {
479         return dependsOnU;
480     }
481
482     /**
483      * @param dependsOnT ?
484      */
485     public void setDependsOnT(boolean dependsOnT) {
486                 if (this.dependsOnT != dependsOnT) {
487                         
488                         final boolean oldValue = this.dependsOnT;
489                         this.dependsOnT = dependsOnT;
490                         parametersPCS.firePropertyChange("dependsOnT", oldValue, dependsOnT);
491                 }
492     }
493
494     /**
495      * @return ?
496      */
497     public boolean isDependsOnT() {
498         return dependsOnT;
499     }
500
501     /**
502      * @param blockType block type
503      */
504     public void setBlockType(String blockType) {
505                 if ((this.blockType == null && blockType != null)
506                                 || !this.blockType.equals(blockType)) {
507                         
508                         final String oldValue = this.blockType;
509                         this.blockType = blockType;
510                         parametersPCS.firePropertyChange("blockType", oldValue, blockType);
511                 }
512     }
513
514     /**
515      * @return block type
516      */
517     public String getBlockType() {
518         return blockType;
519     }
520
521     /**
522      * @param ordering order value
523      */
524     public void setOrdering(int ordering) {
525                 if (this.ordering != ordering) {
526                         
527                         final int oldValue = this.ordering;
528                         this.ordering = ordering;
529                         parametersPCS.firePropertyChange("ordering", oldValue, ordering);
530                 }
531     }
532
533     /**
534      * @return order value
535      */
536     public int getOrdering() {
537         return ordering;
538     }
539
540     /**
541      * @param exprs expression
542      */
543     public void setExprs(ScilabType exprs) {
544                 if ((this.exprs == null && exprs != null)
545                                 || !this.exprs.equals(exprs)) {
546                         
547                         final ScilabType oldValue = this.exprs;
548                         this.exprs = exprs;
549                         parametersPCS.firePropertyChange("exprs", oldValue, exprs);
550                 }
551     }
552
553     /**
554      * @return expression
555      */
556     public ScilabType getExprs() {
557         return exprs;
558     }
559
560     /**
561      * @return zero crossing value
562      */
563     public ScilabType getNbZerosCrossing() {
564         return nbZerosCrossing;
565     }
566
567     /**
568      * @param nbZerosCrossing zero crossing value
569      */
570     public void setNbZerosCrossing(ScilabType nbZerosCrossing) {
571                 if ((this.nbZerosCrossing == null && nbZerosCrossing != null)
572                                 || !this.nbZerosCrossing.equals(nbZerosCrossing)) {
573                         
574                         final ScilabType oldValue = this.nbZerosCrossing;
575                         this.nbZerosCrossing = nbZerosCrossing;
576                         parametersPCS.firePropertyChange("nbZerosCrossing", oldValue, nbZerosCrossing);
577                 }
578     }
579
580     /**
581      * @return nmode
582      */
583     public ScilabType getNmode() {
584         return nmode;
585     }
586
587     /**
588      * @param nmode nmode
589      */
590     public void setNmode(ScilabType nmode) {
591                 if ((this.nmode == null && nmode != null)
592                                 || !this.nmode.equals(nmode)) {
593                         
594                         final ScilabType oldValue = this.nmode;
595                         this.nmode = nmode;
596                         parametersPCS.firePropertyChange("nmode", oldValue, nmode);
597                 }
598     }
599
600     /**
601      * @return current state
602      */
603     public ScilabType getState() {
604         return state;
605     }
606
607     /**
608      * @param state new state
609      */
610     public void setState(ScilabType state) {
611                 if ((this.state == null && state != null)
612                                 || !this.state.equals(state)) {
613                         
614                         final ScilabType oldValue = this.state;
615                         this.state = state;
616                         parametersPCS.firePropertyChange("state", oldValue, state);
617                 }
618     }
619
620     /**
621      * @return current dstate
622      */
623     public ScilabType getDState() {
624         return dState;
625     }
626
627     /**
628      * @param state new dstate
629      */
630     public void setDState(ScilabType dState) {
631                 if ((this.dState == null && dState != null)
632                                 || !this.dState.equals(dState)) {
633                         
634                         final ScilabType oldValue = this.dState;
635                         this.dState = dState;
636                         parametersPCS.firePropertyChange("dState", oldValue, dState);
637                 }
638     }
639
640     /**
641      * @return current ostate
642      */
643     public ScilabType getODState() {
644         return oDState;
645     }
646
647     /**
648      * @param state new ostate
649      */
650     public void setODState(ScilabType oDState) {
651                 if ((this.oDState == null && oDState != null)
652                                 || !this.oDState.equals(oDState)) {
653                         
654                         final ScilabType oldValue = this.oDState;
655                         this.oDState = oDState;
656                         parametersPCS.firePropertyChange("oDState", oldValue, oDState);
657                 }
658     }
659
660     /**
661      * @return equations
662      */
663     public ScilabType getEquations() {
664         return equations;
665     }
666
667     /**
668      * @param equations equations
669      */
670     public void setEquations(ScilabType equations) {
671                 if ((this.equations == null && equations != null)
672                                 || !this.equations.equals(equations)) {
673                         
674                         final ScilabType oldValue = this.equations;
675                         this.equations = equations;
676                         parametersPCS.firePropertyChange("equations", oldValue, equations);
677                 }
678     }
679
680     /**
681      * @return locked status
682      */
683     public synchronized boolean isLocked() {
684         return locked;
685     }
686
687     /**
688      * @param locked change locked status
689      */
690     public synchronized void setLocked(boolean locked) {
691         this.locked = locked;
692     }
693
694     /**
695      * @param port to remove
696      */
697     public void removePort(BasicPort port) {
698         if (port.getEdgeCount() != 0) {
699             getParentDiagram().removeCells(new Object[]{port.getEdgeAt(0)});
700         }
701         remove(port);
702     }
703     
704     /**
705      * Add a port on the block.
706      * @param port The port to be added to the block
707      */
708     public void addPort(BasicPort port) {
709         insert(port);
710         BlockPositioning.updateBlockView(this);
711         port.setOrdering(BasicBlockInfo.getAllTypedPorts(this, false, port.getClass()).size());
712     }
713
714         /**
715          * @return command ports initial state
716          */
717         public ScilabDouble getAllCommandPortsInitialStates() {
718                 final List<CommandPort> cmdPorts = BasicBlockInfo.getAllTypedPorts(
719                                 this, false, CommandPort.class);
720                 if (cmdPorts.isEmpty()) {
721                         return new ScilabDouble();
722                 }
723
724                 double[][] data = new double[cmdPorts.size()][1];
725                 for (int i = 0; i < cmdPorts.size(); ++i) {
726                         data[i][0] = cmdPorts.get(i).getInitialState();
727                 }
728
729                 return new ScilabDouble(data);
730         }
731
732     /**
733      * @return name and type of the simulation function
734      */
735     public ScilabType getSimulationFunctionNameAndType() {
736         if (getSimulationFunctionType() == SimulationFunctionType.DEFAULT) {
737             return new ScilabString(getSimulationFunctionName());
738         }
739         ScilabList data = new ScilabList();
740
741         data.add(new ScilabString(getSimulationFunctionName()));
742         data.add(new ScilabDouble(getSimulationFunctionType().getAsDouble()));
743
744         return data;
745     }
746
747     /**
748      * Does the block update and register on the undo manager 
749      * @param modifiedBlock the new settings
750      */
751     public void updateBlockSettings(BasicBlock modifiedBlock) {
752         doUpdateBlockSettings(modifiedBlock);
753     }
754
755     /**
756      * Does the block update without using the undo manager 
757      * @param modifiedBlock the new settings
758      */
759     public void doUpdateBlockSettings(BasicBlock modifiedBlock) {
760         setDependsOnT(modifiedBlock.isDependsOnT());
761         setDependsOnU(modifiedBlock.isDependsOnU());
762         setExprs(modifiedBlock.getExprs());
763
764         setRealParameters(modifiedBlock.getRealParameters());
765         setIntegerParameters(modifiedBlock.getIntegerParameters());
766         setObjectsParameters(modifiedBlock.getObjectsParameters());
767
768         setState(modifiedBlock.getState());
769         setDState(modifiedBlock.getDState());
770         setODState(modifiedBlock.getODState());
771
772         setEquations(modifiedBlock.getEquations());
773
774                 // Update the children according to the modified block children. We are
775                 // working on the last index in order to simplify the List.remove()
776                 // call.
777                 final int oldChildCount = getChildCount();
778                 final int newChildCount = modifiedBlock.getChildCount();
779                 final int portStep = newChildCount - oldChildCount;
780                 if (portStep > 0) {
781                         for (int i = portStep - 1; i >= 0; i--) {
782                                 addPort((BasicPort) modifiedBlock.getChildAt(oldChildCount + i - 1));
783                         }
784                 } else {
785                         for (int i = -portStep - 1; i >= 0; i--) {
786                                 removePort((BasicPort) getChildAt(newChildCount + i));
787                         }
788                 }
789
790         /*
791          * If the block is in a superblock then update it.
792          */
793         if (getParentDiagram() instanceof SuperBlockDiagram) {
794             SuperBlock parentBlock = ((SuperBlockDiagram) getParentDiagram()).getContainer();
795             parentBlock.getParentDiagram().fireEvent(new mxEventObject(XcosEvent.SUPER_BLOCK_UPDATED, 
796                     XcosConstants.EVENT_BLOCK_UPDATED, parentBlock));
797         }
798     }
799
800     /**
801      * @param context parent diagram context
802      */
803     public void openBlockSettings(String[] context) {
804         
805         if (getParentDiagram() instanceof PaletteDiagram) {
806             return;
807         }
808         
809         //prevent to open twice
810         if (isLocked()) {
811             return;
812         }
813         
814         final File tempOutput;
815         final File tempInput;
816         final File tempContext;
817         final BasicBlock currentBlock = this;
818         
819         try {
820             tempInput = FileUtils.createTempFile();
821
822             // Write scs_m
823             tempOutput = exportBlockStruct();
824             // Write context
825             tempContext = exportContext(context);
826             
827             final ActionListener action = new ActionListener() {
828                         @Override
829                         public void actionPerformed(ActionEvent e) {
830                                 if (tempInput.exists()) {
831                                         LOG.trace("Updating data.");
832                                         
833                                 // Now read new Block
834                             BasicBlock modifiedBlock = new H5RWHandler(tempInput).readBlock();
835                             updateBlockSettings(modifiedBlock);
836                             
837                             getParentDiagram().fireEvent(new mxEventObject(XcosEvent.ADD_PORTS, XcosConstants.EVENT_BLOCK_UPDATED, 
838                                     currentBlock));
839                             delete(tempInput);
840                                 } else {
841                                         LOG.trace("No needs to update data.");
842                                 }
843                                 
844                             setLocked(false);
845                             delete(tempOutput);
846                             delete(tempContext);
847                         }
848                 };
849                 
850             try {
851                         ScilabInterpreterManagement.asynchronousScilabExec(action, 
852                                 "xcosBlockInterface", 
853                                 tempOutput.getAbsolutePath(),
854                                 tempInput.getAbsolutePath(),
855                                 getInterfaceFunctionName().toCharArray(),
856                                 "set",
857                                 tempContext.getAbsolutePath());
858                 } catch (InterpreterException e) {
859                         LOG.error(e);
860                 }
861             setLocked(true);
862
863         } catch (IOException e) {
864             LOG.error(e);
865         }
866     }
867
868     /**
869      * @return exported file
870      */
871     protected File exportBlockStruct() {
872
873         // Write scs_m
874         File tempOutput;
875         try {
876             tempOutput = FileUtils.createTempFile();
877             tempOutput.deleteOnExit();
878             
879             new H5RWHandler(tempOutput).writeBlock(this);
880             return tempOutput;
881         } catch (IOException e) {
882             e.printStackTrace();
883         }
884         return null;
885     }
886     
887     /**
888      * @param context parent diagram context
889      * @return exported file
890      */
891     protected File exportContext(String[] context) {
892
893         // Write context
894         try {
895             File tempContext = FileUtils.createTempFile();
896             tempContext.deleteOnExit();
897             int contextFileId = H5Write.createFile(tempContext.getAbsolutePath());
898             H5Write.writeInDataSet(contextFileId, "context", new ScilabString(context));
899             H5Write.closeFile(contextFileId);
900             return tempContext;
901         } catch (IOException e) {
902             e.printStackTrace();
903         } catch (HDF5Exception e) {
904             e.printStackTrace();
905         }
906         return null;
907     }
908     
909     /**
910      * @return tooltip text
911      */
912     public String getToolTipText() {
913         StringBuilder result = new StringBuilder();
914         result.append(XcosConstants.HTML_BEGIN);
915         result.append("Block Name : " + getInterfaceFunctionName() + XcosConstants.HTML_NEWLINE);
916         result.append("Simulation : " + getSimulationFunctionName() + XcosConstants.HTML_NEWLINE);
917
918         if (getParentDiagram() instanceof PaletteDiagram) {
919             if (getIntegerParameters() != null) {
920                 result.append("Integer parameters : " + getIntegerParameters() + XcosConstants.HTML_NEWLINE);
921             }
922             
923             if (getRealParameters() != null && getRealParameters().getHeight() != 0 && getRealParameters().getWidth() != 0) {
924                 result.append("Real parameters : " + getRealParameters() + XcosConstants.HTML_NEWLINE);
925             }
926             
927             if (getObjectsParameters() != null) {
928                 result.append("Object parameters : " + getObjectsParameters() + XcosConstants.HTML_NEWLINE);
929             }
930         } else {
931             result.append("UID : " + getId() + XcosConstants.HTML_NEWLINE);
932                 final int length = getStyle().length();
933                 result.append("Style : ");
934                 if (length > XcosConstants.MAX_CHAR_IN_STYLE) {
935                         result.append(getStyle().substring(0, XcosConstants.MAX_CHAR_IN_STYLE));
936                         result.append(XcosMessages.DOTS);
937                 } else {
938                         result.append(getStyle());
939                 }
940                 result.append(XcosConstants.HTML_NEWLINE);
941             result.append("Flip : " + getFlip() + XcosConstants.HTML_NEWLINE);
942             result.append("Mirror : " + getMirror() + XcosConstants.HTML_NEWLINE);
943             result.append("Input ports : " + BasicBlockInfo.getAllTypedPorts(this, false, InputPort.class).size() + XcosConstants.HTML_NEWLINE);
944             result.append("Output ports : " + BasicBlockInfo.getAllTypedPorts(this, false, OutputPort.class).size() + XcosConstants.HTML_NEWLINE);
945             result.append("Control ports : " + BasicBlockInfo.getAllTypedPorts(this, false, ControlPort.class).size() + XcosConstants.HTML_NEWLINE);
946             result.append("Command ports : " + BasicBlockInfo.getAllTypedPorts(this, false, CommandPort.class).size() + XcosConstants.HTML_NEWLINE);
947         }
948
949         result.append("x : " + getGeometry().getX() + XcosConstants.HTML_NEWLINE);
950         result.append("y : " + getGeometry().getY() + XcosConstants.HTML_NEWLINE);
951         result.append("w : " + getGeometry().getWidth() + XcosConstants.HTML_NEWLINE);
952         result.append("h : " + getGeometry().getHeight() + XcosConstants.HTML_NEWLINE);
953         result.append(XcosConstants.HTML_END);
954         return result.toString();
955     }
956
957     /**
958      * @param graph parent graph
959      */
960     public void openContextMenu(ScilabGraph graph) {
961         ContextMenu menu = null;
962         if (getParentDiagram() instanceof PaletteDiagram) {
963             menu = createPaletteContextMenu(graph);
964         } else {
965             menu = createContextMenu(graph);
966         }
967         menu.setVisible(true);
968     }
969
970     /**
971      * @param graph parent graph
972      * @return context menu
973      */
974     public ContextMenu createPaletteContextMenu(ScilabGraph graph) {
975         ContextMenu menu = ScilabContextMenu.createContextMenu();
976
977         final List<XcosDiagram> allDiagrams = Xcos.getInstance().getDiagrams();
978
979         if (allDiagrams.size() == 0) {
980             // No diagram opened: should never happen if Xcos opens an empty diagram when it is launched
981             MenuItem addTo = ScilabMenuItem.createMenuItem();
982
983             addTo.setText(XcosMessages.ADDTO_NEW_DIAGRAM);
984             addTo.setCallback(new CallBack(XcosMessages.ADDTO_NEW_DIAGRAM) {
985                 @Override
986                 public void callBack() {
987                         
988                     XcosDiagram theDiagram = new XcosDiagram();
989                     BasicBlock block = (BasicBlock) BlockFactory.createClone(BasicBlock.this);
990                     theDiagram.getModel().add(theDiagram.getDefaultParent(), block, 0);
991                     mxGeometry geom = BasicBlock.this.getGeometry();
992                     setDefaultPosition(geom);
993                     theDiagram.getModel().setGeometry(block, geom);
994                     
995                     new XcosTab(theDiagram).setVisible(true);
996                     BlockPositioning.updateBlockView(block);
997                 }
998             });
999
1000             menu.add(addTo);
1001
1002         } else if (allDiagrams.size() == 1) {
1003             // A single diagram opened: add to this diagram
1004             MenuItem addTo = ScilabMenuItem.createMenuItem();
1005
1006             addTo.setText(XcosMessages.ADDTO + " " + allDiagrams.get(0).getParentTab().getName());
1007             final XcosDiagram theDiagram = allDiagrams.get(0);
1008             addTo.setCallback(new CallBack(theDiagram.getTitle()) {
1009                 private static final long serialVersionUID = -99601763227525686L;
1010
1011                 @Override
1012                 public void callBack() {
1013                     BasicBlock block = (BasicBlock) BlockFactory.createClone(BasicBlock.this);
1014                     theDiagram.getModel().add(theDiagram.getDefaultParent(), block, 0);
1015                     mxGeometry geom = BasicBlock.this.getGeometry();
1016                     setDefaultPosition(geom);
1017                     theDiagram.getModel().setGeometry(block, geom);
1018                     BlockPositioning.updateBlockView(block);
1019                     block.setParentDiagram(theDiagram);
1020                 }
1021             });
1022
1023             menu.add(addTo);
1024
1025         } else {
1026             // The user has to choose
1027             Menu addTo = ScilabMenu.createMenu();
1028
1029             addTo.setText(XcosMessages.ADDTO);
1030
1031             for (int i = 0; i < allDiagrams.size(); i++) {
1032                 MenuItem diagram = ScilabMenuItem.createMenuItem();
1033                 final XcosDiagram theDiagram = allDiagrams.get(i);
1034                 diagram.setText(allDiagrams.get(i).getParentTab().getName());
1035                 diagram.setCallback(new CallBack(theDiagram.getTitle()) {
1036                     private static final long serialVersionUID = 3345416658377835057L;
1037
1038                         @Override
1039                     public void callBack() {
1040                         BasicBlock block = (BasicBlock) BlockFactory.createClone(BasicBlock.this);
1041                         theDiagram.getModel().add(theDiagram.getDefaultParent(), block, 0);
1042                         mxGeometry geom = BasicBlock.this.getGeometry();
1043                     setDefaultPosition(geom);
1044                         theDiagram.getModel().setGeometry(block, geom);
1045                         BlockPositioning.updateBlockView(block);
1046                     }
1047                 });
1048                 addTo.add(diagram);
1049             }
1050
1051             menu.add(addTo);
1052         }
1053
1054
1055         menu.getAsSimpleContextMenu().addSeparator();
1056
1057         MenuItem help = ScilabMenuItem.createMenuItem();
1058         help.setText(XcosMessages.BLOCK_DOCUMENTATION);
1059         help.setCallback(new CallBack(XcosMessages.BLOCK_DOCUMENTATION) {
1060             private static final long serialVersionUID = -1480947262397441951L;
1061
1062                 @Override
1063             public void callBack() {
1064                 ScilabInterpreterManagement.requestScilabExec("help " + getInterfaceFunctionName());
1065             }
1066         });
1067         menu.add(help);
1068
1069         menu.setVisible(true);
1070
1071         ((SwingScilabContextMenu) menu.getAsSimpleContextMenu()).setLocation(
1072                 MouseInfo.getPointerInfo().getLocation().x, MouseInfo.getPointerInfo().getLocation().y);
1073         
1074         return menu;
1075     }
1076
1077     /**
1078      * @param graph parent graph
1079      * @return context menu
1080      */
1081     public ContextMenu createContextMenu(ScilabGraph graph) {
1082                 ContextMenu menu = ScilabContextMenu.createContextMenu();
1083                 Map<Class< ? extends DefaultAction>, Menu> menuList = new HashMap<Class< ? extends DefaultAction>, Menu>();
1084                 
1085                 MenuItem value = BlockParametersAction.createMenu(graph);
1086                 menuList.put(BlockParametersAction.class, value);
1087                 menu.add(value);
1088                 /*--- */
1089                 menu.getAsSimpleContextMenu().addSeparator();
1090                 /*--- */
1091                 value = CutAction.cutMenu(graph);
1092                 menuList.put(CutAction.class, value);
1093                 menu.add(value);
1094                 value = CopyAction.copyMenu(graph);
1095                 menuList.put(CopyAction.class, value);
1096                 menu.add(value);
1097                 value = DeleteAction.createMenu(graph);
1098                 menuList.put(DeleteAction.class, value);
1099                 menu.add(value);
1100                 /*--- */
1101                 menu.getAsSimpleContextMenu().addSeparator();
1102                 /*--- */
1103                 value = RegionToSuperblockAction.createMenu(graph);
1104                 menuList.put(RegionToSuperblockAction.class, value);
1105                 menu.add(value);
1106                 /*--- */
1107                 menu.getAsSimpleContextMenu().addSeparator();
1108                 /*--- */
1109                 Menu format = ScilabMenu.createMenu();
1110                 format.setText(XcosMessages.FORMAT);
1111                 menu.add(format);
1112                 value = RotateAction.createMenu(graph);
1113                 menuList.put(RotateAction.class, value);
1114                 format.add(value);
1115                 value = MirrorAction.createMenu(graph);
1116                 menuList.put(MirrorAction.class, value);
1117                 format.add(value);
1118                 value = FlipAction.createMenu(graph);
1119                 menuList.put(FlipAction.class, value);
1120                 format.add(value);
1121                 value = ShowHideShadowAction.createMenu(graph);
1122                 menuList.put(ShowHideShadowAction.class, value);
1123                 format.add(value);
1124                 /*--- */
1125                 format.addSeparator();
1126                 /*--- */
1127                 Menu alignMenu = ScilabMenu.createMenu();
1128                 alignMenu.setText(XcosMessages.ALIGN_BLOCKS);
1129                 alignMenu.add(AlignBlockActionLeft.createMenu(graph));
1130                 alignMenu.add(AlignBlockActionCenter.createMenu(graph));
1131                 alignMenu.add(AlignBlockActionRight.createMenu(graph));
1132                 alignMenu.addSeparator();
1133                 alignMenu.add(AlignBlockActionTop.createMenu(graph));
1134                 alignMenu.add(AlignBlockActionMiddle.createMenu(graph));
1135                 alignMenu.add(AlignBlockActionBottom.createMenu(graph));
1136                 menuList.put(AlignBlockAction.class, alignMenu);
1137                 format.add(alignMenu);
1138                 /*--- */
1139                 format.addSeparator();
1140                 /*--- */
1141                 if (graph.getSelectionCells().length > 1) {
1142                         format.add(BorderColorAction.createMenu(graph));
1143                         format.add(FilledColorAction.createMenu(graph));
1144                 } else {
1145                         format.add(EditBlockFormatAction.createMenu(graph));
1146                 }
1147                 /*--- */
1148                 menu.getAsSimpleContextMenu().addSeparator();
1149                 /*--- */
1150                 menu.add(ViewDetailsAction.createMenu(graph));
1151                 /*--- */
1152                 menu.getAsSimpleContextMenu().addSeparator();
1153                 /*--- */
1154                 menu.add(BlockDocumentationAction.createMenu(graph));
1155
1156                 ((SwingScilabContextMenu) menu.getAsSimpleContextMenu()).setLocation(MouseInfo.getPointerInfo().getLocation().x, 
1157                         MouseInfo.getPointerInfo().getLocation().y);
1158                 
1159                 customizeMenu(menuList);
1160                 
1161                 return menu;
1162     }
1163     
1164     /**
1165      * @param flip value
1166      */
1167     public void setFlip(boolean flip) {
1168         if (getParentDiagram() != null) {
1169             isFlipped = flip;
1170             if (flip) {
1171                 mxUtils.setCellStyles(getParentDiagram().getModel(), new Object[] {this}, XcosConstants.STYLE_FLIP, Boolean.TRUE.toString());
1172             } else {
1173                 mxUtils.setCellStyles(getParentDiagram().getModel(), new Object[] {this}, XcosConstants.STYLE_FLIP, Boolean.FALSE.toString());
1174             }
1175         }
1176     }
1177
1178     /**
1179      * Override this to customize contextual menu
1180      * @param menuList list of menu
1181      */
1182     protected void customizeMenu(Map<Class< ? extends DefaultAction>, Menu> menuList) {
1183         // To be overridden by sub-classes
1184     }
1185     
1186
1187     /**
1188      * @return mirror value
1189      */
1190     public boolean getMirror() {
1191         return isMirrored;
1192     }
1193     
1194     /**
1195      * @param mirror new mirror value
1196      */
1197     public void setMirror(boolean mirror) {
1198         if (getParentDiagram() != null) {
1199             isMirrored = mirror;
1200             if (mirror) {
1201                 mxUtils.setCellStyles(getParentDiagram().getModel(), new Object[] {this}, XcosConstants.STYLE_MIRROR, "true");
1202             } else {
1203                 mxUtils.setCellStyles(getParentDiagram().getModel(), new Object[] {this}, XcosConstants.STYLE_MIRROR, "false");
1204             }
1205         }
1206     }
1207
1208     /**
1209      * @return flip status
1210      */
1211     public boolean getFlip() {
1212         return isFlipped;
1213     }
1214
1215     /**
1216      * invert flip status
1217      */
1218     public void toggleFlip() {
1219         BlockPositioning.toggleFlip(this);
1220     }
1221
1222     /**
1223      * invert mirror value
1224      */
1225     public void toggleMirror() {
1226         BlockPositioning.toggleMirror(this);
1227     }
1228
1229     /**
1230      * 
1231      */
1232     public void toggleAntiClockwiseRotation() {
1233         BlockPositioning.toggleAntiClockwiseRotation(this);
1234
1235     }
1236
1237     /**
1238      * @return current angle
1239      */
1240     public int getAngle() {
1241         return angle;
1242     }
1243
1244     /**
1245      * @param angle new block angle
1246      */
1247     public void setAngle(int angle) {
1248         this.angle = angle;
1249         
1250         if (getParentDiagram() != null) {
1251             mxUtils.setCellStyles(getParentDiagram().getModel(), new Object[] {this}, XcosConstants.STYLE_ROTATION, Integer.toString(angle));
1252         }
1253     }
1254
1255     /**
1256      * Useful when we need to update local properties with mxCell style properties 
1257      */
1258         public void updateFieldsFromStyle() {
1259                 StyleMap map = new StyleMap(getStyle());
1260
1261                 if (map.get(XcosConstants.STYLE_ROTATION) != null) {
1262                         angle = Integer.parseInt(map.get(XcosConstants.STYLE_ROTATION));
1263                 } else {
1264                         angle = 0;
1265                 }
1266                 
1267                 isFlipped = Boolean.parseBoolean(map.get(XcosConstants.STYLE_FLIP));
1268                 isMirrored = Boolean.parseBoolean(map.get(XcosConstants.STYLE_MIRROR));
1269         }
1270
1271         /**
1272          * Set the default block position on the geom
1273          * @param geom the current geom
1274          */
1275         private void setDefaultPosition(mxGeometry geom) {
1276                 geom.setX(DEFAULT_POSITION_X);
1277                 geom.setY(DEFAULT_POSITION_Y);
1278         }
1279         
1280         /**
1281          * Get the parameters change support.
1282          * 
1283          * The property name for each event is the field name, so one of:
1284          *     - "interfaceFunctionName"
1285          *     - "simulationFunctionName"
1286          *     - "simulationFunctionType"
1287          *     - "exprs"
1288          *     - "realParameters"
1289          *     - "integerParameters"
1290          *     - "objectsParameters"
1291          *     - "nbZerosCrossing"
1292          *     - "nmode"
1293          *     - "state"
1294          *     - "dState"
1295          *     - "oDState"
1296          *     - "equations"
1297          *     - "dependsOnU"
1298          *     - "dependsOnT"
1299          *     - "blockType"
1300          *     - "ordering"
1301          * 
1302          * @return the associated {@link PropertyChangeSupport} instance
1303          */
1304         public PropertyChangeSupport getParametersPCS() {
1305                 return parametersPCS;
1306         }
1307         
1308         /**
1309          * Re-associate fields with the new instance.
1310          * 
1311          * @return a new clone instance
1312          * @throws CloneNotSupportedException never
1313          * @see com.mxgraph.model.mxCell#clone()
1314          */
1315         @Override
1316         public Object clone() throws CloneNotSupportedException {
1317                 BasicBlock clone = (BasicBlock) super.clone();
1318                 
1319                 /* Reinstall the PropertyChangeSupport and all of it listeners */
1320                 clone.parametersPCS = new PropertyChangeSupport(clone);
1321                 PropertyChangeSupport pcs = getParametersPCS();
1322                 for (PropertyChangeListener iter : pcs.getPropertyChangeListeners()) {
1323                         clone.parametersPCS.addPropertyChangeListener(iter);
1324                 }
1325                 
1326                 return clone;
1327         }
1328         
1329         /**
1330          * Overriden to correct jgraphx bug fixed in 1.4.0.4
1331          * 
1332          * @param child the child to insert
1333          * @return the previous child
1334          * @see com.mxgraph.model.mxCell#insert(com.mxgraph.model.mxICell)
1335          * @see http://www.jgraphsupport.co.uk/bugzilla/show_bug.cgi?id=39
1336          * @deprecated Will be left after the switch to jgraphx >= 1.4.0.4
1337          */
1338         @Deprecated
1339         @Override
1340         public mxICell insert(mxICell child) {
1341                 int index = getChildCount();
1342                 
1343                 if (child.getParent() == this) {
1344                         index--;
1345                 }
1346                 
1347                 return insert(child, index);
1348         }
1349 }