Salome HOME
Join modifications from BR_Dev_For_4_0 tag V4_1_1.
[modules/superv.git] / src / SUPERVGUI / SUPERVGUI_Clipboard.cxx
1 //  SUPERV SUPERVGUI : GUI for Supervisor component
2 //
3 //  Copyright (C) 2003  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 //  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS 
5 // 
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. 
10 // 
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. 
15 // 
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 
19 // 
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22 //
23 //
24 //  File   : SUPERVGUI_Clipboard.cxx
25 //  Author : Alexander SLADKOV
26 //  Module : SUPERV
27
28
29 #include "SUPERVGUI_Clipboard.h"
30 #include "SUPERVGUI_CanvasNode.h"
31 #include "SUPERVGUI.h"
32
33
34 SUPERVGUI_Clipboard* SUPERVGUI_Clipboard::myCB = 0;
35
36
37 /**
38  * Compute the next valid name for a Python function (add "_N" if a function with given name already exists)
39  */
40 QString getNewName( QStringList& allNames, const QString& oldName ) {
41   QString newName;
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 );
46   
47   return newName;
48 }
49
50 /**
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!
55  */
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();
69       }
70       index = aLine.find( origName, index+newName.length() ); // find NEXT occurance of origName in aLine
71     }
72   }
73 }
74
75 /**
76  * "Copies" all ports from fromNode to toNode: creates the sames ports in toNode in fact
77  */
78 void copyPorts( const SUPERV::CNode_var& fromNode, const SUPERV::INode_var& toNode ) {
79   if ( CORBA::is_nil( fromNode ) || CORBA::is_nil( toNode ) )
80     return;
81   SUPERV::ListOfPorts_var aPList = fromNode->Ports();
82   QString aName, aType;
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() );
88     else
89       toNode->OutPort( aName.latin1(), aType.latin1() );
90   }
91 }
92
93 /**
94  * Constructor
95  */
96 SUPERVGUI_Clipboard::SUPERVGUI_Clipboard( QObject* parent ) 
97 : QObject( parent ) {
98 }
99
100 /**
101  * Destructor
102  */
103 SUPERVGUI_Clipboard::~SUPERVGUI_Clipboard() {
104 }
105
106 /**
107  * Returns all inline functions defined in inline (switch, loop, goto) nodes of given dataflow
108  */
109 QStringList getAllFunctions( SUPERV::Graph_var dataflow ) {
110   QStringList aFuncNames;
111   if ( !CORBA::is_nil( dataflow ) ) {
112     SUPERV::ListOfNodes_var nodes = dataflow->Nodes();
113     //InLine nodes
114     for(int i = 0; i < nodes->INodes.length(); i++)
115       aFuncNames.append(nodes->INodes[i]->PyFuncName());
116     //Loop nodes
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());
121     }
122     //Switch nodes
123     for(int i = 0; i < nodes->SNodes.length(); i++)
124       aFuncNames.append(nodes->SNodes[i]->PyFuncName());
125     //GOTO nodes
126     for(int i = 0; i < nodes->GNodes.length(); i++)
127       aFuncNames.append(nodes->GNodes[i]->PyFuncName());
128   }
129   return aFuncNames;
130 }
131
132 /**
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).
135  */
136 void SUPERVGUI_Clipboard::pasteNode() {
137   Trace("SUPERVGUI_Main::pasteNode");
138   SUPERV::CNode_var aNode = getCopyNode();
139   
140   SUPERVGUI* aSupMod = SUPERVGUI::Supervision();
141   if ( !aSupMod ) {
142     MESSAGE("NULL Supervision module!");
143     return;
144   }
145   
146   SUPERVGUI_Main* aMain = aSupMod->getMain();
147   if ( !CORBA::is_nil( aNode ) && aMain ) {
148     
149     if ( !aMain->ReadyToModify() ) // null dataflow or executing, ..
150       return;
151
152     aMain->Editing(); // PAL6170: GUI->Engine: setting "Editing" flag, why here? -> PAL7960
153
154     SUPERV::Graph_var dataflow = aMain->getDataflow();
155
156     switch ( aNode->Kind() ) {
157
158     case SUPERV::FactoryNode : 
159       {
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"));
169           return;
170         }
171
172         SUPERV::INode_var aDummyEndNode;
173         aSupMod->getBrowser()->addNode(SUPERV::CNode::_narrow(aFNode), aDummyEndNode, myXCopyNode, myYCopyNode);
174       }
175       break;
176
177     case SUPERV::ComputingNode : 
178       {
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"));
182           return;
183         }
184         
185         SUPERV::INode_var aDummyEndNode;
186         aSupMod->getBrowser()->addNode(aCNode, aDummyEndNode, myXCopyNode, myYCopyNode);
187       }
188       break;
189
190     case SUPERV::InLineNode : 
191       {
192         QString aFName;                  // new node's Py_function name
193         SUPERV::ListOfStrings_var aFunc; // new node's Py_function body
194
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 );
204         } 
205         else { // empty function name and body
206           aFName = QString( "" ); 
207           aFunc = new SUPERV::ListOfStrings(); 
208         }
209
210         // create the Engine's node
211         SUPERV::INode_var aINode = dataflow->INode( aFName, aFunc );
212
213         if (CORBA::is_nil(aINode)) {
214           QMessageBox::warning(SUIT_Session::session()->activeApplication()->desktop(), tr("ERROR"), tr("MSG_CANT_CREATE_NODE"));
215           return;
216         }
217         copyPorts( aNode, aINode );
218
219         SUPERV::INode_var aDummyEndNode;
220         aSupMod->getBrowser()->addNode(SUPERV::CNode::_narrow(aINode), aDummyEndNode, myXCopyNode, myYCopyNode);
221       }
222       break;
223
224     case SUPERV::LoopNode :
225       {
226         QString aInitFName, aMoreFName, aNextFName;                // new node's Py_functions names
227         SUPERV::ListOfStrings_var aInitFunc, aMoreFunc, aNextFunc; // new node's Py_functions bodies
228
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 );
238         }
239         else { // empty function name and body
240           aInitFName = QString( "" ); 
241           aInitFunc = new SUPERV::ListOfStrings(); 
242         }
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 );
249         }
250         else { // empty function name and body
251           aMoreFName = QString( "" ); 
252           aMoreFunc = new SUPERV::ListOfStrings(); 
253         }
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 );
260         }
261         else { // empty function name and body
262           aNextFName = QString( "" ); 
263           aNextFunc = new SUPERV::ListOfStrings(); 
264         }
265
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"));
271           return;
272         }
273         copyPorts( aNode, SUPERV::INode::_narrow( aStartNode ) );
274
275         aSupMod->getBrowser()->addNode(SUPERV::CNode::_narrow(aStartNode), aEndNode, myXCopyNode, myYCopyNode);
276       }
277       break;
278
279     case SUPERV::SwitchNode :
280       {
281         QString aFName;                  // new node's Py_function name
282         SUPERV::ListOfStrings_var aFunc; // new node's Py_function body
283
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 );
293         } 
294         else { // empty function name and body
295           aFName = QString( "" ); 
296           aFunc = new SUPERV::ListOfStrings(); 
297         }
298
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"));
304           return;
305         }
306         copyPorts( aNode, SUPERV::INode::_narrow( aStartNode ) );
307         SUPERV::INode_var aNodeEnd = SUPERV::SNode::_narrow(aNode)->Coupled();
308         copyPorts( SUPERV::CNode::_narrow( aNodeEnd ), aEndNode );
309
310         aSupMod->getBrowser()->addNode(SUPERV::CNode::_narrow(aStartNode), aEndNode, myXCopyNode, myYCopyNode);
311       }
312       break;
313
314     case SUPERV::GOTONode :
315       {
316         QString aFName;                  // new node's Py_function name
317         SUPERV::ListOfStrings_var aFunc; // new node's Py_function body
318
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 );
328         } 
329         else { // empty function name and body
330           aFName = QString( "" ); 
331           aFunc = new SUPERV::ListOfStrings(); 
332         }
333
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"));
338           return;
339         }
340         copyPorts( aNode, SUPERV::INode::_narrow( aGNode ) );
341
342         SUPERV::INode_var aDummyEndNode;
343         aSupMod->getBrowser()->addNode(SUPERV::CNode::_narrow(aGNode), aDummyEndNode, myXCopyNode, myYCopyNode);
344       }
345       break;
346
347     case SUPERV::MacroNode :
348       {
349         /* to implement in the future */
350         /*
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();
356         else
357           aGraph = aMacro->FlowObjRef();
358         SUPERV::Graph_var aMacroNode = dataflow->GraphMNode(aGraph);
359         
360         if (CORBA::is_nil(aMacroNode)) {
361           QMessageBox::warning(SUIT_Session::session()->activeApplication()->desktop(), tr("ERROR"), tr("MSG_CANT_CREATE_NODE"));
362           return;
363         }
364
365         SUPERV::INode_var aDummyEndNode;
366         aSupMod->getBrowser()->addNode(SUPERV::CNode::_narrow(aMacroNode), aDummyEndNode, myXCopyNode, myYCopyNode);
367         */
368       }
369       break;
370     }
371   }
372 }
373
374
375 /** 
376  * Called from CanvasNode on "Paste port" command of popup menu
377  */
378 void SUPERVGUI_Clipboard::pastePort( SUPERVGUI_CanvasNode* node )
379 {
380   SUPERV::Port_var aPort = getCopyPort();
381
382   SUPERVGUI* aSupMod = SUPERVGUI::Supervision();
383   if ( !aSupMod ) {
384     MESSAGE("NULL Supervision module!");
385     return;
386   }
387
388   SUPERVGUI_Main* aMain = aSupMod->getMain();
389   if ( !CORBA::is_nil(aPort) && aMain ) {
390
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") );
401         else {
402           aMain->Editing(); // PAL6170: GUI->Engine: setting "Editing" flag, why here? -> PAL7960
403           aPastePort = aNode->InPort(aName.latin1(), aType.latin1());
404         }
405       }
406       else {
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") );
411         else {
412           aMain->Editing(); // PAL6170: GUI->Engine: setting "Editing" flag, why here? -> PAL7960
413           aPastePort = aNode->OutPort(aName.latin1(), aType.latin1());
414         }
415       }
416       if ( !CORBA::is_nil(aPastePort) )
417         node->createPort( aPastePort.in() );
418     }
419   }
420 }