Salome HOME
refs #249 - Undo after Join selected sections operation works not properly
[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             // Construct undo for RemovePoints command.
194             int anISection = theIntParam1;
195             const int aNbPoints2  = theCurve->getNbPoints(theIntParam2);
196             CurveCreator_ICurve::SectionToPointList aSectionToPointList;
197             int aJoinedSize = aNbPoints + aNbPoints2;
198             for (int anIPoint = aNbPoints; anIPoint < aJoinedSize; anIPoint++)
199               aSectionToPointList.push_back(std::make_pair( anISection, anIPoint ) );
200             isOK = myPUndo[0].init(CurveCreator_Operation::RemovePoints,
201                                    aSectionToPointList);
202
203             //isOK = myPUndo[0].init(CurveCreator_Operation::RemovePoints,
204             //                       theIntParam1, aNbPoints, -1);
205
206             if (isOK) {
207               isOK = addSectionToUndo(theCurve, theIntParam2, myPUndo[1]);
208
209               if (isOK && theIntParam2 != aLastIndex) {
210                 isOK = myPUndo[2].init(CurveCreator_Operation::MoveSection,
211                                        aLastIndex, theIntParam2);
212               }
213             }
214           }
215           break;
216         default:
217           break;
218       }
219     }
220
221     if (!isOK) {
222       clear();
223     }
224   }
225
226   return isOK;
227 }
228
229 //=======================================================================
230 // function: init
231 // purpose:
232 //=======================================================================
233 bool CurveCreator_Diff::init(const CurveCreator_Curve *theCurve,
234                              const CurveCreator_Operation::Type theType,
235                              const int theIntParam1,
236                              const int theIntParam2,
237                              const int theIntParam3)
238 {
239   bool isOK = false;
240
241   if (theCurve != NULL) {
242     clear();
243
244     // Set redo.
245     myPRedo = new CurveCreator_Operation;
246
247     if (myPRedo->init(theType, theIntParam1, theIntParam2, theIntParam3)) {
248     }
249
250     if (!isOK) {
251       clear();
252     }
253   }
254
255   return isOK;
256 }
257
258 //=======================================================================
259 // function: init
260 // purpose:
261 //=======================================================================
262 bool CurveCreator_Diff::init(const CurveCreator_Curve *theCurve,
263                              const CurveCreator_Operation::Type theType,
264                              const CurveCreator::Coordinates &theCoords,
265                              const int theIntParam)
266 {
267   bool isOK = false;
268
269   if (theCurve != NULL) {
270     clear();
271
272     // Set redo.
273     myPRedo = new CurveCreator_Operation;
274
275     if (myPRedo->init(theType, theCoords, theIntParam)) {
276       // Construct undo for AddPoints command.
277       const int aSectionInd = getSectionIndex(theCurve, theIntParam);
278       const CurveCreator::Dimension aDim = theCurve->getDimension();
279       const CurveCreator::Coordinates &aPoints =
280               theCurve->getPoints(aSectionInd);
281       const int aNbPoints = (aPoints.size()/aDim);
282
283       setNbUndos(1);
284       isOK = myPUndo[0].init(CurveCreator_Operation::RemovePoints,
285                              aSectionInd, aNbPoints, -1);
286     }
287
288     if (!isOK) {
289       clear();
290     }
291   }
292
293   return isOK;
294 }
295
296 //=======================================================================
297 // function: init
298 // purpose:
299 //=======================================================================
300 bool CurveCreator_Diff::init(const CurveCreator_Curve *theCurve,
301                              const CurveCreator_Operation::Type theType,
302                              const std::string& theName,
303                              const CurveCreator::Coordinates &theCoords,
304                              const int theIntParam1,
305                              const int theIntParam2)
306 {
307     bool isOK = false;
308
309     if (theCurve != NULL) {
310       clear();
311
312       // Set redo.
313       myPRedo = new CurveCreator_Operation;
314
315       if (myPRedo->init(theType, theName, theCoords, theIntParam1, theIntParam2)) {
316         // Construct undo for different commands.
317         switch (theType) {
318           case CurveCreator_Operation::AddSection:
319             setNbUndos(1);
320             isOK = myPUndo[0].init(CurveCreator_Operation::RemoveSection, -1);
321             break;
322         }
323       }
324     }
325     if( !isOK )
326         clear();
327     return isOK;
328 }
329
330 bool CurveCreator_Diff::init(const CurveCreator_Curve *theCurve,
331                              const CurveCreator_Operation::Type theType,
332                              const std::string &theName,
333                              const int theIntParam1 )
334 {
335   bool isOK = false;
336   myPRedo = new CurveCreator_Operation;
337
338   if (myPRedo->init(theType, theName, theIntParam1 )) {
339     // Construct undo for different commands.
340     switch (theType) {
341       case CurveCreator_Operation::RenameSection:
342         setNbUndos(1);
343         isOK = myPUndo[0].init(CurveCreator_Operation::RenameSection,
344                                theCurve->getSectionName(theIntParam1), theIntParam1);
345         break;
346     }
347   }
348   if( !isOK ){
349     clear();
350   }
351   return isOK;
352 }
353
354 bool CurveCreator_Diff::init(const CurveCreator_Curve *theCurve,
355                              const CurveCreator_Operation::Type theType,
356                              const CurveCreator_ICurve::SectionToPointList &theParamList1)
357 {
358   bool isOK = false;
359
360   if (theCurve != NULL) {
361     clear();
362
363     // Set redo.
364     myPRedo = new CurveCreator_Operation;
365
366     if (myPRedo->init(theType, theParamList1)) {
367       // Construct undo for different commands.
368       switch (theType) {
369         case CurveCreator_Operation::RemovePoints:
370           {
371             // Construct undo for RemovePoints command.
372             CurveCreator_ICurve::SectionToPointCoordsList aSectionToPointCoords;
373             CurveCreator::Coordinates aPointsToAdd;
374             const CurveCreator::Dimension aDim = theCurve->getDimension();
375             CurveCreator_ICurve::SectionToPointList::const_iterator anIt = theParamList1.begin(), aLast = theParamList1.end();
376             std::list<int> aPoints;
377             int aSectionId, aPointId;
378             for ( ; anIt != aLast; anIt++ ) {
379               aPointsToAdd.clear();
380               aSectionId = anIt->first;
381               aPointId = anIt->second;
382               const CurveCreator::Coordinates &aPoints =
383                       theCurve->getPoints(aSectionId);
384               CurveCreator::Coordinates::const_iterator anIterBegin =
385                   aPoints.begin() + (aDim*aPointId);
386               CurveCreator::Coordinates::const_iterator anIterEnd = 
387                 anIterBegin + aDim;
388               aPointsToAdd.insert(aPointsToAdd.end(), anIterBegin, anIterEnd);
389               aSectionToPointCoords.push_back(std::make_pair(*anIt, aPointsToAdd));
390             }
391             setNbUndos(1);
392             isOK = myPUndo[0].init(CurveCreator_Operation::InsertPoints,
393                                    aSectionToPointCoords);
394           }
395           break;
396         default:
397           break;
398       }
399     }
400
401     if (!isOK) {
402       clear();
403     }
404   }
405
406   return isOK;
407 }
408
409 bool CurveCreator_Diff::init(const CurveCreator_Curve *theCurve,
410                              const CurveCreator_Operation::Type theType,
411                              const CurveCreator_ICurve::SectionToPointCoordsList &theParamList1)
412 {
413   bool isOK = false;
414
415   if (theCurve != NULL) {
416     clear();
417
418     // Set redo.
419     myPRedo = new CurveCreator_Operation;
420
421     if (myPRedo->init(theType, theParamList1)) {
422       // Construct undo for different commands.
423       switch (theType) {
424         case CurveCreator_Operation::InsertPoints:
425           {
426             // Construct undo for RemovePoints command.
427             CurveCreator_ICurve::SectionToPointList aSectionToPointList;
428             CurveCreator_ICurve::SectionToPointCoordsList::const_iterator anIt = theParamList1.begin(), aLast = theParamList1.end();
429             for ( ; anIt != aLast; anIt++ ) {
430               aSectionToPointList.push_back(anIt->first);
431             }
432             setNbUndos(1);
433             isOK = myPUndo[0].init(CurveCreator_Operation::RemovePoints,
434                                    aSectionToPointList);
435           }
436           break;
437         case CurveCreator_Operation::SetCoordinates:
438           {
439             // Construct undo for SetCoordinates command.
440             CurveCreator_ICurve::SectionToPointCoordsList aSectionToPointOldCoords;
441             CurveCreator_ICurve::SectionToPointCoordsList::const_iterator anIt = theParamList1.begin(), aLast = theParamList1.end();
442             for ( ; anIt != aLast; anIt++ ) {
443               CurveCreator::Coordinates anOldCoords = theCurve->getPoint(anIt->first.first, anIt->first.second);
444               aSectionToPointOldCoords.push_back(std::make_pair(anIt->first, anOldCoords));
445             }
446
447             setNbUndos(1);
448             isOK = myPUndo[0].init(CurveCreator_Operation::SetCoordinates,
449                                    aSectionToPointOldCoords);
450           }
451           break;
452         default:
453           break;
454       }
455     }
456
457     if (!isOK) {
458       clear();
459     }
460   }
461
462   return isOK;
463 }
464
465 bool CurveCreator_Diff::init(const CurveCreator_Curve *theCurve,
466                              const CurveCreator_ICurve::SectionToPointCoordsList &theOldParamList)
467 {
468   bool isOK = false;
469
470   if (theCurve != NULL && theOldParamList.size() > 0) {
471     clear();
472
473     // Set redo.
474     myPRedo = new CurveCreator_Operation;
475
476     // Construct redo for SetCoordinates command.
477     CurveCreator_ICurve::SectionToPointCoordsList aSectionToPointActualCoords;
478     CurveCreator_ICurve::SectionToPointCoordsList::const_iterator anIt = 
479       theOldParamList.begin(), aLast = theOldParamList.end();
480     for ( ; anIt != aLast; anIt++ ) {
481       CurveCreator::Coordinates anActualCoords = theCurve->getPoint(anIt->first.first, anIt->first.second);
482       aSectionToPointActualCoords.push_back(std::make_pair(anIt->first, anActualCoords));
483     }
484
485     if (myPRedo->init(CurveCreator_Operation::SetCoordinates, aSectionToPointActualCoords)) {
486       // Undo for SetCoordinates command.
487       setNbUndos(1);
488       isOK = myPUndo[0].init(CurveCreator_Operation::SetCoordinates,
489                              theOldParamList);
490     }
491
492     if (!isOK) {
493       clear();
494     }
495   }
496
497   return isOK;
498 }
499
500 //=======================================================================
501 // function: applyUndo
502 // purpose:
503 //=======================================================================
504 void CurveCreator_Diff::applyUndo(CurveCreator_Curve *theCurve)
505 {
506   if (myNbUndos > 0 && myPUndo != NULL) {
507     for (int i = 0; i < myNbUndos; i++) {
508       myPUndo[i].apply(theCurve);
509     }
510   }
511 }
512
513 //=======================================================================
514 // function: applyRedo
515 // purpose:
516 //=======================================================================
517 void CurveCreator_Diff::applyRedo(CurveCreator_Curve *theCurve)
518 {
519   if (myPRedo != NULL) {
520     myPRedo->apply(theCurve);
521   }
522 }
523
524 //=======================================================================
525 // function: clear
526 // purpose:
527 //=======================================================================
528 void CurveCreator_Diff::clear()
529 {
530   if (myPUndo != NULL) {
531     delete [] myPUndo;
532     myPUndo = NULL;
533   }
534
535   myNbUndos = 0;
536
537   if (myPRedo != NULL) {
538     delete myPRedo;
539     myPRedo = NULL;
540   }
541 }
542
543 //=======================================================================
544 // function: setNbUndos
545 // purpose:
546 //=======================================================================
547 void CurveCreator_Diff::setNbUndos(const int theNbUndos)
548 {
549   myNbUndos = theNbUndos;
550   myPUndo = new CurveCreator_Operation[myNbUndos];
551 }
552
553 //=======================================================================
554 // function: getSectionIndex
555 // purpose:
556 //=======================================================================
557 int CurveCreator_Diff::getSectionIndex(const CurveCreator_Curve *theCurve,
558                                        const int theIndex) const
559 {
560   return (theIndex == -1 ? theCurve->getNbSections() - 1 : theIndex);
561 }
562
563 //=======================================================================
564 // function: addSectionToUndo
565 // purpose:
566 //=======================================================================
567 bool CurveCreator_Diff::addSectionToUndo
568                       (const CurveCreator_Curve *theCurve,
569                        const int theIndex,
570                        CurveCreator_Operation &theOperation) const
571 {
572   const std::string aName = theCurve->getSectionName(theIndex);
573   const CurveCreator::Coordinates &aPnts = theCurve->getPoints(theIndex);
574   const CurveCreator::SectionType aType = theCurve->getSectionType(theIndex);
575   const bool isClosed = theCurve->isClosed(theIndex);
576
577   bool isOK = theOperation.init(CurveCreator_Operation::AddSection,
578                                 aName, aPnts, aType, isClosed);
579
580   return isOK;
581 }
582
583 //=======================================================================
584 // function: setTypeOrClosedToUndo
585 // purpose:
586 //=======================================================================
587 bool CurveCreator_Diff::setTypeOrClosedToUndo
588                             (const CurveCreator_Curve *theCurve,
589                              const CurveCreator_Operation::Type theType,
590                              const int theIntParam1,
591                              const int theIntParam2)
592 {
593   bool isOK = true;
594
595   // Compute number of modified sections.
596   const bool isSetType = (theType == CurveCreator_Operation::SetType);
597   int aNbModif = 0;
598   std::list<int> aListOfInd;
599   int aValue;
600   int i;
601
602   if (theIntParam2 == -1) {
603     // The operation is applied to all sections. We need to collect
604     // really modified sections for undo.
605     const int aNbSections = theCurve->getNbSections();
606
607     if (aNbSections > 0) {
608       // Get sections to be modified.
609       for (i = 0; i < aNbSections; i++) {
610         if (isSetType) {
611           aValue = theCurve->getSectionType(i);
612         } else {
613           aValue = theCurve->isClosed(i);
614         }
615
616         if (theIntParam1 != aValue) {
617           aNbModif++;
618           aListOfInd.push_back(i);
619         }
620       }
621
622       if (aNbSections == aNbModif) {
623         // All sections are modified. We can use one single command
624         // with -1 section index.
625         aNbModif = 1;
626         aListOfInd.clear();
627         aListOfInd.push_back(-1);
628       }
629     }
630   } else {
631     // There is only particular section modified.
632     // Check if there is a real modification required.
633     if (isSetType) {
634       aValue = theCurve->getSectionType(theIntParam2);
635     } else {
636       aValue = theCurve->isClosed(theIntParam2);
637     }
638
639     if (theIntParam1 != aValue) {
640       aNbModif = 1;
641       aListOfInd.push_back(theIntParam2);
642     }
643   }
644
645   if (aNbModif > 0) {
646     // Store the undos
647     std::list<int>::iterator anIter = aListOfInd.begin();
648
649     if (isSetType) {
650       aValue = theCurve->getSectionType(*anIter);
651     } else {
652       aValue = theCurve->isClosed(*anIter);
653     }
654
655     setNbUndos(aNbModif);
656
657     for (i = 0; anIter != aListOfInd.end() && isOK; i++, anIter++) {
658       isOK = myPUndo[i].init(theType, aValue, *anIter);
659     }
660   }
661
662   return isOK;
663 }