Developer Documentation
GroupData.cc
1 /*===========================================================================*\
2  * *
3  * OpenFlipper *
4  * Copyright (c) 2001-2015, RWTH-Aachen University *
5  * Department of Computer Graphics and Multimedia *
6  * All rights reserved. *
7  * www.openflipper.org *
8  * *
9  *---------------------------------------------------------------------------*
10  * This file is part of OpenFlipper. *
11  *---------------------------------------------------------------------------*
12  * *
13  * Redistribution and use in source and binary forms, with or without *
14  * modification, are permitted provided that the following conditions *
15  * are met: *
16  * *
17  * 1. Redistributions of source code must retain the above copyright notice, *
18  * this list of conditions and the following disclaimer. *
19  * *
20  * 2. Redistributions in binary form must reproduce the above copyright *
21  * notice, this list of conditions and the following disclaimer in the *
22  * documentation and/or other materials provided with the distribution. *
23  * *
24  * 3. Neither the name of the copyright holder nor the names of its *
25  * contributors may be used to endorse or promote products derived from *
26  * this software without specific prior written permission. *
27  * *
28  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
29  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
30  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
31  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
32  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *
33  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
34  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *
35  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
36  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *
37  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *
38  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
39  * *
40 \*===========================================================================*/
41 
42 /*===========================================================================*\
43 * *
44 * $Revision$ *
45 * $LastChangedBy$ *
46 * $Date$ *
47 * *
48 \*===========================================================================*/
49 
50 #include "GroupData.hh"
51 
52 #include "GroupBackup.hh"
54 
55 //-----------------------------------------------------------------------------
56 
58 {
59 }
60 
61 //-----------------------------------------------------------------------------
62 
64 }
65 
66 //-----------------------------------------------------------------------------
67 
76 
77  if ( undoStates_.empty() )
78  return;
79 
80  GroupBackup* current = dynamic_cast< GroupBackup* >( currentState_ );
81 
82  if ( current == 0 )
83  return;
84 
85  IdList ids = current->objectIDs();
86 
87  for (unsigned int i=0; i < ids.size(); i++ ){
88 
89  //get backup data and perform object undo
90  BaseObjectData* object = 0;
91  PluginFunctions::getObject(ids[i], object);
92 
93  if ( object != 0 ){
94 
95  if ( object->hasObjectData( OBJECT_BACKUPS ) ){
96 
97  //get backup object data
98  BackupData* backupData = 0;
99 
100  backupData = dynamic_cast< BackupData* >(object->objectData(OBJECT_BACKUPS));
101  backupData->undo();
102  }
103  }
104  }
105 
106  //get backup
107  BaseBackup* backup = undoStates_.back();
108 
109  // update current state
110  undoStates_.pop_back();
111  redoStates_.push_back( currentState_ );
112  currentState_ = backup;
113 }
114 
115 //-----------------------------------------------------------------------------
116 
125 
126  if ( redoStates_.empty() )
127  return;
128 
129  GroupBackup* redoState = dynamic_cast< GroupBackup* >( redoStates_.back() );
130 
131  if ( redoState == 0 )
132  return;
133 
134  IdList ids = redoState->objectIDs();
135 
136  for (unsigned int i=0; i < ids.size(); i++ ){
137 
138  //get backup data and perform object undo
139  BaseObjectData* object = 0;
140  PluginFunctions::getObject(ids[i], object);
141 
142  if ( object != 0 ){
143 
144  if ( object->hasObjectData( OBJECT_BACKUPS ) ){
145 
146  //get backup object data
147  BackupData* backupData = 0;
148 
149  backupData = dynamic_cast< BackupData* >(object->objectData(OBJECT_BACKUPS));
150  backupData->redo();
151  }
152  }
153  }
154 
155  //get backup
156  BaseBackup* backup = redoStates_.back();
157 
158  // update current state
159  redoStates_.pop_back();
160  undoStates_.push_back( currentState_ );
161  currentState_ = backup;
162 }
163 
164 //-----------------------------------------------------------------------------
165 
172 void GroupData::updateBackupData(int _objectid, bool _isUndo){
173 
174  GroupBackup* current = dynamic_cast< GroupBackup* >( currentState_ );
175 
176  if ( current == 0)
177  return;
178 
179  //find last backup that involves this object in the group backupData
180  if ( _isUndo ){
181  //UNDO ACTION
182 
183  //first case the undo is the last one on the stack
184  if ( current->contains(_objectid) ){
185  //get backup
186  BaseBackup* backup = undoStates_.back();
187 
188  // update current state
189  undoStates_.pop_back();
190  redoStates_.push_back( currentState_ );
191  currentState_ = backup;
192 
193  } else {
194  //in this case the global currentState is unaffected by the current action
195  //we find the last action in the undo queue that affects the object and move it to the redoQueue
196  GroupBackup* backup = 0;
197  int backupIndex = -1;
198 
199  for(int i=undoStates_.size()-1; i >= 0; --i){
200  GroupBackup* back = dynamic_cast< GroupBackup* >( undoStates_[i] );
201  if ( back->contains(_objectid) ){
202  backup = back;
203  backupIndex = i;
204  break;
205  }
206  }
207 
208  if (backup != 0){
209  if ( !backup->blocked() ){
210  // we found the backup that was reverted
211  // move it to the redo states
212  undoStates_.erase( undoStates_.begin() + backupIndex );
213  redoStates_.push_back( backup );
214  } else
215  std::cerr << "Error: Cannot updateBackupData. Backup is blocked!" << std::endl;
216  }
217  }
218 
219  } else {
220  //REDO ACTION
221  GroupBackup* backup = 0;
222  int backupIndex = -1;
223 
224  for(int i=redoStates_.size()-1; i >= 0; --i){
225  GroupBackup* back = dynamic_cast< GroupBackup* >( redoStates_[i] );
226  if ( back->contains(_objectid) ){
227  backup = back;
228  backupIndex = i;
229  break;
230  }
231  }
232 
233  if (backup != 0){
234  if ( !backup->blocked() ){
235  // we found the backup that was reverted
236  // it becomes the new current state
237  redoStates_.erase( redoStates_.begin() + backupIndex );
238  undoStates_.push_back( currentState_ );
239  currentState_ = backup;
240  } else
241  std::cerr << "Error: Cannot updateBackupData. Backup is blocked!" << std::endl;
242  }
243  }
244 }
245 
246 //-----------------------------------------------------------------------------
247 
248 void GroupData::undo(int _objectid){
249 
250  //get backup data and perform object undo
251  BaseObjectData* object = 0;
252  PluginFunctions::getObject(_objectid, object);
253 
254  if ( object != 0 ){
255 
256  if ( object->hasObjectData( OBJECT_BACKUPS ) ){
257 
258  //get backup object data
259  BackupData* backupData = dynamic_cast< BackupData* >(object->objectData(OBJECT_BACKUPS));
260 
261  if ( !backupData->undoBlocked() ){
262  backupData->undo();
263  updateBackupData(_objectid, true);
264  }else
265  std::cerr << "Cannot undo operation. This backup involves multiple objects!" << std::endl;
266  }
267  }
268 }
269 
270 //-----------------------------------------------------------------------------
271 
272 void GroupData::redo(int _objectid){
273 
274  //get backup data and perform object undo
275  BaseObjectData* object = 0;
276  PluginFunctions::getObject(_objectid, object);
277 
278  if ( object != 0 ){
279 
280 
281 
282  if ( object->hasObjectData( OBJECT_BACKUPS ) ){
283 
284  //get backup object data
285  BackupData* backupData = dynamic_cast< BackupData* >(object->objectData(OBJECT_BACKUPS));
286 
287  if ( !backupData->redoBlocked() ){
288  backupData->redo();
289  updateBackupData(_objectid, false);
290  }else
291  std::cerr << "Cannot redo operation. This backup involves multiple objects!" << std::endl;
292  }
293  }
294 }
295 
296 //-----------------------------------------------------------------------------
297 
299 {
300 
301  ContainsId_deleter(int _id):id_(_id){}
302  bool operator()(const BaseBackup* _b)
303  {
304  if (dynamic_cast<const GroupBackup* >(_b) && dynamic_cast<const GroupBackup* >(_b)->contains(id_))
305  {
306  delete _b;
307  return true;
308  }
309  return false;
310  }
311 private:
312  int id_;
313 };
314 
315 void GroupData::eraseBackups(int _objectid)
316 {
317  // remove all backups in undo
318  undoStates_.erase(std::remove_if(undoStates_.begin(),undoStates_.end(),ContainsId_deleter(_objectid)), undoStates_.end());
319  redoStates_.erase(std::remove_if(redoStates_.begin(),redoStates_.end(),ContainsId_deleter(_objectid)), redoStates_.end());
320 
321  //reset current state
322  if (ContainsId_deleter(_objectid)(currentState_))
323  {
324  currentState_ = 0;
325  if (!undoStates_.empty())
326  {
327  currentState_ = undoStates_.back();
328  undoStates_.pop_back();
329  }else if (!redoStates_.empty())
330  {
331  currentState_ = redoStates_.back();
332  redoStates_.pop_back();
333  }
334  }
335 
336 }
337 
338 //-----------------------------------------------------------------------------
void updateBackupData(int _objectid, bool _isUndo)
remove object from data
Definition: GroupData.cc:172
bool redoBlocked()
return if a redo backup is blocked
Definition: BackupData.cc:213
void redo()
perform an redo if possible
Definition: GroupData.cc:124
bool getObject(int _identifier, BSplineCurveObject *&_object)
bool blocked()
Returns if this backup is blocked.
Definition: BaseBackup.cc:156
void undo()
perform an undo if possible
Definition: GroupData.cc:75
Abstract class that is used to store backups.
Definition: BackupData.hh:66
Class that encapsulates a backup.
Definition: BaseBackup.hh:62
bool undoBlocked()
return if an undo backup is blocked
Definition: BackupData.cc:203
void eraseBackups(int _objectid)
erase all backups containing given id
Definition: GroupData.cc:315
bool hasObjectData(QString _dataName)
Checks if object data with given name is available.
Definition: BaseObject.cc:806
std::vector< int > IdList
Standard Type for id Lists used for scripting.
Definition: DataTypes.hh:192
void redo()
perform a redo if possible
Definition: BackupData.cc:122
Class that encapsulates simultaneous backups on multiple objects.
Definition: GroupBackup.hh:58
void undo()
perform an undo if possible
Definition: BackupData.cc:103
GroupData()
Constructor.
Definition: GroupData.cc:57
~GroupData()
Destructor.
Definition: GroupData.cc:63