From: asv Date: Tue, 28 Dec 2004 07:01:10 +0000 (+0000) Subject: Import and Export of InLine nodes to Library (external file) is implemented. This... X-Git-Url: http://git.salome-platform.org/gitweb/?a=commitdiff_plain;h=91e74443c3007401e5cf9303978d232868d39f85;p=modules%2Fsuperv.git Import and Export of InLine nodes to Library (external file) is implemented. This integration has all functionality done. --- diff --git a/src/SUPERVGUI/SUPERVGUI_Library.cxx b/src/SUPERVGUI/SUPERVGUI_Library.cxx index 0972fd5..f42463b 100644 --- a/src/SUPERVGUI/SUPERVGUI_Library.cxx +++ b/src/SUPERVGUI/SUPERVGUI_Library.cxx @@ -27,6 +27,8 @@ #include "SUPERVGUI_Library.h" +#include "SUPERVGUI_Main.h" +#include "SUPERVGUI.h" #include "QAD_MessageBox.h" #include "QAD_Application.h" @@ -35,7 +37,6 @@ #include #include #include -#include #include using namespace std; @@ -44,6 +45,8 @@ using namespace std; #define DOCTYPE "InLineNodesLibrary" // XML DocType #define ROOT_ELEMENT "inlinenodeslibrary" // XML Element and Attribute tags (many) #define NODE_ELEMENT "INode" +#define NODE_NAME_ATT "Name" +#define NODE_KIND_ATT "Kind" #define PORT_ELEMENT "Port" #define ES_PORT_ELEMENT "ESPort" #define PORT_INPUT_ATT "IsInput" @@ -92,7 +95,7 @@ bool SUPERVGUI_Library::createLibFile() const { QDomDocument doc( DOCTYPE ); // create a simple XML stub doc.appendChild( doc.createElement( ROOT_ELEMENT ) ); // IMPORTANT: do not delete this root element QTextStream stream( &libFile ); - stream << doc.toString(); + doc.save( stream, 0 ); libFile.close(); return true; } @@ -130,147 +133,420 @@ void saveStrings( QDomDocument doc, QDomElement element, const char* theNameAtt, * Export an InLine node to Library */ bool SUPERVGUI_Library::Export( SUPERV::INode_var theNode ) const { - if ( CORBA::is_nil( theNode ) ) { - QAD_MessageBox::error1( (QWidget*)QAD_Application::getDesktop(), tr( "ERROR" ), tr( "MSG_ERROR_LIB_NIL_NODE" ), tr( "OK" ) ); - return false; // null node - } - - // open existing library file or create a new one and set some empty XML content - QFile libFile( GetLibraryFileName() ); - if ( !libFile.exists() ) { // new library - if ( !createLibFile() ) - return false; // error opening library file for writing. MB was already displayed - } + try { + if ( CORBA::is_nil( theNode ) ) { + QAD_MessageBox::error1( (QWidget*)QAD_Application::getDesktop(), tr( "ERROR" ), tr( "MSG_ERROR_LIB_NIL_NODE" ), tr( "OK" ) ); + return false; // null node + } - // create the main XML document object - QString docName( DOCTYPE ) ; - QDomDocument doc( docName ); - bool xmlOk = doc.setContent( &libFile ); - if ( xmlOk ) - xmlOk = ( doc.elementsByTagName( ROOT_ELEMENT ).length() == 1 ); // find "root" element - QDomNode rootElement; - if ( xmlOk ) { - rootElement = doc.elementsByTagName( ROOT_ELEMENT ).item( 0 ); - xmlOk = ( !rootElement.isNull() ); - } - if ( !xmlOk ) { - const int toRecreate = QAD_MessageBox::error2( (QWidget*)QAD_Application::getDesktop(), tr( "ERROR" ), - tr( "MSG_ERROR_LIB_IS_RECREATE" ), tr( "BUT_YES" ), tr( "BUT_NO" ), 1, 0, 0 ); - if ( toRecreate ) { // user selected to recreate a bad XML file - libFile.close(); // in case it was opened by doc.setContent() + // open existing library file or create a new one and set some empty XML content + QFile libFile( GetLibraryFileName() ); + if ( !libFile.exists() ) { // new library if ( !createLibFile() ) return false; // error opening library file for writing. MB was already displayed - - // library file was successfully recreated. now re-set content, init rooElement. No checking - it MUST be OK. - libFile.setName( GetLibraryFileName() ); // IMPORTANT: re-read the file - doc.setContent( &libFile ); + } + + // create the main XML document object + QString docName( DOCTYPE ) ; + QDomDocument doc( docName ); + bool xmlOk = doc.setContent( &libFile ); + if ( xmlOk ) + xmlOk = ( doc.elementsByTagName( ROOT_ELEMENT ).length() == 1 ); // find "root" element + QDomNode rootElement; + if ( xmlOk ) { rootElement = doc.elementsByTagName( ROOT_ELEMENT ).item( 0 ); + xmlOk = ( !rootElement.isNull() ); + } + if ( !xmlOk ) { + const int toRecreate = QAD_MessageBox::error2( (QWidget*)QAD_Application::getDesktop(), tr( "ERROR" ), + tr( "MSG_ERROR_LIB_IS_RECREATE" ), tr( "BUT_YES" ), tr( "BUT_NO" ), 1, 0, 0 ); + if ( toRecreate ) { // user selected to recreate a bad XML file + libFile.close(); // in case it was opened by doc.setContent() + if ( !createLibFile() ) + return false; // error opening library file for writing. MB was already displayed + + // library file was successfully recreated. now re-set content, init rooElement. No checking - it MUST be OK. + libFile.setName( GetLibraryFileName() ); // IMPORTANT: re-read the file + doc.setContent( &libFile ); // no checking of setContent() and find root element is done, since we are sure + rootElement = doc.elementsByTagName( ROOT_ELEMENT ).item( 0 ); // that in newly created file everything is OK + } + else // user chose not to recreate a bad library file + return false; // library file is corrupt (bad XML structure), don't recreate } - else // user chose not to recreate a bad library file - return false; // library file is corrupt (bad XML structure), don't recreate - } - // if theNode is EndSwitch or EndLoop -> first export Switch or Loop node - if ( theNode->IsEndLoop() || theNode->IsEndSwitch() ) { - SUPERV::GNode_var aTmpNode = SUPERV::GNode::_narrow( theNode ); - theNode = aTmpNode->Coupled(); - if ( CORBA::is_nil( theNode ) ) { - QAD_MessageBox::error1( (QWidget*)QAD_Application::getDesktop(), tr( "ERROR" ), tr( "MSG_ERROR_LIB_NIL_COUPLED" ), tr( "OK" ) ); - return false; // null coupled node + // if theNode is EndSwitch or EndLoop -> first export Switch or Loop node + if ( theNode->IsEndLoop() || theNode->IsEndSwitch() ) { + SUPERV::GNode_var aTmpNode = SUPERV::GNode::_narrow( theNode ); + theNode = aTmpNode->Coupled(); + if ( CORBA::is_nil( theNode ) ) { + QAD_MessageBox::error1( (QWidget*)QAD_Application::getDesktop(), tr( "ERROR" ), tr( "MSG_ERROR_LIB_NIL_COUPLED" ), tr( "OK" ) ); + return false; // null coupled node + } } - } - // create element under main document - QDomElement element = doc.createElement( NODE_ELEMENT ) ; - rootElement.appendChild( element ); - - // save the 'main' Py function of the node - saveStrings( doc, element, FUNC_NAME_ATT, theNode->PyFuncName(), FUNC_ELEMENT, theNode->PyFunction() ); - - // create DOM elements for ports - SUPERV::ListOfPorts_var aPorts = theNode->Ports(); - for ( int i = 0, n = aPorts->length(); i < n; i++) { - if ( !CORBA::is_nil( aPorts[i] ) && !aPorts[i]->IsGate() ) { - QDomElement portElement = doc.createElement( PORT_ELEMENT ); - portElement.setAttribute( PORT_INPUT_ATT, aPorts[i]->IsInput() ); - portElement.setAttribute( PORT_NAME_ATT, aPorts[i]->Name() ); - portElement.setAttribute( PORT_TYPE_ATT, aPorts[i]->Type() ); - element.appendChild( portElement ); + // create element under main document + QDomElement element = doc.createElement( NODE_ELEMENT ) ; + rootElement.appendChild( element ); + + // save node's name and kind + element.setAttribute( NODE_NAME_ATT, theNode->Name() ); + element.setAttribute( NODE_KIND_ATT, theNode->Kind() ); + // save the 'main' Py function of the node + saveStrings( doc, element, FUNC_NAME_ATT, theNode->PyFuncName(), FUNC_ELEMENT, theNode->PyFunction() ); + + // create DOM elements for ports + SUPERV::ListOfPorts_var aPorts = theNode->Ports(); + for ( int i = 0, n = aPorts->length(); i < n; i++) { + if ( !CORBA::is_nil( aPorts[i] ) && !aPorts[i]->IsGate() ) { + QDomElement portElement = doc.createElement( PORT_ELEMENT ); + portElement.setAttribute( PORT_INPUT_ATT, aPorts[i]->IsInput() ); + portElement.setAttribute( PORT_NAME_ATT, aPorts[i]->Name() ); + portElement.setAttribute( PORT_TYPE_ATT, aPorts[i]->Type() ); + element.appendChild( portElement ); + } } - } - // if the node is Loop -> additionally export Init(), More(), Next() and EndLoop's function - if ( theNode->IsLoop() ) { - SUPERV::LNode_var aLoopNode = SUPERV::LNode::_narrow( theNode ); - if ( CORBA::is_nil( aLoopNode ) ) { - QAD_MessageBox::error1( (QWidget*)QAD_Application::getDesktop(), tr( "ERROR" ), tr( "MSG_ERROR_LIB_BAD_LOOP" ), tr( "OK" ) ); - return false; - } - SUPERV::INode_var aEndLoopNode = aLoopNode->Coupled(); - if ( CORBA::is_nil( aEndLoopNode ) ) { - QAD_MessageBox::error1( (QWidget*)QAD_Application::getDesktop(), tr( "ERROR" ), tr( "MSG_ERROR_LIB_BAD_LOOP" ), tr( "OK" ) ); + // if the node is Loop -> additionally export Init(), More(), Next() and EndLoop's function + if ( theNode->IsLoop() ) { + SUPERV::LNode_var aLoopNode = SUPERV::LNode::_narrow( theNode ); + if ( CORBA::is_nil( aLoopNode ) ) { + QAD_MessageBox::error1( (QWidget*)QAD_Application::getDesktop(), tr( "ERROR" ), tr( "MSG_ERROR_LIB_BAD_LOOP" ), tr( "OK" ) ); + return false; + } + SUPERV::INode_var aEndLoopNode = aLoopNode->Coupled(); + if ( CORBA::is_nil( aEndLoopNode ) ) { + QAD_MessageBox::error1( (QWidget*)QAD_Application::getDesktop(), tr( "ERROR" ), tr( "MSG_ERROR_LIB_BAD_LOOP" ), tr( "OK" ) ); + return false; + } + // save init, more, next, end-loop functions of the Loop node + saveStrings( doc, element, FUNC_INIT_NAME_ATT, aLoopNode->PyInitName(), FUNC_INIT_ELEMENT, aLoopNode->PyInit() ); + saveStrings( doc, element, FUNC_MORE_NAME_ATT, aLoopNode->PyMoreName(), FUNC_MORE_ELEMENT, aLoopNode->PyMore() ); + saveStrings( doc, element, FUNC_NEXT_NAME_ATT, aLoopNode->PyNextName(), FUNC_NEXT_ELEMENT, aLoopNode->PyNext() ); + saveStrings( doc, element, FUNC_EL_NAME_ATT, aEndLoopNode->PyFuncName(), FUNC_EL_ELEMENT, aEndLoopNode->PyFunction() ); + } + + // if the node is Switch -> additionally export EndSwitch's function and ports + if ( theNode->IsSwitch() ) { + SUPERV::SNode_var aSwitchNode = SUPERV::SNode::_narrow( theNode ); + if ( CORBA::is_nil( aSwitchNode ) ) { + QAD_MessageBox::error1( (QWidget*)QAD_Application::getDesktop(), tr( "ERROR" ), tr( "MSG_ERROR_LIB_BAD_SWITCH" ), tr( "OK" ) ); + return false; + } + SUPERV::INode_var aEndSwitchNode = aSwitchNode->Coupled(); + if ( CORBA::is_nil( aEndSwitchNode ) ) { + QAD_MessageBox::error1( (QWidget*)QAD_Application::getDesktop(), tr( "ERROR" ), tr( "MSG_ERROR_LIB_BAD_SWITCH" ), tr( "OK" ) ); + return false; + } + // save EndSwitch function + saveStrings( doc, element, FUNC_ES_NAME_ATT, aEndSwitchNode->PyFuncName(), FUNC_ES_ELEMENT, aEndSwitchNode->PyFunction() ); + + // save ports of EndSwitch + SUPERV::ListOfPorts_var aESPorts = aEndSwitchNode->Ports(); + for ( int i = 0, n = aESPorts->length(); i < n; i++) { + if ( !CORBA::is_nil( aESPorts[i] ) && !aESPorts[i]->IsGate() ) { + QDomElement portElement = doc.createElement( ES_PORT_ELEMENT ); + portElement.setAttribute( PORT_INPUT_ATT, aESPorts[i]->IsInput() ); + portElement.setAttribute( PORT_NAME_ATT, aESPorts[i]->Name() ); + portElement.setAttribute( PORT_TYPE_ATT, aESPorts[i]->Type() ); + element.appendChild( portElement ); + } + } + } // end of IsSwitch() + + // OK, done with file export. write the document to the file + libFile.close(); // it seems that QDomDocument opens the file when doing + // setContent() and does not close it + if ( libFile.open( IO_WriteOnly ) ) { // IO_WriteOnly truncates the file! + QTextStream stream( &libFile ); + doc.save( stream, 0 ); + libFile.close(); + return true; + } + else { // error opening library file for final writing + QAD_MessageBox::error1( (QWidget*)QAD_Application::getDesktop(), tr( "ERROR" ), tr( "MSG_ERROR_LIB_WRITE" ), tr( "OK" ) ); return false; - } - // save init, more, next, end-loop functions of the Loop node - saveStrings( doc, element, FUNC_INIT_NAME_ATT, aLoopNode->PyInitName(), FUNC_INIT_ELEMENT, aLoopNode->PyInit() ); - saveStrings( doc, element, FUNC_MORE_NAME_ATT, aLoopNode->PyMoreName(), FUNC_MORE_ELEMENT, aLoopNode->PyMore() ); - saveStrings( doc, element, FUNC_NEXT_NAME_ATT, aLoopNode->PyNextName(), FUNC_NEXT_ELEMENT, aLoopNode->PyNext() ); - saveStrings( doc, element, FUNC_EL_NAME_ATT, aEndLoopNode->PyFuncName(), FUNC_EL_ELEMENT, aEndLoopNode->PyFunction() ); + } + } // try + catch ( ... ) { } - // if the node is Switch -> additionally export EndSwitch's function and ports - if ( theNode->IsSwitch() ) { - SUPERV::SNode_var aSwitchNode = SUPERV::SNode::_narrow( theNode ); - if ( CORBA::is_nil( aSwitchNode ) ) { - QAD_MessageBox::error1( (QWidget*)QAD_Application::getDesktop(), tr( "ERROR" ), tr( "MSG_ERROR_LIB_BAD_SWITCH" ), tr( "OK" ) ); - return false; - } - SUPERV::INode_var aEndSwitchNode = aSwitchNode->Coupled(); - if ( CORBA::is_nil( aEndSwitchNode ) ) { - QAD_MessageBox::error1( (QWidget*)QAD_Application::getDesktop(), tr( "ERROR" ), tr( "MSG_ERROR_LIB_BAD_SWITCH" ), tr( "OK" ) ); - return false; - } - // save EndSwitch function - saveStrings( doc, element, FUNC_ES_NAME_ATT, aEndSwitchNode->PyFuncName(), FUNC_ES_ELEMENT, aEndSwitchNode->PyFunction() ); - - // save ports of EndSwitch - SUPERV::ListOfPorts_var aESPorts = aEndSwitchNode->Ports(); - for ( int i = 0, n = aESPorts->length(); i < n; i++) { - if ( !CORBA::is_nil( aESPorts[i] ) && !aESPorts[i]->IsGate() ) { - QDomElement portElement = doc.createElement( ES_PORT_ELEMENT ); - portElement.setAttribute( PORT_INPUT_ATT, aESPorts[i]->IsInput() ); - portElement.setAttribute( PORT_NAME_ATT, aESPorts[i]->Name() ); - portElement.setAttribute( PORT_TYPE_ATT, aESPorts[i]->Type() ); - element.appendChild( portElement ); + // should get here only in case of exception + QAD_MessageBox::error1( (QWidget*)QAD_Application::getDesktop(), tr( "ERROR" ), tr( "MSG_ERROR_EXPORT_EXCEPTION" ), tr( "OK" ) ); + return false; +} + +/** + * Returns in out parameters Py function name and Py function body + */ +void getStrings( QDomElement element, const char* pyFuncName, QString& thePyFuncName, + const char* theFuncElem, SUPERV::ListOfStrings_var& pyFunc ) { + QDomNamedNodeMap aNodeAtt = element.attributes(); + if ( !aNodeAtt.namedItem( pyFuncName ).isNull() ) { // if pyFuncName is found - fill pyFunc. + thePyFuncName = aNodeAtt.namedItem( pyFuncName ).nodeValue(); + + // every 'theFuncElem' element has a CDATA child - one line + // iterate through all of them twice: 1) to count the number of these items (number of strings) + // 2) to fill pyFunc out-parameter + int nStrings( 0 ); + QDomNode n = element.firstChild(); + while ( !n.isNull() ) { + if ( n.isElement() && n.nodeName() == theFuncElem && n.firstChild().isCDATASection() ) + nStrings++; + n = n.nextSibling(); + } + + pyFunc->length( nStrings ); + + int i( 0 ); + n = element.firstChild(); + while ( !n.isNull() ) { + if ( n.isElement() && n.nodeName() == theFuncElem && n.firstChild().isCDATASection() ) { + QDomCDATASection aCDATA = n.firstChild().toCDATASection(); + pyFunc[i++] = aCDATA.nodeValue(); } + n = n.nextSibling(); } - } // end of IsSwitch() - - // OK, done with file export. write the document to the file - libFile.close(); // it seems that QDomDocument opens the file when doing - // setContent() and does not close it - if ( libFile.open( IO_WriteOnly ) ) { // IO_WriteOnly truncates the file! - QTextStream stream( &libFile ); - stream << doc.toString(); - libFile.close(); - return true; + } // if ( pyFuncName ) +} +/** + * Adds ports stored in Dom node to the CNode + */ +void addPorts( SUPERV::INode_var theINode, QDomElement element, const char* portElement ) { + QDomNodeList aPorts = element.elementsByTagName( portElement ); + for ( int i = 0, n = aPorts.length(); i < n; i++ ) { + QDomNode aPort = aPorts.item( i ); + QDomNamedNodeMap anAtt = aPort.attributes(); + bool isInput = ( anAtt.namedItem( PORT_INPUT_ATT ).nodeValue() == "1" ); + QString portName = anAtt.namedItem( PORT_NAME_ATT ).nodeValue(); + QString portType = anAtt.namedItem( PORT_TYPE_ATT ).nodeValue(); + if ( isInput ) + theINode->InPort( portName.latin1(), portType.latin1() ); + else + theINode->OutPort( portName.latin1(), portType.latin1() ); } - else { // error opening library file for final writing - QAD_MessageBox::error1( (QWidget*)QAD_Application::getDesktop(), tr( "ERROR" ), tr( "MSG_ERROR_LIB_WRITE" ), tr( "OK" ) ); +} + +/** + * Import an InLine node from Library into the dataflow + */ +bool SUPERVGUI_Library::Import( SUPERV::Graph_var theDataflow, SUPERV::INode_var& theNode, + SUPERV::INode_var& theEndNode, const int i ) const { + try { + QDomNodeList aNodes; + QDomDocument doc; + if ( getNodes( doc, aNodes ) ) { // xml is ok + if ( i >=0 && i < aNodes.length() ) { // index is ok + // 1. retrieve the node with given index + QDomElement aNode = aNodes.item( i ).toElement(); + // 2. create an Engines node + QDomNamedNodeMap aNodeAtt = aNode.attributes(); + const int aKind = aNodeAtt.namedItem( NODE_KIND_ATT ).nodeValue().toInt(); + QString aNodeName = aNodeAtt.namedItem( NODE_NAME_ATT ).nodeValue(); + switch ( aKind ) { + case SUPERV::InLineNode : // PyFunction + case SUPERV::GOTONode : + { + // get all the Python function + QString aPyFuncName; + SUPERV::ListOfStrings_var aPyFunc = new SUPERV::ListOfStrings(); + getStrings( aNode, FUNC_NAME_ATT, aPyFuncName, FUNC_ELEMENT, aPyFunc ); + + // create the corresponding Engines node + SUPERV::INode_var aINode; + if ( aKind == SUPERV::InLineNode ) + aINode = theDataflow->INode( aPyFuncName.latin1(), aPyFunc ); + else + aINode = theDataflow->GNode( aPyFuncName.latin1(), aPyFunc, "" ); + + aINode->SetName( aNodeName.latin1() ); // try to set the same name of node (might be changed by CNode::SetName) + addPorts( aINode, aNode, PORT_ELEMENT ); // add stored ports + + theNode = aINode; // init out-parameter + return true; + } + case SUPERV::LoopNode : // PyInit, PyNext, PyMore, PyEndLoopFunction + { + // get all required Python function + QString aInitName, aMoreName, aNextName, aELName; + SUPERV::ListOfStrings_var aInitFunc = new SUPERV::ListOfStrings(), + aMoreFunc = new SUPERV::ListOfStrings(), + aNextFunc = new SUPERV::ListOfStrings(), + aELFunc = new SUPERV::ListOfStrings(); + getStrings( aNode, FUNC_INIT_NAME_ATT, aInitName, FUNC_INIT_ELEMENT, aInitFunc ); + getStrings( aNode, FUNC_MORE_NAME_ATT, aMoreName, FUNC_MORE_ELEMENT, aMoreFunc ); + getStrings( aNode, FUNC_NEXT_NAME_ATT, aNextName, FUNC_NEXT_ELEMENT, aNextFunc ); + getStrings( aNode, FUNC_EL_NAME_ATT, aELName, FUNC_EL_ELEMENT, aELFunc ); + + // create Engines Loop node + SUPERV::INode_var aELNode; + SUPERV::INode_var aINode = theDataflow->LNode( aInitName.latin1(), aInitFunc, + aMoreName.latin1(), aMoreFunc, + aNextName.latin1(), aNextFunc, aELNode ); + // EndLoop node may have or may NOT have pyFunc. set it if it was stored. + if ( !aELName.isEmpty() ) + aELNode->SetPyFunction( aELName.latin1(), aELFunc ); + + aINode->SetName( aNodeName.latin1() );// try to set the same name of node (might be changed by CNode::SetName) + addPorts( aINode, aNode, PORT_ELEMENT ); // add stored ports + + theNode = aINode; // init out-parameters + theEndNode = aELNode; + return true; + } + case SUPERV::SwitchNode : // PyFunction, PyESFunction, ESPorts + { + // get all required Python function + QString aPyFuncName, aESPyFuncName; + SUPERV::ListOfStrings_var aPyFunc = new SUPERV::ListOfStrings(), + aESPyFunc = new SUPERV::ListOfStrings(); + getStrings( aNode, FUNC_NAME_ATT, aPyFuncName, FUNC_ELEMENT, aPyFunc ); + getStrings( aNode, FUNC_ES_NAME_ATT, aESPyFuncName, FUNC_ES_ELEMENT, aESPyFunc ); + + // create Engines Switch node + SUPERV::INode_var aESNode; + SUPERV::INode_var aINode = theDataflow->SNode( aPyFuncName.latin1(), aPyFunc, aESNode ); + + // EndSwitch node may have or may NOT have pyFunc + if ( !aESPyFuncName.isEmpty() ) + aESNode->SetPyFunction( aESPyFuncName.latin1(), aESPyFunc ); + + aINode->SetName( aNodeName.latin1() );// try to set the same name of node (might be changed by CNode::SetName) + addPorts( aINode, aNode, PORT_ELEMENT ); // add stored ports + addPorts( aESNode, aNode, ES_PORT_ELEMENT ); // add stores ports of EndSwitch + + theNode = aINode; // init out-parameters + theEndNode = aESNode; + return true; + } + default: // wrong kind of node error + QAD_MessageBox::error1( (QWidget*)QAD_Application::getDesktop(), tr( "ERROR" ), tr( "MSG_ERROR_IMPORT_BAD_KIND_OF_NODE" ), tr( "OK" ) ); + return false; + } // switch ( kind_of_node ) + } // if ( index >= 0...) + else { + QAD_MessageBox::error1( (QWidget*)QAD_Application::getDesktop(), tr( "ERROR" ), tr( "MSG_ERROR_IMPORT_BAD_INDEX" ), tr( "OK" ) ); + } + } // if ( getNodes() ) + else { + return false; // no MB, getNodes() in case of errors displays MB itself + } + } // try + catch ( ... ) { } + + // Normally we get here ONLY if an exception occured. All other paths of execution must return before. + // But - who knows, maybe we can get here by some other means.. anyway, it's an error and we report it here + QAD_MessageBox::error1( (QWidget*)QAD_Application::getDesktop(), tr( "ERROR" ), tr( "MSG_ERROR_IMPORT_EXCEPTION" ), tr( "OK" ) ); return false; } /** - * Import an InLine node from Library into the dataflow + * Returns list of NODE_ELEMENT-s and error result (false) if failed (also displays MB) */ -SUPERV::CNode_var SUPERVGUI_Library::Import( SUPERV::Graph_var theDataflow, const int theLibIndex ) const { - SUPERV::CNode_var aNode; +bool SUPERVGUI_Library::getNodes( QDomDocument& doc, QDomNodeList& theNodes ) const { + QFile libFile( GetLibraryFileName() ); // open existing library file + if ( !libFile.exists() ) { + QAD_MessageBox::error1( (QWidget*)QAD_Application::getDesktop(), tr( "ERROR" ), tr( "MSG_ERROR_IMPORT_LIB_NO_XML" ), tr( "OK" ) ); + return false; + } + + // create the main XML document object + QString docName( DOCTYPE ) ; + doc = QDomDocument( docName ); + bool xmlOk = doc.setContent( &libFile ); + // check XML for validity: 1) find root element with predefined name 2) check xml doctype + if ( xmlOk ) + xmlOk = ( doc.doctype().name() == DOCTYPE && doc.elementsByTagName( ROOT_ELEMENT ).length() == 1 ); + if ( !xmlOk ) { + QAD_MessageBox::error1( (QWidget*)QAD_Application::getDesktop(), tr( "ERROR" ), tr( "MSG_ERROR_IMPORT_LIB_BAD_XML" ), tr( "OK" ) ); + return false; + } - return aNode; + theNodes = doc.elementsByTagName( NODE_ELEMENT ); + return true; } +/** + * Remove an InLine node with given index from Library + */ +bool SUPERVGUI_Library::Remove( const int i ) const { + QDomNodeList aNodes; + QDomDocument doc; + if ( getNodes( doc, aNodes ) && doc.elementsByTagName( ROOT_ELEMENT ).length() == 1 ) { // xml is ok + if ( i >=0 && i < aNodes.length() ) { + // 1. remove the child element (node) from Dom Document + QDomElement root = doc.elementsByTagName( ROOT_ELEMENT ).item( 0 ).toElement(); + root.removeChild( aNodes.item( i ) ); + // 2. write the modified document to the file + QFile libFile( GetLibraryFileName() ); + if ( libFile.open( IO_WriteOnly | IO_Truncate ) ) { + QTextStream stream( &libFile ); + doc.save( stream, 0 ); + libFile.close(); + return true; + } + } + } + return false; +} +/** + * Returns a string descriptor of KindOfNode enumeration + */ +QString getKindStr( const QString& theKind ) { + switch ( theKind.toInt() ) { + case SUPERV::InLineNode : return "InLine"; + case SUPERV::LoopNode : return "Loop"; + case SUPERV::SwitchNode : return "Switch"; + case SUPERV::GOTONode : return "GOTO"; + case SUPERV::FactoryNode : + case SUPERV::DataFlowGraph : + case SUPERV::ComputingNode : + case SUPERV::EndLoopNode : + case SUPERV::EndSwitchNode : + case SUPERV::DataStreamGraph : + case SUPERV::MacroNode : + case SUPERV::UnknownNode : + default: + ; + } + return "INCORRECT kind"; +} + +/** + * returns a list of node names currently stored in the library. Indexes of the nodes in + * this list can be used for futher calls to Import(.., index) + */ +SUPERV::ListOfStrings SUPERVGUI_Library::GetLibraryNodesNames() const { + SUPERV::ListOfStrings aNodesNames; + aNodesNames.length( 0 ); + + QDomNodeList aNodes; + QDomDocument doc; + if ( !getNodes( doc, aNodes ) ) + return aNodesNames; + + const int n = aNodes.length(); + aNodesNames.length( n ); + QDomNode aNode; + for ( int i = 0; i < n; i++ ) { + QString aNodeName( "" ); + aNode = aNodes.item( i ); + if ( !aNode.isNull() ) { + QDomNode aNameAtt = aNode.attributes().namedItem( NODE_NAME_ATT ); + QDomNode aTypeAtt = aNode.attributes().namedItem( NODE_KIND_ATT ); + if ( !aNameAtt.isNull() && !aTypeAtt.isNull() ) { + aNodeName = QString( "%1 ( %2 )" ).arg( aNameAtt.toAttr().value() ).arg( + getKindStr( aTypeAtt.toAttr().value() ) ); + } + } + // if NodeName attribute was not found or some error (NULL node), + // then an empty string is added for that index in the list + aNodesNames[i] = aNodeName.latin1(); + } + + return aNodesNames; +} /** @@ -310,6 +586,8 @@ SUPERVGUI_LibDlg::SUPERVGUI_LibDlg( QWidget* parent, int& theX, int& theY ) aMainLayout->addMultiCellWidget( aBtnBox, 3, 3, 0, 3 ); aMainLayout->setRowStretch( 2, 1 ); + + initList(); } /** @@ -321,12 +599,38 @@ SUPERVGUI_LibDlg::~SUPERVGUI_LibDlg() {} * Called when user presses "Add" button. Add a selected node from library to graph */ void SUPERVGUI_LibDlg::add() { + const int i = myLB->currentItem(); + if ( i >= 0 && i < myLB->count() ) { + SUPERV::Graph_var aDataflow = Supervision.getMain()->getDataflow(); + SUPERV::INode_var aNode, aEndNode; + if ( SUPERVGUI_Library::getLibrary()->Import( aDataflow, aNode, aEndNode, i ) ) { + SUPERVGUI_Service::addNode( SUPERV::CNode::_narrow( aNode ), aEndNode, myX, myY ); + Supervision.getMain()->sync(); + } + else { // all errors must be reported to user in Import(), MB shown, etc.. + } // so we don't need to report errors if Import() returned false. + } } /** * Called when user presses "Remove" button. Remove a selected node from library */ void SUPERVGUI_LibDlg::remove() { + const int i = myLB->currentItem(); + if ( i >= 0 && i < myLB->count() ) { + SUPERVGUI_Library::getLibrary()->Remove( i ); + initList(); // re-initialize the list to reflect the changes + } } +/** + * Fills the list with names of nodes currently stored in the library. Indexes in the list + * can be used for calls to Library::Import() + */ +void SUPERVGUI_LibDlg::initList() { + myLB->clear(); + SUPERV::ListOfStrings aNodesNames = SUPERVGUI_Library::getLibrary()->GetLibraryNodesNames(); + for ( int i = 0, n = aNodesNames.length(); i < n; i++ ) + myLB->insertItem( (const char*)aNodesNames[i] ); +} diff --git a/src/SUPERVGUI/SUPERVGUI_Library.h b/src/SUPERVGUI/SUPERVGUI_Library.h index 840e0be..4999b7b 100644 --- a/src/SUPERVGUI/SUPERVGUI_Library.h +++ b/src/SUPERVGUI/SUPERVGUI_Library.h @@ -29,6 +29,7 @@ #define SUPERVGUI_Library_H #include +#include #include "utilities.h" #include "SALOME_LifeCycleCORBA.hxx" @@ -63,13 +64,24 @@ public: bool Export( SUPERV::INode_var theNode ) const; // Import an InLine node from Library into the dataflow - SUPERV::CNode_var Import( SUPERV::Graph_var theDataflow, const int theLibIndex ) const; + bool Import( SUPERV::Graph_var theDataflow, SUPERV::INode_var& theNode, + SUPERV::INode_var& theEndNode, const int theLibIndex ) const; + + // Remove an InLine node with given index from Library + bool Remove( const int i ) const; + + // returns a list of node names currently stored in the library. Indexes of the nodes in + // this list can be used for futher calls to Import(.., index) + SUPERV::ListOfStrings GetLibraryNodesNames() const; private: static SUPERVGUI_Library* myLibrary; bool createLibFile() const; // returns false on file creation error (also displays MB) + // returns list of NODE_ELEMENT-s and error result (false) if failed (also displays MB) + bool getNodes( QDomDocument& theDoc, QDomNodeList& theNodes ) const; + }; /** @@ -83,6 +95,8 @@ public: SUPERVGUI_LibDlg( QWidget* parent, int& theX, int& theY ); ~SUPERVGUI_LibDlg(); + void initList(); + private slots: void add(); // add selected node from library to graph void remove(); // remove selected node from library