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 //-----------------------------------------------------------------------------
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 
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 
DLLEXPORT OpenFlipperQSettings & OpenFlipperSettings()
QSettings object containing all program settings of OpenFlipper.
bool redoBlocked()
return if a redo backup is blocked
Definition: BackupData.cc:205
Update type class.
Definition: UpdateType.hh:60
const UpdateType UPDATE_ALL(UpdateTypeSet(1))
Identifier for all updates.
Class that encapsulates simultaneous backups on multiple objects.
Definition: GroupBackup.hh:52
void setValue(const QString &key, const QVariant &value)
Wrapper function which makes it possible to enable Debugging output with -DOPENFLIPPER_SETTINGS_DEBUG...
QString undoName()
return the name of the next undo backup
Definition: BackupData.cc:133
bool getObject(const int _identifier, BaseObject *&_object)
Get the object which has the given identifier.
void createBackup(int _objectId, QString _name, UpdateType _type=UPDATE_ALL)
Tell Backup Plugin to create a backup.
std::vector< int > IdList
Standard Type for id Lists used for scripting.
Definition: DataTypes.hh:179
Abstract class that is used to store backups.
Definition: BackupData.hh:57
QString redoName()
return the name of the next redo backup
Definition: BackupData.cc:143
QVariant value(const QString &key, const QVariant &defaultValue=QVariant()) const
bool hasObjectData(QString _dataName)
Checks if object data with given name is available.
Definition: BaseObject.cc:795
void slotEnableDisableBackups()
Backups enabled or disabled checkbox.
bool redoAvailable()
return if a redo backup is available
Definition: BackupData.cc:189
bool undoAvailable()
return if an undo backup is available
Definition: BackupData.cc:183
const DataType DATA_ALL(UINT_MAX)
Identifier for all available objects.
The Menu will be shown when an object was picked.
bool undoBlocked()
return if an undo backup is blocked
Definition: BackupData.cc:195