Developer Documentation

BackupPlugin.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 "BackupPlugin.hh"
45
46 #include <OpenFlipper/BasePlugin/PluginFunctions.hh>
47 #include <OpenFlipper/common/GlobalOptions.hh>
48
49 #include "GroupBackup.hh"
50
51 #include <QLabel>
52 #include <QHBoxLayout>
53
54 //-----------------------------------------------------------------------------
55 BackupPlugin::BackupPlugin():
56 globalBackup_(),
57 backupMenu_(0),
58 backupsEnabledAction_(0),
59 undoMenuAction_(0),
60 redoMenuAction_(0),
61 undoToolAction_(0),
62 redoToolAction_(0),
63 undoContextAction_(0),
64 redoContextAction_(0),
65 maxBackupSpinBox_(0)
66 {
67
68 }
69
70 //-----------------------------------------------------------------------------
71
72 void BackupPlugin::initializePlugin()
73 {
74 int maxBackups = OpenFlipperSettings().value("BackupPlugin/MaxBackups",static_cast<unsigned>(globalBackup_.maxBackups())).toInt();
75 globalBackup_.setMaxBackups(maxBackups);
76 }
77
78 //-----------------------------------------------------------------------------
79
80 void BackupPlugin::pluginsInitialized() {
81
82 // Create Backup menu
83 emit getMenubarMenu(tr("&Backup"), backupMenu_, true );
84
85 if ( OpenFlipper::Options::gui() ) {
86 //construct the menu
87 backupsEnabledAction_ = new QAction("Backups Enabled",0);
88 backupsEnabledAction_->setCheckable(true);
89 connect (backupsEnabledAction_, SIGNAL(triggered(bool)), this, SLOT(slotEnableDisableBackups()) );
90
91 undoMenuAction_ = new QAction(tr("&Undo"), this);
92 undoMenuAction_->setEnabled(false);
93 undoMenuAction_->setStatusTip(tr("Undo the last action."));
94 undoMenuAction_->setIcon(QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"edit-undo.png") );
95 connect(undoMenuAction_, SIGNAL(triggered()), this, SIGNAL( undo() ) );
96
97 redoMenuAction_ = new QAction(tr("&Redo"), this);
98 redoMenuAction_->setEnabled(false);
99 redoMenuAction_->setStatusTip(tr("Redo the last action"));
100 redoMenuAction_->setIcon(QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"edit-redo.png") );
101 connect(redoMenuAction_, SIGNAL(triggered()), this, SIGNAL( redo() ) );
102
103 backupMenu_->addAction(undoMenuAction_);
104 backupMenu_->addAction(redoMenuAction_);
105 backupMenu_->addSeparator();
106 backupMenu_->addAction(backupsEnabledAction_);
107
108 // Add a backup Toolbar
109 QToolBar* toolbar = new QToolBar("Backup Toolbar");
110
111 //Undo
112 undoToolAction_ = new QAction(tr("&Undo"), this);
113 undoToolAction_->setEnabled(false);
114 undoToolAction_->setStatusTip(tr("Undo the last action."));
115 undoToolAction_->setIcon(QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"edit-undo.png") );
116 connect(undoToolAction_, SIGNAL(triggered()), this, SIGNAL( undo() ) );
117 toolbar->addAction(undoToolAction_);
118
119 //Redo
120 redoToolAction_ = new QAction(tr("&Redo"), this);
121 redoToolAction_->setEnabled(false);
122 redoToolAction_->setStatusTip(tr("Redo the last action"));
123 redoToolAction_->setIcon(QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"edit-redo.png") );
124 connect(redoToolAction_, SIGNAL(triggered()), this, SIGNAL( redo() ) );
125 toolbar->addAction(redoToolAction_);
126
127 emit addToolbar( toolbar );
128
129 //the release event does not contain the modifier
130 emit registerKey(Qt::Key_Z, Qt::ControlModifier, tr("Undo Action"));
131 emit registerKey(Qt::Key_Z, (Qt::ControlModifier | Qt::ShiftModifier), tr("Redo Action"));
132
133 //add actions for the context menu
134 undoContextAction_ = new QAction(tr("&Undo"), this);
135 undoContextAction_->setEnabled(false);
136 undoContextAction_->setStatusTip(tr("Undo the last action."));
137 undoContextAction_->setIcon(QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"edit-undo.png") );
138 connect(undoContextAction_, SIGNAL(triggered()), this, SLOT(slotObjectUndo()) );
139 emit addContextMenuItem(undoContextAction_, DATA_ALL, CONTEXTOBJECTMENU);
140
141 redoContextAction_ = new QAction(tr("&Redo"), this);
142 redoContextAction_->setEnabled(false);
143 redoContextAction_->setStatusTip(tr("Redo the last action"));
144 redoContextAction_->setIcon(QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"edit-redo.png") );
145 connect(redoContextAction_, SIGNAL(triggered()), this, SLOT(slotObjectRedo()) );
146 emit addContextMenuItem(redoContextAction_, DATA_ALL, CONTEXTOBJECTMENU);
147
148 //update option widget since it is created earlier
149 if (maxBackupSpinBox_)
150 maxBackupSpinBox_->setValue(globalBackup_.maxBackups());
151
152 }
153
154 //createBackup(int _objectId, QString _name, UpdateType _type= UPDATE_ALL)
155 emit setSlotDescription("createBackup(int,QString)", tr("Creates a backup which can be restored via undo."),
156 QString("objectId,name").split(","), QString("Id of the object,name of the backup").split(","));
157 emit setSlotDescription("createBackup(int,QString,UpdateType)", tr("Creates a backup which can be restored via undo."),
158 QString("objectId,name,type").split(","), QString("Id of the object,name of the backup,updatetypes which are changed").split(","));
159 }
160
161 //-----------------------------------------------------------------------------
162
163 void BackupPlugin::slotAllCleared(){
164 globalBackup_.clear();
165 updateButtons();
166 }
167
168 //-----------------------------------------------------------------------------
169
170 void BackupPlugin::updateButtons() {
171
172 if ( globalBackup_.undoAvailable() ){
173 undoMenuAction_->setText( tr("Undo '%1'").arg( globalBackup_.undoName() ) );
174 undoMenuAction_->setEnabled(true);
175 undoToolAction_->setText( tr("Undo '%1'").arg( globalBackup_.undoName() ) );
176 undoToolAction_->setEnabled(true);
177 } else {
178 undoMenuAction_->setText( tr("Undo") );
179 undoMenuAction_->setEnabled(false);
180 undoToolAction_->setText( tr("Undo") );
181 undoToolAction_->setEnabled(false);
182 }
183
184 if ( globalBackup_.redoAvailable() ){
185 redoMenuAction_->setText( tr("Redo '%1'").arg( globalBackup_.redoName() ) );
186 redoMenuAction_->setEnabled(true);
187 redoToolAction_->setText( tr("Redo '%1'").arg( globalBackup_.redoName() ) );
188 redoToolAction_->setEnabled(true);
189 } else {
190 redoMenuAction_->setText( tr("Redo") );
191 redoMenuAction_->setEnabled(false);
192 redoToolAction_->setText( tr("Redo") );
193 redoToolAction_->setEnabled(false);
194 }
195
196 backupsEnabledAction_->setChecked( OpenFlipper::Options::backupEnabled() );
197 }
198
199 //-----------------------------------------------------------------------------
200
201 void BackupPlugin::slotEnableDisableBackups() {
202 OpenFlipper::Options::enableBackup(backupsEnabledAction_->isChecked());
203 }
204
205 //-----------------------------------------------------------------------------
206
207 void BackupPlugin::slotKeyEvent( QKeyEvent* _event ){
208 switch (_event->key())
209 {
210 case Qt::Key_Z :
211 if ( _event->modifiers() == Qt::ControlModifier )
212 emit undo();
213 else if ( _event->modifiers() == (Qt::ControlModifier | Qt::ShiftModifier) )
214 emit redo();
215 break;
216 default:
217 break;
218 }
219 }
220
221 //-----------------------------------------------------------------------------
222
223 void BackupPlugin::objectDeleted(int _objectid) {
224 globalBackup_.eraseBackups(_objectid);
225 updateButtons();
226 }
227
228 //-----------------------------------------------------------------------------
229
230 void BackupPlugin::slotUpdateContextMenu( int _objectId ){
231
232 //disable everything
233 undoContextAction_->setText( tr("Undo") );
234 undoContextAction_->setEnabled(false);
235 redoContextAction_->setText( tr("Redo") );
236 redoContextAction_->setEnabled(false);
237
238 //get backup data
239 BaseObjectData* object = 0;
240 PluginFunctions::getObject(_objectId, object);
241
242 if ( object != 0 ){
243
244 if ( object->hasObjectData( OBJECT_BACKUPS ) ){
245
246 //get backup object data
247 BackupData* backupData = dynamic_cast< BackupData* >(object->objectData(OBJECT_BACKUPS));
248
249 if ( backupData->undoAvailable() ){
250 undoContextAction_->setData(_objectId);
251 undoContextAction_->setText( tr("Undo '%1'").arg( backupData->undoName() ) );
252 undoContextAction_->setEnabled( !backupData->undoBlocked() );
253 }
254
255 if ( backupData->redoAvailable() ){
256 redoContextAction_->setData(_objectId);
257 redoContextAction_->setText( tr("Redo '%1'").arg( backupData->redoName() ) );
258 redoContextAction_->setEnabled( !backupData->redoBlocked() );
259 }
260 }
261 }
262
263 }
264
265 //-----------------------------------------------------------------------------
266
267 void BackupPlugin::slotObjectUndo(){
268
269 int id = undoContextAction_->data().toInt();
270 emit undo(id);
271 }
272
273 //-----------------------------------------------------------------------------
274
275 void BackupPlugin::slotObjectRedo(){
276
277 int id = undoContextAction_->data().toInt();
278 emit redo(id);
279 }
280
281 //-----------------------------------------------------------------------------
282
283 void BackupPlugin::slotCreateBackup( int _objectid, QString _name, UpdateType _type){
284
285 if ( !OpenFlipper::Options::backupEnabled() )
286 return;
287
288 BaseObjectData* object;
289
290 if ( !PluginFunctions::getObject(_objectid,object) ){
291 emit log(LOGWARN,"Unable to find backup object with id " + QString::number(_objectid));
292 return;
293 }
294
295 //tell TypePlugin to Backup
296 emit generateBackup( _objectid, _name, _type );
297
298 //add global backup
299 IdList groupIds;
300 groupIds.push_back( _objectid );
301
302 bool skipBackup = false;
303
304 if ( globalBackup_.undoAvailable() ){
305 //skip 'Original Object' Backups in global view
306 BackupData* backupData = dynamic_cast< BackupData* >(object->objectData(OBJECT_BACKUPS));
307
308 if ( backupData != 0 )
309 skipBackup = !backupData->undoAvailable();
310 }
311
312 if ( !skipBackup ){
313 GroupBackup* backup = new GroupBackup(groupIds, _name);
314 globalBackup_.storeBackup( backup );
315 }
316
317 updateButtons();
318 emit log(LOGOUT,"Created backup for " + QString::number(_objectid)+ " , Name : '" + _name + "'" );
319 }
320
321 //-----------------------------------------------------------------------------
322
323 void BackupPlugin::slotCreateBackup( IdList _objectids , QString _name, std::vector<UpdateType> _types){
324
325 if ( !OpenFlipper::Options::backupEnabled() )
326 return;
327
328 IdList groupIds;
329
330 if ( _objectids.size() != _types.size() ){
331 emit log(LOGWARN,"Unable to create backup sizes of ids and updateTypes do not match!");
332 return;
333 }
334
335 //generate backups on all objects
336 for (unsigned int i=0; i < _objectids.size(); ++i){
337
338 BaseObjectData* object;
339
340 if ( !PluginFunctions::getObject(_objectids[i],object) ){
341 emit log(LOGWARN,"Unable to find backup object with id " + QString::number(_objectids[i]));
342 continue;
343 }
344
345 //tell TypePlugin to generate a backup
346 emit generateBackup( _objectids[i], _name, _types[i] );
347 groupIds.push_back( _objectids[i] );
348 }
349
350 //add global backup
351 if ( ! groupIds.empty() ){
352
353 GroupBackup* backup = new GroupBackup(groupIds, _name);
354 globalBackup_.storeBackup( backup );
355
356 updateButtons();
357 emit log(LOGOUT,"Created grouped backup, Name : '" + _name + "'" );
358 }
359 }
360
361 //-----------------------------------------------------------------------------
362
363 void BackupPlugin::slotUndo(int _objectid){
364
365 emit aboutToRestore(_objectid);
366 globalBackup_.undo(_objectid);
367 emit restored(_objectid);
368 emit updatedObject(_objectid, UPDATE_ALL);
369
370 updateButtons();
371 }
372
373 //-----------------------------------------------------------------------------
374
375 void BackupPlugin::slotUndo(){
376 GroupBackup* group = dynamic_cast< GroupBackup* >( globalBackup_.currentState() );
377
378 if (group) {
379 IdList ids = group->objectIDs();
380 IdList::const_iterator it, end;
381 for (it = ids.begin(), end = ids.end(); it != end; ++it)
382 emit aboutToRestore(*it);
383
384 globalBackup_.undo();
385
386 for (unsigned int i=0; i < group->objectIDs().size(); i++)
387 {
388 emit restored(group->objectIDs()[i]);
389 emit updatedObject(group->objectIDs()[i], UPDATE_ALL);
390 }
391
392 updateButtons();
393 } else
394 emit log(LOGWARN,"Unable to find the current GroupBackup");
395 }
396
397 //-----------------------------------------------------------------------------
398
399 void BackupPlugin::slotRedo(int _objectid){
400
401 emit aboutToRestore(_objectid);
402 globalBackup_.redo(_objectid);
403 emit restored(_objectid);
404 emit updatedObject(_objectid, UPDATE_ALL);
405
406 updateButtons();
407 }
408
409 //-----------------------------------------------------------------------------
410
411 void BackupPlugin::slotRedo(){
412 globalBackup_.redo();
413
414 GroupBackup* group = dynamic_cast< GroupBackup* >( globalBackup_.currentState() );
415
416 if ( group != 0)
417 for (unsigned int i=0; i < group->objectIDs().size(); i++)
418 {
419 emit restored(group->objectIDs()[i]);
420 emit updatedObject(group->objectIDs()[i], UPDATE_ALL);
421 }
422
423 updateButtons();
424 }
425
426 //-----------------------------------------------------------------------------
427
428 void BackupPlugin::createBackup(int _objectId, QString _name, UpdateType _type)
429 {
430 slotCreateBackup(_objectId,_name,_type);
431 }
432
433 //-----------------------------------------------------------------------------
434
435 bool BackupPlugin::initializeOptionsWidget(QWidget*& _widget)
436 {
437 QLabel* maxBackupLabel = new QLabel();
438 maxBackupLabel->setText(tr("Max. saved backups: "));
439 maxBackupSpinBox_ = new QSpinBox();
440 maxBackupSpinBox_->setValue(globalBackup_.maxBackups());
441 maxBackupSpinBox_->setRange(0,100);
442
443 QHBoxLayout* layout = new QHBoxLayout();
444 layout->addWidget(maxBackupLabel);
445 layout->addWidget(maxBackupSpinBox_);
446
447 QWidget* baseWidget = new QWidget();
448 baseWidget->setLayout(layout);
449 _widget = baseWidget;
450
451 return true;
452 }
453
454 //-----------------------------------------------------------------------------
455
456 void BackupPlugin::applyOptions()
457 {
458 int maxBackups = maxBackupSpinBox_->value();
459 globalBackup_.setMaxBackups(maxBackups);
460 OpenFlipperSettings().setValue("BackupPlugin/MaxBackups", maxBackups);
461 }
462
463
OpenFlipperSettings
DLLEXPORT OpenFlipperQSettings & OpenFlipperSettings()
QSettings object containing all program settings of OpenFlipper.
Definition: GlobalOptions.cc:1038
BackupData::redoBlocked
bool redoBlocked()
return if a redo backup is blocked
Definition: BackupData.cc:205
LOGWARN
Definition: LoggingInterface.hh:95
UpdateType
Update type class.
Definition: UpdateType.hh:60
UPDATE_ALL
const UpdateType UPDATE_ALL(UpdateTypeSet(1))
Identifier for all updates.
PluginFunctions.hh
GroupBackup
Class that encapsulates simultaneous backups on multiple objects.
Definition: GroupBackup.hh:52
OpenFlipperQSettings::setValue
void setValue(const QString &key, const QVariant &value)
Wrapper function which makes it possible to enable Debugging output with -DOPENFLIPPER_SETTINGS_DEBUG...
Definition: OpenFlipperQSettings.cc:61
GlobalOptions.hh
BackupData::undoName
QString undoName()
return the name of the next undo backup
Definition: BackupData.cc:133
PluginFunctions::getObject
bool getObject(const int _identifier, BaseObject *&_object)
Get the object which has the given identifier.
Definition: PluginFunctions.cc:294
BackupPlugin::createBackup
void createBackup(int _objectId, QString _name, UpdateType _type=UPDATE_ALL)
Tell Backup Plugin to create a backup.
Definition: BackupPlugin.cc:428
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
BackupData::redoName
QString redoName()
return the name of the next redo backup
Definition: BackupData.cc:143
OpenFlipperQSettings::value
QVariant value(const QString &key, const QVariant &defaultValue=QVariant()) const
Definition: OpenFlipperQSettings.cc:46
BaseObject::hasObjectData
bool hasObjectData(QString _dataName)
Checks if object data with given name is available.
Definition: BaseObject.cc:795
BackupPlugin::slotEnableDisableBackups
void slotEnableDisableBackups()
Backups enabled or disabled checkbox.
Definition: BackupPlugin.cc:201
BackupData::redoAvailable
bool redoAvailable()
return if a redo backup is available
Definition: BackupData.cc:189
BackupData::undoAvailable
bool undoAvailable()
return if an undo backup is available
Definition: BackupData.cc:183
BaseObjectData
Definition: BaseObjectData.hh:102
DATA_ALL
const DataType DATA_ALL(UINT_MAX)
Identifier for all available objects.
CONTEXTOBJECTMENU
The Menu will be shown when an object was picked.
Definition: ContextMenuInterface.hh:59
LOGOUT
Definition: LoggingInterface.hh:93
BackupData::undoBlocked
bool undoBlocked()
return if an undo backup is blocked
Definition: BackupData.cc:195