Salome HOME
Copyright update 2021
[modules/yacs.git] / src / hmi / commands.cxx
1 // Copyright (C) 2006-2021  CEA/DEN, EDF R&D
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19
20 #include "commands.hxx"
21 #include "guiContext.hxx"
22 #include "Proc.hxx"
23 #include "Catalog.hxx"
24 #include "RuntimeSALOME.hxx"
25
26 //#define _DEVDEBUG_
27 #include "YacsTrace.hxx"
28 #include <sstream>
29
30 using namespace std;
31
32 using namespace YACS;
33 using namespace YACS::HMI;
34
35 int Invocator::_ctr = 0;
36
37 Command::Command()
38 {
39   _subCommands.clear();
40   _normalReverse = true;
41 }
42
43 //! the command is executed a first time after its registration for undo redo, then on redo
44 /*!
45  *  Execute may induce subcommands to be registered during its execution.
46  *  Subcommands must be deleted before redo, to be recreated by redo.
47  *  CommandDestroy is a special case, where subcommands are registered before Execute, and
48  *  undo action calls executeSubOnly instead of reverse. Subcommands pf CommandDestroy must 
49  *  not be deleted.
50  */
51 bool Command::execute()
52 {
53   if ( !GuiContext::getCurrent() || !GuiContext::getCurrent()->getInvoc() )
54     return false;
55
56   bool commandInProgress = !GuiContext::getCurrent()->getInvoc()->isSpecialReverse();
57   if (commandInProgress)
58     GuiContext::getCurrent()->getInvoc()->_commandsInProgress.push_back(this);
59
60   bool ret=true;
61   if (GuiContext::getCurrent()->getInvoc()->_isRedo && _normalReverse) 
62     {
63       for (int i=0; i<_subCommands.size(); i++)
64         delete _subCommands[i];
65       _subCommands.clear();
66     }
67   ret = localExecute();
68   if (ret) GuiContext::getCurrent()->setNotSaved(true);
69
70   if (commandInProgress)
71     GuiContext::getCurrent()->getInvoc()->_commandsInProgress.pop_back();
72   return ret;
73 }
74
75 //! Reverse action: undo
76 /*! Recursive reverse of sub commands then local action
77  *  @param isNormal: true for ordinary command, false for command Destroy
78  */
79 bool Command::reverse(bool isNormal)
80 {
81   bool ret=true;
82   if (! _subCommands.empty())
83     {
84       for (int i=0; i<_subCommands.size(); i++)
85         {
86           ret =_subCommands[i]->reverse(isNormal);
87           if (!ret) break;
88         }
89     }
90   if (ret)
91     {
92       if (isNormal) // true for all commands but commandDestroy
93         ret = localReverse();
94       else
95         ret = localExecute(); // subCommand of command Destroy 
96     }
97   return ret;
98 }
99
100 //! execute only sub commands in a reverse action
101 /*!
102  * for undo of commandDestroy, only sub commands of commandDestroy must be executed,
103  * via subcommand->reverse(false)
104  */
105 bool Command::executeSubOnly()
106 {
107   bool ret=true;
108   if (! _subCommands.empty())
109     {
110       for (int i=0; i<_subCommands.size(); i++)
111         {
112           ret =_subCommands[i]->reverse(false);
113           if (!ret) break;
114         }
115     }
116   return ret;
117 }
118
119 std::string Command::dump()
120 {
121   return "=== generic command dump ===";
122 }
123
124 std::string Command::recursiveDump(int level)
125 {
126   string prefix = "";
127   for (int i=0; i<level; i++) prefix += "  ";
128   string ret = prefix + dump() + "\n";
129   for (int i=0; i<_subCommands.size(); i++)
130     ret += _subCommands[i]->recursiveDump(level+1);
131   return ret;
132 }
133
134 void Command::addSubCommand(Command* command)
135 {
136   _subCommands.push_back(command); 
137 }
138
139
140
141
142
143 Invocator::Invocator()
144 {
145   _commandsDone.clear();
146   _commandsUndone.clear();
147   _commandsInProgress.clear();
148   _isRedo = false;
149   _isUndo = false;
150   _specialReverse = false;
151   _undoCata = new YACS::ENGINE::Catalog("undoCata");
152   YACS::ENGINE::RuntimeSALOME* runTime = YACS::ENGINE::getSALOMERuntime();
153   _undoProc= runTime->createProc("undoProc");
154 }
155
156 void Invocator::add(Command* command)
157 {
158   DEBTRACE("Invocator::add");
159   if(_isUndo)
160     return;
161   if (GuiContext::getCurrent()->getInvoc()->isSpecialReverse())
162     {
163       delete command;
164       return;
165     }
166   if (_commandsInProgress.empty())
167     {
168       _commandsDone.push_back(command); // --- to do after execute ok
169       _commandsUndone.clear();           // --- undone stack is no more relevant
170     }
171   else
172     {
173       DEBTRACE("addSubCommand");
174       _commandsInProgress.back()->addSubCommand(command);
175     }
176 }
177
178 bool Invocator::undo()
179 {
180   DEBTRACE("Invocator::undo");
181   bool ret = true;
182
183   {
184     stringstream ret1;
185     ret1 << "_commandsDone" << endl;
186     for (int i=0; i<_commandsDone.size(); i++)
187       ret1 << i << _commandsDone[i]->recursiveDump(2);
188     DEBTRACE(ret1.str());
189     stringstream ret2;
190     ret2 << "_commandsUndone" << endl;
191     for (int i=0; i<_commandsUndone.size(); i++)
192       ret2 << i << _commandsUndone[i]->recursiveDump(2);
193     DEBTRACE(ret2.str());
194   }
195
196   if (! _commandsDone.empty())
197     {
198       bool isNormal = _commandsDone.back()->isNormalReverse();
199       _specialReverse = !isNormal;
200       _isUndo=true;
201       if (isNormal)
202         ret = _commandsDone.back()->reverse(isNormal);
203       else
204         ret = _commandsDone.back()->executeSubOnly();
205       _isUndo=false;
206       _commandsUndone.push_back(_commandsDone.back());
207       _commandsDone.pop_back();
208       _specialReverse = false;
209     }
210
211   {
212     stringstream ret1;
213     ret1 << "_commandsDone" << endl;
214     for (int i=0; i<_commandsDone.size(); i++)
215       ret1 << i << _commandsDone[i]->recursiveDump(2);
216     DEBTRACE(ret1.str());
217     stringstream ret2;
218     ret2 << "_commandsUndone" << endl;
219     for (int i=0; i<_commandsUndone.size(); i++)
220       ret2 << i << _commandsUndone[i]->recursiveDump(2);
221     DEBTRACE(ret2.str());
222   }
223
224   return ret;
225 }
226
227 bool Invocator::redo()
228 {
229   DEBTRACE("Invocator::redo");
230   bool ret = true;
231
232   {
233     stringstream ret1;
234     ret1 << "_commandsDone" << endl;
235     for (int i=0; i<_commandsDone.size(); i++)
236       ret1 << i << _commandsDone[i]->recursiveDump(2);
237     DEBTRACE(ret1.str());
238     stringstream ret2;
239     ret2 << "_commandsUndone" << endl;
240     for (int i=0; i<_commandsUndone.size(); i++)
241       ret2 << i << _commandsUndone[i]->recursiveDump(2);
242     DEBTRACE(ret2.str());
243   }
244
245   if (! _commandsUndone.empty())
246     {
247       _isRedo=true;
248       ret = _commandsUndone.back()->execute();
249       _isRedo=false;
250       _commandsDone.push_back(_commandsUndone.back());
251       _commandsUndone.pop_back();
252     }
253
254   {
255     stringstream ret1;
256     ret1 << "_commandsDone" << endl;
257     for (int i=0; i<_commandsDone.size(); i++)
258       ret1 << i << _commandsDone[i]->recursiveDump(2);
259     DEBTRACE(ret1.str());
260     stringstream ret2;
261     ret2 << "_commandsUndone" << endl;
262     for (int i=0; i<_commandsUndone.size(); i++)
263       ret2 << i << _commandsUndone[i]->recursiveDump(2);
264     DEBTRACE(ret2.str());
265   }
266
267   return ret;
268 }
269
270 std::list<std::string> Invocator::getDone()
271 {
272   list<string> listDone;
273   listDone.clear();
274   for (int i=0; i<_commandsDone.size(); i++)
275     listDone.push_back(_commandsDone[i]->recursiveDump());
276   return listDone;
277 }
278
279 std::list<std::string> Invocator::getUndone()
280 {
281   list<string> listUndone;
282   listUndone.clear();
283   for (int i=0; i<_commandsUndone.size(); i++)
284     listUndone.push_back(_commandsUndone[i]->recursiveDump());
285   return listUndone;
286 }