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