1 // SUPERV SUPERVGUI : GUI for Supervisor component
3 // Copyright (C) 2003 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
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.
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.
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
20 // See http://www.opencascade.org/SALOME/ or email : webmaster.salome@opencascade.org
24 // File : SUPERVGUI_Library.cxx
25 // Author : Alexander SLADKOV
29 #include "SUPERVGUI_Library.h"
30 #include "SUPERVGUI_Main.h"
31 #include "SUPERVGUI.h"
33 #include "QAD_MessageBox.h"
34 #include "QAD_Application.h"
38 #include <qgroupbox.h>
39 #include <qpushbutton.h>
44 #define LIBFILE "/.salome/InLineLibrary.xml" // $HOME+LIBFILE
45 #define DOCTYPE "InLineNodesLibrary" // XML DocType
46 #define ROOT_ELEMENT "inlinenodeslibrary" // XML Element and Attribute tags (many)
47 #define NODE_ELEMENT "INode"
48 #define NODE_NAME_ATT "Name"
49 #define NODE_KIND_ATT "Kind"
50 #define PORT_ELEMENT "Port"
51 #define ES_PORT_ELEMENT "ESPort"
52 #define PORT_INPUT_ATT "IsInput"
53 #define PORT_NAME_ATT "Name"
54 #define PORT_TYPE_ATT "Type"
56 #define FUNC_NAME_ATT "PyFuncName" // XML attributes and elements
57 #define FUNC_ELEMENT "PyFunc" // for Python functions defined
58 #define FUNC_INIT_NAME_ATT "InitFuncName" // in different types of InLine nodes
59 #define FUNC_INIT_ELEMENT "InitPyFunc"
60 #define FUNC_MORE_NAME_ATT "MoreFuncName"
61 #define FUNC_MORE_ELEMENT "MorePyFunc"
62 #define FUNC_NEXT_NAME_ATT "NextFuncName"
63 #define FUNC_NEXT_ELEMENT "NextPyFunc"
64 #define FUNC_EL_NAME_ATT "ELFuncName" // EndLoop
65 #define FUNC_EL_ELEMENT "ELPyFunc"
66 #define FUNC_ES_NAME_ATT "ESFuncName" // EndSwitch
67 #define FUNC_ES_ELEMENT "ESPyFunc"
70 SUPERVGUI_Library* SUPERVGUI_Library::myLibrary = 0;
73 * Inline nodes library. constructor.
75 SUPERVGUI_Library::SUPERVGUI_Library() {
79 * Returns the XML file name used as InLine nodes repository
81 const char* SUPERVGUI_Library::GetLibraryFileName() const {
82 string aFileName = getenv( "HOME" );
84 return aFileName.c_str();
88 * Creates a new library file, truncates the length to zero, writes an empty
89 * XML stub to it. If fails - displays an error message box and returns false
91 bool SUPERVGUI_Library::createLibFile() const {
92 QFile libFile( GetLibraryFileName() );
94 if ( libFile.open( IO_WriteOnly | IO_Truncate ) ) {
95 QDomDocument doc( DOCTYPE ); // create a simple XML stub
96 doc.appendChild( doc.createElement( ROOT_ELEMENT ) ); // IMPORTANT: do not delete this root element
97 QTextStream stream( &libFile );
98 doc.save( stream, 0 );
103 QAD_MessageBox::error1( (QWidget*)QAD_Application::getDesktop(), tr( "ERROR" ), tr( "MSG_ERROR_LIB1" ), tr( "OK" ) );
104 return false; // error opening library file for writing
108 QAD_MessageBox::error1( (QWidget*)QAD_Application::getDesktop(), tr( "ERROR" ), tr( "MSG_ERROR_LIB_IO" ), tr( "OK" ) );
114 * Save Function Name as attribute of given DomElement, and Function strings as its children with CDATASection
115 * saveStrings() is called to save 'main' Py function of a node, and Init(), More(), Next() for Loop node
117 void saveStrings( QDomDocument doc, QDomElement element, const char* theNameAtt, const char* theFuncName,
118 const char* theFuncElem, SUPERV::ListOfStrings_var pyFunc ) {
119 QString pyFuncName( theFuncName );
120 element.setAttribute( theNameAtt, pyFuncName ); // store Py function name
122 // store Py functions as children of 'element'.
123 for ( int i = 0, n = pyFunc->length(); i < n; i++ ) {
124 QString pyFuncStr( pyFunc[i] );
125 QDomCDATASection aCDATA = doc.createCDATASection( pyFuncStr );
126 QDomElement funcElement = doc.createElement( theFuncElem );
127 element.appendChild( funcElement );
128 funcElement.appendChild( aCDATA );
133 * Export an InLine node to Library
135 bool SUPERVGUI_Library::Export( SUPERV::INode_var theNode ) const {
137 if ( CORBA::is_nil( theNode ) ) {
138 QAD_MessageBox::error1( (QWidget*)QAD_Application::getDesktop(), tr( "ERROR" ), tr( "MSG_ERROR_LIB_NIL_NODE" ), tr( "OK" ) );
139 return false; // null node
142 // open existing library file or create a new one and set some empty XML content
143 QFile libFile( GetLibraryFileName() );
144 if ( !libFile.exists() ) { // new library
145 if ( !createLibFile() )
146 return false; // error opening library file for writing. MB was already displayed
149 // create the main XML document object
150 QString docName( DOCTYPE ) ;
151 QDomDocument doc( docName );
152 bool xmlOk = doc.setContent( &libFile );
154 xmlOk = ( doc.elementsByTagName( ROOT_ELEMENT ).length() == 1 ); // find "root" element
155 QDomNode rootElement;
157 rootElement = doc.elementsByTagName( ROOT_ELEMENT ).item( 0 );
158 xmlOk = ( !rootElement.isNull() );
161 const int toRecreate = QAD_MessageBox::error2( (QWidget*)QAD_Application::getDesktop(), tr( "ERROR" ),
162 tr( "MSG_ERROR_LIB_IS_RECREATE" ), tr( "BUT_YES" ), tr( "BUT_NO" ), 1, 0, 0 );
163 if ( toRecreate ) { // user selected to recreate a bad XML file
164 libFile.close(); // in case it was opened by doc.setContent()
165 if ( !createLibFile() )
166 return false; // error opening library file for writing. MB was already displayed
168 // library file was successfully recreated. now re-set content, init rooElement. No checking - it MUST be OK.
169 libFile.setName( GetLibraryFileName() ); // IMPORTANT: re-read the file
170 doc.setContent( &libFile ); // no checking of setContent() and find root element is done, since we are sure
171 rootElement = doc.elementsByTagName( ROOT_ELEMENT ).item( 0 ); // that in newly created file everything is OK
173 else // user chose not to recreate a bad library file
174 return false; // library file is corrupt (bad XML structure), don't recreate
177 // if theNode is EndSwitch or EndLoop -> first export Switch or Loop node
178 if ( theNode->IsEndLoop() || theNode->IsEndSwitch() ) {
179 SUPERV::GNode_var aTmpNode = SUPERV::GNode::_narrow( theNode );
180 theNode = aTmpNode->Coupled();
181 if ( CORBA::is_nil( theNode ) ) {
182 QAD_MessageBox::error1( (QWidget*)QAD_Application::getDesktop(), tr( "ERROR" ), tr( "MSG_ERROR_LIB_NIL_COUPLED" ), tr( "OK" ) );
183 return false; // null coupled node
187 // create element under main document
188 QDomElement element = doc.createElement( NODE_ELEMENT ) ;
189 rootElement.appendChild( element );
191 // save node's name and kind
192 element.setAttribute( NODE_NAME_ATT, theNode->Name() );
193 element.setAttribute( NODE_KIND_ATT, theNode->Kind() );
194 // save the 'main' Py function of the node
195 saveStrings( doc, element, FUNC_NAME_ATT, theNode->PyFuncName(), FUNC_ELEMENT, theNode->PyFunction() );
197 // create DOM elements for ports
198 SUPERV::ListOfPorts_var aPorts = theNode->Ports();
199 for ( int i = 0, n = aPorts->length(); i < n; i++) {
200 if ( !CORBA::is_nil( aPorts[i] ) && !aPorts[i]->IsGate() ) {
201 QDomElement portElement = doc.createElement( PORT_ELEMENT );
202 portElement.setAttribute( PORT_INPUT_ATT, aPorts[i]->IsInput() );
203 portElement.setAttribute( PORT_NAME_ATT, aPorts[i]->Name() );
204 portElement.setAttribute( PORT_TYPE_ATT, aPorts[i]->Type() );
205 element.appendChild( portElement );
209 // if the node is Loop -> additionally export Init(), More(), Next() and EndLoop's function
210 if ( theNode->IsLoop() ) {
211 SUPERV::LNode_var aLoopNode = SUPERV::LNode::_narrow( theNode );
212 if ( CORBA::is_nil( aLoopNode ) ) {
213 QAD_MessageBox::error1( (QWidget*)QAD_Application::getDesktop(), tr( "ERROR" ), tr( "MSG_ERROR_LIB_BAD_LOOP" ), tr( "OK" ) );
216 SUPERV::INode_var aEndLoopNode = aLoopNode->Coupled();
217 if ( CORBA::is_nil( aEndLoopNode ) ) {
218 QAD_MessageBox::error1( (QWidget*)QAD_Application::getDesktop(), tr( "ERROR" ), tr( "MSG_ERROR_LIB_BAD_LOOP" ), tr( "OK" ) );
221 // save init, more, next, end-loop functions of the Loop node
222 saveStrings( doc, element, FUNC_INIT_NAME_ATT, aLoopNode->PyInitName(), FUNC_INIT_ELEMENT, aLoopNode->PyInit() );
223 saveStrings( doc, element, FUNC_MORE_NAME_ATT, aLoopNode->PyMoreName(), FUNC_MORE_ELEMENT, aLoopNode->PyMore() );
224 saveStrings( doc, element, FUNC_NEXT_NAME_ATT, aLoopNode->PyNextName(), FUNC_NEXT_ELEMENT, aLoopNode->PyNext() );
225 saveStrings( doc, element, FUNC_EL_NAME_ATT, aEndLoopNode->PyFuncName(), FUNC_EL_ELEMENT, aEndLoopNode->PyFunction() );
228 // if the node is Switch -> additionally export EndSwitch's function and ports
229 if ( theNode->IsSwitch() ) {
230 SUPERV::SNode_var aSwitchNode = SUPERV::SNode::_narrow( theNode );
231 if ( CORBA::is_nil( aSwitchNode ) ) {
232 QAD_MessageBox::error1( (QWidget*)QAD_Application::getDesktop(), tr( "ERROR" ), tr( "MSG_ERROR_LIB_BAD_SWITCH" ), tr( "OK" ) );
235 SUPERV::INode_var aEndSwitchNode = aSwitchNode->Coupled();
236 if ( CORBA::is_nil( aEndSwitchNode ) ) {
237 QAD_MessageBox::error1( (QWidget*)QAD_Application::getDesktop(), tr( "ERROR" ), tr( "MSG_ERROR_LIB_BAD_SWITCH" ), tr( "OK" ) );
240 // save EndSwitch function
241 saveStrings( doc, element, FUNC_ES_NAME_ATT, aEndSwitchNode->PyFuncName(), FUNC_ES_ELEMENT, aEndSwitchNode->PyFunction() );
243 // save ports of EndSwitch
244 SUPERV::ListOfPorts_var aESPorts = aEndSwitchNode->Ports();
245 for ( int i = 0, n = aESPorts->length(); i < n; i++) {
246 if ( !CORBA::is_nil( aESPorts[i] ) && !aESPorts[i]->IsGate() ) {
247 QDomElement portElement = doc.createElement( ES_PORT_ELEMENT );
248 portElement.setAttribute( PORT_INPUT_ATT, aESPorts[i]->IsInput() );
249 portElement.setAttribute( PORT_NAME_ATT, aESPorts[i]->Name() );
250 portElement.setAttribute( PORT_TYPE_ATT, aESPorts[i]->Type() );
251 element.appendChild( portElement );
254 } // end of IsSwitch()
256 // OK, done with file export. write the document to the file
257 libFile.close(); // it seems that QDomDocument opens the file when doing
258 // setContent() and does not close it
259 if ( libFile.open( IO_WriteOnly ) ) { // IO_WriteOnly truncates the file!
260 QTextStream stream( &libFile );
261 doc.save( stream, 0 );
265 else { // error opening library file for final writing
266 QAD_MessageBox::error1( (QWidget*)QAD_Application::getDesktop(), tr( "ERROR" ), tr( "MSG_ERROR_LIB_WRITE" ), tr( "OK" ) );
273 // should get here only in case of exception
274 QAD_MessageBox::error1( (QWidget*)QAD_Application::getDesktop(), tr( "ERROR" ), tr( "MSG_ERROR_EXPORT_EXCEPTION" ), tr( "OK" ) );
279 * Returns in out parameters Py function name and Py function body
281 void getStrings( QDomElement element, const char* pyFuncName, QString& thePyFuncName,
282 const char* theFuncElem, SUPERV::ListOfStrings_var& pyFunc ) {
283 QDomNamedNodeMap aNodeAtt = element.attributes();
284 if ( !aNodeAtt.namedItem( pyFuncName ).isNull() ) { // if pyFuncName is found - fill pyFunc.
285 thePyFuncName = aNodeAtt.namedItem( pyFuncName ).nodeValue();
287 // every 'theFuncElem' element has a CDATA child - one line
288 // iterate through all of them twice: 1) to count the number of these items (number of strings)
289 // 2) to fill pyFunc out-parameter
291 QDomNode n = element.firstChild();
292 while ( !n.isNull() ) {
293 if ( n.isElement() && n.nodeName() == theFuncElem && n.firstChild().isCDATASection() )
298 pyFunc->length( nStrings );
301 n = element.firstChild();
302 while ( !n.isNull() ) {
303 if ( n.isElement() && n.nodeName() == theFuncElem && n.firstChild().isCDATASection() ) {
304 QDomCDATASection aCDATA = n.firstChild().toCDATASection();
305 pyFunc[i++] = aCDATA.nodeValue();
309 } // if ( pyFuncName )
312 * Adds ports stored in Dom node to the CNode
314 void addPorts( SUPERV::INode_var theINode, QDomElement element, const char* portElement ) {
315 QDomNodeList aPorts = element.elementsByTagName( portElement );
316 for ( int i = 0, n = aPorts.length(); i < n; i++ ) {
317 QDomNode aPort = aPorts.item( i );
318 QDomNamedNodeMap anAtt = aPort.attributes();
319 bool isInput = ( anAtt.namedItem( PORT_INPUT_ATT ).nodeValue() == "1" );
320 QString portName = anAtt.namedItem( PORT_NAME_ATT ).nodeValue();
321 QString portType = anAtt.namedItem( PORT_TYPE_ATT ).nodeValue();
323 theINode->InPort( portName.latin1(), portType.latin1() );
325 theINode->OutPort( portName.latin1(), portType.latin1() );
330 * Import an InLine node from Library into the dataflow
332 bool SUPERVGUI_Library::Import( SUPERV::Graph_var theDataflow, SUPERV::INode_var& theNode,
333 SUPERV::INode_var& theEndNode, const int i ) const {
337 if ( getNodes( doc, aNodes ) ) { // xml is ok
338 if ( i >=0 && i < aNodes.length() ) { // index is ok
339 // 1. retrieve the node with given index
340 QDomElement aNode = aNodes.item( i ).toElement();
341 // 2. create an Engines node
342 QDomNamedNodeMap aNodeAtt = aNode.attributes();
343 const int aKind = aNodeAtt.namedItem( NODE_KIND_ATT ).nodeValue().toInt();
344 QString aNodeName = aNodeAtt.namedItem( NODE_NAME_ATT ).nodeValue();
346 case SUPERV::InLineNode : // PyFunction
347 case SUPERV::GOTONode :
349 // get all the Python function
351 SUPERV::ListOfStrings_var aPyFunc = new SUPERV::ListOfStrings();
352 getStrings( aNode, FUNC_NAME_ATT, aPyFuncName, FUNC_ELEMENT, aPyFunc );
354 // create the corresponding Engines node
355 SUPERV::INode_var aINode;
356 if ( aKind == SUPERV::InLineNode )
357 aINode = theDataflow->INode( aPyFuncName.latin1(), aPyFunc );
359 aINode = theDataflow->GNode( aPyFuncName.latin1(), aPyFunc, "" );
361 aINode->SetName( aNodeName.latin1() ); // try to set the same name of node (might be changed by CNode::SetName)
362 addPorts( aINode, aNode, PORT_ELEMENT ); // add stored ports
364 theNode = aINode; // init out-parameter
367 case SUPERV::LoopNode : // PyInit, PyNext, PyMore, PyEndLoopFunction
369 // get all required Python function
370 QString aInitName, aMoreName, aNextName, aELName;
371 SUPERV::ListOfStrings_var aInitFunc = new SUPERV::ListOfStrings(),
372 aMoreFunc = new SUPERV::ListOfStrings(),
373 aNextFunc = new SUPERV::ListOfStrings(),
374 aELFunc = new SUPERV::ListOfStrings();
375 getStrings( aNode, FUNC_INIT_NAME_ATT, aInitName, FUNC_INIT_ELEMENT, aInitFunc );
376 getStrings( aNode, FUNC_MORE_NAME_ATT, aMoreName, FUNC_MORE_ELEMENT, aMoreFunc );
377 getStrings( aNode, FUNC_NEXT_NAME_ATT, aNextName, FUNC_NEXT_ELEMENT, aNextFunc );
378 getStrings( aNode, FUNC_EL_NAME_ATT, aELName, FUNC_EL_ELEMENT, aELFunc );
380 // create Engines Loop node
381 SUPERV::INode_var aELNode;
382 SUPERV::INode_var aINode = theDataflow->LNode( aInitName.latin1(), aInitFunc,
383 aMoreName.latin1(), aMoreFunc,
384 aNextName.latin1(), aNextFunc, aELNode );
385 // EndLoop node may have or may NOT have pyFunc. set it if it was stored.
386 if ( !aELName.isEmpty() )
387 aELNode->SetPyFunction( aELName.latin1(), aELFunc );
389 aINode->SetName( aNodeName.latin1() );// try to set the same name of node (might be changed by CNode::SetName)
390 addPorts( aINode, aNode, PORT_ELEMENT ); // add stored ports
392 theNode = aINode; // init out-parameters
393 theEndNode = aELNode;
396 case SUPERV::SwitchNode : // PyFunction, PyESFunction, ESPorts
398 // get all required Python function
399 QString aPyFuncName, aESPyFuncName;
400 SUPERV::ListOfStrings_var aPyFunc = new SUPERV::ListOfStrings(),
401 aESPyFunc = new SUPERV::ListOfStrings();
402 getStrings( aNode, FUNC_NAME_ATT, aPyFuncName, FUNC_ELEMENT, aPyFunc );
403 getStrings( aNode, FUNC_ES_NAME_ATT, aESPyFuncName, FUNC_ES_ELEMENT, aESPyFunc );
405 // create Engines Switch node
406 SUPERV::INode_var aESNode;
407 SUPERV::INode_var aINode = theDataflow->SNode( aPyFuncName.latin1(), aPyFunc, aESNode );
409 // EndSwitch node may have or may NOT have pyFunc
410 if ( !aESPyFuncName.isEmpty() )
411 aESNode->SetPyFunction( aESPyFuncName.latin1(), aESPyFunc );
413 aINode->SetName( aNodeName.latin1() );// try to set the same name of node (might be changed by CNode::SetName)
414 addPorts( aINode, aNode, PORT_ELEMENT ); // add stored ports
415 addPorts( aESNode, aNode, ES_PORT_ELEMENT ); // add stores ports of EndSwitch
417 theNode = aINode; // init out-parameters
418 theEndNode = aESNode;
421 default: // wrong kind of node error
422 QAD_MessageBox::error1( (QWidget*)QAD_Application::getDesktop(), tr( "ERROR" ), tr( "MSG_ERROR_IMPORT_BAD_KIND_OF_NODE" ), tr( "OK" ) );
424 } // switch ( kind_of_node )
425 } // if ( index >= 0...)
427 QAD_MessageBox::error1( (QWidget*)QAD_Application::getDesktop(), tr( "ERROR" ), tr( "MSG_ERROR_IMPORT_BAD_INDEX" ), tr( "OK" ) );
429 } // if ( getNodes() )
431 return false; // no MB, getNodes() in case of errors displays MB itself
437 // Normally we get here ONLY if an exception occured. All other paths of execution must return before.
438 // But - who knows, maybe we can get here by some other means.. anyway, it's an error and we report it here
439 QAD_MessageBox::error1( (QWidget*)QAD_Application::getDesktop(), tr( "ERROR" ), tr( "MSG_ERROR_IMPORT_EXCEPTION" ), tr( "OK" ) );
444 * Returns list of NODE_ELEMENT-s and error result (false) if failed (also displays MB)
446 bool SUPERVGUI_Library::getNodes( QDomDocument& doc, QDomNodeList& theNodes ) const {
447 QFile libFile( GetLibraryFileName() ); // open existing library file
448 if ( !libFile.exists() ) {
449 QAD_MessageBox::error1( (QWidget*)QAD_Application::getDesktop(), tr( "ERROR" ), tr( "MSG_ERROR_IMPORT_LIB_NO_XML" ), tr( "OK" ) );
453 // create the main XML document object
454 QString docName( DOCTYPE ) ;
455 doc = QDomDocument( docName );
456 bool xmlOk = doc.setContent( &libFile );
457 // check XML for validity: 1) find root element with predefined name 2) check xml doctype
459 xmlOk = ( doc.doctype().name() == DOCTYPE && doc.elementsByTagName( ROOT_ELEMENT ).length() == 1 );
461 QAD_MessageBox::error1( (QWidget*)QAD_Application::getDesktop(), tr( "ERROR" ), tr( "MSG_ERROR_IMPORT_LIB_BAD_XML" ), tr( "OK" ) );
465 theNodes = doc.elementsByTagName( NODE_ELEMENT );
470 * Remove an InLine node with given index from Library
472 bool SUPERVGUI_Library::Remove( const int i ) const {
475 if ( getNodes( doc, aNodes ) && doc.elementsByTagName( ROOT_ELEMENT ).length() == 1 ) { // xml is ok
476 if ( i >=0 && i < aNodes.length() ) {
477 // 1. remove the child element (node) from Dom Document
478 QDomElement root = doc.elementsByTagName( ROOT_ELEMENT ).item( 0 ).toElement();
479 root.removeChild( aNodes.item( i ) );
480 // 2. write the modified document to the file
481 QFile libFile( GetLibraryFileName() );
482 if ( libFile.open( IO_WriteOnly | IO_Truncate ) ) {
483 QTextStream stream( &libFile );
484 doc.save( stream, 0 );
494 * Returns a string descriptor of KindOfNode enumeration
496 QString getKindStr( const QString& theKind ) {
497 switch ( theKind.toInt() ) {
498 case SUPERV::InLineNode : return "InLine";
499 case SUPERV::LoopNode : return "Loop";
500 case SUPERV::SwitchNode : return "Switch";
501 case SUPERV::GOTONode : return "GOTO";
502 case SUPERV::FactoryNode :
503 case SUPERV::DataFlowGraph :
504 case SUPERV::ComputingNode :
505 case SUPERV::EndLoopNode :
506 case SUPERV::EndSwitchNode :
507 case SUPERV::DataStreamGraph :
508 case SUPERV::MacroNode :
509 case SUPERV::UnknownNode :
513 return "INCORRECT kind";
517 * returns a list of node names currently stored in the library. Indexes of the nodes in
518 * this list can be used for futher calls to Import(.., index)
520 SUPERV::ListOfStrings SUPERVGUI_Library::GetLibraryNodesNames() const {
521 SUPERV::ListOfStrings aNodesNames;
522 aNodesNames.length( 0 );
526 if ( !getNodes( doc, aNodes ) )
529 const int n = aNodes.length();
530 aNodesNames.length( n );
532 for ( int i = 0; i < n; i++ ) {
533 QString aNodeName( "" );
534 aNode = aNodes.item( i );
535 if ( !aNode.isNull() ) {
536 QDomNode aNameAtt = aNode.attributes().namedItem( NODE_NAME_ATT );
537 QDomNode aTypeAtt = aNode.attributes().namedItem( NODE_KIND_ATT );
538 if ( !aNameAtt.isNull() && !aTypeAtt.isNull() ) {
539 aNodeName = QString( "%1 ( %2 )" ).arg( aNameAtt.toAttr().value() ).arg(
540 getKindStr( aTypeAtt.toAttr().value() ) );
543 // if NodeName attribute was not found or some error (NULL node),
544 // then an empty string is added for that index in the list
545 aNodesNames[i] = aNodeName.latin1();
553 * Inline nodes library management dialog. constructor.
555 SUPERVGUI_LibDlg::SUPERVGUI_LibDlg( QWidget* parent, int& theX, int& theY )
556 :QDialog( parent, "SUPERVGUI_LibDlg", true, WStyle_Customize | WStyle_NormalBorder | WStyle_Title | WStyle_SysMenu),
557 myX( theX ), myY( theY )
559 setSizeGripEnabled( true );
560 setCaption(tr("TIT_FUNC_PYTHON"));
562 QGridLayout* aMainLayout = new QGridLayout( this, 4, 4, 11, 6 );
564 myLB = new QListBox( this );
566 QPushButton* anAddBtn = new QPushButton( tr("TIT_ADDFNODE"), this );
567 connect( anAddBtn, SIGNAL( clicked() ), this, SLOT( add() ) );
568 QPushButton* aRemBtn = new QPushButton( tr("BUT_REMOVE"), this );
569 connect( aRemBtn, SIGNAL( clicked() ), this, SLOT( remove() ) );
571 aMainLayout->addMultiCellWidget( myLB, 0, 2, 0, 2 );
572 aMainLayout->addWidget( anAddBtn, 0, 3 );
573 aMainLayout->addWidget( aRemBtn, 1, 3 );
575 QGroupBox* aBtnBox = new QGroupBox( 0, Qt::Vertical, this );
576 aBtnBox->layout()->setSpacing( 0 ); aBtnBox->layout()->setMargin( 0 );
577 QHBoxLayout* aBtnLayout = new QHBoxLayout( aBtnBox->layout() );
578 aBtnLayout->setAlignment( Qt::AlignTop );
579 aBtnLayout->setSpacing( 6 ); aBtnLayout->setMargin( 11 );
581 QPushButton* aCloseBtn = new QPushButton( tr("BUT_CLOSE"), aBtnBox );
582 connect( aCloseBtn, SIGNAL( clicked() ), this, SLOT( reject() ) );
583 aBtnLayout->addStretch();
584 aBtnLayout->addWidget( aCloseBtn );
585 aBtnLayout->addStretch();
587 aMainLayout->addMultiCellWidget( aBtnBox, 3, 3, 0, 3 );
588 aMainLayout->setRowStretch( 2, 1 );
594 * Inline nodes library management dialog. destructor.
596 SUPERVGUI_LibDlg::~SUPERVGUI_LibDlg() {}
599 * Called when user presses "Add" button. Add a selected node from library to graph
601 void SUPERVGUI_LibDlg::add() {
602 const int i = myLB->currentItem();
603 if ( i >= 0 && i < myLB->count() ) {
604 SUPERV::Graph_var aDataflow = Supervision.getMain()->getDataflow();
605 SUPERV::INode_var aNode, aEndNode;
606 if ( SUPERVGUI_Library::getLibrary()->Import( aDataflow, aNode, aEndNode, i ) ) {
607 SUPERVGUI_Service::addNode( SUPERV::CNode::_narrow( aNode ), aEndNode, myX, myY );
608 Supervision.getMain()->sync();
610 else { // all errors must be reported to user in Import(), MB shown, etc..
611 } // so we don't need to report errors if Import() returned false.
616 * Called when user presses "Remove" button. Remove a selected node from library
618 void SUPERVGUI_LibDlg::remove() {
619 const int i = myLB->currentItem();
620 if ( i >= 0 && i < myLB->count() ) {
621 SUPERVGUI_Library::getLibrary()->Remove( i );
622 initList(); // re-initialize the list to reflect the changes
627 * Fills the list with names of nodes currently stored in the library. Indexes in the list
628 * can be used for calls to Library::Import()
630 void SUPERVGUI_LibDlg::initList() {
632 SUPERV::ListOfStrings aNodesNames = SUPERVGUI_Library::getLibrary()->GetLibraryNodesNames();
633 for ( int i = 0, n = aNodesNames.length(); i < n; i++ )
634 myLB->insertItem( (const char*)aNodesNames[i] );