Salome HOME
Fix Undo/Redo of removing of middle point.
[modules/hydro.git] / src / HYDROCurveCreator / CurveCreator_Diff.cxx
1 // Copyright (C) 2013  CEA/DEN, EDF R&D, OPEN CASCADE
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.
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 // File:        CurveCreator_Diff.cxx
21 // Author:      Sergey KHROMOV
22
23 #include "CurveCreator_Diff.hxx"
24 #include "CurveCreator_Curve.hxx"
25
26 #include <list>
27
28 //=======================================================================
29 // function: Constructor
30 // purpose:
31 //=======================================================================
32 CurveCreator_Diff::CurveCreator_Diff()
33 : myNbUndos (0),
34   myPUndo   (NULL),
35   myPRedo   (NULL)
36 {
37 }
38
39 //=======================================================================
40 // function: Destructor
41 // purpose:
42 //=======================================================================
43 CurveCreator_Diff::~CurveCreator_Diff()
44 {
45   clear();
46 }
47
48 //=======================================================================
49 // function: init
50 // purpose:
51 //=======================================================================
52 bool CurveCreator_Diff::init(const CurveCreator_Curve *theCurve,
53                              const CurveCreator_Operation::Type theType)
54 {
55   bool isOK = false;
56
57   if (theCurve != NULL) {
58     clear();
59
60     // Set redo.
61     myPRedo = new CurveCreator_Operation;
62
63     if (myPRedo->init(theType)) {
64       isOK = true;
65
66       const int aNbSections = theCurve->getNbSections();
67
68       if (theType == CurveCreator_Operation::Clear) {
69         // Construct undo for Clear command.
70         if (aNbSections > 0) {
71           setNbUndos(aNbSections);
72
73           for (int i = 0; i < aNbSections && isOK; i++) {
74             // Add AddSection command.
75             isOK = addSectionToUndo(theCurve, i, myPUndo[i]);
76           }
77         }
78       } else { // theType == CurveCreator_Operation::Join
79         // Construct undo for Join command.
80         if (aNbSections > 1) {
81           // Add the RemovePoints command to remove points of
82           // the second section fron the first one.
83           const int aNbPoints = theCurve->getNbPoints(0);
84
85           setNbUndos(aNbSections);
86           isOK = myPUndo[0].init(CurveCreator_Operation::RemovePoints,
87                                  0, aNbPoints, -1);
88
89           for (int i = 1; i < aNbSections && isOK; i++) {
90             // Add AddSection command.
91             isOK = addSectionToUndo(theCurve, i, myPUndo[i]);
92           }
93         }
94       }
95     }
96
97     if (!isOK) {
98       clear();
99     }
100   }
101
102   return isOK;
103 }
104
105 //=======================================================================
106 // function: init
107 // purpose:
108 //=======================================================================
109 bool CurveCreator_Diff::init(const CurveCreator_Curve *theCurve,
110                              const CurveCreator_Operation::Type theType,
111                              const int theIntParam)
112 {
113   bool isOK = false;
114
115   if (theCurve != NULL) {
116     clear();
117
118     // Set redo.
119     myPRedo = new CurveCreator_Operation;
120
121     if (myPRedo->init(theType, theIntParam)) {
122       // Construct undo for RemoveSection command.
123       // If the last section is removed, one AddSection command is enough.
124       // If not last section is removed, two commands are requred: AddSection
125       // and MoveSection.
126       const int aLastIndex = theCurve->getNbSections() - 1;
127
128       if (theIntParam == aLastIndex) {
129         setNbUndos(1);
130       } else {
131         setNbUndos(2);
132       }
133
134       isOK = addSectionToUndo(theCurve, theIntParam, myPUndo[0]);
135
136       if (isOK && theIntParam != aLastIndex) {
137         isOK = myPUndo[1].init(CurveCreator_Operation::MoveSection,
138                                aLastIndex, theIntParam);
139       }
140     }
141
142     if (!isOK) {
143       clear();
144     }
145   }
146
147   return isOK;
148 }
149
150 //=======================================================================
151 // function: init
152 // purpose:
153 //=======================================================================
154 bool CurveCreator_Diff::init(const CurveCreator_Curve *theCurve,
155                              const CurveCreator_Operation::Type theType,
156                              const int theIntParam1,
157                              const int theIntParam2)
158 {
159   bool isOK = false;
160
161   if (theCurve != NULL) {
162     clear();
163
164     // Set redo.
165     myPRedo = new CurveCreator_Operation;
166
167     if (myPRedo->init(theType, theIntParam1, theIntParam2)) {
168       // Construct undo for different commands.
169       switch (theType) {
170         case CurveCreator_Operation::SetType:
171         case CurveCreator_Operation::SetClosed:
172             isOK = setTypeOrClosedToUndo
173               (theCurve, theType, theIntParam1, theIntParam2);
174           break;
175         case CurveCreator_Operation::MoveSection:
176           setNbUndos(1);
177           isOK = myPUndo[0].init(theType, theIntParam2, theIntParam1);
178           break;
179         case CurveCreator_Operation::Join:
180           {
181             // If the last section is removed, one AddSection command is
182             // enough. If not last section is removed, two commands are
183             // requred: AddSection and MoveSection.
184             const int aLastIndex = theCurve->getNbSections() - 1;
185             const int aNbPoints  = theCurve->getNbPoints(theIntParam1);
186
187             if (theIntParam2 == aLastIndex) {
188               setNbUndos(2);
189             } else {
190               setNbUndos(3);
191             }
192
193             isOK = myPUndo[0].init(CurveCreator_Operation::RemovePoints,
194                                    theIntParam1, aNbPoints, -1);
195
196             if (isOK) {
197               isOK = addSectionToUndo(theCurve, theIntParam2, myPUndo[1]);
198
199               if (isOK && theIntParam2 != aLastIndex) {
200                 isOK = myPUndo[2].init(CurveCreator_Operation::MoveSection,
201                                        aLastIndex, theIntParam2);
202               }
203             }
204           }
205           break;
206         case CurveCreator_Operation::RemovePoints:
207           {
208             // Construct undo for RemovePoints command.
209             const CurveCreator::Dimension aDim = theCurve->getDimension();
210             const CurveCreator::Coordinates &aPoints =
211                     theCurve->getPoints(theIntParam1);
212             CurveCreator::Coordinates::const_iterator anIterBegin =
213                 aPoints.begin() + (aDim*theIntParam2);
214             CurveCreator::Coordinates::const_iterator anIterEnd = 
215               anIterBegin + aDim;
216
217             CurveCreator::Coordinates aPointsToAdd;
218
219             setNbUndos(1);
220             aPointsToAdd.insert(aPointsToAdd.end(), anIterBegin, anIterEnd);
221             isOK = myPUndo[0].init(CurveCreator_Operation::InsertPoints,
222                                    aPointsToAdd, theIntParam1, theIntParam2);
223           }
224           break;
225         default:
226           break;
227       }
228     }
229
230     if (!isOK) {
231       clear();
232     }
233   }
234
235   return isOK;
236 }
237
238 //=======================================================================
239 // function: init
240 // purpose:
241 //=======================================================================
242 bool CurveCreator_Diff::init(const CurveCreator_Curve *theCurve,
243                              const CurveCreator_Operation::Type theType,
244                              const int theIntParam1,
245                              const int theIntParam2,
246                              const int theIntParam3)
247 {
248   bool isOK = false;
249
250   if (theCurve != NULL) {
251     clear();
252
253     // Set redo.
254     myPRedo = new CurveCreator_Operation;
255
256     if (myPRedo->init(theType, theIntParam1, theIntParam2, theIntParam3)) {
257     }
258
259     if (!isOK) {
260       clear();
261     }
262   }
263
264   return isOK;
265 }
266
267 //=======================================================================
268 // function: init
269 // purpose:
270 //=======================================================================
271 bool CurveCreator_Diff::init(const CurveCreator_Curve *theCurve,
272                              const CurveCreator_Operation::Type theType,
273                              const CurveCreator::Coordinates &theCoords,
274                              const int theIntParam)
275 {
276   bool isOK = false;
277
278   if (theCurve != NULL) {
279     clear();
280
281     // Set redo.
282     myPRedo = new CurveCreator_Operation;
283
284     if (myPRedo->init(theType, theCoords, theIntParam)) {
285       // Construct undo for AddPoints command.
286       const int aSectionInd = getSectionIndex(theCurve, theIntParam);
287       const CurveCreator::Dimension aDim = theCurve->getDimension();
288       const CurveCreator::Coordinates &aPoints =
289               theCurve->getPoints(aSectionInd);
290       const int aNbPoints = (aPoints.size()/aDim);
291
292       setNbUndos(1);
293       isOK = myPUndo[0].init(CurveCreator_Operation::RemovePoints,
294                              aSectionInd, aNbPoints, -1);
295     }
296
297     if (!isOK) {
298       clear();
299     }
300   }
301
302   return isOK;
303 }
304
305 //=======================================================================
306 // function: init
307 // purpose:
308 //=======================================================================
309 bool CurveCreator_Diff::init(const CurveCreator_Curve *theCurve,
310                              const CurveCreator_Operation::Type theType,
311                              const std::string& theName,
312                              const CurveCreator::Coordinates &theCoords,
313                              const int theIntParam1,
314                              const int theIntParam2)
315 {
316     bool isOK = false;
317
318     if (theCurve != NULL) {
319       clear();
320
321       // Set redo.
322       myPRedo = new CurveCreator_Operation;
323
324       if (myPRedo->init(theType, theName, theCoords, theIntParam1, theIntParam2)) {
325         // Construct undo for different commands.
326         switch (theType) {
327           case CurveCreator_Operation::AddSection:
328             setNbUndos(1);
329             isOK = myPUndo[0].init(CurveCreator_Operation::RemoveSection, -1);
330             break;
331         }
332       }
333     }
334     if( !isOK )
335         clear();
336     return isOK;
337 }
338
339 //=======================================================================
340 // function: init
341 // purpose:
342 //=======================================================================
343 bool CurveCreator_Diff::init(const CurveCreator_Curve *theCurve,
344                              const CurveCreator_Operation::Type theType,
345                              const CurveCreator::Coordinates &theCoords,
346                              const int theIntParam1,
347                              const int theIntParam2)
348 {
349   bool isOK = false;
350
351   if (theCurve != NULL) {
352     clear();
353
354     // Set redo.
355     myPRedo = new CurveCreator_Operation;
356
357     if (myPRedo->init(theType, theCoords, theIntParam1, theIntParam2)) {
358       // Construct undo for different commands.
359       switch (theType) {
360         case CurveCreator_Operation::InsertPoints:
361           {
362             const CurveCreator::Dimension aDim = theCurve->getDimension();
363             const int aNbPoints = (theCoords.size()/aDim);
364             const int aSectionInd = getSectionIndex(theCurve, theIntParam1);
365             int aPointInd;
366
367             if (theIntParam2 == -1) {
368               aPointInd = theCurve->getNbPoints(aSectionInd);
369             } else {
370               aPointInd = theIntParam2;
371             }
372
373             setNbUndos(1);
374             isOK = myPUndo[0].init(CurveCreator_Operation::RemovePoints,
375                                    aSectionInd, aPointInd);
376           }
377           break;
378         case CurveCreator_Operation::SetCoordinates:
379           {
380             const CurveCreator::Coordinates anOldCoords =
381               theCurve->getPoint(theIntParam1, theIntParam2);
382
383             setNbUndos(1);
384             isOK = myPUndo[0].init(CurveCreator_Operation::SetCoordinates,
385                                    anOldCoords, theIntParam1, theIntParam2);
386           }
387           break;
388         default:
389           break;
390       }
391     }
392
393     if (!isOK) {
394       clear();
395     }
396   }
397
398   return isOK;
399 }
400
401 bool CurveCreator_Diff::init(const CurveCreator_Curve *theCurve,
402                              const CurveCreator_Operation::Type theType,
403                              const std::string &theName,
404                              const int theIntParam1 )
405 {
406   bool isOK = false;
407   myPRedo = new CurveCreator_Operation;
408
409   if (myPRedo->init(theType, theName, theIntParam1 )) {
410     // Construct undo for different commands.
411     switch (theType) {
412       case CurveCreator_Operation::RenameSection:
413         setNbUndos(1);
414         isOK = myPUndo[0].init(CurveCreator_Operation::RenameSection,
415                                theCurve->getSectionName(theIntParam1), theIntParam1);
416         break;
417     }
418   }
419   if( !isOK ){
420     clear();
421   }
422   return isOK;
423 }
424
425 //=======================================================================
426 // function: applyUndo
427 // purpose:
428 //=======================================================================
429 void CurveCreator_Diff::applyUndo(CurveCreator_Curve *theCurve)
430 {
431   if (myNbUndos > 0 && myPUndo != NULL) {
432     for (int i = 0; i < myNbUndos; i++) {
433       myPUndo[i].apply(theCurve);
434     }
435   }
436 }
437
438 //=======================================================================
439 // function: applyRedo
440 // purpose:
441 //=======================================================================
442 void CurveCreator_Diff::applyRedo(CurveCreator_Curve *theCurve)
443 {
444   if (myPRedo != NULL) {
445     myPRedo->apply(theCurve);
446   }
447 }
448
449 //=======================================================================
450 // function: clear
451 // purpose:
452 //=======================================================================
453 void CurveCreator_Diff::clear()
454 {
455   if (myPUndo != NULL) {
456     delete [] myPUndo;
457     myPUndo = NULL;
458   }
459
460   myNbUndos = 0;
461
462   if (myPRedo != NULL) {
463     delete myPRedo;
464     myPRedo = NULL;
465   }
466 }
467
468 //=======================================================================
469 // function: setNbUndos
470 // purpose:
471 //=======================================================================
472 void CurveCreator_Diff::setNbUndos(const int theNbUndos)
473 {
474   myNbUndos = theNbUndos;
475   myPUndo = new CurveCreator_Operation[myNbUndos];
476 }
477
478 //=======================================================================
479 // function: getSectionIndex
480 // purpose:
481 //=======================================================================
482 int CurveCreator_Diff::getSectionIndex(const CurveCreator_Curve *theCurve,
483                                        const int theIndex) const
484 {
485   return (theIndex == -1 ? theCurve->getNbSections() - 1 : theIndex);
486 }
487
488 //=======================================================================
489 // function: addSectionToUndo
490 // purpose:
491 //=======================================================================
492 bool CurveCreator_Diff::addSectionToUndo
493                       (const CurveCreator_Curve *theCurve,
494                        const int theIndex,
495                        CurveCreator_Operation &theOperation) const
496 {
497   const CurveCreator::Coordinates &aPnts = theCurve->getPoints(theIndex);
498   const CurveCreator::SectionType aType = theCurve->getSectionType(theIndex);
499   const bool isClosed = theCurve->isClosed(theIndex);
500
501   bool isOK = theOperation.init(CurveCreator_Operation::AddSection,
502                                 aPnts, aType, isClosed);
503
504   return isOK;
505 }
506
507 //=======================================================================
508 // function: setTypeOrClosedToUndo
509 // purpose:
510 //=======================================================================
511 bool CurveCreator_Diff::setTypeOrClosedToUndo
512                             (const CurveCreator_Curve *theCurve,
513                              const CurveCreator_Operation::Type theType,
514                              const int theIntParam1,
515                              const int theIntParam2)
516 {
517   bool isOK = true;
518
519   // Compute number of modified sections.
520   const bool isSetType = (theType == CurveCreator_Operation::SetType);
521   int aNbModif = 0;
522   std::list<int> aListOfInd;
523   int aValue;
524   int i;
525
526   if (theIntParam2 == -1) {
527     // The operation is applied to all sections. We need to collect
528     // really modified sections for undo.
529     const int aNbSections = theCurve->getNbSections();
530
531     if (aNbSections > 0) {
532       // Get sections to be modified.
533       for (i = 0; i < aNbSections; i++) {
534         if (isSetType) {
535           aValue = theCurve->getSectionType(i);
536         } else {
537           aValue = theCurve->isClosed(i);
538         }
539
540         if (theIntParam1 != aValue) {
541           aNbModif++;
542           aListOfInd.push_back(i);
543         }
544       }
545
546       if (aNbSections == aNbModif) {
547         // All sections are modified. We can use one single command
548         // with -1 section index.
549         aNbModif = 1;
550         aListOfInd.clear();
551         aListOfInd.push_back(-1);
552       }
553     }
554   } else {
555     // There is only particular section modified.
556     // Check if there is a real modification required.
557     if (isSetType) {
558       aValue = theCurve->getSectionType(theIntParam2);
559     } else {
560       aValue = theCurve->isClosed(theIntParam2);
561     }
562
563     if (theIntParam1 != aValue) {
564       aNbModif = 1;
565       aListOfInd.push_back(theIntParam2);
566     }
567   }
568
569   if (aNbModif > 0) {
570     // Store the undos
571     std::list<int>::iterator anIter = aListOfInd.begin();
572
573     if (isSetType) {
574       aValue = theCurve->getSectionType(*anIter);
575     } else {
576       aValue = theCurve->isClosed(*anIter);
577     }
578
579     setNbUndos(aNbModif);
580
581     for (i = 0; anIter != aListOfInd.end() && isOK; i++, anIter++) {
582       isOK = myPUndo[i].init(theType, aValue, *anIter);
583     }
584   }
585
586   return isOK;
587 }