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