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