From 49d62390045bfc3794f98da72fee9ce0351415fd Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 3 Dec 2012 21:44:16 +0100 Subject: [PATCH] added pop-up menu with create record action --- apps/opencs/CMakeLists.txt | 6 +- apps/opencs/model/world/commands.cpp | 18 ++++++ apps/opencs/model/world/commands.hpp | 18 ++++++ apps/opencs/model/world/idcollection.hpp | 56 +++++++++++++++++++ apps/opencs/model/world/idtable.cpp | 30 ++++++++++ apps/opencs/model/world/idtable.hpp | 18 ++++-- apps/opencs/model/world/idtableproxymodel.cpp | 18 ++++++ apps/opencs/model/world/idtableproxymodel.hpp | 24 ++++++++ apps/opencs/model/world/record.hpp | 17 +++--- apps/opencs/view/world/globals.cpp | 2 +- apps/opencs/view/world/table.cpp | 45 +++++++++++++-- apps/opencs/view/world/table.hpp | 18 +++++- 12 files changed, 246 insertions(+), 24 deletions(-) create mode 100644 apps/opencs/model/world/idtableproxymodel.cpp create mode 100644 apps/opencs/model/world/idtableproxymodel.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index dfd9873450..6d18a1811a 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -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/commands.cpp model/world/idtableproxymodel.cpp view/doc/viewmanager.cpp view/doc/view.cpp view/doc/operations.cpp view/doc/operation.cpp @@ -18,10 +18,10 @@ set (OPENCS_HDR model/doc/documentmanager.hpp model/doc/document.hpp model/world/universalid.hpp model/world/record.hpp model/world/idcollection.hpp model/world/data.hpp - model/world/idtable.hpp model/world/columns.hpp + model/world/idtable.hpp model/world/columns.hpp model/world/idtableproxymodel.hpp + model/world/commands.hpp view/doc/viewmanager.hpp view/doc/view.hpp view/doc/operations.hpp view/doc/operation.hpp - model/world/commands.hpp view/world/subview.hpp view/world/table.hpp view/world/globals.hpp ) diff --git a/apps/opencs/model/world/commands.cpp b/apps/opencs/model/world/commands.cpp index a15d00619f..7bb76acd0a 100644 --- a/apps/opencs/model/world/commands.cpp +++ b/apps/opencs/model/world/commands.cpp @@ -3,6 +3,8 @@ #include +#include "idtableproxymodel.hpp" + CSMWorld::ModifyCommand::ModifyCommand (QAbstractItemModel& model, const QModelIndex& index, const QVariant& new_, QUndoCommand *parent) : QUndoCommand (parent), mModel (model), mIndex (index), mNew (new_) @@ -20,4 +22,20 @@ void CSMWorld::ModifyCommand::redo() void CSMWorld::ModifyCommand::undo() { mModel.setData (mIndex, mOld); +} + +CSMWorld::CreateCommand::CreateCommand (IdTableProxyModel& model, const std::string& id, QUndoCommand *parent) +: QUndoCommand (parent), mModel (model), mId (id) +{ + setText (("Create record " + id).c_str()); +} + +void CSMWorld::CreateCommand::redo() +{ + mModel.addRecord (mId); +} + +void CSMWorld::CreateCommand::undo() +{ + mModel.removeRow (mModel.getModelIndex (mId, 0).row()); } \ No newline at end of file diff --git a/apps/opencs/model/world/commands.hpp b/apps/opencs/model/world/commands.hpp index ffaee59ef5..50b9045c61 100644 --- a/apps/opencs/model/world/commands.hpp +++ b/apps/opencs/model/world/commands.hpp @@ -3,6 +3,8 @@ #include "record.hpp" +#include + #include #include #include @@ -12,6 +14,8 @@ class QAbstractItemModel; namespace CSMWorld { + class IdTableProxyModel; + class ModifyCommand : public QUndoCommand { QAbstractItemModel& mModel; @@ -28,6 +32,20 @@ namespace CSMWorld virtual void undo(); }; + + class CreateCommand : public QUndoCommand + { + IdTableProxyModel& mModel; + std::string mId; + + public: + + CreateCommand (IdTableProxyModel& model, const std::string& id, QUndoCommand *parent = 0); + + virtual void redo(); + + virtual void undo(); + }; } #endif \ No newline at end of file diff --git a/apps/opencs/model/world/idcollection.hpp b/apps/opencs/model/world/idcollection.hpp index d9ab167470..be7891bd29 100644 --- a/apps/opencs/model/world/idcollection.hpp +++ b/apps/opencs/model/world/idcollection.hpp @@ -50,6 +50,8 @@ namespace CSMWorld virtual std::string getId (int index) const = 0; + virtual int getIndex (const std::string& id) const = 0; + virtual int getColumns() const = 0; virtual std::string getTitle (int column) const = 0; @@ -65,6 +67,10 @@ namespace CSMWorld virtual void purge() = 0; ///< Remove records that are flagged as erased. + + virtual void removeRows (int index, int count) = 0; + + virtual void appendBlankRecord (const std::string& id) = 0; }; ///< \brief Collection of ID-based records @@ -92,6 +98,8 @@ namespace CSMWorld virtual std::string getId (int index) const; + virtual int getIndex (const std::string& id) const; + virtual int getColumns() const; virtual QVariant getData (int index, int column) const; @@ -108,6 +116,10 @@ namespace CSMWorld virtual void purge(); ///< Remove records that are flagged as erased. + virtual void removeRows (int index, int count) ; + + virtual void appendBlankRecord (const std::string& id); + void addColumn (Column *column); }; @@ -159,6 +171,17 @@ namespace CSMWorld return mRecords.at (index).get().mId; } + template + int IdCollection::getIndex (const std::string& id) const + { + std::map::const_iterator iter = mIndex.find (id); + + if (iter==mIndex.end()) + throw std::runtime_error ("invalid ID: " + id); + + return iter->second; + } + template int IdCollection::getColumns() const { @@ -211,6 +234,39 @@ namespace CSMWorld std::mem_fun_ref (&Record::isErased) // I want lambda :( ), mRecords.end()); } + + template + void IdCollection::removeRows (int index, int count) + { + mRecords.erase (mRecords.begin()+index, mRecords.begin()+index+count); + + typename std::map::iterator iter = mIndex.begin(); + + while (iter!=mIndex.end()) + { + if (iter->second>=index) + { + if (iter->second>=index+count) + { + iter->second -= count; + } + else + { + mIndex.erase (iter++); + } + } + + ++iter; + } + } + + template + void IdCollection::appendBlankRecord (const std::string& id) + { + ESXRecordT record; + record.mId = id; + add (record); + } } #endif diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index 1fc2bfedbe..50a6953d60 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -71,4 +71,34 @@ Qt::ItemFlags CSMWorld::IdTable::flags (const QModelIndex & index) const flags |= Qt::ItemIsEditable; return flags; +} + +bool CSMWorld::IdTable::removeRows (int row, int count, const QModelIndex& parent) +{ + if (parent.isValid()) + return false; + + beginRemoveRows (parent, row, row+count-1); + + mIdCollection->removeRows (row, count); + + endRemoveRows(); + + return true; +} + +void CSMWorld::IdTable::addRecord (const std::string& id) +{ + int index = mIdCollection->getSize(); + + beginInsertRows (QModelIndex(), index, index); + + mIdCollection->appendBlankRecord (id); + + endInsertRows(); +} + +QModelIndex CSMWorld::IdTable::getModelIndex (const std::string& id, int column) const +{ + return index (mIdCollection->getIndex (id), column); } \ No newline at end of file diff --git a/apps/opencs/model/world/idtable.hpp b/apps/opencs/model/world/idtable.hpp index 30af3aaf70..f95873c7a4 100644 --- a/apps/opencs/model/world/idtable.hpp +++ b/apps/opencs/model/world/idtable.hpp @@ -24,17 +24,23 @@ namespace CSMWorld virtual ~IdTable(); - int rowCount (const QModelIndex & parent = QModelIndex()) const; + virtual int rowCount (const QModelIndex & parent = QModelIndex()) const; - int columnCount (const QModelIndex & parent = QModelIndex()) const; + virtual int columnCount (const QModelIndex & parent = QModelIndex()) const; - QVariant data (const QModelIndex & index, int role = Qt::DisplayRole) const; + virtual QVariant data (const QModelIndex & index, int role = Qt::DisplayRole) const; - QVariant headerData (int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; + virtual QVariant headerData (int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; - bool setData ( const QModelIndex &index, const QVariant &value, int role = Qt::EditRole); + virtual bool setData ( const QModelIndex &index, const QVariant &value, int role = Qt::EditRole); - Qt::ItemFlags flags (const QModelIndex & index) const; + virtual Qt::ItemFlags flags (const QModelIndex & index) const; + + virtual bool removeRows (int row, int count, const QModelIndex& parent = QModelIndex()); + + void addRecord (const std::string& id); + + QModelIndex getModelIndex (const std::string& id, int column) const; }; } diff --git a/apps/opencs/model/world/idtableproxymodel.cpp b/apps/opencs/model/world/idtableproxymodel.cpp new file mode 100644 index 0000000000..78995f60bc --- /dev/null +++ b/apps/opencs/model/world/idtableproxymodel.cpp @@ -0,0 +1,18 @@ + +#include "idtableproxymodel.hpp" + +#include "idtable.hpp" + +CSMWorld::IdTableProxyModel::IdTableProxyModel (QObject *parent) +: QSortFilterProxyModel (parent) +{} + +void CSMWorld::IdTableProxyModel::addRecord (const std::string& id) +{ + dynamic_cast (*sourceModel()).addRecord (id); +} + +QModelIndex CSMWorld::IdTableProxyModel::getModelIndex (const std::string& id, int column) const +{ + return mapFromSource (dynamic_cast (*sourceModel()).getModelIndex (id, column)); +} \ No newline at end of file diff --git a/apps/opencs/model/world/idtableproxymodel.hpp b/apps/opencs/model/world/idtableproxymodel.hpp new file mode 100644 index 0000000000..3f1537cce6 --- /dev/null +++ b/apps/opencs/model/world/idtableproxymodel.hpp @@ -0,0 +1,24 @@ +#ifndef CSM_WOLRD_IDTABLEPROXYMODEL_H +#define CSM_WOLRD_IDTABLEPROXYMODEL_H + +#include + +#include + +namespace CSMWorld +{ + class IdTableProxyModel : public QSortFilterProxyModel + { + Q_OBJECT + + public: + + IdTableProxyModel (QObject *parent = 0); + + virtual void addRecord (const std::string& id); + + virtual QModelIndex getModelIndex (const std::string& id, int column) const; + }; +} + +#endif \ No newline at end of file diff --git a/apps/opencs/model/world/record.hpp b/apps/opencs/model/world/record.hpp index c08d2e0d1f..df93501f3e 100644 --- a/apps/opencs/model/world/record.hpp +++ b/apps/opencs/model/world/record.hpp @@ -5,18 +5,21 @@ namespace CSMWorld { - template - struct Record + struct RecordBase { enum State { - State_BaseOnly, // defined in base only - State_Modified, // exists in base, but has been modified - State_ModifiedOnly, // newly created in modified - State_Deleted, // exists in base, but has been deleted - State_Erased // does not exist at all (we mostly treat that the same way as deleted) + State_BaseOnly = 0, // defined in base only + State_Modified = 1, // exists in base, but has been modified + State_ModifiedOnly = 2, // newly created in modified + 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 + struct Record : public RecordBase + { ESXRecordT mBase; ESXRecordT mModified; State mState; diff --git a/apps/opencs/view/world/globals.cpp b/apps/opencs/view/world/globals.cpp index 68c9012aa9..20cdb80f4d 100644 --- a/apps/opencs/view/world/globals.cpp +++ b/apps/opencs/view/world/globals.cpp @@ -6,7 +6,7 @@ CSVWorld::Globals::Globals (const CSMWorld::UniversalId& id, CSMWorld::Data& data, QUndoStack& undoStack) : SubView (id) { - setWidget (mTable = new Table (id, data, undoStack)); + setWidget (mTable = new Table (id, data, undoStack, true)); } void CSVWorld::Globals::setEditLock (bool locked) diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index 590f7ea982..862ebdc79d 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -3,12 +3,14 @@ #include #include -#include #include +#include +#include +#include #include "../../model/world/data.hpp" - #include "../../model/world/commands.hpp" +#include "../../model/world/idtableproxymodel.hpp" namespace CSVWorld { @@ -104,7 +106,19 @@ void CSVWorld::CommandDelegate::setEditLock (bool locked) } -CSVWorld::Table::Table (const CSMWorld::UniversalId& id, CSMWorld::Data& data, QUndoStack& undoStack) + void CSVWorld::Table::contextMenuEvent (QContextMenuEvent *event) +{ + QMenu menu (this); + + if (mCreateAction) + menu.addAction (mCreateAction); + + menu.exec (event->globalPos()); +} + +CSVWorld::Table::Table (const CSMWorld::UniversalId& id, CSMWorld::Data& data, QUndoStack& undoStack, + bool createAndDelete) +: mUndoStack (undoStack), mCreateAction (0) { QAbstractTableModel *model = data.getTableModel (id); @@ -117,10 +131,10 @@ CSVWorld::Table::Table (const CSMWorld::UniversalId& id, CSMWorld::Data& data, Q setItemDelegateForColumn (i, delegate); } - QSortFilterProxyModel *proxyModel = new QSortFilterProxyModel (this); - proxyModel->setSourceModel (model); + mModel = new CSMWorld::IdTableProxyModel (this); + mModel->setSourceModel (model); - setModel (proxyModel); + setModel (mModel); horizontalHeader()->setResizeMode (QHeaderView::Interactive); verticalHeader()->hide(); setSortingEnabled (true); @@ -128,10 +142,29 @@ CSVWorld::Table::Table (const CSMWorld::UniversalId& id, CSMWorld::Data& data, Q setSelectionMode (QAbstractItemView::ExtendedSelection); /// \todo make initial layout fill the whole width of the table + + if (createAndDelete) + { + mCreateAction = new QAction (tr ("CreateRecord"), this); + connect (mCreateAction, SIGNAL (triggered()), this, SLOT (createRecord())); + addAction (mCreateAction); + } } void CSVWorld::Table::setEditLock (bool locked) { for (std::vector::iterator iter (mDelegates.begin()); iter!=mDelegates.end(); ++iter) (*iter)->setEditLock (locked); +} + +#include /// \todo remove +void CSVWorld::Table::createRecord() +{ + /// \todo ask the user for an ID instead. + static int index = 0; + + std::ostringstream stream; + stream << "id" << index++; + + mUndoStack.push (new CSMWorld::CreateCommand (*mModel, stream.str())); } \ No newline at end of file diff --git a/apps/opencs/view/world/table.hpp b/apps/opencs/view/world/table.hpp index ae203f5161..f07f3ff24b 100644 --- a/apps/opencs/view/world/table.hpp +++ b/apps/opencs/view/world/table.hpp @@ -6,11 +6,13 @@ #include class QUndoStack; +class QAction; namespace CSMWorld { class Data; class UniversalId; + class IdTableProxyModel; } namespace CSVWorld @@ -20,13 +22,27 @@ namespace CSVWorld ///< Table widget class Table : public QTableView { + Q_OBJECT + std::vector mDelegates; + QUndoStack& mUndoStack; + QAction *mCreateAction; + CSMWorld::IdTableProxyModel *mModel; + + private: + + void contextMenuEvent (QContextMenuEvent *event); public: - Table (const CSMWorld::UniversalId& id, CSMWorld::Data& data, QUndoStack& undoStack); + Table (const CSMWorld::UniversalId& id, CSMWorld::Data& data, QUndoStack& undoStack, bool createAndDelete); + ///< \param createAndDelete Allow creation and deletion of records. void setEditLock (bool locked); + + private slots: + + void createRecord(); }; }