API compatibility with jgraphx-1.2.0.5
[scilab.git] / scilab / modules / xcos / src / java / org / scilab / modules / xcos / block / SuperBlock.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 java.util.ArrayList;
16 import java.util.List;
17
18 import org.scilab.modules.graph.ScilabGraph;
19 import org.scilab.modules.gui.contextmenu.ContextMenu;
20 import org.scilab.modules.gui.menu.Menu;
21 import org.scilab.modules.gui.menu.ScilabMenu;
22 import org.scilab.modules.gui.utils.UIElementMapper;
23 import org.scilab.modules.gui.window.ScilabWindow;
24 import org.scilab.modules.hdf5.scilabTypes.ScilabDouble;
25 import org.scilab.modules.hdf5.scilabTypes.ScilabList;
26 import org.scilab.modules.hdf5.scilabTypes.ScilabMList;
27 import org.scilab.modules.xcos.XcosTab;
28 import org.scilab.modules.xcos.actions.CodeGenerationAction;
29 import org.scilab.modules.xcos.block.actions.SuperblockMaskCreateAction;
30 import org.scilab.modules.xcos.block.actions.SuperblockMaskCustomizeAction;
31 import org.scilab.modules.xcos.block.actions.SuperblockMaskRemoveAction;
32 import org.scilab.modules.xcos.block.io.EventInBlock;
33 import org.scilab.modules.xcos.block.io.EventOutBlock;
34 import org.scilab.modules.xcos.block.io.ExplicitInBlock;
35 import org.scilab.modules.xcos.block.io.ExplicitOutBlock;
36 import org.scilab.modules.xcos.block.io.ImplicitInBlock;
37 import org.scilab.modules.xcos.block.io.ImplicitOutBlock;
38 import org.scilab.modules.xcos.graph.PaletteDiagram;
39 import org.scilab.modules.xcos.graph.SuperBlockDiagram;
40 import org.scilab.modules.xcos.io.BasicBlockInfo;
41 import org.scilab.modules.xcos.io.BlockReader;
42 import org.scilab.modules.xcos.io.BlockWriter;
43 import org.scilab.modules.xcos.port.command.CommandPort;
44 import org.scilab.modules.xcos.port.control.ControlPort;
45 import org.scilab.modules.xcos.port.input.ExplicitInputPort;
46 import org.scilab.modules.xcos.port.input.ImplicitInputPort;
47 import org.scilab.modules.xcos.port.output.ExplicitOutputPort;
48 import org.scilab.modules.xcos.port.output.ImplicitOutputPort;
49 import org.scilab.modules.xcos.utils.XcosEvent;
50 import org.scilab.modules.xcos.utils.XcosMessages;
51
52 import com.mxgraph.model.mxCell;
53 import com.mxgraph.util.mxEventObject;
54
55 public final class SuperBlock extends BasicBlock {
56
57         private static final long serialVersionUID = 3005281208417373333L;
58         private SuperBlockDiagram child = null;
59
60         public SuperBlock() {
61                 super();
62         }
63
64         protected SuperBlock(String label) {
65                 this();
66                 setDefaultValues();
67                 setValue(label);
68         }
69
70         protected SuperBlock(boolean masked) {
71                 this();
72                 if (masked) {
73                         mask();
74                 }
75         }
76         
77         protected SuperBlock(String label, boolean masked) {
78                 this(label);
79                 if (masked) {
80                         mask();
81                 }
82         }
83         
84         /**
85          * Initialize the block with the default values
86          */
87         @Override
88         protected void setDefaultValues() {
89                 super.setDefaultValues();
90                 setInterfaceFunctionName("SUPER_f");
91                 setSimulationFunctionName("super");
92                 setRealParameters(new ScilabDouble());
93                 setIntegerParameters(new ScilabDouble());
94                 setObjectsParameters(new ScilabList());
95                 setExprs(new ScilabDouble());
96                 setBlockType("h");
97                 setNbZerosCrossing(new ScilabDouble(0));
98                 setNmode(new ScilabDouble(0));
99         }
100
101         /**
102          * openBlockSettings this method is called when a double click occured on a
103          * super block 
104          * 
105          * @see BasicBlock.openBlockSettings
106          */
107         @Override
108         public void openBlockSettings(String[] context) {
109                 if (getParentDiagram() instanceof PaletteDiagram) {
110                         return;
111                 }
112
113                 if (getChild() == null
114                                 && getSimulationFunctionType().compareTo(
115                                                 SimulationFunctionType.DEFAULT) != 0) {
116                         // This means we have a SuperBlock and we generated C code for it.
117                         this.setLocked(false);
118                         return;
119                 }
120
121                 if (isMasked()) {
122                         super.openBlockSettings(context);
123                 } else {
124                         if (createChildDiagram() == true) {
125                                 getChild().setModifiedNonRecursively(false);
126                                 XcosTab.createTabFromDiagram(getChild());
127                                 XcosTab.showTabFromDiagram(getChild());
128                         } else {
129                                 getChild().setVisible(true);
130                         }
131
132                         getChild().updateCellsContext();
133                 }
134         }
135
136         public void closeBlockSettings() {
137
138                 // Do not ask the user, the diagram is saved and closed
139                 if (getChild().isModified()) {
140                         setRealParameters(BlockWriter.convertDiagramToMList(getChild()));
141                         getChild().setModified(true);
142                         getChild().setModifiedNonRecursively(false);
143                 }
144
145                 if (getChild().canClose() == false) {
146                         getChild().setVisible(false);
147                         return;
148                 }
149
150                 if (getChild().getParentTab() != null) {
151                         ScilabWindow xcosWindow = (ScilabWindow) UIElementMapper
152                                         .getCorrespondingUIElement(getChild().getParentTab()
153                                                         .getParentWindowId());
154                         xcosWindow.removeTab(getChild().getParentTab());
155                         getChild().getViewPort().close();
156                         getChild().setOpened(false);
157                         XcosTab.closeDiagram(getChild());
158                         if (getParentDiagram().isOpened()
159                                         && getParentDiagram().isVisible() == false) {
160                                 getParentDiagram().closeDiagram();
161                         }
162                 }
163
164                 child.removeListener(null);
165                 setLocked(false);
166                 child = null;
167         }
168
169         public void openContextMenu(ScilabGraph graph) {
170                 ContextMenu menu = null;
171
172                 if (getParentDiagram() instanceof PaletteDiagram) {
173                         menu = createPaletteContextMenu(graph);
174                 } else {
175                         menu = createContextMenu(graph);
176                         menu.getAsSimpleContextMenu().addSeparator();
177                         menu.add(CodeGenerationAction.createMenu(graph));
178
179                         /*
180                          * FIXME: It is not possible to use Mask. So remove any possibility.
181                          * Mask removing only option is not applicable : if remove the mask
182                          * you have no way to edit the values anymore.
183                          */
184                         Menu maskMenu = ScilabMenu.createMenu();
185                         maskMenu.setText(XcosMessages.SUPERBLOCK_MASK);
186
187                         if (isMasked()) {
188                                 maskMenu.add(SuperblockMaskRemoveAction.createMenu(graph));
189                                 menu.add(maskMenu);
190                         } else {
191                                 maskMenu.add(SuperblockMaskCreateAction.createMenu(graph));
192                         }
193                         maskMenu.add(SuperblockMaskCustomizeAction.createMenu(graph));
194                         menu.add(maskMenu);
195                          
196                 }
197                 menu.setVisible(true);
198         }
199
200         public boolean createChildDiagram() {
201                 return createChildDiagram(false);
202         }
203
204         public boolean createChildDiagram(boolean generatedUID) {
205                 if (child == null) {
206                         child = new SuperBlockDiagram(this);
207                         child.installListeners();
208                         child.loadDiagram(BlockReader.convertMListToDiagram(
209                                         (ScilabMList) getRealParameters(), false));
210                         child.installSuperBlockListeners();
211                         child.setChildrenParentDiagram();
212                         updateAllBlocksColor();
213                         // only for loading and generate sub block UID
214                         if (generatedUID) {
215                                 child.generateUID();
216                         }
217                 } else {
218                         return false;
219                 }
220
221                 return true;
222         }
223
224         public SuperBlockDiagram getChild() {
225                 return child;
226         }
227
228         public void setChild(SuperBlockDiagram child) {
229                 this.child = child;
230         }
231
232         public ScilabMList getAsScilabObj() {
233                 if (child != null) {
234                         setRealParameters(BlockWriter.convertDiagramToMList(child));
235                 }
236                 return BasicBlockInfo.getAsScilabObj(this);
237         }
238
239         protected List<mxCell> getAllExplicitInBlock() {
240                 List<mxCell> list = new ArrayList<mxCell>();
241                 if (child == null) {
242                         return list;
243                 }
244
245                 int blockCount = child.getModel().getChildCount(
246                                 child.getDefaultParent());
247
248                 for (int i = 0; i < blockCount; i++) {
249                         mxCell cell = (mxCell) child.getModel().getChildAt(
250                                         child.getDefaultParent(), i);
251                         if (cell instanceof ExplicitInBlock) {
252                                 list.add(cell);
253                         }
254                 }
255                 return list;
256         }
257
258         protected List<mxCell> getAllImplicitInBlock() {
259                 List<mxCell> list = new ArrayList<mxCell>();
260                 if (child == null) {
261                         return list;
262                 }
263
264                 int blockCount = child.getModel().getChildCount(
265                                 child.getDefaultParent());
266
267                 for (int i = 0; i < blockCount; i++) {
268                         mxCell cell = (mxCell) child.getModel().getChildAt(
269                                         child.getDefaultParent(), i);
270                         if (cell instanceof ImplicitInBlock) {
271                                 list.add(cell);
272                         }
273                 }
274                 return list;
275         }
276
277         protected List<mxCell> getAllEventInBlock() {
278                 List<mxCell> list = new ArrayList<mxCell>();
279                 if (child == null) {
280                         return list;
281                 }
282
283                 int blockCount = child.getModel().getChildCount(
284                                 child.getDefaultParent());
285
286                 for (int i = 0; i < blockCount; i++) {
287                         mxCell cell = (mxCell) child.getModel().getChildAt(
288                                         child.getDefaultParent(), i);
289                         if (cell instanceof EventInBlock) {
290                                 list.add(cell);
291                         }
292                 }
293                 return list;
294         }
295
296         protected List<mxCell> getAllExplicitOutBlock() {
297                 List<mxCell> list = new ArrayList<mxCell>();
298                 if (child == null) {
299                         return list;
300                 }
301
302                 int blockCount = child.getModel().getChildCount(
303                                 child.getDefaultParent());
304
305                 for (int i = 0; i < blockCount; i++) {
306                         mxCell cell = (mxCell) child.getModel().getChildAt(
307                                         child.getDefaultParent(), i);
308                         if (cell instanceof ExplicitOutBlock) {
309                                 list.add(cell);
310                         }
311                 }
312                 return list;
313         }
314
315         protected List<mxCell> getAllImplicitOutBlock() {
316                 List<mxCell> list = new ArrayList<mxCell>();
317                 if (child == null) {
318                         return list;
319                 }
320
321                 int blockCount = child.getModel().getChildCount(
322                                 child.getDefaultParent());
323
324                 for (int i = 0; i < blockCount; i++) {
325                         mxCell cell = (mxCell) child.getModel().getChildAt(
326                                         child.getDefaultParent(), i);
327                         if (cell instanceof ImplicitOutBlock) {
328                                 list.add(cell);
329                         }
330                 }
331                 return list;
332         }
333
334         protected List<mxCell> getAllEventOutBlock() {
335                 List<mxCell> list = new ArrayList<mxCell>();
336
337                 int blockCount = child.getModel().getChildCount(
338                                 child.getDefaultParent());
339
340                 for (int i = 0; i < blockCount; i++) {
341                         mxCell cell = (mxCell) child.getModel().getChildAt(
342                                         child.getDefaultParent(), i);
343                         if (cell instanceof EventOutBlock) {
344                                 list.add(cell);
345                         }
346                 }
347                 return list;
348         }
349
350         protected int getBlocksConsecutiveUniqueValueCount(List<mxCell> blocks) {
351                 if (blocks == null) {
352                         return 0;
353                 }
354
355                 int count = blocks.size();
356                 int[] array = new int[blocks.size()];
357
358                 // initialize
359                 for (int i = 0; i < array.length; i++) {
360                         array[i] = 0;
361                 }
362
363                 // populate
364                 for (int i = 0; i < array.length; i++) {
365                         int index = (Integer) ((BasicBlock) blocks.get(i)).getValue();
366                         if (index <= array.length) {
367                                 array[index - 1] = 1;
368                         }
369                 }
370
371                 // parse
372                 for (int i = 0; i < array.length; i++) {
373                         if (array[i] == 0) {
374                                 count = i;
375                                 break;
376                         }
377                 }
378
379                 return count;
380         }
381
382         public void updateAllBlocksColor() {
383                 updateBlocksColor(getAllExplicitInBlock());
384                 updateBlocksColor(getAllImplicitInBlock());
385                 updateBlocksColor(getAllEventInBlock());
386
387                 updateBlocksColor(getAllExplicitOutBlock());
388                 updateBlocksColor(getAllImplicitOutBlock());
389                 updateBlocksColor(getAllEventOutBlock());
390         }
391
392         private void updateBlocksColor(List<mxCell> blocks) {
393
394                 try {
395                         child.getModel().beginUpdate();
396                         if (blocks == null || blocks.size() == 0) {
397                                 return;
398                         }
399
400                         int countUnique = getBlocksConsecutiveUniqueValueCount(blocks);
401                         boolean isDone[] = new boolean[countUnique];
402
403                         // Initialize
404                         for (int i = 0; i < countUnique; i++) {
405                                 isDone[i] = false;
406                         }
407
408                         for (int i = 0; i < blocks.size(); i++) {
409                                 int index = (Integer) ((BasicBlock) blocks.get(i)).getValue();
410                                 if (index > countUnique || isDone[index - 1] == true) {
411                                         child.getAsComponent().setCellWarning(blocks.get(i),
412                                                         "Wrong port number");
413                                 } else {
414                                         isDone[index - 1] = true;
415                                         child.getAsComponent().setCellWarning(blocks.get(i), null);
416                                 }
417                         }
418                 } finally {
419                         child.getModel().endUpdate();
420                 }
421         }
422
423         public void updateExportedPort() {
424                 if (child == null) {
425                         return;
426                 }
427
428                 updateExportedExplicitInputPort();
429                 updateExportedImplicitInputPort();
430                 updateExportedEventInputPort();
431                 updateExportedExplicitOutputPort();
432                 updateExportedImplicitOutputPort();
433                 updateExportedEventOutputPort();
434                 getParentDiagram().fireEvent(new mxEventObject(XcosEvent.SUPER_BLOCK_UPDATED, "block", this));
435         }
436
437         private void updateExportedExplicitInputPort() {
438                 int blockCount = getBlocksConsecutiveUniqueValueCount(getAllExplicitInBlock());
439                 List<ExplicitInputPort> ports = BasicBlockInfo
440                                 .getAllExplicitInputPorts(this, false);
441
442                 int portCount = ports.size();
443
444                 while (blockCount > portCount) { // add if required
445                         ExplicitInputPort port = new ExplicitInputPort();
446                         port.setDefaultValues();
447                         addPort(port);
448                         portCount++;
449                 }
450
451                 while (portCount > blockCount) { // remove if required
452                         removePort(ports.get(portCount - 1));
453                         portCount--;
454                 }
455         }
456
457         private void updateExportedImplicitInputPort() {
458                 int blockCount = getBlocksConsecutiveUniqueValueCount(getAllImplicitInBlock());
459                 List<ImplicitInputPort> ports = BasicBlockInfo
460                                 .getAllImplicitInputPorts(this, false);
461
462                 int portCount = ports.size();
463
464                 while (blockCount > portCount) { // add if required
465                         addPort(new ImplicitInputPort());
466                         portCount++;
467                 }
468
469                 while (portCount > blockCount) { // remove if required
470                         removePort(ports.get(portCount - 1));
471                         portCount--;
472                 }
473         }
474
475         private void updateExportedEventInputPort() {
476                 int blockCount = getBlocksConsecutiveUniqueValueCount(getAllEventInBlock());
477                 List<ControlPort> ports = BasicBlockInfo
478                                 .getAllControlPorts(this, false);
479
480                 int portCount = ports.size();
481
482                 while (blockCount > portCount) { // add if required
483                         addPort(new ControlPort());
484                         portCount++;
485                 }
486
487                 while (portCount > blockCount) { // remove if required
488                         removePort(ports.get(portCount - 1));
489                         portCount--;
490                 }
491         }
492
493         private void updateExportedExplicitOutputPort() {
494                 int blockCount = getBlocksConsecutiveUniqueValueCount(getAllExplicitOutBlock());
495                 List<ExplicitOutputPort> ports = BasicBlockInfo
496                                 .getAllExplicitOutputPorts(this, false);
497
498                 int portCount = ports.size();
499
500                 while (blockCount > portCount) { // add if required
501                         ExplicitOutputPort port = new ExplicitOutputPort();
502                         port.setDefaultValues();
503                         addPort(port);
504                         portCount++;
505                 }
506
507                 while (portCount > blockCount) { // remove if required
508                         removePort(ports.get(portCount - 1));
509                         portCount--;
510                 }
511         }
512
513         private void updateExportedImplicitOutputPort() {
514                 int blockCount = getBlocksConsecutiveUniqueValueCount(getAllImplicitOutBlock());
515                 List<ImplicitOutputPort> ports = BasicBlockInfo
516                                 .getAllImplicitOutputPorts(this, false);
517
518                 int portCount = ports.size();
519
520                 while (blockCount > portCount) { // add if required
521                         addPort(new ImplicitOutputPort());
522                         portCount++;
523                 }
524
525                 while (portCount > blockCount) { // remove if required
526                         removePort(ports.get(portCount - 1));
527                         portCount--;
528                 }
529         }
530
531         private void updateExportedEventOutputPort() {
532                 int blockCount = getBlocksConsecutiveUniqueValueCount(getAllEventOutBlock());
533                 List<CommandPort> ports = BasicBlockInfo
534                                 .getAllCommandPorts(this, false);
535
536                 int portCount = ports.size();
537
538                 while (blockCount > portCount) { // add if required
539                         addPort(new CommandPort());
540                         portCount++;
541                 }
542
543                 while (portCount > blockCount) { // remove if required
544                         removePort(ports.get(portCount - 1));
545                         portCount--;
546                 }
547         }
548
549         /**
550          * Mask the SuperBlock
551          */
552         public void mask() {
553                 setInterfaceFunctionName("DSUPER");
554                 setSimulationFunctionName("csuper");
555         }
556
557         /**
558          * Unmask the SuperBlock
559          */
560         public void unmask() {
561                 setInterfaceFunctionName("SUPER_f");
562                 setSimulationFunctionName("super");
563         }
564
565         /**
566          * @return True is the SuperBlock is masked, false otherwise
567          */
568         public boolean isMasked() {
569                 return getInterfaceFunctionName().compareTo("SUPER_f") != 0;
570         }
571 }