Salome HOME
Merge with OCC_development_01
[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.h"
32 #include "QAD_Tools.h"
33 #include "QAD_FileDlg.h"
34
35 #include "SALOME_NamingService.hxx"
36 #include CORBA_CLIENT_HEADER(SALOME_ModuleCatalog)
37 #include <qlayout.h>
38 #include <qtextstream.h>
39
40
41 static const char * ComponentIcon[] = {
42 "20 20 2 1",
43 "       c None",
44 ".      c #000000",
45 "                    ",
46 "                    ",
47 "                    ",
48 " .................. ",
49 " .                . ",
50 " .                . ",
51 " .                . ",
52 " .                . ",
53 " .                . ",
54 " .                . ",
55 " .                . ",
56 " .                . ",
57 " .................. ",
58 "    .     .     .   ",
59 "    .     .     .   ",
60 "   ...   ...   ...  ",
61 "  .. .. .. .. .. .. ",
62 "  .   . .   . .   . ",
63 "  .. .. .. .. .. .. ",
64 "   ...   ...   ...  "};
65
66
67 static const char * InterfaceIcon[] = {
68 "20 20 2 1",
69 "       c None",
70 ".      c #000000",
71 "                    ",
72 "                    ",
73 "                    ",
74 "                    ",
75 "                    ",
76 "            ..      ",
77 "          ......    ",
78 "         ..    ..   ",
79 "         .      .   ",
80 "..........      ..  ",
81 "         .      .   ",
82 "         ..    ..   ",
83 "          ......    ",
84 "            ..      ",
85 "                    ",
86 "                    ",
87 "                    ",
88 "                    ",
89 "                    ",
90 "                    "};
91
92
93
94
95 SUPERVGUI_Service::SUPERVGUI_Service(SALOME_NamingService* ns):
96     QDialog(QAD_Application::getDesktop(), 0, false, WStyle_Customize | WStyle_NormalBorder | WStyle_Title | WStyle_SysMenu),
97     naming(ns), myMFile(0)
98 {
99   setSizeGripEnabled( true );
100   setCaption(tr("TIT_SERVICES"));
101
102   QVBoxLayout* aMainLayout = new QVBoxLayout(this, 7, 4);
103
104   myTabPane = new QTabWidget(this);
105   connect(myTabPane, SIGNAL(currentChanged(QWidget *)), this, SLOT(tabChanged(QWidget *)));
106
107   // Create Tab for Corba services
108   QWidget* aCorbaPane = new QWidget(myTabPane);
109   QVBoxLayout* aBaseLayoutV= new QVBoxLayout(aCorbaPane, 0, 4);
110   aBaseLayoutV->setMargin(5);
111   aBaseLayoutV->setSpacing(10);
112
113   QHBoxLayout* aBaseLayout = new QHBoxLayout(aCorbaPane); //!!
114  
115   components = new QListView(aCorbaPane);
116   components->addColumn(tr("COL_COMPONENTS"));
117   components->addColumn(tr("COL_PORTTYPE"));
118   components->addColumn(tr("COL_PORTWAY"));
119   components->setColumnAlignment(1, AlignLeft);
120   components->setColumnAlignment(2, AlignLeft);
121   components->setColumnAlignment(3, AlignLeft);
122   components->setSelectionMode(QListView::Extended);
123   components->setRootIsDecorated(true);
124 //  aBaseLayout->addWidget(components);
125   aBaseLayoutV->addWidget(components); //!!
126
127   //QHGroupBox* aAddBox = new QHGroupBox(tr("TIT_ADDNODE"), aCorbaPane); //!!
128   //aAddBox->setInsideSpacing(20); //!!
129
130 //NRI   QPushButton* aComputeCBtn = new QPushButton(tr("TIT_ADDCNODE"), aCorbaPane); //!!
131 //NRI   connect(aComputeCBtn, SIGNAL(clicked()), this, SLOT(addComputeNode())); //!!
132 //NRI   aComputeCBtn->setDefault(false); 
133
134   QPushButton* aComputeBtn = new QPushButton(tr("TIT_ADDFNODE"), aCorbaPane);
135   connect(aComputeBtn, SIGNAL(clicked()), this, SLOT(addFactoryNode()));
136   aComputeBtn->setDefault(true); 
137
138   aBaseLayout->addWidget(aComputeBtn);
139   //NRI  aBaseLayout->addWidget(aComputeCBtn); //!!
140
141   aBaseLayoutV->insertLayout(-1, aBaseLayout);
142   myTabPane->addTab(aCorbaPane, tr("MODULES_PANE"));
143
144
145   // Create Tab for Python services
146   QWidget* aPythonPane = new QWidget(myTabPane);
147   QVBoxLayout* aPythonLayout = new QVBoxLayout(aPythonPane, 0, 4);
148   aPythonLayout->setMargin(5);
149   aPythonLayout->setSpacing(10);
150
151   // Type pane
152   QHGroupBox* aAddBox2 = new QHGroupBox(tr("TIT_ADDNODE"), aPythonPane);
153   aAddBox2->setInsideSpacing(20);
154
155   /*QLabel* aTypeLbl = */new QLabel(tr("LBL_NODETYPE"), aAddBox2);
156
157   myTypeCombo = new QComboBox(aAddBox2);
158   myTypeCombo->insertItem("Computation");
159   myTypeCombo->insertItem("Switch");
160   myTypeCombo->insertItem("Loop");
161   myTypeCombo->insertItem("GoTo");
162   //myTypeCombo->insertItem("Label");
163   connect(myTypeCombo, SIGNAL(activated(int)), this, SLOT(typeNodeSelected(int)));
164
165   aPythonLayout->addWidget(aAddBox2);
166
167   // Edit pane
168   myStackWidget = new QWidgetStack(aPythonPane);
169
170   // other pane
171   myScriptPane = new SUPERVGUI_PythonEditPane(myStackWidget);
172   myOtherId = myStackWidget->addWidget(myScriptPane);
173
174   // loop pane
175   QTabWidget* aLoopTabPane = new QTabWidget(myStackWidget);
176   myInitPane = new SUPERVGUI_PythonEditPane(myStackWidget); 
177   aLoopTabPane->addTab(myInitPane, "Init");
178
179   myMorePane = new SUPERVGUI_PythonEditPane(myStackWidget);
180   aLoopTabPane->addTab(myMorePane, "More");
181
182   myNextPane = new SUPERVGUI_PythonEditPane(myStackWidget);
183   aLoopTabPane->addTab(myNextPane, "Next");
184   myLoopId = myStackWidget->addWidget(aLoopTabPane);
185
186   myStackWidget->raiseWidget(myOtherId);
187
188   aPythonLayout->addWidget(myStackWidget, 1);
189
190   // Create button
191   QPushButton* aCreateBtn = new QPushButton(tr("TIT_ADDNODE"), aPythonPane);
192   connect(aCreateBtn, SIGNAL(clicked()), this, SLOT(addInlineNode()));
193   aPythonLayout->addWidget(aCreateBtn);
194
195   myTabPane->addTab(aPythonPane, tr("INLINE_PANE"));
196
197   // Create Tab for Macro node only if environmental variable ENABLE_MACRO_NODE is set
198         if ( getenv( "ENABLE_MACRO_NODE" ) != NULL )
199         {
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           } else {
390             const SALOME_ModuleCatalog::Service* myService = myComponent->GetService(interface, service);
391             b  = true;
392             
393             SUPERV_CNode node = aMain->getDataflow()->CNode(*myService);
394             if (CORBA::is_nil(node)) {
395               QMessageBox::warning(aDesktop, tr("ERROR"), tr("MSG_CANT_CREATE_NODE"));    
396               return;
397             }
398             //to appear a new node in the top-left corner of the current viewport
399             int cx, cy;
400             aMain->getCanvasView()->viewportToContents(myX, myY, cx, cy);
401             node->Coords(cx, cy);
402             myX += NODE_DX;
403             myY += NODE_DY;
404             aMain->addComputeNode(SUPERV::CNode::_narrow(node));
405           }
406         }
407       }
408       if (!b) {
409         QMessageBox::warning(aDesktop, tr("WARNING"), tr("MSG_NONODE_TOADD"));
410       }
411     }
412   }
413 }
414
415 void SUPERVGUI_Service::addFactoryNode() {
416   QAD_Desktop* aDesktop = QAD_Application::getDesktop();
417   SUPERVGUI_Main* aMain = Supervision.getMain();
418   if (aMain==0) {
419     QMessageBox::warning(aDesktop, tr("WARNING"), tr("MSG_NO_SUPERVISION_WINDOW"));
420   } else if (!aMain->isEditable()) {
421     QMessageBox::warning(aDesktop, tr("ERROR"), tr("MSG_CANT_CREATE_NODE"));      
422   } else {
423     CORBA::Object_ptr obj  = naming->Resolve("/Kernel/ModulCatalog");
424     SALOME_ModuleCatalog::ModuleCatalog_var* aModuleCatalog = new SALOME_ModuleCatalog::ModuleCatalog_var;
425     *aModuleCatalog = SALOME_ModuleCatalog::ModuleCatalog::_narrow(obj);
426     if (CORBA::is_nil(*aModuleCatalog)) {
427       QMessageBox::warning(aDesktop, tr("ERROR"), tr("MSG_CANT_CHOOSE_SERVICE"));
428     } else {
429       QListViewItem*        item;
430       bool                  b = false;
431       QListViewItemIterator i(components);
432       for (; i.current(); ++i) {
433         item = i.current();
434         if (item->isSelected()) {
435           const char* service   = item->text(0).latin1();
436           const char* interface = item->parent()->text(0).latin1();
437           const char* component = aDesktop->getComponentName(item->parent()->parent()->text(0).latin1());
438           SALOME_ModuleCatalog::Acomponent_ptr myComponent = (*aModuleCatalog)->GetComponent(component);
439           if (myComponent==NULL) {
440             QMessageBox::warning(aDesktop, tr("ERROR"), tr("MSG_CANT_CHOOSE_SERVICE"));
441           } else {
442             const SALOME_ModuleCatalog::Service* myService = myComponent->GetService(interface, service);
443             b  = true;
444             
445             MESSAGE ( " myService->TypeOfNode == " << myService->TypeOfNode ) 
446
447             int cx, cy;
448             if ( myService->TypeOfNode == 0 ) { // ComputeNode
449               SUPERV_CNode node = aMain->getDataflow()->CNode(*myService);
450               if (CORBA::is_nil(node)) {
451                 QMessageBox::warning(aDesktop, tr("ERROR"), tr("MSG_CANT_CREATE_NODE"));          
452                 return;
453               }
454               //to appear a new node in the top-left corner of the current viewport
455               aMain->getCanvasView()->viewportToContents(myX, myY, cx, cy);
456               node->Coords(cx, cy);
457               myX += NODE_DX;
458               myY += NODE_DY;
459               aMain->addComputeNode(SUPERV::CNode::_narrow(node));
460             } else { // Factory Node
461               SUPERV_FNode node = aMain->getDataflow()->FNode(component, interface, *myService);
462               if (CORBA::is_nil(node)) {
463                 QMessageBox::warning(aDesktop, tr("ERROR"), tr("MSG_CANT_CREATE_NODE"));          
464                 return;
465               }
466               //to appear a new node in the top-left corner of the current viewport
467               aMain->getCanvasView()->viewportToContents(myX, myY, cx, cy);
468               node->Coords(cx, cy);
469               myX += NODE_DX;
470               myY += NODE_DY;
471               aMain->addComputeNode(SUPERV::CNode::_narrow(node));
472               
473             }
474
475 //          SUPERV_FNode node = aMain->getDataflow()->FNode(component, interface, *myService);
476 //          if (CORBA::is_nil(node)) {
477 //            QMessageBox::warning(0, tr("ERROR"), tr("MSG_CANT_CREATE_NODE"));   
478 //            return;
479 //          }
480 //          node->Coords(myX, myY);
481 //          myX += NODE_DX;
482 //          myY += NODE_DY;
483 //          aMain->addComputeNode(SUPERV::CNode::_narrow(node));
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_Main* aMain = Supervision.getMain();
497   if (aMain==0) {
498     QMessageBox::warning(QAD_Application::getDesktop(), tr("WARNING"), tr("MSG_NO_SUPERVISION_WINDOW"));
499   } else if (!aMain->isEditable()) {
500     QMessageBox::warning(QAD_Application::getDesktop(), tr("ERROR"), tr("MSG_CANT_CREATE_NODE"));         
501   } else {
502     int aSel = myTypeCombo->currentItem();
503     int cx, cy;
504     switch (aSel) {
505     case 0: // Computation
506       if (myScriptPane->isDefined()) {  
507         SUPERV_INode aNode = aMain->getDataflow()->INode(myScriptPane->getFuncName().latin1(), 
508                                                          (myScriptPane->getFunction()).in());
509         if (CORBA::is_nil(aNode)) {
510           QMessageBox::warning(0, tr("ERROR"), tr("MSG_CANT_CREATE_NODE"));       
511           return;
512         }
513         //to appear a new node in the top-left corner of the current viewport
514         aMain->getCanvasView()->viewportToContents(myX, myY, cx, cy);
515         aNode->Coords(cx, cy);
516         myX += NODE_DX;
517         myY += NODE_DY;
518         aMain->addComputeNode(SUPERV::CNode::_narrow(aNode));
519       }
520       break;
521       
522     case 1: // Switch
523       if (myScriptPane->isDefined()) {
524         SUPERV_INode aEndNode;
525         SUPERV_SNode aStartNode = aMain->getDataflow()->SNode(myScriptPane->getFuncName().latin1(),
526                                                               (myScriptPane->getFunction()).in(),
527                                                               aEndNode);
528         if (CORBA::is_nil(aStartNode) || CORBA::is_nil(aEndNode)) {
529           QMessageBox::warning(0, tr("ERROR"), tr("MSG_CANT_CREATE_NODE"));       
530           return;
531         }
532         //to appear a new node in the top-left corner of the current viewport
533         aMain->getCanvasView()->viewportToContents(myX, myY, cx, cy);
534         aStartNode->Coords(cx, cy);
535         aEndNode->Coords(cx + LABEL_WIDTH*2, cy);
536         myX += NODE_DX;
537         myY += NODE_DY;
538         aMain->addControlNode(SUPERV::CNode::_narrow(aStartNode), SUPERV::CNode::_narrow(aEndNode), true);
539       }
540       break;
541       
542     case 2: // Loop
543       {
544         SUPERV_INode aEndNode;
545         SUPERV_LNode aStartNode = aMain->getDataflow()->LNode(myInitPane->getFuncName().latin1(), (myInitPane->getFunction()).in(),
546                                                               myMorePane->getFuncName().latin1(), (myMorePane->getFunction()).in(),
547                                                               myNextPane->getFuncName().latin1(), (myNextPane->getFunction()).in(),
548                                                               aEndNode);
549         if (CORBA::is_nil(aStartNode) || CORBA::is_nil(aEndNode)) {
550           QMessageBox::warning(0, tr("ERROR"), tr("MSG_CANT_CREATE_NODE"));       
551           return;
552         }
553         //to appear a new node in the top-left corner of the current viewport
554         aMain->getCanvasView()->viewportToContents(myX, myY, cx, cy);
555         aStartNode->Coords(cx, cy);
556         aEndNode->Coords(cx + LABEL_WIDTH*2, cy);
557         myX += NODE_DX;
558         myY += NODE_DY;
559         aMain->addControlNode(SUPERV::CNode::_narrow(aStartNode), SUPERV::CNode::_narrow(aEndNode), true);
560       }
561       break;
562       
563     case 3: // GoTo
564       {
565         SUPERV_GNode aGotoNode;
566         if (myScriptPane->isDefined()) 
567           aGotoNode = aMain->getDataflow()->GNode(myScriptPane->getFuncName().latin1(), 
568                                                   (myScriptPane->getFunction()).in(), "");
569         else
570           aGotoNode = aMain->getDataflow()->GNode("GoTo", (myScriptPane->getFunction()).in(), "");
571         if (CORBA::is_nil(aGotoNode)) {
572           QMessageBox::warning(0, tr("ERROR"), tr("MSG_CANT_CREATE_NODE"));       
573           return;
574         }
575         //to appear a new node in the top-left corner of the current viewport
576         aMain->getCanvasView()->viewportToContents(myX, myY, cx, cy);
577         aGotoNode->Coords(cx, cy);
578         myX += NODE_DX;
579         myY += NODE_DY;
580         aMain->addGOTONode(SUPERV::GNode::_narrow(aGotoNode));
581       }
582       break;
583     }
584   }
585 }
586
587 void SUPERVGUI_Service::addMacroNode() {
588   SUPERVGUI_Main* aMain = Supervision.getMain();
589   if (aMain==0) {
590     QMessageBox::warning(QAD_Application::getDesktop(), tr("WARNING"), tr("MSG_NO_SUPERVISION_WINDOW"));
591   } else if (!aMain->isEditable()) {
592     QMessageBox::warning(QAD_Application::getDesktop(), tr("ERROR"), tr("MSG_CANT_CREATE_NODE"));         
593   } else {
594     if (myMFile) {
595       SUPERV_Graph aNode;
596       if (aMain->getDataflow()->IsStreamGraph()) {
597         SUPERV_StreamGraph aSGraph = aMain->getDataflow()->ToStreamGraph();
598         if (!SUPERV_isNull(aSGraph)) 
599           aNode = aSGraph->StreamMNode(myMFile->name().latin1());
600         // TMP: while stream macro nodes doesn't impemented 
601         if (CORBA::is_nil(aNode)) {
602           aNode = aSGraph->MNode(myMFile->name().latin1());
603         }
604       }
605       else 
606         aNode = aMain->getDataflow()->MNode(myMFile->name().latin1());
607       if (CORBA::is_nil(aNode)) {
608         QMessageBox::warning(0, tr("ERROR"), tr("MSG_CANT_CREATE_NODE"));         
609         return;
610       }
611       //to appear a new node in the top-left corner of the current viewport
612       int cx, cy;
613       aMain->getCanvasView()->viewportToContents(myX, myY, cx, cy);
614       aNode->Coords(cx, cy);
615       myX += NODE_DX;
616       myY += NODE_DY;
617       aMain->addMacroNode(SUPERV::CNode::_narrow(aNode));
618     }
619     else {
620       QMessageBox::warning(QAD_Application::getDesktop(), tr("WARNING"), tr("MSG_NONODE_TOADD"));
621     }
622   }
623 }
624
625 void SUPERVGUI_Service::loadGraph() {
626         if ( getenv( "ENABLE_MACRO_NODE" ) == NULL )
627         // error! if ENABLE_MACRO_NODE is set - we should NOT get here by any means..
628         {
629                 //MESSAGE("Error: ENABLE_MACRO_NODE is not set, but loadGraph() was called!");
630                 return;
631         }
632
633   QString aFileName = QAD_FileDlg::getFileName(QAD_Application::getDesktop(),
634                                                "",
635                                                "*.xml",
636                                                tr("MSG_GRAPH_INSERT"),
637                                                true);
638   if (aFileName.isEmpty()) return;
639
640   myMacroPane->clear();
641
642   myMFile = new QFile(aFileName);
643   if (!myMFile->open(IO_ReadOnly)) {
644     QMessageBox::warning(QAD_Application::getDesktop(), tr("ERROR"), 
645                          tr("MSG_CANT_LOADSCRIPT"));
646     delete myMFile; myMFile = 0;
647     return;
648   }
649
650   QTextStream* aStream = new QTextStream(myMFile);
651   if (aStream->atEnd()) {
652     QMessageBox::warning(QAD_Application::getDesktop(), tr("ERROR"), 
653                          tr("MSG_EMTY_FILE"));
654     delete aStream;
655     myMFile->close();
656     delete myMFile; myMFile = 0;
657     return;
658   }
659
660   // read graph info
661   // temporary display only file name
662   QFileInfo anInfo(*myMFile);
663   QListViewItem* anItem = new QListViewItem(myMacroPane, anInfo.baseName());
664   anItem->setSelectable(true);
665 }
666
667 void SUPERVGUI_Service::typeNodeSelected(int theRow) {
668   if (theRow == 2)
669     myStackWidget->raiseWidget(myLoopId);
670   else
671     myStackWidget->raiseWidget(myOtherId);
672 }
673
674
675
676 void SUPERVGUI_Service::choose() {
677     Trace("SUPERVGUI_Service::choose")
678     show();
679     raise();
680 }
681     
682
683 void SUPERVGUI_Service::showEvent(QShowEvent* theEvent) {
684   SUPERVGUI_Main* aMain = Supervision.getMain();
685   if (aMain && (!aMain->isArrayShown())) {
686     aMain->getGraph()->viewportToContents(0, 0, myX, myY);
687   }
688   QDialog::showEvent(theEvent);
689 }
690
691
692 void SUPERVGUI_Service::tabChanged(QWidget* theWidget) {
693   myIsInline = (myTabPane->currentPageIndex() == 1);
694 }
695
696
697
698 //*****************************************************
699 //  Pane for Python script editing
700 //*****************************************************
701 SUPERVGUI_PythonEditPane::SUPERVGUI_PythonEditPane(QWidget* theParent) 
702   : QFrame(theParent)
703 {
704   QGridLayout* aEditLayout = new QGridLayout(this, 2, 4);
705
706   // First row
707   QPushButton* aLoadBtn = new QPushButton(tr("BUT_LOAD"), this);
708   connect(aLoadBtn, SIGNAL(clicked()), this, SLOT(loadFile()));
709   
710   aEditLayout->addWidget(aLoadBtn, 0, 2);
711
712   myNextBtn = new QPushButton(tr("BUT_NEXT"), this);
713   myNextBtn->setEnabled(false);
714   connect(myNextBtn, SIGNAL(clicked()), this, SLOT(readFunction()));
715   
716   aEditLayout->addWidget(myNextBtn, 0, 3);
717   
718   //Second row
719   myText = new QTextEdit(this);
720   myText->setWordWrap(QTextEdit::FixedColumnWidth);
721   myText->setWrapColumnOrWidth(80);
722
723   aEditLayout->addMultiCellWidget(myText, 1, 1, 0, 3);
724 }
725    
726 /**
727  * Searches for text beginning with "def" and ending with any meanful character at 
728  * beginning of line.  Starts searching with current position of given stream.
729  * Fills the myPyFunctions with strings corresponding to found fucntions.
730  */
731 void SUPERVGUI_PythonEditPane::initPyFunctions( QTextStream& theStream ) {
732
733   if ( theStream.atEnd() )
734     return;
735
736   QString aPyFunction;
737   QString aLine = theStream.readLine(); 
738
739   while ( !theStream.atEnd() ) { // not EOF
740
741     // asv : 23.11.04 : fix for PAL6870 : skip empty lines in the beginning or  between functions
742     //       find("def)==0 -> analizing only global function definitions which start with 0 indentation
743     while ( !aLine.isNull() && aLine.find( "def" ) != 0 ) 
744       aLine = theStream.readLine();
745     
746     if ( !aLine.isNull() && aLine.find("def") == 0 ) { 
747       aPyFunction += aLine;
748       aPyFunction += '\n'; 
749
750       // read function body
751       aLine = theStream.readLine();
752       // asv : 23.11.04 : added "|| aLine.isEmpty()" - fix for PAL6870. readLine() returns an empty
753       //       string for "\n" string, it trails \n caracter.  but we accept such lines..
754       while ( !aLine.isNull() && ( aLine.isEmpty() || aLine[0].isSpace() ) ) {
755         aPyFunction += aLine;
756         aPyFunction += '\n'; 
757         aLine = theStream.readLine();
758       }
759
760       myPyFunctions << aPyFunction;
761       aPyFunction.setLength( 0 );
762     }
763   }
764 }
765
766 /**
767  * Load existing Python script
768  */
769 void SUPERVGUI_PythonEditPane::loadFile() {
770   QString aFileName = QAD_FileDlg::getFileName(QAD_Application::getDesktop(),
771                                                "",
772                                                "*.py",
773                                                tr("TIT_LOADSCRIPT"),
774                                                true);
775   if (aFileName.isEmpty()) return;
776
777   QFile aFile( aFileName );
778   if (!aFile.open(IO_ReadOnly)) {
779     QMessageBox::warning(QAD_Application::getDesktop(), tr("ERROR"), 
780                          tr("MSG_CANT_LOADSCRIPT"));
781     return;
782   }
783
784   myPyFunctions.clear();
785   myPyIndex = -1;
786   myNextBtn->setEnabled( false );
787   myText->clear();
788
789   QTextStream aFileReader(&aFile);
790   if ( aFileReader.atEnd() ) {
791     QMessageBox::warning(QAD_Application::getDesktop(), tr("ERROR"), tr("MSG_EMTY_FILE"));
792     aFile.close();
793     return;
794   }
795
796   initPyFunctions( aFileReader );
797
798   if ( myPyFunctions.size() ) {
799     myNextBtn->setEnabled( true );
800     myPyIndex = 0;
801     readFunction();
802   }
803 }
804   
805 /**
806  * Finds and Reads a function from current position in the opened file
807  * asv : Comment above is old! Present model: just take an already read string = PyFunction
808  * from the list which is filled in loadFile().
809  */
810 void SUPERVGUI_PythonEditPane::readFunction() {
811   myText->clear();
812   if ( myPyIndex != -1 && myPyFunctions.size() && myPyFunctions.size() > myPyIndex )
813     myText->append( myPyFunctions[ myPyIndex++ ] );
814   if ( myPyFunctions.size() <= myPyIndex ) // last index was reached
815     myNextBtn->setEnabled( false );
816 }
817
818 /**
819  * Returns the text after "def" and before "(" -- first defined function name
820  */
821 QString SUPERVGUI_PythonEditPane::getFuncName() {
822   QString aName("");
823   for (int i=0; i < myText->paragraphs(); i++) {
824     QString aLine = myText->text(i);
825     int aDefPos = aLine.find("def");
826     if (aDefPos == 0) {
827       int aStart = aLine.find(" ", aDefPos);
828       int aEnd = aLine.find("(", aStart);
829       QString aName = aLine.mid(aStart, (aEnd-aStart));
830       return aName.stripWhiteSpace();
831     }
832   }
833   return aName;
834 }
835
836 /**
837  * Returns the contents of the myText widget without trailing spacing 
838  */
839 SUPERV_Strings SUPERVGUI_PythonEditPane::getFunction() {
840   SUPERV_Strings aStrings = new SUPERV::ListOfStrings();
841   aStrings->length(myText->paragraphs());
842   for (int i=0; i < myText->paragraphs(); i++) {
843     QString aLine = myText->text(i);
844     // asv : 30.11.04 - why do we have to remove trailing spaces??  
845     // it's user's responsibility to enter correct Python code, we don't do anything with it.
846     // if (..) -- initial, while(..) -- my improvement, but also commented out -- needless.
847     //if (!aLine.right(1).compare(" ")) // replaced with the line below -- loop
848     //while (aLine.at(aLine.length()-1).isSpace()) // remove trailing spaces
849     //  aLine = aLine.remove(aLine.length()-1,1);
850     aStrings[i] = CORBA::string_dup(aLine.latin1());
851   }
852   return aStrings._retn();
853 }
854
855
856 void SUPERVGUI_PythonEditPane::setFunction(SUPERV_Strings theStr) {
857   int aLen = theStr->length();
858   for (int i=0; i < aLen; i++)
859     myText->append(QString(theStr[i]));
860
861   // asv : 30.11.04 : 2.7 - Inline node function editor improvement
862   // 2.7.1 - set focus to editor widget on editor window opening
863   // 2.7.2 - scroll to the beginning of function on editor window opening
864   myText->setFocus();
865   myText->ensureVisible( 0,0 );
866 }
867
868
869
870 /*!
871  * Edit Python dialog
872  */
873 SUPERVGUI_EditPythonDlg::SUPERVGUI_EditPythonDlg(bool isLoop)
874   :QDialog(QAD_Application::getDesktop(), 0, true, WStyle_Customize | WStyle_NormalBorder | WStyle_Title | WStyle_SysMenu)
875 {
876   setSizeGripEnabled( true );
877   setCaption(tr("TIT_FUNC_PYTHON"));
878   resize( 500, 250 );
879   QVBoxLayout* aMainLayout = new QVBoxLayout(this, 7, 4);
880   if (isLoop) {
881     QTabWidget* aLoopTabPane = new QTabWidget(this);
882     myInitPane = new SUPERVGUI_PythonEditPane(this); 
883     aLoopTabPane->addTab(myInitPane, "Init");
884     
885     myMorePane = new SUPERVGUI_PythonEditPane(this);
886     aLoopTabPane->addTab(myMorePane, "More");
887     
888     myNextPane = new SUPERVGUI_PythonEditPane(this);
889     aLoopTabPane->addTab(myNextPane, "Next");
890
891     aMainLayout->addWidget(aLoopTabPane);    
892   } else {
893     myEditPane = new SUPERVGUI_PythonEditPane(this);
894     aMainLayout->addWidget(myEditPane);
895   }
896   QGroupBox* aBtnBox = new QGroupBox( this );
897   aBtnBox->setColumnLayout( 0, Qt::Vertical );
898   aBtnBox->layout()->setSpacing( 0 ); aBtnBox->layout()->setMargin( 0 );
899   QHBoxLayout* aBtnLayout = new QHBoxLayout( aBtnBox->layout() );
900   aBtnLayout->setAlignment( Qt::AlignTop );
901   aBtnLayout->setSpacing( 6 ); aBtnLayout->setMargin( 11 );
902   
903   QPushButton* aOKBtn = new QPushButton( tr( "BUT_OK" ), aBtnBox );
904   connect( aOKBtn, SIGNAL( clicked() ), this, SLOT( accept() ) );
905   aBtnLayout->addWidget( aOKBtn );
906
907   aBtnLayout->addStretch();
908
909   QPushButton* aCancelBtn = new QPushButton( tr("BUT_CANCEL"), aBtnBox );
910   connect( aCancelBtn, SIGNAL( clicked() ), this, SLOT( reject() ) );
911   aBtnLayout->addWidget( aCancelBtn );
912
913   aMainLayout->addWidget(aBtnBox);
914 }