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.salome-platform.org/ or email : webmaster.salome@opencascade.com
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 "SUIT_Application.h"
34 #include "SUIT_MessageBox.h"
35 #include "SUIT_Session.h"
39 #include <qgroupbox.h>
40 #include <qpushbutton.h>
45 #define LIBFILE "/.salome/InLineLibrary.xml" // $HOME+LIBFILE
46 #define DOCTYPE "InLineNodesLibrary" // XML DocType
47 #define ROOT_ELEMENT "inlinenodeslibrary" // XML Element and Attribute tags (many)
48 #define NODE_ELEMENT "INode"
49 #define NODE_NAME_ATT "Name"
50 #define NODE_KIND_ATT "Kind"
51 #define PORT_ELEMENT "Port"
52 #define ES_PORT_ELEMENT "ESPort"
53 #define PORT_INPUT_ATT "IsInput"
54 #define PORT_NAME_ATT "Name"
55 #define PORT_TYPE_ATT "Type"
57 #define FUNC_NAME_ATT "PyFuncName" // XML attributes and elements
58 #define FUNC_ELEMENT "PyFunc" // for Python functions defined
59 #define FUNC_INIT_NAME_ATT "InitFuncName" // in different types of InLine nodes
60 #define FUNC_INIT_ELEMENT "InitPyFunc"
61 #define FUNC_MORE_NAME_ATT "MoreFuncName"
62 #define FUNC_MORE_ELEMENT "MorePyFunc"
63 #define FUNC_NEXT_NAME_ATT "NextFuncName"
64 #define FUNC_NEXT_ELEMENT "NextPyFunc"
65 #define FUNC_EL_NAME_ATT "ELFuncName" // EndLoop
66 #define FUNC_EL_ELEMENT "ELPyFunc"
67 #define FUNC_ES_NAME_ATT "ESFuncName" // EndSwitch
68 #define FUNC_ES_ELEMENT "ESPyFunc"
71 SUPERVGUI_Library* SUPERVGUI_Library::myLibrary = 0;
74 * Inline nodes library. constructor.
76 SUPERVGUI_Library::SUPERVGUI_Library() {
80 * Returns the XML file name used as InLine nodes repository
82 const char* SUPERVGUI_Library::GetLibraryFileName() const {
83 string aFileName = getenv( "HOME" );
85 return aFileName.c_str();
89 * Creates a new library file, truncates the length to zero, writes an empty
90 * XML stub to it. If fails - displays an error message box and returns false
92 bool SUPERVGUI_Library::createLibFile() const {
93 QFile libFile( GetLibraryFileName() );
95 if ( libFile.open( IO_WriteOnly | IO_Truncate ) ) {
96 QDomDocument doc( DOCTYPE ); // create a simple XML stub
97 doc.appendChild( doc.createElement( ROOT_ELEMENT ) ); // IMPORTANT: do not delete this root element
98 QTextStream stream( &libFile );
99 doc.save( stream, 0 );
105 QString aFullPath = GetLibraryFileName();
106 QString aDir = aFullPath.left( aFullPath.findRev('/')+1 );
107 const int toCreateDir = SUIT_MessageBox::warn2( (QWidget*)(SUIT_Session::session()->activeApplication()->desktop()), tr( "ERROR" ),
108 tr( "MSG_ERROR_LIB_DIR_NOT_EXIST_RECREATE" ).arg(aDir), tr( "BUT_YES" ), tr( "BUT_NO" ), 1, 0, 0 );
109 if ( toCreateDir ) { // user selected to create a new ./salome subdirectory in HOME directory
112 QString aCommand = QString("mkdir ") + aDir;
113 int status = system( aCommand.latin1() );
115 if ( status == -1 || status == 217 ) {
116 SUIT_MessageBox::error1( (QWidget*)(SUIT_Session::session()->activeApplication()->desktop()), tr( "ERROR" ), tr( "MSG_ERROR_LIB_RECREATE_DIR" ).arg(aDir), tr( "OK" ) );
121 libFile.open( IO_WriteOnly | IO_Truncate );
122 QDomDocument doc( DOCTYPE ); // create a simple XML stub
123 doc.appendChild( doc.createElement( ROOT_ELEMENT ) ); // IMPORTANT: do not delete this root element
124 QTextStream stream( &libFile );
125 doc.save( stream, 0 );
129 else // user chose not to create a new ./salome subdirectory in HOME directory
134 SUIT_MessageBox::error1( (QWidget*)(SUIT_Session::session()->activeApplication()->desktop()), tr( "ERROR" ), tr( "MSG_ERROR_LIB_IO" ), tr( "OK" ) );
140 * Save Function Name as attribute of given DomElement, and Function strings as its children with CDATASection
141 * saveStrings() is called to save 'main' Py function of a node, and Init(), More(), Next() for Loop node
143 void saveStrings( QDomDocument doc, QDomElement element, const char* theNameAtt, const char* theFuncName,
144 const char* theFuncElem, SUPERV::ListOfStrings_var pyFunc ) {
145 QString pyFuncName( theFuncName );
146 element.setAttribute( theNameAtt, pyFuncName ); // store Py function name
148 // store Py functions as children of 'element'.
149 for ( int i = 0, n = pyFunc->length(); i < n; i++ ) {
150 QString pyFuncStr( pyFunc[i] );
151 QDomCDATASection aCDATA = doc.createCDATASection( pyFuncStr );
152 QDomElement funcElement = doc.createElement( theFuncElem );
153 element.appendChild( funcElement );
154 funcElement.appendChild( aCDATA );
159 * Export an InLine node to Library
161 bool SUPERVGUI_Library::Export( SUPERV::INode_var theNode ) const {
163 if ( CORBA::is_nil( theNode ) ) {
164 SUIT_MessageBox::error1( (QWidget*)(SUIT_Session::session()->activeApplication()->desktop()), tr( "ERROR" ), tr( "MSG_ERROR_LIB_NIL_NODE" ), tr( "OK" ) );
165 return false; // null node
168 // open existing library file or create a new one and set some empty XML content
169 QFile libFile( GetLibraryFileName() );
170 if ( !libFile.exists() ) { // new library
171 if ( !createLibFile() )
172 return false; // error opening library file for writing. MB was already displayed
175 // create the main XML document object
176 QString docName( DOCTYPE ) ;
177 QDomDocument doc( docName );
178 bool xmlOk = doc.setContent( &libFile );
180 xmlOk = ( doc.elementsByTagName( ROOT_ELEMENT ).length() == 1 ); // find "root" element
181 QDomNode rootElement;
183 rootElement = doc.elementsByTagName( ROOT_ELEMENT ).item( 0 );
184 xmlOk = ( !rootElement.isNull() );
187 const int toRecreate = SUIT_MessageBox::error2( (QWidget*)(SUIT_Session::session()->activeApplication()->desktop()), tr( "ERROR" ),
188 tr( "MSG_ERROR_LIB_IS_RECREATE" ), tr( "BUT_YES" ), tr( "BUT_NO" ), 1, 0, 0 );
189 if ( toRecreate ) { // user selected to recreate a bad XML file
190 libFile.close(); // in case it was opened by doc.setContent()
192 // remove old bad file
193 QString aCommand = QString("rm -f ") + libFile.name();
194 system( aCommand.latin1() );
196 if ( !createLibFile() )
197 return false; // error opening library file for writing. MB was already displayed
199 // library file was successfully recreated. now re-set content, init rooElement. No checking - it MUST be OK.
200 libFile.setName( GetLibraryFileName() ); // IMPORTANT: re-read the file
201 doc.setContent( &libFile ); // no checking of setContent() and find root element is done, since we are sure
202 rootElement = doc.elementsByTagName( ROOT_ELEMENT ).item( 0 ); // that in newly created file everything is OK
204 else // user chose not to recreate a bad library file
205 return false; // library file is corrupt (bad XML structure), don't recreate
208 // if theNode is EndSwitch or EndLoop -> first export Switch or Loop node
209 if ( theNode->IsEndLoop() || theNode->IsEndSwitch() ) {
210 SUPERV::GNode_var aTmpNode = SUPERV::GNode::_narrow( theNode );
211 theNode = aTmpNode->Coupled();
212 if ( CORBA::is_nil( theNode ) ) {
213 SUIT_MessageBox::error1( (QWidget*)(SUIT_Session::session()->activeApplication()->desktop()), tr( "ERROR" ), tr( "MSG_ERROR_LIB_NIL_COUPLED" ), tr( "OK" ) );
214 return false; // null coupled node
218 // create element under main document
219 QDomElement element = doc.createElement( NODE_ELEMENT ) ;
220 rootElement.appendChild( element );
222 // save node's name and kind
223 element.setAttribute( NODE_NAME_ATT, theNode->Name() );
224 element.setAttribute( NODE_KIND_ATT, theNode->Kind() );
225 // save the 'main' Py function of the node
226 saveStrings( doc, element, FUNC_NAME_ATT, theNode->PyFuncName(), FUNC_ELEMENT, theNode->PyFunction() );
228 // create DOM elements for ports
229 SUPERV::ListOfPorts_var aPorts = theNode->Ports();
230 for ( int i = 0, n = aPorts->length(); i < n; i++) {
231 if ( !CORBA::is_nil( aPorts[i] ) && !aPorts[i]->IsGate() ) {
232 QDomElement portElement = doc.createElement( PORT_ELEMENT );
233 portElement.setAttribute( PORT_INPUT_ATT, aPorts[i]->IsInput() );
234 portElement.setAttribute( PORT_NAME_ATT, aPorts[i]->Name() );
235 portElement.setAttribute( PORT_TYPE_ATT, aPorts[i]->Type() );
236 element.appendChild( portElement );
240 // if the node is Loop -> additionally export Init(), More(), Next() and EndLoop's function
241 if ( theNode->IsLoop() ) {
242 SUPERV::LNode_var aLoopNode = SUPERV::LNode::_narrow( theNode );
243 if ( CORBA::is_nil( aLoopNode ) ) {
244 SUIT_MessageBox::error1( (QWidget*)(SUIT_Session::session()->activeApplication()->desktop()), tr( "ERROR" ), tr( "MSG_ERROR_LIB_BAD_LOOP" ), tr( "OK" ) );
247 SUPERV::INode_var aEndLoopNode = aLoopNode->Coupled();
248 if ( CORBA::is_nil( aEndLoopNode ) ) {
249 SUIT_MessageBox::error1( (QWidget*)(SUIT_Session::session()->activeApplication()->desktop()), tr( "ERROR" ), tr( "MSG_ERROR_LIB_BAD_LOOP" ), tr( "OK" ) );
252 // save init, more, next, end-loop functions of the Loop node
253 saveStrings( doc, element, FUNC_INIT_NAME_ATT, aLoopNode->PyInitName(), FUNC_INIT_ELEMENT, aLoopNode->PyInit() );
254 saveStrings( doc, element, FUNC_MORE_NAME_ATT, aLoopNode->PyMoreName(), FUNC_MORE_ELEMENT, aLoopNode->PyMore() );
255 saveStrings( doc, element, FUNC_NEXT_NAME_ATT, aLoopNode->PyNextName(), FUNC_NEXT_ELEMENT, aLoopNode->PyNext() );
256 saveStrings( doc, element, FUNC_EL_NAME_ATT, aEndLoopNode->PyFuncName(), FUNC_EL_ELEMENT, aEndLoopNode->PyFunction() );
259 // if the node is Switch -> additionally export EndSwitch's function and ports
260 if ( theNode->IsSwitch() ) {
261 SUPERV::SNode_var aSwitchNode = SUPERV::SNode::_narrow( theNode );
262 if ( CORBA::is_nil( aSwitchNode ) ) {
263 SUIT_MessageBox::error1( (QWidget*)(SUIT_Session::session()->activeApplication()->desktop()), tr( "ERROR" ), tr( "MSG_ERROR_LIB_BAD_SWITCH" ), tr( "OK" ) );
266 SUPERV::INode_var aEndSwitchNode = aSwitchNode->Coupled();
267 if ( CORBA::is_nil( aEndSwitchNode ) ) {
268 SUIT_MessageBox::error1( (QWidget*)(SUIT_Session::session()->activeApplication()->desktop()), tr( "ERROR" ), tr( "MSG_ERROR_LIB_BAD_SWITCH" ), tr( "OK" ) );
271 // save EndSwitch function
272 saveStrings( doc, element, FUNC_ES_NAME_ATT, aEndSwitchNode->PyFuncName(), FUNC_ES_ELEMENT, aEndSwitchNode->PyFunction() );
274 // save ports of EndSwitch
275 SUPERV::ListOfPorts_var aESPorts = aEndSwitchNode->Ports();
276 for ( int i = 0, n = aESPorts->length(); i < n; i++) {
277 if ( !CORBA::is_nil( aESPorts[i] ) && !aESPorts[i]->IsGate() ) {
278 QDomElement portElement = doc.createElement( ES_PORT_ELEMENT );
279 portElement.setAttribute( PORT_INPUT_ATT, aESPorts[i]->IsInput() );
280 portElement.setAttribute( PORT_NAME_ATT, aESPorts[i]->Name() );
281 portElement.setAttribute( PORT_TYPE_ATT, aESPorts[i]->Type() );
282 element.appendChild( portElement );
285 } // end of IsSwitch()
287 // OK, done with file export. write the document to the file
288 libFile.close(); // it seems that QDomDocument opens the file when doing
289 // setContent() and does not close it
290 if ( libFile.open( IO_WriteOnly ) ) { // IO_WriteOnly truncates the file!
291 QTextStream stream( &libFile );
292 doc.save( stream, 0 );
296 else { // error opening library file for final writing
297 SUIT_MessageBox::error1( (QWidget*)(SUIT_Session::session()->activeApplication()->desktop()), tr( "ERROR" ), tr( "MSG_ERROR_LIB_WRITE" ), tr( "OK" ) );
304 // should get here only in case of exception
305 SUIT_MessageBox::error1( (QWidget*)(SUIT_Session::session()->activeApplication()->desktop()), tr( "ERROR" ), tr( "MSG_ERROR_EXPORT_EXCEPTION" ), tr( "OK" ) );
310 * Returns in out parameters Py function name and Py function body
312 void getStrings( QDomElement element, const char* pyFuncName, QString& thePyFuncName,
313 const char* theFuncElem, SUPERV::ListOfStrings_var& pyFunc ) {
314 QDomNamedNodeMap aNodeAtt = element.attributes();
315 if ( !aNodeAtt.namedItem( pyFuncName ).isNull() ) { // if pyFuncName is found - fill pyFunc.
316 thePyFuncName = aNodeAtt.namedItem( pyFuncName ).nodeValue();
318 // every 'theFuncElem' element has a CDATA child - one line
319 // iterate through all of them twice: 1) to count the number of these items (number of strings)
320 // 2) to fill pyFunc out-parameter
322 QDomNode n = element.firstChild();
323 while ( !n.isNull() ) {
324 if ( n.isElement() && n.nodeName() == theFuncElem && n.firstChild().isCDATASection() )
329 pyFunc->length( nStrings );
332 n = element.firstChild();
333 while ( !n.isNull() ) {
334 if ( n.isElement() && n.nodeName() == theFuncElem && n.firstChild().isCDATASection() ) {
335 QDomCDATASection aCDATA = n.firstChild().toCDATASection();
336 pyFunc[i++] = aCDATA.nodeValue();
340 } // if ( pyFuncName )
343 * Adds ports stored in Dom node to the CNode
345 void addPorts( SUPERV::INode_var theINode, QDomElement element, const char* portElement ) {
346 QDomNodeList aPorts = element.elementsByTagName( portElement );
347 for ( int i = 0, n = aPorts.length(); i < n; i++ ) {
348 QDomNode aPort = aPorts.item( i );
349 QDomNamedNodeMap anAtt = aPort.attributes();
350 bool isInput = ( anAtt.namedItem( PORT_INPUT_ATT ).nodeValue() == "1" );
351 QString portName = anAtt.namedItem( PORT_NAME_ATT ).nodeValue();
352 QString portType = anAtt.namedItem( PORT_TYPE_ATT ).nodeValue();
354 theINode->InPort( portName.latin1(), portType.latin1() );
356 theINode->OutPort( portName.latin1(), portType.latin1() );
361 * Import an InLine node from Library into the dataflow
363 bool SUPERVGUI_Library::Import( SUPERV::Graph_var theDataflow, SUPERV::INode_var& theNode,
364 SUPERV::INode_var& theEndNode, const int i ) const {
368 if ( getNodes( doc, aNodes ) ) { // xml is ok
369 if ( i >=0 && i < aNodes.length() ) { // index is ok
370 // 1. retrieve the node with given index
371 QDomElement aNode = aNodes.item( i ).toElement();
372 // 2. create an Engines node
373 QDomNamedNodeMap aNodeAtt = aNode.attributes();
374 const int aKind = aNodeAtt.namedItem( NODE_KIND_ATT ).nodeValue().toInt();
375 QString aNodeName = aNodeAtt.namedItem( NODE_NAME_ATT ).nodeValue();
377 case SUPERV::InLineNode : // PyFunction
378 case SUPERV::GOTONode :
380 // get all the Python function
382 SUPERV::ListOfStrings_var aPyFunc = new SUPERV::ListOfStrings();
383 getStrings( aNode, FUNC_NAME_ATT, aPyFuncName, FUNC_ELEMENT, aPyFunc );
385 // create the corresponding Engines node
386 SUPERV::INode_var aINode;
387 if ( aKind == SUPERV::InLineNode )
388 aINode = theDataflow->INode( aPyFuncName.latin1(), aPyFunc );
390 aINode = theDataflow->GNode( aPyFuncName.latin1(), aPyFunc, "" );
392 aINode->SetName( aNodeName.latin1() ); // try to set the same name of node (might be changed by CNode::SetName)
393 addPorts( aINode, aNode, PORT_ELEMENT ); // add stored ports
395 theNode = aINode; // init out-parameter
398 case SUPERV::LoopNode : // PyInit, PyNext, PyMore, PyEndLoopFunction
400 // get all required Python function
401 QString aInitName, aMoreName, aNextName, aELName;
402 SUPERV::ListOfStrings_var aInitFunc = new SUPERV::ListOfStrings(),
403 aMoreFunc = new SUPERV::ListOfStrings(),
404 aNextFunc = new SUPERV::ListOfStrings(),
405 aELFunc = new SUPERV::ListOfStrings();
406 getStrings( aNode, FUNC_INIT_NAME_ATT, aInitName, FUNC_INIT_ELEMENT, aInitFunc );
407 getStrings( aNode, FUNC_MORE_NAME_ATT, aMoreName, FUNC_MORE_ELEMENT, aMoreFunc );
408 getStrings( aNode, FUNC_NEXT_NAME_ATT, aNextName, FUNC_NEXT_ELEMENT, aNextFunc );
409 getStrings( aNode, FUNC_EL_NAME_ATT, aELName, FUNC_EL_ELEMENT, aELFunc );
411 // create Engines Loop node
412 SUPERV::INode_var aELNode;
413 SUPERV::INode_var aINode = theDataflow->LNode( aInitName.latin1(), aInitFunc,
414 aMoreName.latin1(), aMoreFunc,
415 aNextName.latin1(), aNextFunc, aELNode );
416 // EndLoop node may have or may NOT have pyFunc. set it if it was stored.
417 if ( !aELName.isEmpty() )
418 aELNode->SetPyFunction( aELName.latin1(), aELFunc );
420 aINode->SetName( aNodeName.latin1() );// try to set the same name of node (might be changed by CNode::SetName)
421 addPorts( aINode, aNode, PORT_ELEMENT ); // add stored ports
423 theNode = aINode; // init out-parameters
424 theEndNode = aELNode;
427 case SUPERV::SwitchNode : // PyFunction, PyESFunction, ESPorts
429 // get all required Python function
430 QString aPyFuncName, aESPyFuncName;
431 SUPERV::ListOfStrings_var aPyFunc = new SUPERV::ListOfStrings(),
432 aESPyFunc = new SUPERV::ListOfStrings();
433 getStrings( aNode, FUNC_NAME_ATT, aPyFuncName, FUNC_ELEMENT, aPyFunc );
434 getStrings( aNode, FUNC_ES_NAME_ATT, aESPyFuncName, FUNC_ES_ELEMENT, aESPyFunc );
436 // create Engines Switch node
437 SUPERV::INode_var aESNode;
438 SUPERV::INode_var aINode = theDataflow->SNode( aPyFuncName.latin1(), aPyFunc, aESNode );
440 // EndSwitch node may have or may NOT have pyFunc
441 if ( !aESPyFuncName.isEmpty() )
442 aESNode->SetPyFunction( aESPyFuncName.latin1(), aESPyFunc );
444 aINode->SetName( aNodeName.latin1() );// try to set the same name of node (might be changed by CNode::SetName)
445 addPorts( aINode, aNode, PORT_ELEMENT ); // add stored ports
446 addPorts( aESNode, aNode, ES_PORT_ELEMENT ); // add stores ports of EndSwitch
448 theNode = aINode; // init out-parameters
449 theEndNode = aESNode;
452 default: // wrong kind of node error
453 SUIT_MessageBox::error1( (QWidget*)(SUIT_Session::session()->activeApplication()->desktop()), tr( "ERROR" ), tr( "MSG_ERROR_IMPORT_BAD_KIND_OF_NODE" ), tr( "OK" ) );
455 } // switch ( kind_of_node )
456 } // if ( index >= 0...)
458 SUIT_MessageBox::error1( (QWidget*)(SUIT_Session::session()->activeApplication()->desktop()), tr( "ERROR" ), tr( "MSG_ERROR_IMPORT_BAD_INDEX" ), tr( "OK" ) );
460 } // if ( getNodes() )
462 return false; // no MB, getNodes() in case of errors displays MB itself
468 // Normally we get here ONLY if an exception occured. All other paths of execution must return before.
469 // But - who knows, maybe we can get here by some other means.. anyway, it's an error and we report it here
470 SUIT_MessageBox::error1( (QWidget*)(SUIT_Session::session()->activeApplication()->desktop()), tr( "ERROR" ), tr( "MSG_ERROR_IMPORT_EXCEPTION" ), tr( "OK" ) );
475 * Returns list of NODE_ELEMENT-s and error result (false) if failed (also displays MB)
477 bool SUPERVGUI_Library::getNodes( QDomDocument& doc, QDomNodeList& theNodes ) const {
478 QFile libFile( GetLibraryFileName() ); // open existing library file
479 if ( !libFile.exists() ) {
480 SUIT_MessageBox::error1( (QWidget*)(SUIT_Session::session()->activeApplication()->desktop()), tr( "ERROR" ), tr( "MSG_ERROR_IMPORT_LIB_NO_XML" ), tr( "OK" ) );
484 // create the main XML document object
485 QString docName( DOCTYPE ) ;
486 doc = QDomDocument( docName );
487 bool xmlOk = doc.setContent( &libFile );
488 // check XML for validity: 1) find root element with predefined name 2) check xml doctype
490 xmlOk = ( doc.doctype().name() == DOCTYPE && doc.elementsByTagName( ROOT_ELEMENT ).length() == 1 );
492 SUIT_MessageBox::error1( (QWidget*)(SUIT_Session::session()->activeApplication()->desktop()), tr( "ERROR" ), tr( "MSG_ERROR_IMPORT_LIB_BAD_XML" ), tr( "OK" ) );
496 theNodes = doc.elementsByTagName( NODE_ELEMENT );
501 * Remove an InLine node with given index from Library
503 bool SUPERVGUI_Library::Remove( const int i ) const {
506 if ( getNodes( doc, aNodes ) && doc.elementsByTagName( ROOT_ELEMENT ).length() == 1 ) { // xml is ok
507 if ( i >=0 && i < aNodes.length() ) {
508 // 1. remove the child element (node) from Dom Document
509 QDomElement root = doc.elementsByTagName( ROOT_ELEMENT ).item( 0 ).toElement();
510 root.removeChild( aNodes.item( i ) );
511 // 2. write the modified document to the file
512 QFile libFile( GetLibraryFileName() );
513 if ( libFile.open( IO_WriteOnly | IO_Truncate ) ) {
514 QTextStream stream( &libFile );
515 doc.save( stream, 0 );
525 * Returns a string descriptor of KindOfNode enumeration
527 QString getKindStr( const QString& theKind ) {
528 switch ( theKind.toInt() ) {
529 case SUPERV::InLineNode : return "InLine";
530 case SUPERV::LoopNode : return "Loop";
531 case SUPERV::SwitchNode : return "Switch";
532 case SUPERV::GOTONode : return "GOTO";
533 case SUPERV::FactoryNode :
534 case SUPERV::DataFlowGraph :
535 case SUPERV::ComputingNode :
536 case SUPERV::EndLoopNode :
537 case SUPERV::EndSwitchNode :
538 case SUPERV::DataStreamGraph :
539 case SUPERV::MacroNode :
540 case SUPERV::UnknownNode :
544 return "INCORRECT kind";
548 * returns a list of node names currently stored in the library. Indexes of the nodes in
549 * this list can be used for futher calls to Import(.., index)
551 SUPERV::ListOfStrings SUPERVGUI_Library::GetLibraryNodesNames() const {
552 SUPERV::ListOfStrings aNodesNames;
553 aNodesNames.length( 0 );
557 if ( !getNodes( doc, aNodes ) )
560 const int n = aNodes.length();
561 aNodesNames.length( n );
563 for ( int i = 0; i < n; i++ ) {
564 QString aNodeName( "" );
565 aNode = aNodes.item( i );
566 if ( !aNode.isNull() ) {
567 QDomNode aNameAtt = aNode.attributes().namedItem( NODE_NAME_ATT );
568 QDomNode aTypeAtt = aNode.attributes().namedItem( NODE_KIND_ATT );
569 if ( !aNameAtt.isNull() && !aTypeAtt.isNull() ) {
570 aNodeName = QString( "%1 ( %2 )" ).arg( aNameAtt.toAttr().value() ).arg(
571 getKindStr( aTypeAtt.toAttr().value() ) );
574 // if NodeName attribute was not found or some error (NULL node),
575 // then an empty string is added for that index in the list
576 aNodesNames[i] = aNodeName.latin1();
583 * returns status of library: false indicates that library file does not exist or can not be opened
585 bool SUPERVGUI_Library::CanImport() const {
589 return getNodes( doc, aNodes );
601 * Inline nodes library management dialog. constructor.
603 SUPERVGUI_LibDlg::SUPERVGUI_LibDlg( QWidget* parent, int& theX, int& theY )
604 :QDialog( parent, "SUPERVGUI_LibDlg", true, WStyle_Customize | WStyle_NormalBorder | WStyle_Title | WStyle_SysMenu),
605 myX( theX ), myY( theY )
607 setSizeGripEnabled( true );
608 setCaption(tr("TIT_LIB_DLG"));
610 QGridLayout* aMainLayout = new QGridLayout( this, 4, 4, 11, 6 );
612 myLB = new QListBox( this );
614 QPushButton* anAddBtn = new QPushButton( tr("TIT_ADDFNODE"), this );
615 connect( anAddBtn, SIGNAL( clicked() ), this, SLOT( add() ) );
616 QPushButton* aRemBtn = new QPushButton( tr("BUT_REMOVE"), this );
617 connect( aRemBtn, SIGNAL( clicked() ), this, SLOT( remove() ) );
619 aMainLayout->addMultiCellWidget( myLB, 0, 2, 0, 2 );
620 aMainLayout->addWidget( anAddBtn, 0, 3 );
621 aMainLayout->addWidget( aRemBtn, 1, 3 );
623 QGroupBox* aBtnBox = new QGroupBox( 0, Qt::Vertical, this );
624 aBtnBox->layout()->setSpacing( 0 ); aBtnBox->layout()->setMargin( 0 );
625 QHBoxLayout* aBtnLayout = new QHBoxLayout( aBtnBox->layout() );
626 aBtnLayout->setAlignment( Qt::AlignTop );
627 aBtnLayout->setSpacing( 6 ); aBtnLayout->setMargin( 11 );
629 QPushButton* aCloseBtn = new QPushButton( tr("BUT_CLOSE"), aBtnBox );
630 connect( aCloseBtn, SIGNAL( clicked() ), this, SLOT( reject() ) );
631 aBtnLayout->addStretch();
632 aBtnLayout->addWidget( aCloseBtn );
633 aBtnLayout->addStretch();
635 aMainLayout->addMultiCellWidget( aBtnBox, 3, 3, 0, 3 );
636 aMainLayout->setRowStretch( 2, 1 );
642 * Inline nodes library management dialog. destructor.
644 SUPERVGUI_LibDlg::~SUPERVGUI_LibDlg() {}
647 * Called when user presses "Add" button. Add a selected node from library to graph
649 void SUPERVGUI_LibDlg::add() {
650 const int i = myLB->currentItem();
651 if ( i >= 0 && i < myLB->count() ) {
652 SUPERVGUI* aSupMod = SUPERVGUI::Supervision();
654 MESSAGE("NULL Supervision module!");
657 SUPERV::Graph_var aDataflow = aSupMod->getMain()->getDataflow();
658 SUPERV::INode_var aNode, aEndNode;
659 if ( SUPERVGUI_Library::getLibrary()->Import( aDataflow, aNode, aEndNode, i ) ) {
660 SUPERVGUI_Service::addNode( SUPERV::CNode::_narrow( aNode ), aEndNode, myX, myY );
661 aSupMod->getMain()->sync();
663 else { // all errors must be reported to user in Import(), MB shown, etc..
664 } // so we don't need to report errors if Import() returned false.
669 * Called when user presses "Remove" button. Remove a selected node from library
671 void SUPERVGUI_LibDlg::remove() {
672 const int i = myLB->currentItem();
673 if ( i >= 0 && i < myLB->count() ) {
674 SUPERVGUI_Library::getLibrary()->Remove( i );
675 initList(); // re-initialize the list to reflect the changes
680 * Fills the list with names of nodes currently stored in the library. Indexes in the list
681 * can be used for calls to Library::Import()
683 void SUPERVGUI_LibDlg::initList() {
685 SUPERV::ListOfStrings aNodesNames = SUPERVGUI_Library::getLibrary()->GetLibraryNodesNames();
686 for ( int i = 0, n = aNodesNames.length(); i < n; i++ )
687 myLB->insertItem( (const char*)aNodesNames[i] );