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