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"
47 #include <OpenFlipper/BasePlugin/PluginFunctions.hh>
48
49 //-----------------------------------------------------------------------------
50
51 GroupData::GroupData() : BackupData(0)
52 {
53 }
54
55 //-----------------------------------------------------------------------------
56
57 GroupData::~GroupData(){
58 }
59
60 //-----------------------------------------------------------------------------
61
69 void GroupData::undo(){
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
118 void GroupData::redo(){
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
292 struct ContainsId_deleter
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 //-----------------------------------------------------------------------------
BackupData::redoBlocked
bool redoBlocked()
return if a redo backup is blocked
Definition: BackupData.cc:205
BackupData::undo
void undo()
perform an undo if possible
Definition: BackupData.cc:95
GroupData::redo
void redo()
perform an redo if possible
Definition: GroupData.cc:118
PluginFunctions.hh
GroupBackup
Class that encapsulates simultaneous backups on multiple objects.
Definition: GroupBackup.hh:52
GroupData::undo
void undo()
perform an undo if possible
Definition: GroupData.cc:69
BaseBackup::blocked
bool blocked()
Returns if this backup is blocked.
Definition: BaseBackup.cc:148
BaseBackup
Class that encapsulates a backup.
Definition: BaseBackup.hh:53
GroupData::updateBackupData
void updateBackupData(int _objectid, bool _isUndo)
remove object from data
Definition: GroupData.cc:166
GroupData::eraseBackups
void eraseBackups(int _objectid)
erase all backups containing given id
Definition: GroupData.cc:309
PluginFunctions::getObject
bool getObject(const int _identifier, BaseObject *&_object)
Get the object which has the given identifier.
Definition: PluginFunctions.cc:294
GroupData::~GroupData
~GroupData()
Destructor.
Definition: GroupData.cc:57
IdList
std::vector< int > IdList
Standard Type for id Lists used for scripting.
Definition: DataTypes.hh:179
BackupData
Abstract class that is used to store backups.
Definition: BackupData.hh:57
ContainsId_deleter
Definition: GroupData.cc:292
BaseObject::hasObjectData
bool hasObjectData(QString _dataName)
Checks if object data with given name is available.
Definition: BaseObject.cc:795
BaseObjectData
Definition: BaseObjectData.hh:102
BackupData::redo
void redo()
perform a redo if possible
Definition: BackupData.cc:114
GroupData::GroupData
GroupData()
Constructor.
Definition: GroupData.cc:51
BackupData::undoBlocked
bool undoBlocked()
return if an undo backup is blocked
Definition: BackupData.cc:195