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