Salome HOME
Merging with JR_ASV_2_1_0_deb_with_KERNEL_Head branch, which contains many bug fixes...
[modules/superv.git] / src / SUPERVGUI / SUPERVGUI_Service.cxx
1 //  SUPERV SUPERVGUI : GUI for Supervisor component
2 //
3 //  Copyright (C) 2003  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 //  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS 
5 // 
6 //  This library is free software; you can redistribute it and/or 
7 //  modify it under the terms of the GNU Lesser General Public 
8 //  License as published by the Free Software Foundation; either 
9 //  version 2.1 of the License. 
10 // 
11 //  This library is distributed in the hope that it will be useful, 
12 //  but WITHOUT ANY WARRANTY; without even the implied warranty of 
13 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
14 //  Lesser General Public License for more details. 
15 // 
16 //  You should have received a copy of the GNU Lesser General Public 
17 //  License along with this library; if not, write to the Free Software 
18 //  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA 
19 // 
20 //  See http://www.opencascade.org/SALOME/ or email : webmaster.salome@opencascade.org 
21 //
22 //
23 //
24 //  File   : SUPERVGUI_Service.cxx
25 //  Author : Francis KLOSS
26 //  Module : SUPERV
27
28 using namespace std;
29 #include "SUPERVGUI_Service.h"
30 #include "SUPERVGUI_Main.h"
31 #include "SUPERVGUI_Library.h"
32 #include "SUPERVGUI.h"
33 #include "QAD_Tools.h"
34 #include "QAD_FileDlg.h"
35
36 #include "SALOME_NamingService.hxx"
37 #include CORBA_CLIENT_HEADER(SALOME_ModuleCatalog)
38 #include <qlayout.h>
39 #include <qhbox.h>
40 #include <qtextstream.h>
41 #include <qregexp.h>
42
43 static const char * ComponentIcon[] = {
44 "20 20 2 1",
45 "       c None",
46 ".      c #000000",
47 "                    ",
48 "                    ",
49 "                    ",
50 " .................. ",
51 " .                . ",
52 " .                . ",
53 " .                . ",
54 " .                . ",
55 " .                . ",
56 " .                . ",
57 " .                . ",
58 " .                . ",
59 " .................. ",
60 "    .     .     .   ",
61 "    .     .     .   ",
62 "   ...   ...   ...  ",
63 "  .. .. .. .. .. .. ",
64 "  .   . .   . .   . ",
65 "  .. .. .. .. .. .. ",
66 "   ...   ...   ...  "};
67
68
69 static const char * InterfaceIcon[] = {
70 "20 20 2 1",
71 "       c None",
72 ".      c #000000",
73 "                    ",
74 "                    ",
75 "                    ",
76 "                    ",
77 "                    ",
78 "            ..      ",
79 "          ......    ",
80 "         ..    ..   ",
81 "         .      .   ",
82 "..........      ..  ",
83 "         .      .   ",
84 "         ..    ..   ",
85 "          ......    ",
86 "            ..      ",
87 "                    ",
88 "                    ",
89 "                    ",
90 "                    ",
91 "                    ",
92 "                    "};
93
94
95
96
97 SUPERVGUI_Service::SUPERVGUI_Service(SALOME_NamingService* ns):
98     QDialog(QAD_Application::getDesktop(), 0, false, WStyle_Customize | WStyle_NormalBorder | WStyle_Title | WStyle_SysMenu),
99     naming(ns), myMFile(0)
100 {
101   setSizeGripEnabled( true );
102   setCaption(tr("TIT_SERVICES"));
103
104   QVBoxLayout* aMainLayout = new QVBoxLayout(this, 7, 4);
105
106   myTabPane = new QTabWidget(this);
107   connect(myTabPane, SIGNAL(currentChanged(QWidget *)), this, SLOT(tabChanged(QWidget *)));
108
109   // Create Tab for Corba services
110   QWidget* aCorbaPane = new QWidget(myTabPane);
111   QVBoxLayout* aBaseLayoutV= new QVBoxLayout(aCorbaPane, 0, 4);
112   aBaseLayoutV->setMargin(5);
113   aBaseLayoutV->setSpacing(10);
114
115   QHBoxLayout* aBaseLayout = new QHBoxLayout(aCorbaPane); //!!
116  
117   components = new QListView(aCorbaPane);
118   components->addColumn(tr("COL_COMPONENTS"));
119   components->addColumn(tr("COL_PORTTYPE"));
120   components->addColumn(tr("COL_PORTWAY"));
121   components->setColumnAlignment(1, AlignLeft);
122   components->setColumnAlignment(2, AlignLeft);
123   components->setColumnAlignment(3, AlignLeft);
124   components->setSelectionMode(QListView::Extended);
125   components->setRootIsDecorated(true);
126 //  aBaseLayout->addWidget(components);
127   aBaseLayoutV->addWidget(components); //!!
128
129   //QHGroupBox* aAddBox = new QHGroupBox(tr("TIT_ADDNODE"), aCorbaPane); //!!
130   //aAddBox->setInsideSpacing(20); //!!
131
132 //NRI   QPushButton* aComputeCBtn = new QPushButton(tr("TIT_ADDCNODE"), aCorbaPane); //!!
133 //NRI   connect(aComputeCBtn, SIGNAL(clicked()), this, SLOT(addComputeNode())); //!!
134 //NRI   aComputeCBtn->setDefault(false); 
135
136   QPushButton* aComputeBtn = new QPushButton(tr("TIT_ADDFNODE"), aCorbaPane);
137   connect(aComputeBtn, SIGNAL(clicked()), this, SLOT(addFactoryNode()));
138   aComputeBtn->setDefault(true); 
139
140   aBaseLayout->addWidget(aComputeBtn);
141   //NRI  aBaseLayout->addWidget(aComputeCBtn); //!!
142
143   aBaseLayoutV->insertLayout(-1, aBaseLayout);
144   myTabPane->addTab(aCorbaPane, tr("MODULES_PANE"));
145
146
147   // Create Tab for Python services
148   QWidget* aPythonPane = new QWidget(myTabPane);
149   QVBoxLayout* aPythonLayout = new QVBoxLayout(aPythonPane, 0, 4);
150   aPythonLayout->setMargin(5);
151   aPythonLayout->setSpacing(10);
152
153   // Type pane
154   QHGroupBox* aAddBox2 = new QHGroupBox(tr("TIT_ADDNODE"), aPythonPane);
155   aAddBox2->setInsideSpacing(20);
156
157   /*QLabel* aTypeLbl = */new QLabel(tr("LBL_NODETYPE"), aAddBox2);
158
159   myTypeCombo = new QComboBox(aAddBox2);
160   myTypeCombo->insertItem( tr( "INLINE_COMP" ) );
161   myTypeCombo->insertItem( tr( "INLINE_SWTC" ) );
162   myTypeCombo->insertItem( tr( "INLINE_LOOP" ) );
163   myTypeCombo->insertItem( tr( "INLINE_GOTO") );
164   connect(myTypeCombo, SIGNAL(activated(int)), this, SLOT(typeNodeSelected(int)));
165
166   aPythonLayout->addWidget(aAddBox2);
167
168   // Edit pane
169   myStackWidget = new QWidgetStack(aPythonPane);
170
171   // other pane
172   myScriptPane = new SUPERVGUI_PythonEditPane( myStackWidget, true, myX, myY );
173   myOtherId = myStackWidget->addWidget(myScriptPane);
174
175   // loop pane
176   QTabWidget* aLoopTabPane = new QTabWidget(myStackWidget);
177   myInitPane = new SUPERVGUI_PythonEditPane( myStackWidget, true, myX, myY ); 
178   aLoopTabPane->addTab(myInitPane, "Init");
179
180   myMorePane = new SUPERVGUI_PythonEditPane( myStackWidget, true, myX, myY );
181   aLoopTabPane->addTab(myMorePane, "More");
182
183   myNextPane = new SUPERVGUI_PythonEditPane( myStackWidget, true, myX, myY );
184   aLoopTabPane->addTab(myNextPane, "Next");
185   myLoopId = myStackWidget->addWidget(aLoopTabPane);
186
187   myStackWidget->raiseWidget(myOtherId);
188
189   aPythonLayout->addWidget(myStackWidget, 1);
190
191   // Create button
192   QPushButton* aCreateBtn = new QPushButton(tr("TIT_ADDNODE"), aPythonPane);
193   connect(aCreateBtn, SIGNAL(clicked()), this, SLOT(addInlineNode()));
194   aPythonLayout->addWidget(aCreateBtn);
195
196   myTabPane->addTab(aPythonPane, tr("INLINE_PANE"));
197
198   // Create Tab for Macro node only if environmental variable ENABLE_MACRO_NODE is set
199   if ( getenv( "ENABLE_MACRO_NODE" ) != NULL ) {
200     QWidget* aMacroPane = new QWidget(myTabPane);
201     QVBoxLayout* aMacroLayout = new QVBoxLayout(aMacroPane, 0, 4);
202     aMacroLayout->setMargin(5);
203     aMacroLayout->setSpacing(10);
204     
205     QHBoxLayout* aLoadLayout = new QHBoxLayout(aMacroPane); //!!
206     aLoadLayout->addStretch();
207     
208     QPushButton* aLoadBtn = new QPushButton(tr("BUT_LOAD"), aMacroPane);
209     connect(aLoadBtn, SIGNAL(clicked()), this, SLOT(loadGraph()));
210
211     aLoadLayout->addWidget(aLoadBtn);
212
213     aMacroLayout->addLayout(aLoadLayout);
214  
215     myMacroPane = new QListView(aMacroPane);
216     myMacroPane->addColumn(tr("COL_COMPONENTS"));
217     myMacroPane->addColumn(tr("COL_PORTTYPE"));
218     myMacroPane->addColumn(tr("COL_PORTWAY"));
219     myMacroPane->setColumnAlignment(1, AlignLeft);
220     myMacroPane->setColumnAlignment(2, AlignLeft);
221     myMacroPane->setColumnAlignment(3, AlignLeft);
222     myMacroPane->setSelectionMode(QListView::Extended);
223     myMacroPane->setRootIsDecorated(true);
224     aMacroLayout->addWidget(myMacroPane); //!!
225     
226     QPushButton* aAddBtn = new QPushButton(tr("TIT_ADDFNODE"), aMacroPane);
227     connect(aAddBtn, SIGNAL(clicked()), this, SLOT(addMacroNode()));
228     aAddBtn->setDefault(true); 
229     
230     aMacroLayout->addWidget(aAddBtn);
231
232     myTabPane->addTab(aMacroPane, tr("MACRO_PANE"));
233   }
234   
235   aMainLayout->addWidget(myTabPane);
236
237   // Close button
238   QHBox* aBtnBox = new QHBox(this);
239   QHBoxLayout* aBtnLayout = new QHBoxLayout(aBtnBox->layout()); 
240   aBtnLayout->addStretch();
241
242   QPushButton* aCloseBtn = new QPushButton(tr("BUT_CLOSE"), aBtnBox);
243   connect(aCloseBtn, SIGNAL(clicked()), this, SLOT(reject()));
244   
245   aMainLayout->addWidget(aBtnBox);
246
247   initialise();
248   myX = 0;
249   myY = 0;
250   myIsInline = false;
251 }
252
253
254 char* getDataStreamParameterName(int aType)
255 {
256   switch(aType) {
257   case 1:
258     return "integer";
259   case 2:
260     return "float";
261   case 3:
262     return "double";
263   case 4:
264     return "string";
265   case 6:
266     return "boolean";
267   default:
268     return "unknown";
269   }
270 }
271
272 void SUPERVGUI_Service::initialise() {
273   CORBA::Object_ptr obj  = naming->Resolve("/Kernel/ModulCatalog");
274   SALOME_ModuleCatalog::ModuleCatalog_var *aModuleCatalog = new SALOME_ModuleCatalog::ModuleCatalog_var;
275   *aModuleCatalog = SALOME_ModuleCatalog::ModuleCatalog::_narrow(obj);
276   if (CORBA::is_nil(*aModuleCatalog)) {
277     setCaption("Error in Connexion to omniNames with '/Kernel/ModulCatalog'");
278     return;
279   }
280   
281   QAD_ResourceMgr* aResMgr = QAD_Desktop::createResourceManager();
282
283   SALOME_ModuleCatalog::ListOfComponents_var lComponents = (*aModuleCatalog)->GetComponentList();
284   long nbComp = lComponents->length();
285   for (int i=0; i<nbComp; i++) {
286     SALOME_ModuleCatalog::Acomponent_ptr C = (*aModuleCatalog)->GetComponent((char *)lComponents[i]);
287     QListViewItem* myComponentItem = new QListViewItem(components, (char*)C->componentusername());
288     myComponentItem->setSelectable(false);
289     QString aIconName = C->component_icone();
290     if (!aIconName.isEmpty()) {
291       QString resDir = aResMgr->findFile(aIconName, C->componentname()) ;
292       if (resDir) {
293         resDir = QAD_Tools::addSlash(resDir);
294         QPixmap aIcone(resDir + aIconName);
295         QIconSet aIconSet(aIcone);
296         myComponentItem->setPixmap(0, aIconSet.pixmap(QIconSet::Small, QIconSet::Normal));
297       } else {
298         myComponentItem->setPixmap(0, ComponentIcon);
299       }
300     } else {
301       myComponentItem->setPixmap(0, ComponentIcon);
302     }
303     SALOME_ModuleCatalog::ListOfInterfaces* lInterfaces = C->GetInterfaceList();
304     long nbInterf = lInterfaces->length();
305     for (int j=0; j<nbInterf; j++) {
306       SALOME_ModuleCatalog::DefinitionInterface* Interface = C->GetInterface((char*)(*lInterfaces)[j]);
307       QListViewItem* myInterfaceItem = new QListViewItem(myComponentItem, (char*)Interface->interfacename);
308       myInterfaceItem->setSelectable(false);
309       myInterfaceItem->setPixmap(0, InterfaceIcon);
310       
311       long nbServices = Interface->interfaceservicelist.length();
312       for (int k=0; k<nbServices; k++) {
313         SALOME_ModuleCatalog::Service* Service = &(Interface->interfaceservicelist[k]);
314         QListViewItem* myServiceItem = new QListViewItem(myInterfaceItem, (char*)Service->ServiceName);
315         myServiceItem->setSelectable(true);
316         components->ensureItemVisible(myServiceItem);
317         
318         long nbPortsOut = Service->ServiceoutParameter.length();
319         for (int m=0; m<nbPortsOut; m++) {
320           SALOME_ModuleCatalog::ServicesParameter* PortOut = &(Service->ServiceoutParameter[m]);
321           QListViewItem* myPortOutItem = 
322             new QListViewItem(myServiceItem, (char*)PortOut->Parametername, (char*)PortOut->Parametertype, "Out");
323           myPortOutItem->setSelectable(false);
324         }
325
326         long nbStreamPortsOut = Service->ServiceoutDataStreamParameter.length();
327         for (int m=0; m<nbStreamPortsOut; m++) {
328           SALOME_ModuleCatalog::ServicesDataStreamParameter* PortOut = &(Service->ServiceoutDataStreamParameter[m]);
329           QListViewItem* myPortOutItem = 
330             new QListViewItem(myServiceItem, (char*)PortOut->Parametername, 
331                               getDataStreamParameterName(PortOut->Parametertype), "DataStream Out");
332           myPortOutItem->setSelectable(false);
333         }
334         
335         long nbPortsIn = Service->ServiceinParameter.length();
336         for (int l=0; l<nbPortsIn; l++) {
337           SALOME_ModuleCatalog::ServicesParameter* PortIn = &(Service->ServiceinParameter[l]);
338           QListViewItem* myPortInItem = 
339             new QListViewItem(myServiceItem, (char*)PortIn->Parametername, (char*)PortIn->Parametertype, "In");
340           myPortInItem->setSelectable(false);
341         }
342
343         long nbStreamPortsIn = Service->ServiceinDataStreamParameter.length();
344         for (int l=0; l<nbStreamPortsIn; l++) {
345           SALOME_ModuleCatalog::ServicesDataStreamParameter* PortIn = &(Service->ServiceinDataStreamParameter[l]);
346           QListViewItem* myPortInItem = 
347             new QListViewItem(myServiceItem, (char*)PortIn->Parametername, 
348                               getDataStreamParameterName(PortIn->Parametertype), "DataStream In");
349           myPortInItem->setSelectable(false);
350         }
351       }
352     }
353   }
354 }
355
356
357
358 SUPERVGUI_Service::~SUPERVGUI_Service() {
359     Trace("SUPERVGUI_Service::~SUPERVGUI_Service")
360       if (myMFile) delete myMFile;
361 }
362
363 void SUPERVGUI_Service::addComputeNode() {
364   QAD_Desktop* aDesktop = QAD_Application::getDesktop();
365   SUPERVGUI_Main* aMain = Supervision.getMain();
366   if (aMain==0) {
367     QMessageBox::warning(aDesktop, tr("WARNING"), tr("MSG_NO_SUPERVISION_WINDOW"));
368   } else if (!aMain->isEditable()) {
369     QMessageBox::warning(aDesktop, tr("ERROR"), tr("MSG_CANT_CREATE_NODE"));      
370   } else {
371     CORBA::Object_ptr obj  = naming->Resolve("/Kernel/ModulCatalog");
372     SALOME_ModuleCatalog::ModuleCatalog_var* aModuleCatalog = new SALOME_ModuleCatalog::ModuleCatalog_var;
373     *aModuleCatalog = SALOME_ModuleCatalog::ModuleCatalog::_narrow(obj);
374     if (CORBA::is_nil(*aModuleCatalog)) {
375       QMessageBox::warning(aDesktop, tr("ERROR"), tr("MSG_CANT_CHOOSE_SERVICE"));
376     } else {
377       QListViewItem*        item;
378       bool                  b = false;
379       QListViewItemIterator i(components);
380       for (; i.current(); ++i) {
381         item = i.current();
382         if (item->isSelected()) {
383           const char* service   = item->text(0).latin1();
384           const char* interface = item->parent()->text(0).latin1();
385           const char* component = item->parent()->parent()->text(0).latin1();
386           SALOME_ModuleCatalog::Acomponent_ptr myComponent = (*aModuleCatalog)->GetComponent(aDesktop->getComponentName(component));
387           if ( myComponent == NULL ) {
388             QMessageBox::warning(aDesktop, tr("ERROR"), tr("MSG_CANT_CHOOSE_SERVICE"));
389           } 
390           else {
391             const SALOME_ModuleCatalog::Service* myService = myComponent->GetService(interface, service);
392             SUPERV_CNode aNode = aMain->getDataflow()->CNode(*myService);
393             if ( CORBA::is_nil( aNode ) ) {
394               QMessageBox::warning(aDesktop, tr("ERROR"), tr("MSG_CANT_CREATE_NODE"));    
395               return;
396             }
397
398             SUPERV::INode_var aDummyEndNode;
399             addNode( aNode, aDummyEndNode, myX, myY );
400             b = true; // at least one node was added
401           }
402         }
403       }
404       if ( !b ) {
405         QMessageBox::warning(aDesktop, tr("WARNING"), tr("MSG_NONODE_TOADD"));
406       }
407     }
408   }
409 }
410
411 void SUPERVGUI_Service::addFactoryNode() {
412   QAD_Desktop* aDesktop = QAD_Application::getDesktop();
413   SUPERVGUI_Main* aMain = Supervision.getMain();
414   if (aMain==0) {
415     QMessageBox::warning(aDesktop, tr("WARNING"), tr("MSG_NO_SUPERVISION_WINDOW"));
416   } else if (!aMain->isEditable()) {
417     QMessageBox::warning(aDesktop, tr("ERROR"), tr("MSG_CANT_CREATE_NODE"));      
418   } else {
419     CORBA::Object_ptr obj  = naming->Resolve("/Kernel/ModulCatalog");
420     SALOME_ModuleCatalog::ModuleCatalog_var* aModuleCatalog = new SALOME_ModuleCatalog::ModuleCatalog_var;
421     *aModuleCatalog = SALOME_ModuleCatalog::ModuleCatalog::_narrow(obj);
422     if (CORBA::is_nil(*aModuleCatalog)) {
423       QMessageBox::warning(aDesktop, tr("ERROR"), tr("MSG_CANT_CHOOSE_SERVICE"));
424     } else {
425       QListViewItem*        item;
426       bool                  b = false;
427       QListViewItemIterator i(components);
428       for (; i.current(); ++i) {
429         item = i.current();
430         if (item->isSelected()) {
431           const char* service   = item->text(0).latin1();
432           const char* interface = item->parent()->text(0).latin1();
433           const char* component = aDesktop->getComponentName(item->parent()->parent()->text(0).latin1());
434           SALOME_ModuleCatalog::Acomponent_ptr myComponent = (*aModuleCatalog)->GetComponent(component);
435           if (myComponent==NULL) {
436             QMessageBox::warning(aDesktop, tr("ERROR"), tr("MSG_CANT_CHOOSE_SERVICE"));
437           } 
438           else {
439             const SALOME_ModuleCatalog::Service* myService = myComponent->GetService(interface, service);
440             SUPERV_CNode aNode;
441             if ( myService->TypeOfNode == 0 ) { // ComputeNode
442               aNode = aMain->getDataflow()->CNode(*myService);
443               if (CORBA::is_nil( aNode ) ) {
444                 QMessageBox::warning(aDesktop, tr("ERROR"), tr("MSG_CANT_CREATE_NODE"));          
445                 return;
446               }
447             } 
448             else { // Factory Node
449               aNode = aMain->getDataflow()->FNode(component, interface, *myService);
450               if ( CORBA::is_nil( aNode ) ) {
451                 QMessageBox::warning(aDesktop, tr("ERROR"), tr("MSG_CANT_CREATE_NODE"));          
452                 return;
453               }
454             }
455             SUPERV::INode_var aDummyEndNode;
456             addNode( aNode, aDummyEndNode, myX, myY );
457             b = true;
458           }
459         }
460       }
461       if ( !b ) {
462         QMessageBox::warning(aDesktop, tr("WARNING"), tr("MSG_NONODE_TOADD"));
463       }
464     }
465   }
466 }
467
468
469 void SUPERVGUI_Service::addInlineNode() {
470   SUPERVGUI_Main* aMain = Supervision.getMain();
471   if (aMain==0) {
472     QMessageBox::warning(QAD_Application::getDesktop(), tr("WARNING"), tr("MSG_NO_SUPERVISION_WINDOW"));
473   } 
474   else if (!aMain->isEditable()) {
475     QMessageBox::warning(QAD_Application::getDesktop(), tr("ERROR"), tr("MSG_CANT_CREATE_NODE"));         
476   } 
477   else {
478     int aSel = myTypeCombo->currentItem();
479     switch (aSel) {
480     case 0: // Computation
481       { 
482         SUPERV_CNode aNode = aMain->getDataflow()->INode(myScriptPane->getFuncName().latin1(), 
483                                                          (myScriptPane->getFunction()).in());
484         if (CORBA::is_nil(aNode)) {
485           QMessageBox::warning(0, tr("ERROR"), tr("MSG_CANT_CREATE_NODE"));       
486           return;
487         }
488         SUPERV::INode_var aDummyEndNode;
489         addNode( aNode, aDummyEndNode, myX, myY );
490       }
491       break;
492       
493     case 1: // Switch
494       {
495         SUPERV_INode aEndNode;
496         SUPERV_CNode aStartNode = aMain->getDataflow()->SNode(myScriptPane->getFuncName().latin1(),
497                                                               (myScriptPane->getFunction()).in(),
498                                                               aEndNode);
499         if (CORBA::is_nil(aStartNode) || CORBA::is_nil(aEndNode)) {
500           QMessageBox::warning(0, tr("ERROR"), tr("MSG_CANT_CREATE_NODE"));       
501           return;
502         }
503         addNode( aStartNode, aEndNode, myX, myY );
504       }
505       break;
506       
507     case 2: // Loop
508       {
509         SUPERV_INode aEndNode;
510         SUPERV_CNode aStartNode = aMain->getDataflow()->LNode(myInitPane->getFuncName().latin1(), (myInitPane->getFunction()).in(),
511                                                               myMorePane->getFuncName().latin1(), (myMorePane->getFunction()).in(),
512                                                               myNextPane->getFuncName().latin1(), (myNextPane->getFunction()).in(),
513                                                               aEndNode);
514         if (CORBA::is_nil(aStartNode) || CORBA::is_nil(aEndNode)) {
515           QMessageBox::warning(0, tr("ERROR"), tr("MSG_CANT_CREATE_NODE"));       
516           return;
517         }
518         addNode( aStartNode, aEndNode, myX, myY );
519       }
520       break;
521       
522     case 3: // GoTo
523       {
524         SUPERV_CNode aGotoNode;
525         if (myScriptPane->isDefined()) 
526           aGotoNode = aMain->getDataflow()->GNode(myScriptPane->getFuncName().latin1(), 
527                                                   (myScriptPane->getFunction()).in(), "");
528         else
529           aGotoNode = aMain->getDataflow()->GNode("GoTo", (myScriptPane->getFunction()).in(), "");
530         if (CORBA::is_nil(aGotoNode)) {
531           QMessageBox::warning(0, tr("ERROR"), tr("MSG_CANT_CREATE_NODE"));       
532           return;
533         }
534         SUPERV::INode_var aDummyEndNode;
535         addNode( aGotoNode, aDummyEndNode, myX, myY );
536       }
537       break;
538     }
539   }
540 }
541
542 void SUPERVGUI_Service::addMacroNode() {
543   SUPERVGUI_Main* aMain = Supervision.getMain();
544   if (aMain==0) {
545     QMessageBox::warning(QAD_Application::getDesktop(), tr("WARNING"), tr("MSG_NO_SUPERVISION_WINDOW"));
546   } 
547   else if (!aMain->isEditable()) {
548     QMessageBox::warning(QAD_Application::getDesktop(), tr("ERROR"), tr("MSG_CANT_CREATE_NODE"));         
549   } 
550   else {
551     if ( myMFile ) {
552       SUPERV_CNode aNode;
553       if (aMain->getDataflow()->IsStreamGraph()) {
554         SUPERV_StreamGraph aSGraph = aMain->getDataflow()->ToStreamGraph();
555         if (!SUPERV_isNull(aSGraph)) 
556           aNode = aSGraph->StreamMNode(myMFile->name().latin1());
557         // TMP: while stream macro nodes doesn't impemented 
558         if (CORBA::is_nil(aNode)) {
559           aNode = aSGraph->MNode(myMFile->name().latin1());
560         }
561       }
562       else 
563         aNode = aMain->getDataflow()->MNode(myMFile->name().latin1());
564       if (CORBA::is_nil(aNode)) {
565         QMessageBox::warning(0, tr("ERROR"), tr("MSG_CANT_CREATE_NODE"));         
566         return;
567       }
568
569       SUPERV::INode_var aDummyEndNode;
570       addNode( aNode, aDummyEndNode, myX, myY );
571     }
572     else {
573       QMessageBox::warning(QAD_Application::getDesktop(), tr("WARNING"), tr("MSG_NONODE_TOADD"));
574     }
575   }
576 }
577
578 void SUPERVGUI_Service::loadGraph() {
579         if ( getenv( "ENABLE_MACRO_NODE" ) == NULL )
580         // error! if ENABLE_MACRO_NODE is set - we should NOT get here by any means..
581         {
582                 //MESSAGE("Error: ENABLE_MACRO_NODE is not set, but loadGraph() was called!");
583                 return;
584         }
585
586   QString aFileName = QAD_FileDlg::getFileName(QAD_Application::getDesktop(),
587                                                "",
588                                                "*.xml",
589                                                tr("MSG_GRAPH_INSERT"),
590                                                true);
591   if (aFileName.isEmpty()) return;
592
593   myMacroPane->clear();
594
595   myMFile = new QFile(aFileName);
596   if (!myMFile->open(IO_ReadOnly)) {
597     QMessageBox::warning(QAD_Application::getDesktop(), tr("ERROR"), 
598                          tr("MSG_CANT_LOADSCRIPT"));
599     delete myMFile; myMFile = 0;
600     return;
601   }
602
603   QTextStream* aStream = new QTextStream(myMFile);
604   if (aStream->atEnd()) {
605     QMessageBox::warning(QAD_Application::getDesktop(), tr("ERROR"), 
606                          tr("MSG_EMTY_FILE"));
607     delete aStream;
608     myMFile->close();
609     delete myMFile; myMFile = 0;
610     return;
611   }
612
613   // read graph info
614   // temporary display only file name
615   QFileInfo anInfo(*myMFile);
616   QListViewItem* anItem = new QListViewItem(myMacroPane, anInfo.baseName());
617   anItem->setSelectable(true);
618 }
619
620 void SUPERVGUI_Service::typeNodeSelected(int theRow) {
621   if (theRow == 2)
622     myStackWidget->raiseWidget(myLoopId);
623   else
624     myStackWidget->raiseWidget(myOtherId);
625 }
626
627
628
629 void SUPERVGUI_Service::choose() {
630     Trace("SUPERVGUI_Service::choose")
631     show();
632     raise();
633 }
634     
635
636 void SUPERVGUI_Service::showEvent(QShowEvent* theEvent) {
637   SUPERVGUI_Main* aMain = Supervision.getMain();
638   if (aMain && (!aMain->isArrayShown())) {
639     aMain->getArrayView()->viewportToContents(0, 0, myX, myY);
640     //aMain->getGraph()->viewportToContents(0, 0, myX, myY);
641   }
642   QDialog::showEvent(theEvent);
643 }
644
645
646 void SUPERVGUI_Service::tabChanged(QWidget* theWidget) {
647   myIsInline = (myTabPane->currentPageIndex() == 1);
648 }
649
650
651
652 //*****************************************************
653 //  Pane for Python script editing
654 //*****************************************************
655 SUPERVGUI_PythonEditPane::SUPERVGUI_PythonEditPane( QWidget* theParent, const bool isNodeCreation, int& theX, int& theY ) 
656   : myIsWithLibrary( isNodeCreation ), 
657     QFrame( theParent ),
658     myX( theX ), myY( theY )
659 {
660   QGridLayout* aEditLayout = new QGridLayout( this, 2, 8, 0, 6 );
661
662   // First row
663   if ( myIsWithLibrary ) {
664     QPushButton* aLibBtn = new QPushButton(tr("BUT_LIBRARY"), this);
665     connect(aLibBtn, SIGNAL(clicked()), this, SLOT(library()));
666     aEditLayout->addMultiCellWidget( aLibBtn, 0, 0, 1, 2 );
667   }
668
669   QPushButton* aLoadBtn = new QPushButton(tr("BUT_LOAD"), this);
670   connect(aLoadBtn, SIGNAL(clicked()), this, SLOT(loadFile()));
671   
672   aEditLayout->addMultiCellWidget( aLoadBtn, 0, 0, 3, 4 );
673
674   myFunctionsCombo = new QComboBox( this );
675   connect( myFunctionsCombo, SIGNAL( activated( int ) ), this, SLOT( readFunction( int ) ) );
676   
677   aEditLayout->addMultiCellWidget( myFunctionsCombo, 0, 0, 5, 7 );
678   
679   //Second row
680   myText = new QTextEdit(this);
681   myText->setTextFormat( Qt::PlainText ); // NOT rich text, so text() returns plain text
682   myText->setWordWrap( QTextEdit::FixedColumnWidth );
683   myText->setWrapColumnOrWidth( 80 );
684   connect( myText, SIGNAL( returnPressed() ), this, SLOT( autoIndentLine() ) );
685
686   aEditLayout->addMultiCellWidget( myText, 1, 1, 0, 7 );
687   //aEditLayout->setColStretch( 3, 1 ); // to allow myFunctionsCombo be larger when needed
688 }
689
690 /**
691  * Return a text between "def" and "("
692  * "def" must begin with position 0, which means that only global function definitions are possible
693  */ 
694 QString getFunctionName( const QString& aLine ) {
695   int aDefPos = aLine.find("def");
696   if ( aDefPos == 0 ) { // only global function definitions!
697     int aStart = aLine.find(" ", aDefPos);
698     int aEnd = aLine.find("(", aStart);
699     QString aName = aLine.mid(aStart, (aEnd-aStart));
700     return aName.stripWhiteSpace();
701   }
702   return QString();
703 }
704    
705 /**
706  * Searches for text beginning with "def" and ending with any meanful character at 
707  * beginning of line.  Starts searching with current position of given stream.
708  * Fills the myPyFunctions with strings corresponding to found fucntions.
709  */
710 void SUPERVGUI_PythonEditPane::initPyFunctions( QTextStream& theStream ) {
711
712   if ( theStream.atEnd() )
713     return;
714
715   QString aPyFunction;
716   QString aLine = theStream.readLine(); 
717
718   while ( !theStream.atEnd() ) { // not EOF
719
720     // asv : 23.11.04 : fix for PAL6870 : skip empty lines in the beginning or  between functions
721     //       find("def)==0 -> analizing only global function definitions which start with 0 indentation
722     while ( !aLine.isNull() && aLine.find( "def" ) != 0 ) 
723       aLine = theStream.readLine();
724     
725     if ( !aLine.isNull() && aLine.find("def") == 0 ) { 
726       myFunctionsCombo->insertItem( getFunctionName( aLine ) ); // aLine now == function name 
727
728       aPyFunction += aLine;
729       aPyFunction += '\n'; 
730
731       // read function body
732       aLine = theStream.readLine();
733       // asv : 23.11.04 : added "|| aLine.isEmpty()" - fix for PAL6870. readLine() returns an empty
734       //       string for "\n" string, it trails \n caracter.  but we accept such lines..
735       // asv : 22.12.04 : aLine[0].isSpace() || aLine[0]=='#' -> line must begin with space or tab
736       //       (a normal code with indentation) or comment sign.
737       while ( !aLine.isNull() && ( aLine.isEmpty() || aLine[0].isSpace() || aLine[0] == '#' ) ) {
738         aPyFunction += aLine;
739         aPyFunction += '\n'; 
740         aLine = theStream.readLine();
741       }
742
743       myPyFunctions << aPyFunction;
744       aPyFunction.setLength( 0 );
745     }
746   }
747 }
748
749 /**
750  * Load existing Python script
751  */
752 void SUPERVGUI_PythonEditPane::loadFile() {
753   QString aFileName = QAD_FileDlg::getFileName(QAD_Application::getDesktop(),
754                                                "",
755                                                "*.py",
756                                                tr("TIT_LOADSCRIPT"),
757                                                true);
758   if (aFileName.isEmpty()) return;
759
760   QFile aFile( aFileName );
761   if (!aFile.open(IO_ReadOnly)) {
762     QMessageBox::warning(QAD_Application::getDesktop(), tr("ERROR"), 
763                          tr("MSG_CANT_LOADSCRIPT"));
764     return;
765   }
766
767   myPyFunctions.clear();
768   myFunctionsCombo->clear();
769   myText->clear();
770
771   QTextStream aFileReader(&aFile);
772   if ( aFileReader.atEnd() ) {
773     QMessageBox::warning(QAD_Application::getDesktop(), tr("ERROR"), tr("MSG_EMTY_FILE"));
774     aFile.close();
775     return;
776   }
777
778   initPyFunctions( aFileReader );
779
780   if ( myPyFunctions.size() )
781     readFunction( 0 );
782 }
783   
784 /**
785  * Finds and Reads a function from current position in the opened file
786  * asv : Comment above is old! Present model: just take an already read string = PyFunction
787  * from the list which is filled in loadFile().
788  */
789 void SUPERVGUI_PythonEditPane::readFunction( int i ) {
790   myText->clear();
791   if ( i != -1 && myPyFunctions.size() && myPyFunctions.size() > i )
792     myText->append( myPyFunctions[ i ] );
793
794   // asv : 30.11.04 : 2.7 - Inline node function editor improvement
795   // 2.7.1 - set focus to editor widget on editor window opening
796   // 2.7.2 - scroll to the beginning of function on editor window opening
797   myText->setFocus();
798   myText->ensureVisible( 0,0 );
799 }
800
801 /**
802  * Returns the text after "def" and before "(" -- first defined function name
803  */
804 QString SUPERVGUI_PythonEditPane::getFuncName() {
805   for (int i=0; i < myText->paragraphs(); i++) {
806     QString aName = getFunctionName( myText->text(i) );
807     if ( !aName.isEmpty() )
808       return aName;
809   }
810   return QString();
811 }
812
813 /**
814  * Returns the contents of the myText widget without trailing spacing 
815  */
816 SUPERV_Strings SUPERVGUI_PythonEditPane::getFunction() {
817   SUPERV_Strings aStrings = new SUPERV::ListOfStrings();
818   aStrings->length(myText->paragraphs());
819   for (int i=0; i < myText->paragraphs(); i++) {
820     QString aLine = myText->text(i);
821     // asv : 30.11.04 - why do we have to remove trailing spaces??  
822     // it's user's responsibility to enter correct Python code, we don't do anything with it.
823     // if (..) -- initial, while(..) -- my improvement, but also commented out -- needless.
824     //if (!aLine.right(1).compare(" ")) // replaced with the line below -- loop
825     //while (aLine.at(aLine.length()-1).isSpace()) // remove trailing spaces
826     //  aLine = aLine.remove(aLine.length()-1,1);
827     aStrings[i] = CORBA::string_dup(aLine.latin1());
828   }
829   return aStrings._retn();
830 }
831
832
833 void SUPERVGUI_PythonEditPane::setFunction(SUPERV_Strings theStr) {
834   myText->clear();
835   for ( int i=0, aLen = theStr->length(); i < aLen; i++ )
836     myText->append(QString(theStr[i]));
837
838   // asv : 30.11.04 : 2.7 - Inline node function editor improvement
839   // 2.7.1 - set focus to editor widget on editor window opening
840   // 2.7.2 - scroll to the beginning of function on editor window opening
841   myText->setFocus();
842   myText->ensureVisible( 0,0 );
843 }
844
845 /**
846  * Automatic indentation rule: if a previous line ended with 
847  * ':', then add N additional spaces in the current line.  If no ':' found, then 
848  * the same amount of spaces as in the previous line is added. Connected to 
849  * "returnPressed" signal of myText text edit.
850 */
851 void SUPERVGUI_PythonEditPane::autoIndentLine() {
852   const int N = 4; // width of indentation "tab"
853   if ( myText && myText->paragraphs() ) {
854
855     // get current cursor position and previous line (the one to be analized) 
856     int pos, para, i;
857     myText->getCursorPosition( &para, &pos ); // pos==0, beginning of line
858     QString line = myText->text( para-1 ); // previous paragraph line
859
860     // construct a string containing all leading space characters of previous line (tabs, etc.)
861     QString spacesStr;
862     i = -1;
863     while ( line[++i].isSpace() ) // append all isSpace() characters at beginning of line to spacesStr
864       spacesStr += line[i];
865
866     // if ':' was found -- add more spaces to spacesStr
867     line = line.stripWhiteSpace();
868     if ( line[ line.length()-1 ] == ':' ) {
869       i = 0;
870       while ( i++ < N ) 
871         spacesStr += ' ';
872     }
873
874     // ok, append spacesStr at the beginning of the current line = make indentation
875     myText->insertAt( spacesStr, para, pos );
876     myText->setCursorPosition( para, pos+spacesStr.length() );
877   }
878 }
879
880 /**
881  * Create a node by loading it from an external XML library file
882  * This slot opens a dialog box which then "lives" by itself..
883  */
884 void SUPERVGUI_PythonEditPane::library() {
885   // if CanImport() returns false, it displays an error message box, so there is no need to
886   // display such message here ("library file not found", etc.).
887   if ( SUPERVGUI_Library::getLibrary()->CanImport() ) {
888     SUPERVGUI_LibDlg* aDlg = new SUPERVGUI_LibDlg( this, myX, myY );
889     aDlg->exec();
890   }
891 }
892
893 /*!
894  * Edit Python dialog
895  */
896 SUPERVGUI_EditPythonDlg::SUPERVGUI_EditPythonDlg( bool isLoop )
897   :QDialog(QAD_Application::getDesktop(), 0, true, WStyle_Customize | WStyle_NormalBorder | WStyle_Title | WStyle_SysMenu) 
898 {
899   setSizeGripEnabled( true );
900   setCaption(tr("TIT_FUNC_PYTHON"));
901   resize( 500, 250 );
902   QVBoxLayout* aMainLayout = new QVBoxLayout(this, 7, 4);
903   int a,b; // dummies for PythonEditPane, not used, since library = false and myX, myY are not used in PythonEditPane
904   if (isLoop) {
905     QTabWidget* aLoopTabPane = new QTabWidget(this);
906     myInitPane = new SUPERVGUI_PythonEditPane( this, false, a, b ); // library == false, since no creation of a node is needed here
907     aLoopTabPane->addTab(myInitPane, "Init");
908     
909     myMorePane = new SUPERVGUI_PythonEditPane( this, false, a, b );
910     aLoopTabPane->addTab(myMorePane, "More");
911     
912     myNextPane = new SUPERVGUI_PythonEditPane( this, false, a, b );
913     aLoopTabPane->addTab(myNextPane, "Next");
914
915     aMainLayout->addWidget(aLoopTabPane);    
916   } else {
917     myEditPane = new SUPERVGUI_PythonEditPane( this, false, a, b );
918     aMainLayout->addWidget(myEditPane);
919   }
920   QGroupBox* aBtnBox = new QGroupBox( this );
921   aBtnBox->setColumnLayout( 0, Qt::Vertical );
922   aBtnBox->layout()->setSpacing( 0 ); aBtnBox->layout()->setMargin( 0 );
923   QHBoxLayout* aBtnLayout = new QHBoxLayout( aBtnBox->layout() );
924   aBtnLayout->setAlignment( Qt::AlignTop );
925   aBtnLayout->setSpacing( 6 ); aBtnLayout->setMargin( 11 );
926   
927   QPushButton* aOKBtn = new QPushButton( tr( "BUT_OK" ), aBtnBox );
928   connect( aOKBtn, SIGNAL( clicked() ), this, SLOT( accept() ) );
929   aBtnLayout->addWidget( aOKBtn );
930
931   aBtnLayout->addStretch();
932
933   QPushButton* aCancelBtn = new QPushButton( tr("BUT_CANCEL"), aBtnBox );
934   connect( aCancelBtn, SIGNAL( clicked() ), this, SLOT( reject() ) );
935   aBtnLayout->addWidget( aCancelBtn );
936
937   aMainLayout->addWidget(aBtnBox);
938 }
939
940 /**
941  * Do the following actions for newly created Engine's CNode:
942  * 1. Create a presentation for it (CanvasNode)
943  * 2. Place the CanvasNode to the current top-left corner or the current viewport
944  * 3. Increment the coordinates of the next CanvasNode (new nodes are "cascaded" when several of them are created at once)
945  * PS theEndNode is passed only for Loop and Switch nodes (EndLoop and EndSwitch)
946  */ 
947 void SUPERVGUI_Service::addNode( SUPERV::CNode_var theNode, SUPERV::INode_var theEndNode, int& theX, int& theY )  {
948   if ( !CORBA::is_nil( theNode ) ) {
949     int cx, cy;   //to appear a new node in the top-left corner of the current viewport
950     SUPERVGUI_Main* aMain = Supervision.getMain();
951
952     //2.8 point of improvements: Adding node to graph window with taking into account zoom factor
953     QWMatrix aWM = aMain->getCanvasView()->worldMatrix();
954     aMain->getCanvasView()->viewportToContents(theX, theY, cx, cy);
955
956     //2.8 point of improvements:
957     cx = (int)((double)cx/aWM.m11());
958     cy = (int)((double)cy/aWM.m22());
959     theNode->Coords(cx, cy);
960     if ( !CORBA::is_nil( theEndNode ) )
961       theEndNode->Coords(cx + LABEL_WIDTH*2, cy);
962     theX += (int)(NODE_DX*aWM.m11());
963     theY += (int)(NODE_DY*aWM.m22());
964
965     if ( theNode->IsGOTO() )
966       aMain->addGOTONode( theNode );
967     else if ( theNode->IsMacro() )
968       aMain->addMacroNode( theNode );
969     else if ( theNode->IsLoop() || theNode->IsSwitch() )
970       aMain->addControlNode( theNode, SUPERV::CNode::_narrow( theEndNode ), true );
971     else
972       aMain->addComputeNode( theNode );
973   }  
974 }
975