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_Clipboard.cxx
25 // Author : Alexander SLADKOV
29 #include "SUPERVGUI_Clipboard.h"
30 #include "SUPERVGUI_CanvasNode.h"
31 #include "SUPERVGUI.h"
34 SUPERVGUI_Clipboard* SUPERVGUI_Clipboard::myCB = 0;
38 * Compute the next valid name for a Python function (add "_N" if a function with given name already exists)
40 QString getNewName( QStringList& allNames, const QString& oldName ) {
42 int id = 1; //increment index
43 newName = oldName + QString("_") + QString::number( id );
44 while ( allNames.contains( newName ) )
45 newName = oldName + QString("_") + QString::number( ++id );
51 * Replaces origName string with newName string in all lines of theFunc
52 * origName must be preceeded by space and end by space or '('.
53 * asv : 14.01.05 : fix of a bug (exception on node creation):
54 * if origName and theFunc is null, return non-null empty strings!
56 void replaceName( SUPERV::ListOfStrings_var& theFunc, const QString& origName, const QString& newName ) {
57 for ( int i = 0, n = theFunc->length(); i < n; i++ ) {
58 QString aLine( theFunc[i] );
59 int index = aLine.find( origName, 0 ); // find FIRST occurance of origName in aLine
60 while ( index >= 0 ) {
61 bool preceedingCharOk = ( index==0 || ( index > 0 && aLine[index-1].isSpace() ) );
62 const int ll = aLine.length();
63 const int ol = origName.length();
64 const int ni = index + ol;
65 bool nextCharOk = ( ll==ni || ( ll>ni && ( aLine[ni].isSpace() || aLine[ni]=='(' ) ) );
66 if ( preceedingCharOk && nextCharOk ) {
67 aLine = aLine.replace( index, origName.length(), newName );
68 theFunc[i] = aLine.latin1();
70 index = aLine.find( origName, index+newName.length() ); // find NEXT occurance of origName in aLine
76 * "Copies" all ports from fromNode to toNode: creates the sames ports in toNode in fact
78 void copyPorts( const SUPERV::CNode_var& fromNode, const SUPERV::INode_var& toNode ) {
79 if ( CORBA::is_nil( fromNode ) || CORBA::is_nil( toNode ) )
81 SUPERV::ListOfPorts_var aPList = fromNode->Ports();
83 for (int i = 0; i < aPList->length(); i++) {
84 aName = aPList[i].in()->Name();
85 aType = aPList[i].in()->Type();
86 if ( aPList[i].in()->IsInput() )
87 toNode->InPort( aName.latin1(), aType.latin1() );
89 toNode->OutPort( aName.latin1(), aType.latin1() );
96 SUPERVGUI_Clipboard::SUPERVGUI_Clipboard( QObject* parent )
103 SUPERVGUI_Clipboard::~SUPERVGUI_Clipboard() {
107 * Returns all inline functions defined in inline (switch, loop, goto) nodes of given dataflow
109 QStringList getAllFunctions( SUPERV::Graph_var dataflow ) {
110 QStringList aFuncNames;
111 if ( !CORBA::is_nil( dataflow ) ) {
112 SUPERV::ListOfNodes_var nodes = dataflow->Nodes();
114 for(int i = 0; i < nodes->INodes.length(); i++)
115 aFuncNames.append(nodes->INodes[i]->PyFuncName());
117 for(int i = 0; i < nodes->LNodes.length(); i++) {
118 aFuncNames.append(nodes->LNodes[i]->PyInitName());
119 aFuncNames.append(nodes->LNodes[i]->PyMoreName());
120 aFuncNames.append(nodes->LNodes[i]->PyNextName());
123 for(int i = 0; i < nodes->SNodes.length(); i++)
124 aFuncNames.append(nodes->SNodes[i]->PyFuncName());
126 for(int i = 0; i < nodes->GNodes.length(); i++)
127 aFuncNames.append(nodes->GNodes[i]->PyFuncName());
133 * Called on Paste Node command. Inserts a new node to the dataflow equal to the copied node.
134 * For InLine nodes the Python function name is changed ("_N" added).
136 void SUPERVGUI_Clipboard::pasteNode() {
137 Trace("SUPERVGUI_Main::pasteNode");
138 SUPERV::CNode_var aNode = getCopyNode();
140 SUPERVGUI* aSupMod = SUPERVGUI::Supervision();
142 MESSAGE("NULL Supervision module!");
146 SUPERVGUI_Main* aMain = aSupMod->getMain();
147 if ( !CORBA::is_nil( aNode ) && aMain ) {
149 if ( !aMain->ReadyToModify() ) // null dataflow or executing, ..
152 aMain->Editing(); // PAL6170: GUI->Engine: setting "Editing" flag, why here? -> PAL7960
154 SUPERV::Graph_var dataflow = aMain->getDataflow();
156 switch ( aNode->Kind() ) {
158 case SUPERV::FactoryNode :
160 SUPERV::FNode_var aNodeFNode = SUPERV::FNode::_narrow(aNode);
161 SALOME_ModuleCatalog::ImplType anImplType = SALOME_ModuleCatalog::SO;
162 if (!aNodeFNode->IsCimpl()) anImplType = SALOME_ModuleCatalog::PY;
163 SUPERV::FNode_var aFNode = dataflow->FNode(aNodeFNode->GetComponentName(),
164 aNodeFNode->GetInterfaceName(),
165 *aNodeFNode->Service(),
166 anImplType); // mkr : PAL11273
167 if (CORBA::is_nil(aFNode)) {
168 QMessageBox::warning(SUIT_Session::session()->activeApplication()->desktop(), tr("ERROR"), tr("MSG_CANT_CREATE_NODE"));
172 SUPERV::INode_var aDummyEndNode;
173 aSupMod->getBrowser()->addNode(SUPERV::CNode::_narrow(aFNode), aDummyEndNode, myXCopyNode, myYCopyNode);
177 case SUPERV::ComputingNode :
179 SUPERV::CNode_var aCNode = dataflow->CNode(*SUPERV::CNode::_narrow(aNode)->Service());
180 if (CORBA::is_nil(aCNode)) {
181 QMessageBox::warning(SUIT_Session::session()->activeApplication()->desktop(), tr("ERROR"), tr("MSG_CANT_CREATE_NODE"));
185 SUPERV::INode_var aDummyEndNode;
186 aSupMod->getBrowser()->addNode(aCNode, aDummyEndNode, myXCopyNode, myYCopyNode);
190 case SUPERV::InLineNode :
192 QString aFName; // new node's Py_function name
193 SUPERV::ListOfStrings_var aFunc; // new node's Py_function body
195 // Automatic change of Py_function name ( + "_1", etc.)
196 // 1. collect all python functions names of allready exist InLine nodes
197 QStringList aFuncNames = getAllFunctions( dataflow );
198 // 2. "fix" Main function_name and Main function_strings
199 QString aOriginalName = SUPERV::INode::_narrow(aNode)->PyFuncName();
200 if ( !aOriginalName.isEmpty() ) {
201 aFName = getNewName( aFuncNames, aOriginalName );
202 aFunc = SUPERV::INode::_narrow(aNode)->PyFunction();
203 replaceName( aFunc, aOriginalName, aFName );
205 else { // empty function name and body
206 aFName = QString( "" );
207 aFunc = new SUPERV::ListOfStrings();
210 // create the Engine's node
211 SUPERV::INode_var aINode = dataflow->INode( aFName, aFunc );
213 if (CORBA::is_nil(aINode)) {
214 QMessageBox::warning(SUIT_Session::session()->activeApplication()->desktop(), tr("ERROR"), tr("MSG_CANT_CREATE_NODE"));
217 copyPorts( aNode, aINode );
219 SUPERV::INode_var aDummyEndNode;
220 aSupMod->getBrowser()->addNode(SUPERV::CNode::_narrow(aINode), aDummyEndNode, myXCopyNode, myYCopyNode);
224 case SUPERV::LoopNode :
226 QString aInitFName, aMoreFName, aNextFName; // new node's Py_functions names
227 SUPERV::ListOfStrings_var aInitFunc, aMoreFunc, aNextFunc; // new node's Py_functions bodies
229 // Automatic change of Py_function name ( + "_1", etc.)
230 // 1. collect all python functions names of allready exist InLine nodes
231 QStringList aFuncNames = getAllFunctions( dataflow );
232 // 2.1 "fix" Init function_name and Init function_strings
233 QString aOriginalName = SUPERV::LNode::_narrow(aNode)->PyInitName();
234 if (!aOriginalName.isEmpty()) {
235 aInitFName = getNewName( aFuncNames, aOriginalName );
236 aInitFunc = SUPERV::LNode::_narrow(aNode)->PyInit();
237 replaceName( aInitFunc, aOriginalName, aInitFName );
239 else { // empty function name and body
240 aInitFName = QString( "" );
241 aInitFunc = new SUPERV::ListOfStrings();
243 // 2.2 "fix" More function_name and More function_strings
244 aOriginalName = SUPERV::LNode::_narrow(aNode)->PyMoreName();
245 if (!aOriginalName.isEmpty()) {
246 aMoreFName = getNewName( aFuncNames, aOriginalName );
247 aMoreFunc = SUPERV::LNode::_narrow(aNode)->PyMore();
248 replaceName( aMoreFunc, aOriginalName, aMoreFName );
250 else { // empty function name and body
251 aMoreFName = QString( "" );
252 aMoreFunc = new SUPERV::ListOfStrings();
254 // 2.3 "fix" Next function_name and Next function_strings
255 aOriginalName = SUPERV::LNode::_narrow(aNode)->PyNextName();
256 if (!aOriginalName.isEmpty()) {
257 aNextFName = getNewName( aFuncNames, aOriginalName );
258 aNextFunc = SUPERV::LNode::_narrow(aNode)->PyNext();
259 replaceName( aNextFunc, aOriginalName, aNextFName );
261 else { // empty function name and body
262 aNextFName = QString( "" );
263 aNextFunc = new SUPERV::ListOfStrings();
266 // create the Engine's node
267 SUPERV::INode_var aEndNode;
268 SUPERV::LNode_var aStartNode = dataflow->LNode(aInitFName, aInitFunc, aMoreFName, aMoreFunc, aNextFName, aNextFunc, aEndNode);
269 if (CORBA::is_nil(aStartNode) || CORBA::is_nil(aEndNode)) {
270 QMessageBox::warning(SUIT_Session::session()->activeApplication()->desktop(), tr("ERROR"), tr("MSG_CANT_CREATE_NODE"));
273 copyPorts( aNode, SUPERV::INode::_narrow( aStartNode ) );
275 aSupMod->getBrowser()->addNode(SUPERV::CNode::_narrow(aStartNode), aEndNode, myXCopyNode, myYCopyNode);
279 case SUPERV::SwitchNode :
281 QString aFName; // new node's Py_function name
282 SUPERV::ListOfStrings_var aFunc; // new node's Py_function body
284 // Automatic change of Py_function name ( + "_1", etc.)
285 // 1. collect all python functions names of allready exist InLine nodes
286 QStringList aFuncNames = getAllFunctions( dataflow );
287 // 2. "fix" Main function_name and Main function_strings
288 QString aOriginalName = SUPERV::INode::_narrow(aNode)->PyFuncName();
289 if ( !aOriginalName.isEmpty() ) {
290 aFName = getNewName( aFuncNames, aOriginalName );
291 aFunc = SUPERV::INode::_narrow(aNode)->PyFunction();
292 replaceName( aFunc, aOriginalName, aFName );
294 else { // empty function name and body
295 aFName = QString( "" );
296 aFunc = new SUPERV::ListOfStrings();
299 // create the Engine's node
300 SUPERV::INode_var aEndNode;
301 SUPERV::SNode_var aStartNode = dataflow->SNode(aFName, aFunc, aEndNode);
302 if (CORBA::is_nil(aStartNode) || CORBA::is_nil(aEndNode)) {
303 QMessageBox::warning(SUIT_Session::session()->activeApplication()->desktop(), tr("ERROR"), tr("MSG_CANT_CREATE_NODE"));
306 copyPorts( aNode, SUPERV::INode::_narrow( aStartNode ) );
307 SUPERV::INode_var aNodeEnd = SUPERV::SNode::_narrow(aNode)->Coupled();
308 copyPorts( SUPERV::CNode::_narrow( aNodeEnd ), aEndNode );
310 aSupMod->getBrowser()->addNode(SUPERV::CNode::_narrow(aStartNode), aEndNode, myXCopyNode, myYCopyNode);
314 case SUPERV::GOTONode :
316 QString aFName; // new node's Py_function name
317 SUPERV::ListOfStrings_var aFunc; // new node's Py_function body
319 // Automatic change of Py_function name ( + "_1", etc.)
320 // 1. collect all python functions names of allready exist InLine nodes
321 QStringList aFuncNames = getAllFunctions( dataflow );
322 // 2. "fix" Main function_name and Main function_strings
323 QString aOriginalName = SUPERV::INode::_narrow(aNode)->PyFuncName();
324 if ( !aOriginalName.isEmpty() ) {
325 aFName = getNewName( aFuncNames, aOriginalName );
326 aFunc = SUPERV::INode::_narrow(aNode)->PyFunction();
327 replaceName( aFunc, aOriginalName, aFName );
329 else { // empty function name and body
330 aFName = QString( "" );
331 aFunc = new SUPERV::ListOfStrings();
334 // create the Engine's node
335 SUPERV::GNode_var aGNode = dataflow->GNode(aFName, aFunc, "");
336 if (CORBA::is_nil(aGNode)) {
337 QMessageBox::warning(SUIT_Session::session()->activeApplication()->desktop(), tr("ERROR"), tr("MSG_CANT_CREATE_NODE"));
340 copyPorts( aNode, SUPERV::INode::_narrow( aGNode ) );
342 SUPERV::INode_var aDummyEndNode;
343 aSupMod->getBrowser()->addNode(SUPERV::CNode::_narrow(aGNode), aDummyEndNode, myXCopyNode, myYCopyNode);
347 case SUPERV::MacroNode :
349 /* to implement in the future */
351 //get SubGraph from MacroNode
352 SUPERV::Graph_var aMacro = SUPERV::Graph::_narrow(aNode);
353 SUPERV::Graph_var aGraph;
354 if (aMacro->IsStreamMacro())
355 aGraph = aMacro->StreamObjRef();
357 aGraph = aMacro->FlowObjRef();
358 SUPERV::Graph_var aMacroNode = dataflow->GraphMNode(aGraph);
360 if (CORBA::is_nil(aMacroNode)) {
361 QMessageBox::warning(SUIT_Session::session()->activeApplication()->desktop(), tr("ERROR"), tr("MSG_CANT_CREATE_NODE"));
365 SUPERV::INode_var aDummyEndNode;
366 aSupMod->getBrowser()->addNode(SUPERV::CNode::_narrow(aMacroNode), aDummyEndNode, myXCopyNode, myYCopyNode);
376 * Called from CanvasNode on "Paste port" command of popup menu
378 void SUPERVGUI_Clipboard::pastePort( SUPERVGUI_CanvasNode* node )
380 SUPERV::Port_var aPort = getCopyPort();
382 SUPERVGUI* aSupMod = SUPERVGUI::Supervision();
384 MESSAGE("NULL Supervision module!");
388 SUPERVGUI_Main* aMain = aSupMod->getMain();
389 if ( !CORBA::is_nil(aPort) && aMain ) {
391 SUPERV::INode_var aNode = node->getInlineNode();
392 if (!CORBA::is_nil(aNode)) {
393 QString aName = aPort->Name();
394 QString aType = aPort->Type();
395 SUPERV::Port_var aPastePort;
396 if (aPort->IsInput()) {
397 //check if port with such name is alredy exists
398 QStringList aNames = node->getPortsNamesIN(aNode, true);
399 if (aNames.contains(aName))
400 QMessageBox::warning( SUIT_Session::session()->activeApplication()->desktop(), tr("ERROR"), tr("MSG_PORT_EXIST") );
402 aMain->Editing(); // PAL6170: GUI->Engine: setting "Editing" flag, why here? -> PAL7960
403 aPastePort = aNode->InPort(aName.latin1(), aType.latin1());
407 //check if port with such name is already exists
408 QStringList aNames = node->getPortsNamesIN(aNode, false);
409 if (aNames.contains(aName))
410 QMessageBox::warning( SUIT_Session::session()->activeApplication()->desktop(), tr("ERROR"), tr("MSG_PORT_EXIST") );
412 aMain->Editing(); // PAL6170: GUI->Engine: setting "Editing" flag, why here? -> PAL7960
413 aPastePort = aNode->OutPort(aName.latin1(), aType.latin1());
416 if ( !CORBA::is_nil(aPastePort) )
417 node->createPort( aPastePort.in() );