added revert command

actorid
Marc Zinnschlag 12 years ago
parent f07b7d17cd
commit b41cc5e9e9

@ -5,7 +5,7 @@ set (OPENCS_SRC
model/doc/documentmanager.cpp model/doc/document.cpp
model/world/universalid.cpp model/world/idcollection.cpp model/world/data.cpp model/world/idtable.cpp
model/world/commands.cpp model/world/idtableproxymodel.cpp
model/world/commands.cpp model/world/idtableproxymodel.cpp model/world/record.cpp
view/doc/viewmanager.cpp view/doc/view.cpp view/doc/operations.cpp view/doc/operation.cpp

@ -57,9 +57,14 @@ namespace CSMWorld
return static_cast<int> (record.mState);
}
virtual void set (Record<ESXRecordT>& record, const QVariant& data)
{
record.mState = static_cast<RecordBase::State> (data.toInt());
}
virtual bool isEditable() const
{
return false;
return true;
}
};
}

@ -4,6 +4,7 @@
#include <QAbstractTableModel>
#include "idtableproxymodel.hpp"
#include "idtable.hpp"
CSMWorld::ModifyCommand::ModifyCommand (QAbstractItemModel& model, const QModelIndex& index,
const QVariant& new_, QUndoCommand *parent)
@ -38,4 +39,37 @@ void CSMWorld::CreateCommand::redo()
void CSMWorld::CreateCommand::undo()
{
mModel.removeRow (mModel.getModelIndex (mId, 0).row());
}
CSMWorld::RevertCommand::RevertCommand (IdTable& model, const std::string& id, QUndoCommand *parent)
: QUndoCommand (parent), mModel (model), mId (id), mOld (0)
{
setText (("Revert record " + id).c_str());
mOld = model.getRecord (id).clone();
}
CSMWorld::RevertCommand::~RevertCommand()
{
delete mOld;
}
void CSMWorld::RevertCommand::redo()
{
QModelIndex index = mModel.getModelIndex (mId, 1);
RecordBase::State state = static_cast<RecordBase::State> (mModel.data (index).toInt());
if (state==RecordBase::State_ModifiedOnly)
{
mModel.removeRows (index.row(), 1);
}
else
{
mModel.setData (index, static_cast<int> (RecordBase::State_BaseOnly));
}
}
void CSMWorld::RevertCommand::undo()
{
mModel.setRecord (*mOld);
}

@ -15,6 +15,8 @@ class QAbstractItemModel;
namespace CSMWorld
{
class IdTableProxyModel;
class IdTable;
class RecordBase;
class ModifyCommand : public QUndoCommand
{
@ -46,6 +48,27 @@ namespace CSMWorld
virtual void undo();
};
class RevertCommand : public QUndoCommand
{
IdTable& mModel;
std::string mId;
RecordBase *mOld;
// not implemented
RevertCommand (const RevertCommand&);
RevertCommand& operator= (const RevertCommand&);
public:
RevertCommand (IdTable& model, const std::string& id, QUndoCommand *parent = 0);
virtual ~RevertCommand();
virtual void redo();
virtual void undo();
};
}
#endif

@ -71,6 +71,25 @@ namespace CSMWorld
virtual void removeRows (int index, int count) = 0;
virtual void appendBlankRecord (const std::string& id) = 0;
virtual int searchId (const std::string& id) const = 0;
////< Search record with \a id.
/// \return index of record (if found) or -1 (not found)
virtual void replace (int index, const RecordBase& record) = 0;
///< If the record type does not match, an exception is thrown.
///
/// \attention \a record must not change the ID.
virtual void appendRecord (const RecordBase& record) = 0;
///< If the record type does not match, an exception is thrown.
virtual std::string getId (const RecordBase& record) const = 0;
///< Return ID for \a record.
///
/// \attention Throw san exception, if the type of \a record does not match.
virtual const RecordBase& getRecord (const std::string& id) const = 0;
};
///< \brief Collection of ID-based records
@ -120,6 +139,25 @@ namespace CSMWorld
virtual void appendBlankRecord (const std::string& id);
virtual int searchId (const std::string& id) const;
////< Search record with \a id.
/// \return index of record (if found) or -1 (not found)
virtual void replace (int index, const RecordBase& record);
///< If the record type does not match, an exception is thrown.
///
/// \attention \a record must not change the ID.
virtual void appendRecord (const RecordBase& record);
///< If the record type does not match, an exception is thrown.
virtual std::string getId (const RecordBase& record) const;
///< Return ID for \a record.
///
/// \attention Throw san exception, if the type of \a record does not match.
virtual const RecordBase& getRecord (const std::string& id) const;
void addColumn (Column<ESXRecordT> *column);
};
@ -174,12 +212,12 @@ namespace CSMWorld
template<typename ESXRecordT>
int IdCollection<ESXRecordT>::getIndex (const std::string& id) const
{
std::map<std::string, int>::const_iterator iter = mIndex.find (id);
int index = searchId (id);
if (iter==mIndex.end())
if (index==-1)
throw std::runtime_error ("invalid ID: " + id);
return iter->second;
return index;
}
template<typename ESXRecordT>
@ -268,6 +306,49 @@ namespace CSMWorld
record.blank();
add (record);
}
template<typename ESXRecordT>
int IdCollection<ESXRecordT>::searchId (const std::string& id) const
{
std::string id2;
std::transform (id.begin(), id.end(), std::back_inserter (id2),
(int(*)(int)) std::tolower);
std::map<std::string, int>::const_iterator iter = mIndex.find (id2);
if (iter==mIndex.end())
return -1;
return iter->second;
}
template<typename ESXRecordT>
void IdCollection<ESXRecordT>::replace (int index, const RecordBase& record)
{
mRecords.at (index) = dynamic_cast<const Record<ESXRecordT>&> (record);
}
template<typename ESXRecordT>
void IdCollection<ESXRecordT>::appendRecord (const RecordBase& record)
{
mRecords.push_back (dynamic_cast<const Record<ESXRecordT>&> (record));
mIndex.insert (std::make_pair (getId (record), mRecords.size()-1));
}
template<typename ESXRecordT>
std::string IdCollection<ESXRecordT>::getId (const RecordBase& record) const
{
const Record<ESXRecordT>& record2 = dynamic_cast<const Record<ESXRecordT>&> (record);
return (record2.isModified() ? record2.mModified : record2.mBase).mId;
}
template<typename ESXRecordT>
const RecordBase& IdCollection<ESXRecordT>::getRecord (const std::string& id) const
{
int index = getIndex (id);
return mRecords.at (index);
}
}
#endif

