Salome HOME
Merging with JR_ASV_2_1_0_deb_with_KERNEL_Head branch, which contains many bug fixes...
[modules/superv.git] / src / SUPERVGUI / SUPERVGUI_Service.cxx
index 749ed00aee12ec2e87b5c130f8b912147e3410c5..2bd81911ea933f8bef28ce9b5e491f244315c5b1 100644 (file)
@@ -28,6 +28,7 @@
 using namespace std;
 #include "SUPERVGUI_Service.h"
 #include "SUPERVGUI_Main.h"
+#include "SUPERVGUI_Library.h"
 #include "SUPERVGUI.h"
 #include "QAD_Tools.h"
 #include "QAD_FileDlg.h"
@@ -35,8 +36,9 @@ using namespace std;
 #include "SALOME_NamingService.hxx"
 #include CORBA_CLIENT_HEADER(SALOME_ModuleCatalog)
 #include <qlayout.h>
+#include <qhbox.h>
 #include <qtextstream.h>
-
+#include <qregexp.h>
 
 static const char * ComponentIcon[] = {
 "20 20 2 1",
@@ -94,7 +96,7 @@ static const char * InterfaceIcon[] = {
 
 SUPERVGUI_Service::SUPERVGUI_Service(SALOME_NamingService* ns):
     QDialog(QAD_Application::getDesktop(), 0, false, WStyle_Customize | WStyle_NormalBorder | WStyle_Title | WStyle_SysMenu),
-    naming(ns)
+    naming(ns), myMFile(0)
 {
   setSizeGripEnabled( true );
   setCaption(tr("TIT_SERVICES"));
@@ -152,14 +154,13 @@ SUPERVGUI_Service::SUPERVGUI_Service(SALOME_NamingService* ns):
   QHGroupBox* aAddBox2 = new QHGroupBox(tr("TIT_ADDNODE"), aPythonPane);
   aAddBox2->setInsideSpacing(20);
 
-  QLabel* aTypeLbl = new QLabel(tr("LBL_NODETYPE"), aAddBox2);
+  /*QLabel* aTypeLbl = */new QLabel(tr("LBL_NODETYPE"), aAddBox2);
 
   myTypeCombo = new QComboBox(aAddBox2);
-  myTypeCombo->insertItem("Computation");
-  myTypeCombo->insertItem("Switch");
-  myTypeCombo->insertItem("Loop");
-  myTypeCombo->insertItem("GoTo");
-  //myTypeCombo->insertItem("Label");
+  myTypeCombo->insertItem( tr( "INLINE_COMP" ) );
+  myTypeCombo->insertItem( tr( "INLINE_SWTC" ) );
+  myTypeCombo->insertItem( tr( "INLINE_LOOP" ) );
+  myTypeCombo->insertItem( tr( "INLINE_GOTO") );
   connect(myTypeCombo, SIGNAL(activated(int)), this, SLOT(typeNodeSelected(int)));
 
   aPythonLayout->addWidget(aAddBox2);
@@ -168,18 +169,18 @@ SUPERVGUI_Service::SUPERVGUI_Service(SALOME_NamingService* ns):
   myStackWidget = new QWidgetStack(aPythonPane);
 
   // other pane
-  myScriptPane = new SUPERVGUI_PythonEditPane(myStackWidget);
+  myScriptPane = new SUPERVGUI_PythonEditPane( myStackWidget, true, myX, myY );
   myOtherId = myStackWidget->addWidget(myScriptPane);
 
   // loop pane
   QTabWidget* aLoopTabPane = new QTabWidget(myStackWidget);
-  myInitPane = new SUPERVGUI_PythonEditPane(myStackWidget); 
+  myInitPane = new SUPERVGUI_PythonEditPane( myStackWidget, true, myX, myY ); 
   aLoopTabPane->addTab(myInitPane, "Init");
 
-  myMorePane = new SUPERVGUI_PythonEditPane(myStackWidget);
+  myMorePane = new SUPERVGUI_PythonEditPane( myStackWidget, true, myX, myY );
   aLoopTabPane->addTab(myMorePane, "More");
 
-  myNextPane = new SUPERVGUI_PythonEditPane(myStackWidget);
+  myNextPane = new SUPERVGUI_PythonEditPane( myStackWidget, true, myX, myY );
   aLoopTabPane->addTab(myNextPane, "Next");
   myLoopId = myStackWidget->addWidget(aLoopTabPane);
 
@@ -194,6 +195,43 @@ SUPERVGUI_Service::SUPERVGUI_Service(SALOME_NamingService* ns):
 
   myTabPane->addTab(aPythonPane, tr("INLINE_PANE"));
 
+  // Create Tab for Macro node only if environmental variable ENABLE_MACRO_NODE is set
+  if ( getenv( "ENABLE_MACRO_NODE" ) != NULL ) {
+    QWidget* aMacroPane = new QWidget(myTabPane);
+    QVBoxLayout* aMacroLayout = new QVBoxLayout(aMacroPane, 0, 4);
+    aMacroLayout->setMargin(5);
+    aMacroLayout->setSpacing(10);
+    
+    QHBoxLayout* aLoadLayout = new QHBoxLayout(aMacroPane); //!!
+    aLoadLayout->addStretch();
+    
+    QPushButton* aLoadBtn = new QPushButton(tr("BUT_LOAD"), aMacroPane);
+    connect(aLoadBtn, SIGNAL(clicked()), this, SLOT(loadGraph()));
+
+    aLoadLayout->addWidget(aLoadBtn);
+
+    aMacroLayout->addLayout(aLoadLayout);
+    myMacroPane = new QListView(aMacroPane);
+    myMacroPane->addColumn(tr("COL_COMPONENTS"));
+    myMacroPane->addColumn(tr("COL_PORTTYPE"));
+    myMacroPane->addColumn(tr("COL_PORTWAY"));
+    myMacroPane->setColumnAlignment(1, AlignLeft);
+    myMacroPane->setColumnAlignment(2, AlignLeft);
+    myMacroPane->setColumnAlignment(3, AlignLeft);
+    myMacroPane->setSelectionMode(QListView::Extended);
+    myMacroPane->setRootIsDecorated(true);
+    aMacroLayout->addWidget(myMacroPane); //!!
+    
+    QPushButton* aAddBtn = new QPushButton(tr("TIT_ADDFNODE"), aMacroPane);
+    connect(aAddBtn, SIGNAL(clicked()), this, SLOT(addMacroNode()));
+    aAddBtn->setDefault(true); 
+    
+    aMacroLayout->addWidget(aAddBtn);
+
+    myTabPane->addTab(aMacroPane, tr("MACRO_PANE"));
+  }
+  
   aMainLayout->addWidget(myTabPane);
 
   // Close button
@@ -319,6 +357,7 @@ void SUPERVGUI_Service::initialise() {
 
 SUPERVGUI_Service::~SUPERVGUI_Service() {
     Trace("SUPERVGUI_Service::~SUPERVGUI_Service")
+      if (myMFile) delete myMFile;
 }
 
 void SUPERVGUI_Service::addComputeNode() {
@@ -326,12 +365,14 @@ void SUPERVGUI_Service::addComputeNode() {
   SUPERVGUI_Main* aMain = Supervision.getMain();
   if (aMain==0) {
     QMessageBox::warning(aDesktop, tr("WARNING"), tr("MSG_NO_SUPERVISION_WINDOW"));
+  } else if (!aMain->isEditable()) {
+    QMessageBox::warning(aDesktop, tr("ERROR"), tr("MSG_CANT_CREATE_NODE"));     
   } else {
     CORBA::Object_ptr obj  = naming->Resolve("/Kernel/ModulCatalog");
     SALOME_ModuleCatalog::ModuleCatalog_var* aModuleCatalog = new SALOME_ModuleCatalog::ModuleCatalog_var;
     *aModuleCatalog = SALOME_ModuleCatalog::ModuleCatalog::_narrow(obj);
     if (CORBA::is_nil(*aModuleCatalog)) {
-      QMessageBox::warning(0, tr("ERROR"), tr("MSG_CANT_CHOOSE_SERVICE"));
+      QMessageBox::warning(aDesktop, tr("ERROR"), tr("MSG_CANT_CHOOSE_SERVICE"));
     } else {
       QListViewItem*        item;
       bool                  b = false;
@@ -343,25 +384,24 @@ void SUPERVGUI_Service::addComputeNode() {
          const char* interface = item->parent()->text(0).latin1();
          const char* component = item->parent()->parent()->text(0).latin1();
          SALOME_ModuleCatalog::Acomponent_ptr myComponent = (*aModuleCatalog)->GetComponent(aDesktop->getComponentName(component));
-         if (myComponent==NULL) {
+         if ( myComponent == NULL ) {
            QMessageBox::warning(aDesktop, tr("ERROR"), tr("MSG_CANT_CHOOSE_SERVICE"));
-         } else {
+         } 
+         else {
            const SALOME_ModuleCatalog::Service* myService = myComponent->GetService(interface, service);
-           b  = true;
-           
-           SUPERV_CNode node = aMain->getDataflow()->CNode(*myService);
-           if (CORBA::is_nil(node)) {
-             QMessageBox::warning(0, tr("ERROR"), tr("MSG_CANT_CREATE_NODE"));   
+           SUPERV_CNode aNode = aMain->getDataflow()->CNode(*myService);
+           if ( CORBA::is_nil( aNode ) ) {
+             QMessageBox::warning(aDesktop, tr("ERROR"), tr("MSG_CANT_CREATE_NODE"));    
              return;
            }
-           node->Coords(myX, myY);
-           myX += NODE_DX;
-           myY += NODE_DY;
-           aMain->addComputeNode(SUPERV::CNode::_narrow(node));
+
+           SUPERV::INode_var aDummyEndNode;
+           addNode( aNode, aDummyEndNode, myX, myY );
+           b = true; // at least one node was added
          }
        }
       }
-      if (!b) {
+      if ( !b ) {
        QMessageBox::warning(aDesktop, tr("WARNING"), tr("MSG_NONODE_TOADD"));
       }
     }
@@ -373,12 +413,14 @@ void SUPERVGUI_Service::addFactoryNode() {
   SUPERVGUI_Main* aMain = Supervision.getMain();
   if (aMain==0) {
     QMessageBox::warning(aDesktop, tr("WARNING"), tr("MSG_NO_SUPERVISION_WINDOW"));
+  } else if (!aMain->isEditable()) {
+    QMessageBox::warning(aDesktop, tr("ERROR"), tr("MSG_CANT_CREATE_NODE"));     
   } else {
     CORBA::Object_ptr obj  = naming->Resolve("/Kernel/ModulCatalog");
     SALOME_ModuleCatalog::ModuleCatalog_var* aModuleCatalog = new SALOME_ModuleCatalog::ModuleCatalog_var;
     *aModuleCatalog = SALOME_ModuleCatalog::ModuleCatalog::_narrow(obj);
     if (CORBA::is_nil(*aModuleCatalog)) {
-      QMessageBox::warning(0, tr("ERROR"), tr("MSG_CANT_CHOOSE_SERVICE"));
+      QMessageBox::warning(aDesktop, tr("ERROR"), tr("MSG_CANT_CHOOSE_SERVICE"));
     } else {
       QListViewItem*        item;
       bool                  b = false;
@@ -392,49 +434,32 @@ void SUPERVGUI_Service::addFactoryNode() {
          SALOME_ModuleCatalog::Acomponent_ptr myComponent = (*aModuleCatalog)->GetComponent(component);
          if (myComponent==NULL) {
            QMessageBox::warning(aDesktop, tr("ERROR"), tr("MSG_CANT_CHOOSE_SERVICE"));
-         } else {
+         } 
+         else {
            const SALOME_ModuleCatalog::Service* myService = myComponent->GetService(interface, service);
-           b  = true;
-           
-           MESSAGE ( " myService->TypeOfNode == " << myService->TypeOfNode ) 
-
+           SUPERV_CNode aNode;
            if ( myService->TypeOfNode == 0 ) { // ComputeNode
-             SUPERV_CNode node = aMain->getDataflow()->CNode(*myService);
-             if (CORBA::is_nil(node)) {
-               QMessageBox::warning(0, tr("ERROR"), tr("MSG_CANT_CREATE_NODE"));         
+             aNode = aMain->getDataflow()->CNode(*myService);
+             if (CORBA::is_nil( aNode ) ) {
+               QMessageBox::warning(aDesktop, tr("ERROR"), tr("MSG_CANT_CREATE_NODE"));          
                return;
              }
-             node->Coords(myX, myY);
-             myX += NODE_DX;
-             myY += NODE_DY;
-             aMain->addComputeNode(SUPERV::CNode::_narrow(node));
-           } else { // Factory Node
-             SUPERV_FNode node = aMain->getDataflow()->FNode(component, interface, *myService);
-             if (CORBA::is_nil(node)) {
-               QMessageBox::warning(0, tr("ERROR"), tr("MSG_CANT_CREATE_NODE"));         
+           } 
+           else { // Factory Node
+             aNode = aMain->getDataflow()->FNode(component, interface, *myService);
+             if ( CORBA::is_nil( aNode ) ) {
+               QMessageBox::warning(aDesktop, tr("ERROR"), tr("MSG_CANT_CREATE_NODE"));          
                return;
              }
-             node->Coords(myX, myY);
-             myX += NODE_DX;
-             myY += NODE_DY;
-             aMain->addComputeNode(SUPERV::CNode::_narrow(node));
-             
            }
-
-//         SUPERV_FNode node = aMain->getDataflow()->FNode(component, interface, *myService);
-//         if (CORBA::is_nil(node)) {
-//           QMessageBox::warning(0, tr("ERROR"), tr("MSG_CANT_CREATE_NODE"));   
-//           return;
-//         }
-//         node->Coords(myX, myY);
-//         myX += NODE_DX;
-//         myY += NODE_DY;
-//         aMain->addComputeNode(SUPERV::CNode::_narrow(node));
+           SUPERV::INode_var aDummyEndNode;
+           addNode( aNode, aDummyEndNode, myX, myY );
+           b = true;
          }
        }
       }
-      if (!b) {
-       QMessageBox::warning(QAD_Application::getDesktop(), tr("WARNING"), tr("MSG_NONODE_TOADD"));
+      if ( !b ) {
+       QMessageBox::warning(aDesktop, tr("WARNING"), tr("MSG_NONODE_TOADD"));
       }
     }
   }
@@ -445,46 +470,44 @@ void SUPERVGUI_Service::addInlineNode() {
   SUPERVGUI_Main* aMain = Supervision.getMain();
   if (aMain==0) {
     QMessageBox::warning(QAD_Application::getDesktop(), tr("WARNING"), tr("MSG_NO_SUPERVISION_WINDOW"));
-  } else {
+  } 
+  else if (!aMain->isEditable()) {
+    QMessageBox::warning(QAD_Application::getDesktop(), tr("ERROR"), tr("MSG_CANT_CREATE_NODE"));        
+  } 
+  else {
     int aSel = myTypeCombo->currentItem();
     switch (aSel) {
     case 0: // Computation
-      if (myScriptPane->isDefined()) { 
-       SUPERV_INode aNode = aMain->getDataflow()->INode(myScriptPane->getFuncName().latin1(), 
+      {        
+       SUPERV_CNode aNode = aMain->getDataflow()->INode(myScriptPane->getFuncName().latin1(), 
                                                         (myScriptPane->getFunction()).in());
        if (CORBA::is_nil(aNode)) {
          QMessageBox::warning(0, tr("ERROR"), tr("MSG_CANT_CREATE_NODE"));       
          return;
        }
-       aNode->Coords(myX, myY);
-       myX += NODE_DX;
-       myY += NODE_DY;
-       aMain->addComputeNode(SUPERV::CNode::_narrow(aNode));
+       SUPERV::INode_var aDummyEndNode;
+       addNode( aNode, aDummyEndNode, myX, myY );
       }
       break;
       
     case 1: // Switch
-      if (myScriptPane->isDefined()) {
+      {
        SUPERV_INode aEndNode;
-       SUPERV_SNode aStartNode = aMain->getDataflow()->SNode(myScriptPane->getFuncName().latin1(),
+       SUPERV_CNode aStartNode = aMain->getDataflow()->SNode(myScriptPane->getFuncName().latin1(),
                                                              (myScriptPane->getFunction()).in(),
                                                              aEndNode);
        if (CORBA::is_nil(aStartNode) || CORBA::is_nil(aEndNode)) {
          QMessageBox::warning(0, tr("ERROR"), tr("MSG_CANT_CREATE_NODE"));       
          return;
        }
-       aStartNode->Coords(myX, myY);
-       aEndNode->Coords(myX + LABEL_WIDTH*2, myY);
-       myX += NODE_DX;
-       myY += NODE_DY;
-       aMain->addControlNode(SUPERV::CNode::_narrow(aStartNode), SUPERV::CNode::_narrow(aEndNode), true);
+       addNode( aStartNode, aEndNode, myX, myY );
       }
       break;
       
     case 2: // Loop
       {
        SUPERV_INode aEndNode;
-       SUPERV_LNode aStartNode = aMain->getDataflow()->LNode(myInitPane->getFuncName().latin1(), (myInitPane->getFunction()).in(),
+       SUPERV_CNode aStartNode = aMain->getDataflow()->LNode(myInitPane->getFuncName().latin1(), (myInitPane->getFunction()).in(),
                                                              myMorePane->getFuncName().latin1(), (myMorePane->getFunction()).in(),
                                                              myNextPane->getFuncName().latin1(), (myNextPane->getFunction()).in(),
                                                              aEndNode);
@@ -492,17 +515,13 @@ void SUPERVGUI_Service::addInlineNode() {
          QMessageBox::warning(0, tr("ERROR"), tr("MSG_CANT_CREATE_NODE"));       
          return;
        }
-       aStartNode->Coords(myX, myY);
-       aEndNode->Coords(myX + LABEL_WIDTH*2, myY);
-       myX += NODE_DX;
-       myY += NODE_DY;
-       aMain->addControlNode(SUPERV::CNode::_narrow(aStartNode), SUPERV::CNode::_narrow(aEndNode), true);
+       addNode( aStartNode, aEndNode, myX, myY );
       }
       break;
       
     case 3: // GoTo
       {
-       SUPERV_GNode aGotoNode;
+       SUPERV_CNode aGotoNode;
        if (myScriptPane->isDefined()) 
          aGotoNode = aMain->getDataflow()->GNode(myScriptPane->getFuncName().latin1(), 
                                                  (myScriptPane->getFunction()).in(), "");
@@ -512,17 +531,91 @@ void SUPERVGUI_Service::addInlineNode() {
          QMessageBox::warning(0, tr("ERROR"), tr("MSG_CANT_CREATE_NODE"));       
          return;
        }
-       aGotoNode->Coords(myX, myY);
-       myX += NODE_DX;
-       myY += NODE_DY;
-       aMain->addGOTONode(SUPERV::GNode::_narrow(aGotoNode));
+       SUPERV::INode_var aDummyEndNode;
+       addNode( aGotoNode, aDummyEndNode, myX, myY );
       }
       break;
     }
   }
 }
 
+void SUPERVGUI_Service::addMacroNode() {
+  SUPERVGUI_Main* aMain = Supervision.getMain();
+  if (aMain==0) {
+    QMessageBox::warning(QAD_Application::getDesktop(), tr("WARNING"), tr("MSG_NO_SUPERVISION_WINDOW"));
+  } 
+  else if (!aMain->isEditable()) {
+    QMessageBox::warning(QAD_Application::getDesktop(), tr("ERROR"), tr("MSG_CANT_CREATE_NODE"));        
+  } 
+  else {
+    if ( myMFile ) {
+      SUPERV_CNode aNode;
+      if (aMain->getDataflow()->IsStreamGraph()) {
+       SUPERV_StreamGraph aSGraph = aMain->getDataflow()->ToStreamGraph();
+       if (!SUPERV_isNull(aSGraph)) 
+         aNode = aSGraph->StreamMNode(myMFile->name().latin1());
+       // TMP: while stream macro nodes doesn't impemented 
+       if (CORBA::is_nil(aNode)) {
+         aNode = aSGraph->MNode(myMFile->name().latin1());
+       }
+      }
+      else 
+       aNode = aMain->getDataflow()->MNode(myMFile->name().latin1());
+      if (CORBA::is_nil(aNode)) {
+       QMessageBox::warning(0, tr("ERROR"), tr("MSG_CANT_CREATE_NODE"));         
+       return;
+      }
 
+      SUPERV::INode_var aDummyEndNode;
+      addNode( aNode, aDummyEndNode, myX, myY );
+    }
+    else {
+      QMessageBox::warning(QAD_Application::getDesktop(), tr("WARNING"), tr("MSG_NONODE_TOADD"));
+    }
+  }
+}
+
+void SUPERVGUI_Service::loadGraph() {
+       if ( getenv( "ENABLE_MACRO_NODE" ) == NULL )
+       // error! if ENABLE_MACRO_NODE is set - we should NOT get here by any means..
+       {
+               //MESSAGE("Error: ENABLE_MACRO_NODE is not set, but loadGraph() was called!");
+               return;
+       }
+
+  QString aFileName = QAD_FileDlg::getFileName(QAD_Application::getDesktop(),
+                                              "",
+                                              "*.xml",
+                                              tr("MSG_GRAPH_INSERT"),
+                                              true);
+  if (aFileName.isEmpty()) return;
+
+  myMacroPane->clear();
+
+  myMFile = new QFile(aFileName);
+  if (!myMFile->open(IO_ReadOnly)) {
+    QMessageBox::warning(QAD_Application::getDesktop(), tr("ERROR"), 
+                        tr("MSG_CANT_LOADSCRIPT"));
+    delete myMFile; myMFile = 0;
+    return;
+  }
+
+  QTextStream* aStream = new QTextStream(myMFile);
+  if (aStream->atEnd()) {
+    QMessageBox::warning(QAD_Application::getDesktop(), tr("ERROR"), 
+                        tr("MSG_EMTY_FILE"));
+    delete aStream;
+    myMFile->close();
+    delete myMFile; myMFile = 0;
+    return;
+  }
+
+  // read graph info
+  // temporary display only file name
+  QFileInfo anInfo(*myMFile);
+  QListViewItem* anItem = new QListViewItem(myMacroPane, anInfo.baseName());
+  anItem->setSelectable(true);
+}
 
 void SUPERVGUI_Service::typeNodeSelected(int theRow) {
   if (theRow == 2)
@@ -543,7 +636,8 @@ void SUPERVGUI_Service::choose() {
 void SUPERVGUI_Service::showEvent(QShowEvent* theEvent) {
   SUPERVGUI_Main* aMain = Supervision.getMain();
   if (aMain && (!aMain->isArrayShown())) {
-    aMain->getGraph()->viewportToContents(0, 0, myX, myY);
+    aMain->getArrayView()->viewportToContents(0, 0, myX, myY);
+    //aMain->getGraph()->viewportToContents(0, 0, myX, myY);
   }
   QDialog::showEvent(theEvent);
 }
@@ -558,32 +652,99 @@ void SUPERVGUI_Service::tabChanged(QWidget* theWidget) {
 //*****************************************************
 //  Pane for Python script editing
 //*****************************************************
-SUPERVGUI_PythonEditPane::SUPERVGUI_PythonEditPane(QWidget* theParent) 
-  : QFrame(theParent),
-    myIStream(0)
+SUPERVGUI_PythonEditPane::SUPERVGUI_PythonEditPane( QWidget* theParent, const bool isNodeCreation, int& theX, int& theY ) 
+  : myIsWithLibrary( isNodeCreation ), 
+    QFrame( theParent ),
+    myX( theX ), myY( theY )
 {
-  QGridLayout* aEditLayout = new QGridLayout(this, 2, 4);
+  QGridLayout* aEditLayout = new QGridLayout( this, 2, 8, 0, 6 );
 
   // First row
+  if ( myIsWithLibrary ) {
+    QPushButton* aLibBtn = new QPushButton(tr("BUT_LIBRARY"), this);
+    connect(aLibBtn, SIGNAL(clicked()), this, SLOT(library()));
+    aEditLayout->addMultiCellWidget( aLibBtn, 0, 0, 1, 2 );
+  }
+
   QPushButton* aLoadBtn = new QPushButton(tr("BUT_LOAD"), this);
   connect(aLoadBtn, SIGNAL(clicked()), this, SLOT(loadFile()));
   
-  aEditLayout->addWidget(aLoadBtn, 0, 2);
+  aEditLayout->addMultiCellWidget( aLoadBtn, 0, 0, 3, 4 );
 
-  myNextBtn = new QPushButton(tr("BUT_NEXT"), this);
-  myNextBtn->setEnabled(false);
-  connect(myNextBtn, SIGNAL(clicked()), this, SLOT(readFunction()));
+  myFunctionsCombo = new QComboBox( this );
+  connect( myFunctionsCombo, SIGNAL( activated( int ) ), this, SLOT( readFunction( int ) ) );
   
-  aEditLayout->addWidget(myNextBtn, 0, 3);
+  aEditLayout->addMultiCellWidget( myFunctionsCombo, 0, 0, 5, 7 );
   
   //Second row
   myText = new QTextEdit(this);
-  myText->setWordWrap(QTextEdit::FixedColumnWidth);
-  myText->setWrapColumnOrWidth(80);
+  myText->setTextFormat( Qt::PlainText ); // NOT rich text, so text() returns plain text
+  myText->setWordWrap( QTextEdit::FixedColumnWidth );
+  myText->setWrapColumnOrWidth( 80 );
+  connect( myText, SIGNAL( returnPressed() ), this, SLOT( autoIndentLine() ) );
 
-  aEditLayout->addMultiCellWidget(myText, 1, 1, 0, 3);
+  aEditLayout->addMultiCellWidget( myText, 1, 1, 0, 7 );
+  //aEditLayout->setColStretch( 3, 1 ); // to allow myFunctionsCombo be larger when needed
+}
+
+/**
+ * Return a text between "def" and "("
+ * "def" must begin with position 0, which means that only global function definitions are possible
+ */ 
+QString getFunctionName( const QString& aLine ) {
+  int aDefPos = aLine.find("def");
+  if ( aDefPos == 0 ) { // only global function definitions!
+    int aStart = aLine.find(" ", aDefPos);
+    int aEnd = aLine.find("(", aStart);
+    QString aName = aLine.mid(aStart, (aEnd-aStart));
+    return aName.stripWhiteSpace();
+  }
+  return QString();
 }
    
+/**
+ * Searches for text beginning with "def" and ending with any meanful character at 
+ * beginning of line.  Starts searching with current position of given stream.
+ * Fills the myPyFunctions with strings corresponding to found fucntions.
+ */
+void SUPERVGUI_PythonEditPane::initPyFunctions( QTextStream& theStream ) {
+
+  if ( theStream.atEnd() )
+    return;
+
+  QString aPyFunction;
+  QString aLine = theStream.readLine(); 
+
+  while ( !theStream.atEnd() ) { // not EOF
+
+    // asv : 23.11.04 : fix for PAL6870 : skip empty lines in the beginning or  between functions
+    //       find("def)==0 -> analizing only global function definitions which start with 0 indentation
+    while ( !aLine.isNull() && aLine.find( "def" ) != 0 ) 
+      aLine = theStream.readLine();
+    
+    if ( !aLine.isNull() && aLine.find("def") == 0 ) { 
+      myFunctionsCombo->insertItem( getFunctionName( aLine ) ); // aLine now == function name 
+
+      aPyFunction += aLine;
+      aPyFunction += '\n'; 
+
+      // read function body
+      aLine = theStream.readLine();
+      // asv : 23.11.04 : added "|| aLine.isEmpty()" - fix for PAL6870. readLine() returns an empty
+      //       string for "\n" string, it trails \n caracter.  but we accept such lines..
+      // asv : 22.12.04 : aLine[0].isSpace() || aLine[0]=='#' -> line must begin with space or tab
+      //       (a normal code with indentation) or comment sign.
+      while ( !aLine.isNull() && ( aLine.isEmpty() || aLine[0].isSpace() || aLine[0] == '#' ) ) {
+       aPyFunction += aLine;
+       aPyFunction += '\n'; 
+       aLine = theStream.readLine();
+      }
+
+      myPyFunctions << aPyFunction;
+      aPyFunction.setLength( 0 );
+    }
+  }
+}
 
 /**
  * Load existing Python script
@@ -596,135 +757,164 @@ void SUPERVGUI_PythonEditPane::loadFile() {
                                               true);
   if (aFileName.isEmpty()) return;
 
-  myFile = new QFile(aFileName);
-  if (!myFile->open(IO_ReadOnly)) {
+  QFile aFile( aFileName );
+  if (!aFile.open(IO_ReadOnly)) {
     QMessageBox::warning(QAD_Application::getDesktop(), tr("ERROR"), 
                         tr("MSG_CANT_LOADSCRIPT"));
     return;
   }
-  myIStream = new QTextStream(myFile);
 
-  if (myIStream->atEnd()) {
-    QMessageBox::warning(QAD_Application::getDesktop(), tr("ERROR"), 
-                        tr("MSG_EMTY_FILE"));
-    myNextBtn->setEnabled(false);
-    delete myIStream;
-    myIStream = 0;
-    myFile->close();
-    delete myFile;
+  myPyFunctions.clear();
+  myFunctionsCombo->clear();
+  myText->clear();
+
+  QTextStream aFileReader(&aFile);
+  if ( aFileReader.atEnd() ) {
+    QMessageBox::warning(QAD_Application::getDesktop(), tr("ERROR"), tr("MSG_EMTY_FILE"));
+    aFile.close();
     return;
   }
-  myNextBtn->setEnabled(true);
-  readFunction();
+
+  initPyFunctions( aFileReader );
+
+  if ( myPyFunctions.size() )
+    readFunction( 0 );
 }
   
-
 /**
  * Finds and Reads a function from current position in the opened file
+ * asv : Comment above is old! Present model: just take an already read string = PyFunction
+ * from the list which is filled in loadFile().
  */
-void SUPERVGUI_PythonEditPane::readFunction() {
-  if (!myIStream) return;
-
-  while (!myIStream->atEnd()) {
-    QString aLine = myIStream->readLine();
-    if (aLine.isNull()) return;
-
-    // find first function
-    int aDefPos = aLine.find("def");
-    if (aDefPos == 0) { // only not a class members
-      myText->clear();
-      // find name
-      /*int aStart = aLine.find(" ", aDefPos);
-      int aEnd = aLine.find("(", aStart);
-      QString aName = aLine.mid(aStart, (aEnd-aStart));
-      aName = aName.stripWhiteSpace();
-      myNameEdt->setText(aName);*/
-      
-      // find input params
-      /*aStart = aEnd+1;
-      aEnd = aLine.find(")", aStart);
-      QString aParams = aLine.mid(aStart, (aEnd-aStart));
-      aParams = aParams.stripWhiteSpace();
-      myParamEdt->setText(aParams);*/
-
-      myText->append(aLine);
-      // read body
-      QString aBodyLine = myIStream->readLine();
-      while ((!aBodyLine.isNull()) && aBodyLine[0].isSpace()) {
-       myText->append(aBodyLine);
-       aBodyLine = myIStream->readLine();
-      }
-      return;
-    }
-  }
-  QMessageBox::warning(QAD_Application::getDesktop(), tr("WARNING"), 
-                        tr("MSG_NOMORE_FUNCTIONS"));
-  delete myIStream;
-  myIStream = 0;
-  myNextBtn->setEnabled(false);
-  myFile->close();
-  delete myFile;
+void SUPERVGUI_PythonEditPane::readFunction( int i ) {
+  myText->clear();
+  if ( i != -1 && myPyFunctions.size() && myPyFunctions.size() > i )
+    myText->append( myPyFunctions[ i ] );
+
+  // asv : 30.11.04 : 2.7 - Inline node function editor improvement
+  // 2.7.1 - set focus to editor widget on editor window opening
+  // 2.7.2 - scroll to the beginning of function on editor window opening
+  myText->setFocus();
+  myText->ensureVisible( 0,0 );
 }
 
-
+/**
+ * Returns the text after "def" and before "(" -- first defined function name
+ */
 QString SUPERVGUI_PythonEditPane::getFuncName() {
-  QString aName("");
   for (int i=0; i < myText->paragraphs(); i++) {
-    QString aLine = myText->text(i);
-    int aDefPos = aLine.find("def");
-    if (aDefPos == 0) {
-      int aStart = aLine.find(" ", aDefPos);
-      int aEnd = aLine.find("(", aStart);
-      QString aName = aLine.mid(aStart, (aEnd-aStart));
-      return aName.stripWhiteSpace();
-    }
+    QString aName = getFunctionName( myText->text(i) );
+    if ( !aName.isEmpty() )
+      return aName;
   }
-  return aName;
+  return QString();
 }
 
-
+/**
+ * Returns the contents of the myText widget without trailing spacing 
+ */
 SUPERV_Strings SUPERVGUI_PythonEditPane::getFunction() {
   SUPERV_Strings aStrings = new SUPERV::ListOfStrings();
   aStrings->length(myText->paragraphs());
   for (int i=0; i < myText->paragraphs(); i++) {
-    aStrings[i] = CORBA::string_dup(myText->text(i).latin1());
+    QString aLine = myText->text(i);
+    // asv : 30.11.04 - why do we have to remove trailing spaces??  
+    // it's user's responsibility to enter correct Python code, we don't do anything with it.
+    // if (..) -- initial, while(..) -- my improvement, but also commented out -- needless.
+    //if (!aLine.right(1).compare(" ")) // replaced with the line below -- loop
+    //while (aLine.at(aLine.length()-1).isSpace()) // remove trailing spaces
+    //  aLine = aLine.remove(aLine.length()-1,1);
+    aStrings[i] = CORBA::string_dup(aLine.latin1());
   }
   return aStrings._retn();
 }
 
 
 void SUPERVGUI_PythonEditPane::setFunction(SUPERV_Strings theStr) {
-  int aLen = theStr->length();
-  for (int i=0; i < aLen; i++)
+  myText->clear();
+  for ( int i=0, aLen = theStr->length(); i < aLen; i++ )
     myText->append(QString(theStr[i]));
+
+  // asv : 30.11.04 : 2.7 - Inline node function editor improvement
+  // 2.7.1 - set focus to editor widget on editor window opening
+  // 2.7.2 - scroll to the beginning of function on editor window opening
+  myText->setFocus();
+  myText->ensureVisible( 0,0 );
 }
 
+/**
+ * Automatic indentation rule: if a previous line ended with 
+ * ':', then add N additional spaces in the current line.  If no ':' found, then 
+ * the same amount of spaces as in the previous line is added. Connected to 
+ * "returnPressed" signal of myText text edit.
+*/
+void SUPERVGUI_PythonEditPane::autoIndentLine() {
+  const int N = 4; // width of indentation "tab"
+  if ( myText && myText->paragraphs() ) {
+
+    // get current cursor position and previous line (the one to be analized) 
+    int pos, para, i;
+    myText->getCursorPosition( &para, &pos ); // pos==0, beginning of line
+    QString line = myText->text( para-1 ); // previous paragraph line
+
+    // construct a string containing all leading space characters of previous line (tabs, etc.)
+    QString spacesStr;
+    i = -1;
+    while ( line[++i].isSpace() ) // append all isSpace() characters at beginning of line to spacesStr
+      spacesStr += line[i];
+
+    // if ':' was found -- add more spaces to spacesStr
+    line = line.stripWhiteSpace();
+    if ( line[ line.length()-1 ] == ':' ) {
+      i = 0;
+      while ( i++ < N ) 
+       spacesStr += ' ';
+    }
+
+    // ok, append spacesStr at the beginning of the current line = make indentation
+    myText->insertAt( spacesStr, para, pos );
+    myText->setCursorPosition( para, pos+spacesStr.length() );
+  }
+}
 
+/**
+ * Create a node by loading it from an external XML library file
+ * This slot opens a dialog box which then "lives" by itself..
+ */
+void SUPERVGUI_PythonEditPane::library() {
+  // if CanImport() returns false, it displays an error message box, so there is no need to
+  // display such message here ("library file not found", etc.).
+  if ( SUPERVGUI_Library::getLibrary()->CanImport() ) {
+    SUPERVGUI_LibDlg* aDlg = new SUPERVGUI_LibDlg( this, myX, myY );
+    aDlg->exec();
+  }
+}
 
 /*!
  * Edit Python dialog
  */
-SUPERVGUI_EditPythonDlg::SUPERVGUI_EditPythonDlg(bool isLoop)
-  :QDialog(QAD_Application::getDesktop(), 0, true, WStyle_Customize | WStyle_NormalBorder | WStyle_Title | WStyle_SysMenu)
+SUPERVGUI_EditPythonDlg::SUPERVGUI_EditPythonDlg( bool isLoop )
+  :QDialog(QAD_Application::getDesktop(), 0, true, WStyle_Customize | WStyle_NormalBorder | WStyle_Title | WStyle_SysMenu) 
 {
   setSizeGripEnabled( true );
   setCaption(tr("TIT_FUNC_PYTHON"));
   resize( 500, 250 );
   QVBoxLayout* aMainLayout = new QVBoxLayout(this, 7, 4);
+  int a,b; // dummies for PythonEditPane, not used, since library = false and myX, myY are not used in PythonEditPane
   if (isLoop) {
     QTabWidget* aLoopTabPane = new QTabWidget(this);
-    myInitPane = new SUPERVGUI_PythonEditPane(this); 
+    myInitPane = new SUPERVGUI_PythonEditPane( this, false, a, b ); // library == false, since no creation of a node is needed here
     aLoopTabPane->addTab(myInitPane, "Init");
     
-    myMorePane = new SUPERVGUI_PythonEditPane(this);
+    myMorePane = new SUPERVGUI_PythonEditPane( this, false, a, b );
     aLoopTabPane->addTab(myMorePane, "More");
     
-    myNextPane = new SUPERVGUI_PythonEditPane(this);
+    myNextPane = new SUPERVGUI_PythonEditPane( this, false, a, b );
     aLoopTabPane->addTab(myNextPane, "Next");
 
     aMainLayout->addWidget(aLoopTabPane);    
   } else {
-    myEditPane = new SUPERVGUI_PythonEditPane(this);
+    myEditPane = new SUPERVGUI_PythonEditPane( this, false, a, b );
     aMainLayout->addWidget(myEditPane);
   }
   QGroupBox* aBtnBox = new QGroupBox( this );
@@ -746,3 +936,40 @@ SUPERVGUI_EditPythonDlg::SUPERVGUI_EditPythonDlg(bool isLoop)
 
   aMainLayout->addWidget(aBtnBox);
 }
+
+/**
+ * Do the following actions for newly created Engine's CNode:
+ * 1. Create a presentation for it (CanvasNode)
+ * 2. Place the CanvasNode to the current top-left corner or the current viewport
+ * 3. Increment the coordinates of the next CanvasNode (new nodes are "cascaded" when several of them are created at once)
+ * PS theEndNode is passed only for Loop and Switch nodes (EndLoop and EndSwitch)
+ */ 
+void SUPERVGUI_Service::addNode( SUPERV::CNode_var theNode, SUPERV::INode_var theEndNode, int& theX, int& theY )  {
+  if ( !CORBA::is_nil( theNode ) ) {
+    int cx, cy;   //to appear a new node in the top-left corner of the current viewport
+    SUPERVGUI_Main* aMain = Supervision.getMain();
+
+    //2.8 point of improvements: Adding node to graph window with taking into account zoom factor
+    QWMatrix aWM = aMain->getCanvasView()->worldMatrix();
+    aMain->getCanvasView()->viewportToContents(theX, theY, cx, cy);
+
+    //2.8 point of improvements:
+    cx = (int)((double)cx/aWM.m11());
+    cy = (int)((double)cy/aWM.m22());
+    theNode->Coords(cx, cy);
+    if ( !CORBA::is_nil( theEndNode ) )
+      theEndNode->Coords(cx + LABEL_WIDTH*2, cy);
+    theX += (int)(NODE_DX*aWM.m11());
+    theY += (int)(NODE_DY*aWM.m22());
+
+    if ( theNode->IsGOTO() )
+      aMain->addGOTONode( theNode );
+    else if ( theNode->IsMacro() )
+      aMain->addMacroNode( theNode );
+    else if ( theNode->IsLoop() || theNode->IsSwitch() )
+      aMain->addControlNode( theNode, SUPERV::CNode::_narrow( theEndNode ), true );
+    else
+      aMain->addComputeNode( theNode );
+  }  
+}
+