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