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"
31 #include "QAD_MessageBox.h"
32 #include "QAD_Application.h"
36 #include <qgroupbox.h>
37 #include <qpushbutton.h>
43 #define LIBFILE "/.salome/InLineLibrary.xml" // $HOME+LIBFILE
44 #define DOCTYPE "InLineNodesLibrary" // XML DocType
45 #define ROOT_ELEMENT "inlinenodeslibrary" // XML Element and Attribute tags (many)
46 #define NODE_ELEMENT "INode"
47 #define PORT_ELEMENT "Port"
48 #define ES_PORT_ELEMENT "ESPort"
49 #define PORT_INPUT_ATT "IsInput"
50 #define PORT_NAME_ATT "Name"
51 #define PORT_TYPE_ATT "Type"
53 #define FUNC_NAME_ATT "PyFuncName" // XML attributes and elements
54 #define FUNC_ELEMENT "PyFunc" // for Python functions defined
55 #define FUNC_INIT_NAME_ATT "InitFuncName" // in different types of InLine nodes
56 #define FUNC_INIT_ELEMENT "InitPyFunc"
57 #define FUNC_MORE_NAME_ATT "MoreFuncName"
58 #define FUNC_MORE_ELEMENT "MorePyFunc"
59 #define FUNC_NEXT_NAME_ATT "NextFuncName"
60 #define FUNC_NEXT_ELEMENT "NextPyFunc"
61 #define FUNC_EL_NAME_ATT "ELFuncName" // EndLoop
62 #define FUNC_EL_ELEMENT "ELPyFunc"
63 #define FUNC_ES_NAME_ATT "ESFuncName" // EndSwitch
64 #define FUNC_ES_ELEMENT "ESPyFunc"
67 SUPERVGUI_Library* SUPERVGUI_Library::myLibrary = 0;
70 * Inline nodes library. constructor.
72 SUPERVGUI_Library::SUPERVGUI_Library() {
76 * Returns the XML file name used as InLine nodes repository
78 const char* SUPERVGUI_Library::GetLibraryFileName() const {
79 string aFileName = getenv( "HOME" );
81 return aFileName.c_str();
85 * Creates a new library file, truncates the length to zero, writes an empty
86 * XML stub to it. If fails - displays an error message box and returns false
88 bool SUPERVGUI_Library::createLibFile() const {
89 QFile libFile( GetLibraryFileName() );
91 if ( libFile.open( IO_WriteOnly | IO_Truncate ) ) {
92 QDomDocument doc( DOCTYPE ); // create a simple XML stub
93 doc.appendChild( doc.createElement( ROOT_ELEMENT ) ); // IMPORTANT: do not delete this root element
94 QTextStream stream( &libFile );
95 stream << doc.toString();
100 QAD_MessageBox::error1( (QWidget*)QAD_Application::getDesktop(), tr( "ERROR" ), tr( "MSG_ERROR_LIB1" ), tr( "OK" ) );
101 return false; // error opening library file for writing
105 QAD_MessageBox::error1( (QWidget*)QAD_Application::getDesktop(), tr( "ERROR" ), tr( "MSG_ERROR_LIB_IO" ), tr( "OK" ) );
111 * Save Function Name as attribute of given DomElement, and Function strings as its children with CDATASection
112 * saveStrings() is called to save 'main' Py function of a node, and Init(), More(), Next() for Loop node
114 void saveStrings( QDomDocument doc, QDomElement element, const char* theNameAtt, const char* theFuncName,
115 const char* theFuncElem, SUPERV::ListOfStrings_var pyFunc ) {
116 QString pyFuncName( theFuncName );
117 element.setAttribute( theNameAtt, pyFuncName ); // store Py function name
119 // store Py functions as children of 'element'.
120 for ( int i = 0, n = pyFunc->length(); i < n; i++ ) {
121 QString pyFuncStr( pyFunc[i] );
122 QDomCDATASection aCDATA = doc.createCDATASection( pyFuncStr );
123 QDomElement funcElement = doc.createElement( theFuncElem );
124 element.appendChild( funcElement );
125 funcElement.appendChild( aCDATA );
130 * Export an InLine node to Library
132 bool SUPERVGUI_Library::Export( SUPERV::INode_var theNode ) const {
133 if ( CORBA::is_nil( theNode ) ) {
134 QAD_MessageBox::error1( (QWidget*)QAD_Application::getDesktop(), tr( "ERROR" ), tr( "MSG_ERROR_LIB_NIL_NODE" ), tr( "OK" ) );
135 return false; // null node
138 // open existing library file or create a new one and set some empty XML content
139 QFile libFile( GetLibraryFileName() );
140 if ( !libFile.exists() ) { // new library
141 if ( !createLibFile() )
142 return false; // error opening library file for writing. MB was already displayed
145 // create the main XML document object
146 QString docName( DOCTYPE ) ;
147 QDomDocument doc( docName );
148 bool xmlOk = doc.setContent( &libFile );
150 xmlOk = ( doc.elementsByTagName( ROOT_ELEMENT ).length() == 1 ); // find "root" element
151 QDomNode rootElement;
153 rootElement = doc.elementsByTagName( ROOT_ELEMENT ).item( 0 );
154 xmlOk = ( !rootElement.isNull() );
157 const int toRecreate = QAD_MessageBox::error2( (QWidget*)QAD_Application::getDesktop(), tr( "ERROR" ),
158 tr( "MSG_ERROR_LIB_IS_RECREATE" ), tr( "BUT_YES" ), tr( "BUT_NO" ), 1, 0, 0 );
159 if ( toRecreate ) { // user selected to recreate a bad XML file
160 libFile.close(); // in case it was opened by doc.setContent()
161 if ( !createLibFile() )
162 return false; // error opening library file for writing. MB was already displayed
164 // library file was successfully recreated. now re-set content, init rooElement. No checking - it MUST be OK.
165 libFile.setName( GetLibraryFileName() ); // IMPORTANT: re-read the file
166 doc.setContent( &libFile );
167 rootElement = doc.elementsByTagName( ROOT_ELEMENT ).item( 0 );
169 else // user chose not to recreate a bad library file
170 return false; // library file is corrupt (bad XML structure), don't recreate
173 // if theNode is EndSwitch or EndLoop -> first export Switch or Loop node
174 if ( theNode->IsEndLoop() || theNode->IsEndSwitch() ) {
175 SUPERV::GNode_var aTmpNode = SUPERV::GNode::_narrow( theNode );
176 theNode = aTmpNode->Coupled();
177 if ( CORBA::is_nil( theNode ) ) {
178 QAD_MessageBox::error1( (QWidget*)QAD_Application::getDesktop(), tr( "ERROR" ), tr( "MSG_ERROR_LIB_NIL_COUPLED" ), tr( "OK" ) );
179 return false; // null coupled node
183 // create element under main document
184 QDomElement element = doc.createElement( NODE_ELEMENT ) ;
185 rootElement.appendChild( element );
187 // save the 'main' Py function of the node
188 saveStrings( doc, element, FUNC_NAME_ATT, theNode->PyFuncName(), FUNC_ELEMENT, theNode->PyFunction() );
190 // create DOM elements for ports
191 SUPERV::ListOfPorts_var aPorts = theNode->Ports();
192 for ( int i = 0, n = aPorts->length(); i < n; i++) {
193 if ( !CORBA::is_nil( aPorts[i] ) && !aPorts[i]->IsGate() ) {
194 QDomElement portElement = doc.createElement( PORT_ELEMENT );
195 portElement.setAttribute( PORT_INPUT_ATT, aPorts[i]->IsInput() );
196 portElement.setAttribute( PORT_NAME_ATT, aPorts[i]->Name() );
197 portElement.setAttribute( PORT_TYPE_ATT, aPorts[i]->Type() );
198 element.appendChild( portElement );
202 // if the node is Loop -> additionally export Init(), More(), Next() and EndLoop's function
203 if ( theNode->IsLoop() ) {
204 SUPERV::LNode_var aLoopNode = SUPERV::LNode::_narrow( theNode );
205 if ( CORBA::is_nil( aLoopNode ) ) {
206 QAD_MessageBox::error1( (QWidget*)QAD_Application::getDesktop(), tr( "ERROR" ), tr( "MSG_ERROR_LIB_BAD_LOOP" ), tr( "OK" ) );
209 SUPERV::INode_var aEndLoopNode = aLoopNode->Coupled();
210 if ( CORBA::is_nil( aEndLoopNode ) ) {
211 QAD_MessageBox::error1( (QWidget*)QAD_Application::getDesktop(), tr( "ERROR" ), tr( "MSG_ERROR_LIB_BAD_LOOP" ), tr( "OK" ) );
214 // save init, more, next, end-loop functions of the Loop node
215 saveStrings( doc, element, FUNC_INIT_NAME_ATT, aLoopNode->PyInitName(), FUNC_INIT_ELEMENT, aLoopNode->PyInit() );
216 saveStrings( doc, element, FUNC_MORE_NAME_ATT, aLoopNode->PyMoreName(), FUNC_MORE_ELEMENT, aLoopNode->PyMore() );
217 saveStrings( doc, element, FUNC_NEXT_NAME_ATT, aLoopNode->PyNextName(), FUNC_NEXT_ELEMENT, aLoopNode->PyNext() );
218 saveStrings( doc, element, FUNC_EL_NAME_ATT, aEndLoopNode->PyFuncName(), FUNC_EL_ELEMENT, aEndLoopNode->PyFunction() );
221 // if the node is Switch -> additionally export EndSwitch's function and ports
222 if ( theNode->IsSwitch() ) {
223 SUPERV::SNode_var aSwitchNode = SUPERV::SNode::_narrow( theNode );
224 if ( CORBA::is_nil( aSwitchNode ) ) {
225 QAD_MessageBox::error1( (QWidget*)QAD_Application::getDesktop(), tr( "ERROR" ), tr( "MSG_ERROR_LIB_BAD_SWITCH" ), tr( "OK" ) );
228 SUPERV::INode_var aEndSwitchNode = aSwitchNode->Coupled();
229 if ( CORBA::is_nil( aEndSwitchNode ) ) {
230 QAD_MessageBox::error1( (QWidget*)QAD_Application::getDesktop(), tr( "ERROR" ), tr( "MSG_ERROR_LIB_BAD_SWITCH" ), tr( "OK" ) );
233 // save EndSwitch function
234 saveStrings( doc, element, FUNC_ES_NAME_ATT, aEndSwitchNode->PyFuncName(), FUNC_ES_ELEMENT, aEndSwitchNode->PyFunction() );
236 // save ports of EndSwitch
237 SUPERV::ListOfPorts_var aESPorts = aEndSwitchNode->Ports();
238 for ( int i = 0, n = aESPorts->length(); i < n; i++) {
239 if ( !CORBA::is_nil( aESPorts[i] ) && !aESPorts[i]->IsGate() ) {
240 QDomElement portElement = doc.createElement( ES_PORT_ELEMENT );
241 portElement.setAttribute( PORT_INPUT_ATT, aESPorts[i]->IsInput() );
242 portElement.setAttribute( PORT_NAME_ATT, aESPorts[i]->Name() );
243 portElement.setAttribute( PORT_TYPE_ATT, aESPorts[i]->Type() );
244 element.appendChild( portElement );
247 } // end of IsSwitch()
249 // OK, done with file export. write the document to the file
250 libFile.close(); // it seems that QDomDocument opens the file when doing
251 // setContent() and does not close it
252 if ( libFile.open( IO_WriteOnly ) ) { // IO_WriteOnly truncates the file!
253 QTextStream stream( &libFile );
254 stream << doc.toString();
258 else { // error opening library file for final writing
259 QAD_MessageBox::error1( (QWidget*)QAD_Application::getDesktop(), tr( "ERROR" ), tr( "MSG_ERROR_LIB_WRITE" ), tr( "OK" ) );
265 * Import an InLine node from Library into the dataflow
267 SUPERV::CNode_var SUPERVGUI_Library::Import( SUPERV::Graph_var theDataflow, const int theLibIndex ) const {
268 SUPERV::CNode_var aNode;
277 * Inline nodes library management dialog. constructor.
279 SUPERVGUI_LibDlg::SUPERVGUI_LibDlg( QWidget* parent, int& theX, int& theY )
280 :QDialog( parent, "SUPERVGUI_LibDlg", true, WStyle_Customize | WStyle_NormalBorder | WStyle_Title | WStyle_SysMenu),
281 myX( theX ), myY( theY )
283 setSizeGripEnabled( true );
284 setCaption(tr("TIT_FUNC_PYTHON"));
286 QGridLayout* aMainLayout = new QGridLayout( this, 4, 4, 11, 6 );
288 myLB = new QListBox( this );
290 QPushButton* anAddBtn = new QPushButton( tr("TIT_ADDFNODE"), this );
291 connect( anAddBtn, SIGNAL( clicked() ), this, SLOT( add() ) );
292 QPushButton* aRemBtn = new QPushButton( tr("BUT_REMOVE"), this );
293 connect( aRemBtn, SIGNAL( clicked() ), this, SLOT( remove() ) );
295 aMainLayout->addMultiCellWidget( myLB, 0, 2, 0, 2 );
296 aMainLayout->addWidget( anAddBtn, 0, 3 );
297 aMainLayout->addWidget( aRemBtn, 1, 3 );
299 QGroupBox* aBtnBox = new QGroupBox( 0, Qt::Vertical, this );
300 aBtnBox->layout()->setSpacing( 0 ); aBtnBox->layout()->setMargin( 0 );
301 QHBoxLayout* aBtnLayout = new QHBoxLayout( aBtnBox->layout() );
302 aBtnLayout->setAlignment( Qt::AlignTop );
303 aBtnLayout->setSpacing( 6 ); aBtnLayout->setMargin( 11 );
305 QPushButton* aCloseBtn = new QPushButton( tr("BUT_CLOSE"), aBtnBox );
306 connect( aCloseBtn, SIGNAL( clicked() ), this, SLOT( reject() ) );
307 aBtnLayout->addStretch();
308 aBtnLayout->addWidget( aCloseBtn );
309 aBtnLayout->addStretch();
311 aMainLayout->addMultiCellWidget( aBtnBox, 3, 3, 0, 3 );
312 aMainLayout->setRowStretch( 2, 1 );
316 * Inline nodes library management dialog. destructor.
318 SUPERVGUI_LibDlg::~SUPERVGUI_LibDlg() {}
321 * Called when user presses "Add" button. Add a selected node from library to graph
323 void SUPERVGUI_LibDlg::add() {
327 * Called when user presses "Remove" button. Remove a selected node from library
329 void SUPERVGUI_LibDlg::remove() {