@ -56,7 +56,10 @@ bool CSMWorld::IdTable::setData ( const QModelIndex &index, const QVariant &valu
if (mIdCollection->isEditable (index.column()) && role==Qt::EditRole)
{
mIdCollection->setData (index.row(), index.column(), value);
emit dataChanged (index, index);
emit dataChanged (CSMWorld::IdTable::index (index.row(), 0),
CSMWorld::IdTable::index (index.row(), mIdCollection->getColumns()-1));
return true;
}
@ -101,4 +104,31 @@ void CSMWorld::IdTable::addRecord (const std::string& id)
QModelIndex CSMWorld::IdTable::getModelIndex (const std::string& id, int column) const
{
return index (mIdCollection->getIndex (id), column);
}
void CSMWorld::IdTable::setRecord (const RecordBase& record)
{
int index = mIdCollection->searchId (mIdCollection->getId (record));
if (index==-1)
{
int index = mIdCollection->getSize();
beginInsertRows (QModelIndex(), index, index);
mIdCollection->appendRecord (record);
endInsertRows();
}
else
{
mIdCollection->replace (index, record);
emit dataChanged (CSMWorld::IdTable::index (index, 0),
CSMWorld::IdTable::index (index, mIdCollection->getColumns()-1));
}
}
const CSMWorld::RecordBase& CSMWorld::IdTable::getRecord (const std::string& id) const
{
return mIdCollection->getRecord (id);
}

@ -6,6 +6,7 @@
namespace CSMWorld
{
class IdCollectionBase;
class RecordBase;
class IdTable : public QAbstractTableModel
{
@ -41,6 +42,11 @@ namespace CSMWorld
void addRecord (const std::string& id);
QModelIndex getModelIndex (const std::string& id, int column) const;
void setRecord (const RecordBase& record);
///< Add record or overwrite existing recrod.
const RecordBase& getRecord (const std::string& id) const;
};
}

@ -0,0 +1,21 @@
#include "record.hpp"
CSMWorld::RecordBase::~RecordBase() {}
bool CSMWorld::RecordBase::RecordBase::isDeleted() const
{
return mState==State_Deleted || mState==State_Erased;
}
bool CSMWorld::RecordBase::RecordBase::isErased() const
{
return mState==State_Erased;
}
bool CSMWorld::RecordBase::RecordBase::isModified() const
{
return mState==State_Modified || mState==State_ModifiedOnly;
}

@ -15,20 +15,27 @@ namespace CSMWorld
State_Deleted = 3, // exists in base, but has been deleted
State_Erased = 4 // does not exist at all (we mostly treat that the same way as deleted)
};
};
template <typename ESXRecordT>
struct Record : public RecordBase
{
ESXRecordT mBase;
ESXRecordT mModified;
State mState;
virtual ~RecordBase();
virtual RecordBase *clone() const = 0;
bool isDeleted() const;
bool isErased() const;
bool isModified() const;
};
template <typename ESXRecordT>
struct Record : public RecordBase
{
ESXRecordT mBase;
ESXRecordT mModified;
virtual RecordBase *clone() const;
const ESXRecordT& get() const;
///< Throws an exception, if the record is deleted.
@ -44,21 +51,9 @@ namespace CSMWorld
};
template <typename ESXRecordT>
bool Record<ESXRecordT>::isDeleted() const
{
return mState==State_Deleted || mState==State_Erased;
}
template <typename ESXRecordT>
bool Record<ESXRecordT>::isErased() const
{
return mState==State_Erased;
}
template <typename ESXRecordT>
bool Record<ESXRecordT>::isModified() const
RecordBase *Record<ESXRecordT>::clone() const
{
return mState==State_Modified || mState==State_ModifiedOnly;
return new Record<ESXRecordT> (*this);
}
template <typename ESXRecordT>

