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 #include "GroupData.hh"
45 
46 #include "GroupBackup.hh"
48 
49 //-----------------------------------------------------------------------------
50 
52 {
53 }
54 
55 //-----------------------------------------------------------------------------
56 
58 }
59 
60 //-----------------------------------------------------------------------------
61 
70 
71  if ( undoStates_.empty() )
72  return;
73 
74  GroupBackup* current = dynamic_cast< GroupBackup* >( currentState_ );
75 
76  if ( current == 0 )
77  return;
78 
79  IdList ids = current->objectIDs();
80 
81  for (unsigned int i=0; i < ids.size(); i++ ){
82 
83  //get backup data and perform object undo
84  BaseObjectData* object = 0;
85  PluginFunctions::getObject(ids[i], object);
86 
87  if ( object != 0 ){
88 
89  if ( object->hasObjectData( OBJECT_BACKUPS ) ){
90 
91  //get backup object data
92  BackupData* backupData = 0;
93 
94  backupData = dynamic_cast< BackupData* >(object->objectData(OBJECT_BACKUPS));
95  backupData->undo();
96  }
97  }
98  }
99 
100  //get backup
101  BaseBackup* backup = undoStates_.back();
102 
103  // update current state
104  undoStates_.pop_back();
105  redoStates_.push_back( currentState_ );
106  currentState_ = backup;
107 }
108 
109 //-----------------------------------------------------------------------------
110 
119 
120  if ( redoStates_.empty() )
121  return;
122 
123  GroupBackup* redoState = dynamic_cast< GroupBackup* >( redoStates_.back() );
124 
125  if ( redoState == 0 )
126  return;
127 
128  IdList ids = redoState->objectIDs();
129 
130  for (unsigned int i=0; i < ids.size(); i++ ){
131 
132  //get backup data and perform object undo
133  BaseObjectData* object = 0;
134  PluginFunctions::getObject(ids[i], object);
135 
136  if ( object != 0 ){
137 
138  if ( object->hasObjectData( OBJECT_BACKUPS ) ){
139 
140  //get backup object data
141  BackupData* backupData = 0;
142 
143  backupData = dynamic_cast< BackupData* >(object->objectData(OBJECT_BACKUPS));
144  backupData->redo();
145  }
146  }
147  }
148 
149  //get backup
150  BaseBackup* backup = redoStates_.back();
151 
152  // update current state
153  redoStates_.pop_back();
154  undoStates_.push_back( currentState_ );
155  currentState_ = backup;
156 }
157 
158 //-----------------------------------------------------------------------------
159 
166 void GroupData::updateBackupData(int _objectid, bool _isUndo){
167 
168  GroupBackup* current = dynamic_cast< GroupBackup* >( currentState_ );
169 
170  if ( current == 0)
171  return;
172 
173  //find last backup that involves this object in the group backupData
174  if ( _isUndo ){
175  //UNDO ACTION
176 
177  //first case the undo is the last one on the stack
178  if ( current->contains(_objectid) ){
179  //get backup
180  BaseBackup* backup = undoStates_.back();
181 
182  // update current state
183  undoStates_.pop_back();
184  redoStates_.push_back( currentState_ );
185  currentState_ = backup;
186 
187  } else {
188  //in this case the global currentState is unaffected by the current action
189  //we find the last action in the undo queue that affects the object and move it to the redoQueue
190  GroupBackup* backup = 0;
191  int backupIndex = -1;
192 
193  for(int i=undoStates_.size()-1; i >= 0; --i){
194  GroupBackup* back = dynamic_cast< GroupBackup* >( undoStates_[i] );
195  if ( back->contains(_objectid) ){
196  backup = back;
197  backupIndex = i;
198  break;
199  }
200  }
201 
202  if (backup != 0){
203  if ( !backup->blocked() ){
204  // we found the backup that was reverted
205  // move it to the redo states
206  undoStates_.erase( undoStates_.begin() + backupIndex );
207  redoStates_.push_back( backup );
208  } else
209  std::cerr << "Error: Cannot updateBackupData. Backup is blocked!" << std::endl;
210  }
211  }
212 
213  } else {
214  //REDO ACTION
215  GroupBackup* backup = 0;
216  int backupIndex = -1;
217 
218  for(int i=redoStates_.size()-1; i >= 0; --i){
219  GroupBackup* back = dynamic_cast< GroupBackup* >( redoStates_[i] );
220  if ( back->contains(_objectid) ){
221  backup = back;
222  backupIndex = i;
223  break;
224  }
225  }
226 
227  if (backup != 0){
228  if ( !backup->blocked() ){
229  // we found the backup that was reverted
230  // it becomes the new current state
231  redoStates_.erase( redoStates_.begin() + backupIndex );
232  undoStates_.push_back( currentState_ );
233  currentState_ = backup;
234  } else
235  std::cerr << "Error: Cannot updateBackupData. Backup is blocked!" << std::endl;
236  }
237  }
238 }
239 
240 //-----------------------------------------------------------------------------
241 
242 void GroupData::undo(int _objectid){
243 
244  //get backup data and perform object undo
245  BaseObjectData* object = 0;
246  PluginFunctions::getObject(_objectid, object);
247 
248  if ( object != 0 ){
249 
250  if ( object->hasObjectData( OBJECT_BACKUPS ) ){
251 
252  //get backup object data
253  BackupData* backupData = dynamic_cast< BackupData* >(object->objectData(OBJECT_BACKUPS));
254 
255  if ( !backupData->undoBlocked() ){
256  backupData->undo();
257  updateBackupData(_objectid, true);
258  }else
259  std::cerr << "Cannot undo operation. This backup involves multiple objects!" << std::endl;
260  }
261  }
262 }
263 
264 //-----------------------------------------------------------------------------
265 
266 void GroupData::redo(int _objectid){
267 
268  //get backup data and perform object undo
269  BaseObjectData* object = 0;
270  PluginFunctions::getObject(_objectid, object);
271 
272  if ( object != 0 ){
273 
274 
275 
276  if ( object->hasObjectData( OBJECT_BACKUPS ) ){
277 
278  //get backup object data
279  BackupData* backupData = dynamic_cast< BackupData* >(object->objectData(OBJECT_BACKUPS));
280 
281  if ( !backupData->redoBlocked() ){
282  backupData->redo();
283  updateBackupData(_objectid, false);
284  }else
285  std::cerr << "Cannot redo operation. This backup involves multiple objects!" << std::endl;
286  }
287  }
288 }
289 
290 //-----------------------------------------------------------------------------
291 
293 {
294 
295  explicit ContainsId_deleter(int _id):id_(_id){}
296  bool operator()(const BaseBackup* _b)
297  {
298  if (dynamic_cast<const GroupBackup* >(_b) && dynamic_cast<const GroupBackup* >(_b)->contains(id_))
299  {
300  delete _b;
301  return true;
302  }
303  return false;
304  }
305 private:
306  int id_;
307 };
308 
309 void GroupData::eraseBackups(int _objectid)
310 {
311  // remove all backups in undo
312  undoStates_.erase(std::remove_if(undoStates_.begin(),undoStates_.end(),ContainsId_deleter(_objectid)), undoStates_.end());
313  redoStates_.erase(std::remove_if(redoStates_.begin(),redoStates_.end(),ContainsId_deleter(_objectid)), redoStates_.end());
314 
315  //reset current state
316  if (ContainsId_deleter(_objectid)(currentState_))
317  {
318  currentState_ = 0;
319  if (!undoStates_.empty())
320  {
321  currentState_ = undoStates_.back();
322  undoStates_.pop_back();
323  }else if (!redoStates_.empty())
324  {
325  currentState_ = redoStates_.back();
326  redoStates_.pop_back();
327  }
328  }
329 
330 }
331 
332 //-----------------------------------------------------------------------------
void redo()
perform a redo if possible
Definition: BackupData.cc:114
~GroupData()
Destructor.
Definition: GroupData.cc:57
void undo()
perform an undo if possible
Definition: GroupData.cc:69
bool blocked()
Returns if this backup is blocked.
Definition: BaseBackup.cc:148
bool undoBlocked()
return if an undo backup is blocked
Definition: BackupData.cc:195
void updateBackupData(int _objectid, bool _isUndo)
remove object from data
Definition: GroupData.cc:166
bool getObject(const int _identifier, BaseObject *&_object)
Get the object which has the given identifier.
Class that encapsulates simultaneous backups on multiple objects.
Definition: GroupBackup.hh:52
std::vector< int > IdList
Standard Type for id Lists used for scripting.
Definition: DataTypes.hh:181
Abstract class that is used to store backups.
Definition: BackupData.hh:57
GroupData()
Constructor.
Definition: GroupData.cc:51
void eraseBackups(int _objectid)
erase all backups containing given id
Definition: GroupData.cc:309
void redo()
perform an redo if possible
Definition: GroupData.cc:118
bool redoBlocked()
return if a redo backup is blocked
Definition: BackupData.cc:205
Class that encapsulates a backup.
Definition: BaseBackup.hh:53
void undo()
perform an undo if possible
Definition: BackupData.cc:95
bool hasObjectData(QString _dataName)
Checks if object data with given name is available.
Definition: BaseObject.cc:795