Commit 0d78e697 authored by Dirk Wilden's avatar Dirk Wilden

new backup plugin

git-svn-id: http://www.openflipper.org/svnrepo/OpenFlipper/branches/Free@11271 383ad7c9-94d9-4d36-a494-682f7c89f535
parent ffd443d0
This diff is collapsed.
......@@ -53,92 +53,12 @@
#include <OpenFlipper/BasePlugin/BackupInterface.hh>
#include <OpenFlipper/BasePlugin/ToolbarInterface.hh>
#include <OpenFlipper/BasePlugin/LoadSaveInterface.hh>
#include <OpenFlipper/BasePlugin/ContextMenuInterface.hh>
#include <OpenFlipper/common/Types.hh>
#include <ObjectIDPointerManagerT.hh>
#include <ObjectTypes/PolyMesh/PolyMesh.hh>
#include <ObjectTypes/TriangleMesh/TriangleMesh.hh>
#include "GroupData.hh"
#ifdef ENABLE_SKELETON_SUPPORT
#include <ObjectTypes/Skeleton/Skeleton.hh>
#endif
#include <QGroupBox>
#include <queue>
class BackupContainerBase {
public:
BackupContainerBase() :
objectId(-1),
backupName("NONE"),
backupNumber(-1),
persistent(false)
{}
virtual ~BackupContainerBase() {
}
void clear() {
// Delete everything in our per Object Container
QMapIterator<QString, PerObjectData* > i (perObjectDatas);
while (i.hasNext()) {
i.next();
delete i.value();
}
perObjectDatas.clear();
}
// Id of the object backed up
int objectId;
// Human readable Name of the Backup
QString backupName;
// Unique number for the given Backup
int backupNumber;
// Persistence flag ( will not be automatically deleted
bool persistent;
// Stores the per Object data objects per Backup
QMap< QString, PerObjectData* > perObjectDatas;
};
class BackupT: public BackupContainerBase{
public:
BackupT():
BackupContainerBase(),
mesh(0),
polyMesh(0)
#ifdef ENABLE_SKELETON_SUPPORT
,skeleton(0)
#endif
{
}
virtual ~BackupT()
{
// if (mesh != 0)
// delete mesh;
//
// if (polyMesh != 0)
// delete polyMesh;
}
public:
TriMesh* mesh;
PolyMesh* polyMesh;
#ifdef ENABLE_SKELETON_SUPPORT
Skeleton* skeleton;
#endif
};
class BackupPlugin : public QObject, BaseInterface , KeyInterface, MenuInterface, BackupInterface, LoggingInterface, ToolbarInterface, LoadSaveInterface
class BackupPlugin : public QObject, BaseInterface , KeyInterface, MenuInterface, BackupInterface, LoggingInterface, ToolbarInterface, LoadSaveInterface, ContextMenuInterface
{
Q_OBJECT
Q_INTERFACES(BaseInterface)
......@@ -148,11 +68,12 @@ Q_INTERFACES(BackupInterface)
Q_INTERFACES(LoggingInterface)
Q_INTERFACES(ToolbarInterface)
Q_INTERFACES(LoadSaveInterface)
Q_INTERFACES(ContextMenuInterface)
signals:
// BaseInterface
void updateView();
void updatedObject(int);
void updatedObject(int _identifier, const UpdateType _type);
// LoggingInterface
void log(Logtype _type, QString _message);
......@@ -162,12 +83,14 @@ signals:
void getMenubarMenu (QString _name, QMenu *& _menu, bool _create);
// BackupInterface
// Tell Plugins about restore state:
void aboutToRestore(int _objectid , int _internalId);
void restore(int _objectid , int _internalId);
void restored( int _objectid , int _internalId);
void createBackupGroup(QString _name, int& _groupId);
void undo(int _objectid);
void undo();
void redo(int _objectid);
void redo();
void aboutToRestore(int _objectid, UpdateType _type);
void restore(int _objectid, UpdateType _type);
void restored(int _objectid, UpdateType _type);
void generateBackup( int _id, QString _name, UpdateType _type);
// ToolBarInterface
void addToolbar(QToolBar* _toolbar);
......@@ -175,11 +98,13 @@ signals:
//KeyInterface
void registerKey(int _key, Qt::KeyboardModifiers _modifiers, QString _description, bool _multiUse = false);
//ContextMenuInterface
void addContextMenuItem(QAction* _action , DataType _objectType, ContextMenuType _type);
private slots:
// BaseInterface
void initializePlugin();
void pluginsInitialized();
void slotAllCleared();
......@@ -191,22 +116,19 @@ private slots:
void objectDeleted (int _objectid);
// Backup Interface
/// Backup an object ( remember that this slot is called on all plugins.
void slotBackup( int _objectid , QString _name , int _internalId, int _groupId = -1);
// Called to prevent automatic removal of a backup.
void slotMakeBackupPersistent(int _objectid, int _internalId);
/// Restore an object
void slotRestoreObject(int _objectid , int _internalId);
// a backup group was added
void slotBackupGroup( QString _name, int _groupId);
void slotCreateBackup( int _objectid, QString _name, UpdateType _type = UPDATE_ALL);
void slotCreateBackup( IdList _objectids , QString _name, std::vector<UpdateType> _types);
void slotUndo(int _objectid);
void slotRedo(int _objectid);
void slotUndo();
void slotRedo();
private slots:
//ContextMenuInterface
void slotUpdateContextMenu( int _objectId );
private slots:
/// Called before showing Backup Menu ( used for updates )
void slotMenuAboutToShow();
void updateButtons();
/// Backup Menu clicked
void slotBackupMenu(QAction* _action);
......@@ -214,6 +136,8 @@ private slots:
/// Backups enabled or disabled checkbox
void slotEnableDisableBackups();
void slotObjectUndo();
void slotObjectRedo();
public slots:
QString version() { return QString("0.1"); };
......@@ -224,80 +148,22 @@ public:
QString name() { return (QString("Backup")); };
QString description( ) { return (QString("Creates Backups of objects when supported by plugins")); };
private:
/** Restore an object ( only for internal use! )
* @param _objectId id of the object to restore
* @param _backupId id of the backup to restore or -1 for last backup
*/
void backupPluginInternalRestore(int _objectId, int _backupId );
/** \brief Get backup data from storage
*
* This function is used to get a backup from the storage
*
*/
bool getBackupData(int _objectId, int _backupId, BackupT*& _container, BaseObjectData*& _object);
private slots:
/// Restore the last backup
void slotUndo();
/// Redo last operation
void slotRedo();
public slots: // scripting
QString getBackupName(int _objectId, int _backupId);
private :
GroupData globalBackup_;
/// map that associates a list of (object-id,backupIDs) to a groupID
std::map< int, std::vector< std::pair<int,int> > > backupGroups_;
/// map from groupID to group name
std::map< int, QString > groupNames_;
/// queue that stores the chronological order of all groupIDs
/// first element is the oldest groupID
std::queue< int > groupUndoQueue_;
std::queue< int > groupRedoQueue_;
/// the latest backup always represents the active state
/// from which we can undo back to older states
int activeGroup_;
/// Update the backup menu
void update_menu();
/// If an object is deleted or not found, this function will clean the backup map
void removeDeletedObject(int _id);
/// The backup Menu
QMenu* backupMenu_;
/// Maximum number of backups per object
int maxBackupsPerElement;
QAction* backupsEnabledAction_;
/// The backup Menu
QMenu* backupMenu_;
QAction* undoMenuAction_;
QAction* redoMenuAction_;
/// The backup archive
/// Don't use the global perObjectData as this would be changed on restore and or backup!
ObjectIDPointerManagerT< std::vector<BackupT>* > backups_;
/** \brief Flag if the menu needs to be updated before showing it.
*
* This flag enables us to decouple updates from updated object
*/
bool menuDirty_;
QAction* backupsEnabledAction_;
//toolbar
QAction* undoAction_;
QAction* redoAction_;
QAction* undoToolAction_;
QAction* redoToolAction_;
QAction* undoContextAction_;
QAction* redoContextAction_;
};
#endif //BACKUPPLUGIN_HH
include (plugin)
if (EXISTS ${CMAKE_SOURCE_DIR}/ObjectTypes/Skeleton)
add_definitions (-DENABLE_SKELETON_SUPPORT)
endif ()
openflipper_plugin ()
openflipper_plugin()
#include "GroupBackup.hh"
#include <OpenFlipper/common/BackupData.hh>
#include <OpenFlipper/BasePlugin/PluginFunctions.hh>
//-----------------------------------------------------------------------------
GroupBackup::GroupBackup(IdList _objectIDs, QString _name)
: BaseBackup(_name),
objectIDs_(_objectIDs)
{
// std::cerr << "Create GroupBackup with name:" << name_.toStdString() << "(id : " << id_ << ")" << std::endl;
//store the backup ids of all objects
for (unsigned int i=0; i < objectIDs_.size(); ++i ){
BaseObjectData* object = 0;
PluginFunctions::getObject(objectIDs_[i], object);
int id = -1;
if ( object != 0 ){
//get backup object data
BackupData* backupData = 0;
if ( object->hasObjectData( OBJECT_BACKUPS ) ){
backupData = dynamic_cast< BackupData* >(object->objectData(OBJECT_BACKUPS));
id = backupData->currentID();
//add links so that object backups know that they have to be applied together
if ( objectIDs_.size() > 1 )
backupData->setLinks(_objectIDs);
}
}
backupIDs_.push_back(id);
}
}
//-----------------------------------------------------------------------------
GroupBackup::~GroupBackup(){
// std::cerr << "Delete GroupBackup with name:" << name_.toStdString() << "(id : " << id_ << ")" << std::endl;
}
//-----------------------------------------------------------------------------
void GroupBackup::apply(){
}
//-----------------------------------------------------------------------------
IdList GroupBackup::objectIDs(){
return objectIDs_;
}
//-----------------------------------------------------------------------------
bool GroupBackup::contains( int _objectid ){
bool found = false;
for(IdList::iterator it = objectIDs_.begin(); it != objectIDs_.end(); ++it)
if ( *it == _objectid ){
found = true;
break;
}
return found;
}
//-----------------------------------------------------------------------------
\ No newline at end of file
......@@ -34,108 +34,36 @@
/*===========================================================================*\
* *
* $Revision$ *
* $LastChangedBy$ *
* $Date$ *
* $Revision: 10745 $ *
* $LastChangedBy: moebius $ *
* $Date: 2011-01-26 10:23:50 +0100 (Wed, 26 Jan 2011) $ *
* *
\*===========================================================================*/
#ifndef GROUPBACKUP_HH
#define GROUPBACKUP_HH
#include <OpenFlipper/common/BaseBackup.hh>
//=============================================================================
//
// CLASS ObjectIDPointerManagerT
//
//
// Author: Henrik Zimmer <henrik@zimmer.to>
//
// Version: $Revision: 1$
// Date: $Author$
// $Date: XX-XX-200X$
//
//=============================================================================
#ifndef OBJECTIDPOINTERMANAGERT_HH
#define OBJECTIDPOINTERMANAGERT_HH
//== INCLUDES =================================================================
#include <map>
#include <vector>
#include <iostream>
//== FORWARDDECLARATIONS ======================================================
//== NAMESPACES ===============================================================
//== CLASS DEFINITION =========================================================
/** Use this class to manage pointers associated with an object in the framework.
/**
* @brief Class that encapsulates simultaneous backups on multiple objects
*/
template < class Pointer >
class ObjectIDPointerManagerT
class GroupBackup : public BaseBackup
{
public:
/// typedef for the idmap
typedef std::map< int, Pointer > PointerObjectIDMap;
public:
GroupBackup(IdList _objectIDs, QString _name);
~GroupBackup();
/// typedef for the pairs
typedef std::pair< int, Pointer > PointerObjectIDPair;
public:
void apply();
IdList objectIDs();
/// Constructor
ObjectIDPointerManagerT() {}
bool contains( int _objectid );
/// Destructor
~ObjectIDPointerManagerT() {}
/** try to get a pointer with the given id
* @param _identifier identifier of corresponding object
* @param _pointer The returned pointer
* @return true if object exists
* */
bool get_pointer(int _identifier, Pointer & _pointer);
/** try to get a pointer with the given id
* @param _identifier identifier of corresponding object
* @return returns either a pointer or if the id does not exist NULL
* */
Pointer get_pointer(int _identifier);
/** Add a pointer to the map
* @param _identifier identifier of corresponding object
* @param _pointer pointer to be added
* */
bool add_pointer(int _identifier, const Pointer & _pointer);
/// Doesn't actually delete object (pointed to by pointer) only clears entry from the map
bool delete_object(int _identifier);
void get_object_ids(std::vector<int> & _ids);
private:
/// Copy constructor (not used)
ObjectIDPointerManagerT(const ObjectIDPointerManagerT& _rhs);
/// Assignment operator (not used)
ObjectIDPointerManagerT& operator=(const ObjectIDPointerManagerT& _rhs);
/// mapping
PointerObjectIDMap pointer_objectID_map_;
private:
IdList objectIDs_;
IdList backupIDs_;
};
//=============================================================================
#if defined(INCLUDE_TEMPLATES) && !defined(OBJECTIDPOINTERMANAGERT_C)
#define OBJECTIDPOINTERMANAGERT_TEMPLATES
#include "ObjectIDPointerManagerT.cc"
#endif
//=============================================================================
#endif // OBJECTIDPOINTERMANAGERT_HH defined
//=============================================================================
#endif //GROUPBACKUP_HH
#include "GroupData.hh"
#include "GroupBackup.hh"
#include <OpenFlipper/BasePlugin/PluginFunctions.hh>
//-----------------------------------------------------------------------------
GroupData::GroupData() : BackupData(0)
{
}
//-----------------------------------------------------------------------------
GroupData::~GroupData(){
}
//-----------------------------------------------------------------------------
/** \brief Undo operation on groups
*
* The undo on groups is different then on single objects
* we cannot revert to the last undo state. We have to check which objects
* are affected by the current state and revert to the last state for all of them
*
*/
void GroupData::undo(){
if ( undoStates_.empty() )
return;
GroupBackup* current = dynamic_cast< GroupBackup* >( currentState_ );
if ( current == 0 )
return;
IdList ids = current->objectIDs();
for (unsigned int i=0; i < ids.size(); i++ ){
//get backup data and perform object undo
BaseObjectData* object = 0;
PluginFunctions::getObject(ids[i], object);
if ( object != 0 ){
//get backup object data
BackupData* backupData = 0;
if ( object->hasObjectData( OBJECT_BACKUPS ) ){
backupData = dynamic_cast< BackupData* >(object->objectData(OBJECT_BACKUPS));
backupData->undo();
}
}
}
//get backup
BaseBackup* backup = undoStates_.back();
// update current state
undoStates_.pop_back();
redoStates_.push_back( currentState_ );
currentState_ = backup;
}
//-----------------------------------------------------------------------------
/** \brief Redo operation on groups
*
* The redo on groups is different then on single objects
* we revert to the last redo state and perform a redo on every
* involved object
*
*/
void GroupData::redo(){
if ( redoStates_.empty() )
return;
GroupBackup* redoState = dynamic_cast< GroupBackup* >( redoStates_.back() );
if ( redoState == 0 )
return;
IdList ids = redoState->objectIDs();
for (unsigned int i=0; i < ids.size(); i++ ){
//get backup data and perform object undo
BaseObjectData* object = 0;
PluginFunctions::getObject(ids[i], object);
if ( object != 0 ){
//get backup object data
BackupData* backupData = 0;
if ( object->hasObjectData( OBJECT_BACKUPS ) ){
backupData = dynamic_cast< BackupData* >(object->objectData(OBJECT_BACKUPS));
backupData->redo();
}
}
}
//get backup
BaseBackup* backup = redoStates_.back();
// update current state
redoStates_.pop_back();
undoStates_.push_back( currentState_ );
currentState_ = backup;
}
//-----------------------------------------------------------------------------
/** \brief Update GroupData structure after object undo/redo
*
* After and undo/redo on an object the global structure has to be updated
* to stay in sync.
*
*/
void GroupData::updateBackupData(int _objectid, bool _isUndo){
GroupBackup* current = dynamic_cast< GroupBackup* >( currentState_ );
if ( current == 0)
return;
//find last backup that involves this object in the group backupData
if ( _isUndo ){
//UNDO ACTION
//first case the undo is the last one on the stack
if ( current->contains(_objectid) ){
//get backup
BaseBackup* backup = undoStates_.back();
// update current state
undoStates_.pop_back();
redoStates_.push_back( currentState_ );
currentState_ = backup;
} else {
//in this case the global currentState is unaffected by the current action
//we find the last action in the undo queue that affects the object and move it to the redoQueue
GroupBackup* backup = 0;
int backupIndex = -1;
for(int i=undoStates_.size()-1; i >= 0; --i){
GroupBackup* back = dynamic_cast< GroupBackup* >( undoStates_[i] );
if ( back->contains(_objectid) ){
backup = back;
backupIndex = i;
break;
}
}
if (backup != 0){
if ( !backup->blocked() ){
// we found the backup that was reverted
// move it to the redo states
undoStates_.erase( undoStates_.begin() + backupIndex );
redoStates_.push_back( backup );
} else
std::cerr << "Error: Cannot updateBackupData. Backup is blocked!" << std::endl;
}
}
} else {
//REDO ACTION
GroupBackup* backup = 0;
int backupIndex = -1;
for(int i=redoStates_.size()-1; i >= 0; --i){
GroupBackup* back = dynamic_cast< GroupBackup* >( redoStates_[i] );
if ( back->contains(_objectid) ){
backup = back;
backupIndex = i;
break;
}
}
if (backup != 0){
if ( !backup->blocked() ){
// we found the backup that was reverted
// it becomes the new current state
redoStates_.erase( redoStates_.begin() + backupIndex );
undoStates_.push_back( currentState_ );
currentState_ = backup;
} else
std::cerr << "Error: Cannot updateBackupData. Backup is blocked!" << std::endl;
}
}
}
//-----------------------------------------------------------------------------
void GroupData::undo(int _objectid){
//get backup data and perform object undo
BaseObjectData* object = 0;
PluginFunctions::getObject(_objectid, object);
if ( object != 0 ){
//get backup object data
BackupData* backupData = 0;
if ( object->hasObjectData( OBJECT_BACKUPS ) ){
backupData = dynamic_cast< BackupData* >(object->objectData(OBJECT_BACKUPS));
if ( !backupData->undoBlocked() ){
backupData->undo();
updateBackupData(_objectid, true);
}else
std::cerr << "Cannot undo operation. This backup involves multiple objects!" << std::endl;
}
}
}