@ -11,6 +11,8 @@
#include "../../model/world/data.hpp"
#include "../../model/world/commands.hpp"
#include "../../model/world/idtableproxymodel.hpp"
#include "../../model/world/idtable.hpp"
#include "../../model/world/record.hpp"
namespace CSVWorld
{
@ -108,11 +110,16 @@ void CSVWorld::CommandDelegate::setEditLock (bool locked)
void CSVWorld::Table::contextMenuEvent (QContextMenuEvent *event)
{
QMenu menu (this);
QModelIndexList selectedRows = selectionModel()->selectedRows();
QMenu menu (this);
if (mCreateAction)
menu.addAction (mCreateAction);
if (selectedRows.size()>0)
menu.addAction (mRevertAction);
menu.exec (event->globalPos());
}
@ -120,9 +127,9 @@ CSVWorld::Table::Table (const CSMWorld::UniversalId& id, CSMWorld::Data& data, Q
bool createAndDelete)
: mUndoStack (undoStack), mCreateAction (0)
{
QAbstractTableModel *model = data.getTableModel (id);
mModel = &dynamic_cast<CSMWorld::IdTable&> (*data.getTableModel (id));
int columns = model->columnCount();
int columns = mModel->columnCount();
for (int i=0; i<columns; ++i)
{
@ -131,10 +138,10 @@ CSVWorld::Table::Table (const CSMWorld::UniversalId& id, CSMWorld::Data& data, Q
setItemDelegateForColumn (i, delegate);
}
mModel = new CSMWorld::IdTableProxyModel (this);
mModel->setSourceModel (model);
mProxyModel = new CSMWorld::IdTableProxyModel (this);
mProxyModel->setSourceModel (mModel);
setModel (mModel);
setModel (mProxyModel);
horizontalHeader()->setResizeMode (QHeaderView::Interactive);
verticalHeader()->hide();
setSortingEnabled (true);
@ -149,6 +156,10 @@ CSVWorld::Table::Table (const CSMWorld::UniversalId& id, CSMWorld::Data& data, Q
connect (mCreateAction, SIGNAL (triggered()), this, SLOT (createRecord()));
addAction (mCreateAction);
}
mRevertAction = new QAction (tr ("Revert Record"), this);
connect (mRevertAction, SIGNAL (triggered()), this, SLOT (revertRecord()));
addAction (mRevertAction);
}
void CSVWorld::Table::setEditLock (bool locked)
@ -166,5 +177,35 @@ void CSVWorld::Table::createRecord()
std::ostringstream stream;
stream << "id" << index++;
mUndoStack.push (new CSMWorld::CreateCommand (*mModel, stream.str()));
mUndoStack.push (new CSMWorld::CreateCommand (*mProxyModel, stream.str()));
}
void CSVWorld::Table::revertRecord()
{
QModelIndexList selectedRows = selectionModel()->selectedRows();
std::vector<std::string> revertableIds;
for (QModelIndexList::const_iterator iter (selectedRows.begin()); iter!=selectedRows.end(); ++iter)
{
std::string id = mProxyModel->data (*iter).toString().toStdString();
CSMWorld::RecordBase::State state =
static_cast<CSMWorld::RecordBase::State> (mModel->data (mModel->getModelIndex (id, 1)).toInt());
if (state!=CSMWorld::RecordBase::State_BaseOnly)
revertableIds.push_back (id);
}
if (revertableIds.size()>0)
{
if (revertableIds.size()>1)
mUndoStack.beginMacro (tr ("Revert multiple records"));
for (std::vector<std::string>::const_iterator iter (revertableIds.begin()); iter!=revertableIds.end(); ++iter)
mUndoStack.push (new CSMWorld::RevertCommand (*mModel, *iter));
if (revertableIds.size()>1)
mUndoStack.endMacro();
}
}

@ -13,6 +13,7 @@ namespace CSMWorld
class Data;
class UniversalId;
class IdTableProxyModel;
class IdTable;
}
namespace CSVWorld
@ -27,7 +28,9 @@ namespace CSVWorld
std::vector<CommandDelegate *> mDelegates;
QUndoStack& mUndoStack;
QAction *mCreateAction;
CSMWorld::IdTableProxyModel *mModel;
QAction *mRevertAction;
CSMWorld::IdTableProxyModel *mProxyModel;
CSMWorld::IdTable *mModel;
private:
@ -43,6 +46,8 @@ namespace CSVWorld
private slots:
void createRecord();
void revertRecord();
};
}

Loading…
Cancel
Save