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