diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 1f9fe85a24..1cfb5d9a99 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -13,7 +13,8 @@ set (OPENCS_SRC view/doc/viewmanager.cpp view/doc/view.cpp view/doc/operations.cpp view/doc/operation.cpp view/doc/subviewfactory.cpp view/doc/subview.cpp - view/world/table.cpp view/world/tablesubview.cpp view/world/subviews.cpp + view/world/table.cpp view/world/tablesubview.cpp view/world/subviews.cpp view/world/util.cpp + view/world/dialoguesubview.cpp view/tools/reportsubview.cpp view/tools/subviews.cpp ) @@ -33,7 +34,8 @@ set (OPENCS_HDR view/doc/viewmanager.hpp view/doc/view.hpp view/doc/operations.hpp view/doc/operation.hpp view/doc/subviewfactory.hpp view/doc/subview.hpp view/doc/subviewfactoryimp.hpp - view/world/table.hpp view/world/tablesubview.hpp view/world/subviews.hpp + view/world/table.hpp view/world/tablesubview.hpp view/world/subviews.hpp view/world/util.hpp + view/world/dialoguesubview.hpp view/tools/reportsubview.hpp view/tools/subviews.hpp ) diff --git a/apps/opencs/model/world/columnbase.cpp b/apps/opencs/model/world/columnbase.cpp new file mode 100644 index 0000000000..7adc7e6c3a --- /dev/null +++ b/apps/opencs/model/world/columnbase.cpp @@ -0,0 +1,13 @@ + +#include "columnbase.hpp" + +CSMWorld::ColumnBase::ColumnBase (const std::string& title, int flags) +: mTitle (title), mFlags (flags) +{} + +CSMWorld::ColumnBase::~ColumnBase() {} + +bool CSMWorld::ColumnBase::isUserEditable() const +{ + return isEditable(); +} \ No newline at end of file diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp new file mode 100644 index 0000000000..dc077eff60 --- /dev/null +++ b/apps/opencs/model/world/columnbase.hpp @@ -0,0 +1,57 @@ +#ifndef CSM_WOLRD_COLUMNBASE_H +#define CSM_WOLRD_COLUMNBASE_H + +#include + +#include +#include + +#include "record.hpp" + +namespace CSMWorld +{ + struct ColumnBase + { + enum Roles + { + Role_Flags = Qt::UserRole + }; + + enum Flags + { + Flag_Table = 1, // column should be displayed in table view + Flag_Dialogue = 2 // column should be displayed in dialogue view + }; + + std::string mTitle; + int mFlags; + + ColumnBase (const std::string& title, int flag); + + virtual ~ColumnBase(); + + virtual bool isEditable() const = 0; + + virtual bool isUserEditable() const; + ///< Can this column be edited directly by the user? + }; + + template + struct Column : public ColumnBase + { + std::string mTitle; + int mFlags; + + Column (const std::string& title, int flags = Flag_Table | Flag_Dialogue) + : ColumnBase (title, flags) {} + + virtual QVariant get (const Record& record) const = 0; + + virtual void set (Record& record, const QVariant& data) + { + throw std::logic_error ("Column " + mTitle + " is not editable"); + } + }; +} + +#endif diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 188d3a2ac5..f58d77c90b 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -66,6 +66,29 @@ namespace CSMWorld { return true; } + + virtual bool isUserEditable() const + { + return false; + } + }; + + template + struct FixedRecordTypeColumn : public Column + { + int mType; + + FixedRecordTypeColumn (int type) : Column ("Type", 0), mType (type) {} + + virtual QVariant get (const Record& record) const + { + return mType; + } + + virtual bool isEditable() const + { + return false; + } }; } diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index f350299ec7..0da0cba83b 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -14,6 +14,7 @@ CSMWorld::Data::Data() { mGlobals.addColumn (new StringIdColumn); mGlobals.addColumn (new RecordStateColumn); + mGlobals.addColumn (new FixedRecordTypeColumn (UniversalId::Type_Global)); mGlobals.addColumn (new FloatValueColumn); mModels.insert (std::make_pair ( diff --git a/apps/opencs/model/world/idcollection.hpp b/apps/opencs/model/world/idcollection.hpp index 50afa715eb..1b2d1e349f 100644 --- a/apps/opencs/model/world/idcollection.hpp +++ b/apps/opencs/model/world/idcollection.hpp @@ -11,29 +11,10 @@ #include -#include "record.hpp" +#include "columnbase.hpp" namespace CSMWorld { - template - struct Column - { - std::string mTitle; - - Column (const std::string& title) : mTitle (title) {} - - virtual ~Column() {} - - virtual QVariant get (const Record& record) const = 0; - - virtual void set (Record& record, const QVariant& data) - { - throw std::logic_error ("Column " + mTitle + " is not editable"); - } - - virtual bool isEditable() const = 0; - }; - class IdCollectionBase { // not implemented @@ -54,14 +35,12 @@ namespace CSMWorld virtual int getColumns() const = 0; - virtual std::string getTitle (int column) const = 0; + virtual const ColumnBase& getColumn (int column) const = 0; virtual QVariant getData (int index, int column) const = 0; virtual void setData (int index, int column, const QVariant& data) = 0; - virtual bool isEditable (int column) const = 0; - virtual void merge() = 0; ///< Merge modified into base. @@ -125,9 +104,7 @@ namespace CSMWorld virtual void setData (int index, int column, const QVariant& data); - virtual std::string getTitle (int column) const; - - virtual bool isEditable (int column) const; + virtual const ColumnBase& getColumn (int column) const; virtual void merge(); ///< Merge modified into base. @@ -239,15 +216,9 @@ namespace CSMWorld } template - std::string IdCollection::getTitle (int column) const + const ColumnBase& IdCollection::getColumn (int column) const { - return mColumns.at (column)->mTitle; - } - - template - bool IdCollection::isEditable (int column) const - { - return mColumns.at (column)->isEditable(); + return *mColumns.at (column); } template diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index 3fe1fadfef..2815e318c8 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -34,7 +34,7 @@ QVariant CSMWorld::IdTable::data (const QModelIndex & index, int role) const if (role!=Qt::DisplayRole && role!=Qt::EditRole) return QVariant(); - if (role==Qt::EditRole && !mIdCollection->isEditable (index.column())) + if (role==Qt::EditRole && !mIdCollection->getColumn (index.column()).isEditable()) return QVariant(); return mIdCollection->getData (index.row(), index.column()); @@ -42,18 +42,21 @@ QVariant CSMWorld::IdTable::data (const QModelIndex & index, int role) const QVariant CSMWorld::IdTable::headerData (int section, Qt::Orientation orientation, int role) const { - if (role!=Qt::DisplayRole) - return QVariant(); - if (orientation==Qt::Vertical) return QVariant(); - return tr (mIdCollection->getTitle (section).c_str()); + if (role==Qt::DisplayRole) + return tr (mIdCollection->getColumn (section).mTitle.c_str()); + + if (role==ColumnBase::Role_Flags) + return mIdCollection->getColumn (section).mFlags; + + return QVariant(); } bool CSMWorld::IdTable::setData ( const QModelIndex &index, const QVariant &value, int role) { - if (mIdCollection->isEditable (index.column()) && role==Qt::EditRole) + if (mIdCollection->getColumn (index.column()).isEditable() && role==Qt::EditRole) { mIdCollection->setData (index.row(), index.column(), value); @@ -70,7 +73,7 @@ Qt::ItemFlags CSMWorld::IdTable::flags (const QModelIndex & index) const { Qt::ItemFlags flags = Qt::ItemIsSelectable | Qt::ItemIsEnabled; - if (mIdCollection->isEditable (index.column())) + if (mIdCollection->getColumn (index.column()).isUserEditable()) flags |= Qt::ItemIsEditable; return flags; diff --git a/apps/opencs/model/world/universalid.cpp b/apps/opencs/model/world/universalid.cpp index 81561bcf42..d8775643ac 100644 --- a/apps/opencs/model/world/universalid.cpp +++ b/apps/opencs/model/world/universalid.cpp @@ -24,6 +24,7 @@ namespace static const TypeData sIdArg[] = { + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Global, "Global Variable" }, { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker }; @@ -208,8 +209,8 @@ std::string CSMWorld::UniversalId::toString() const switch (mArgumentType) { case ArgumentType_None: break; - case ArgumentType_Id: stream << ": " << mId; - case ArgumentType_Index: stream << ": " << mIndex; + case ArgumentType_Id: stream << ": " << mId; break; + case ArgumentType_Index: stream << ": " << mIndex; break; } return stream.str(); diff --git a/apps/opencs/model/world/universalid.hpp b/apps/opencs/model/world/universalid.hpp index 8f43bf0838..4a73feb12c 100644 --- a/apps/opencs/model/world/universalid.hpp +++ b/apps/opencs/model/world/universalid.hpp @@ -36,6 +36,8 @@ namespace CSMWorld Type_Globals, + Type_Global, + Type_VerificationResults }; diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp new file mode 100644 index 0000000000..e2d16f1e3b --- /dev/null +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -0,0 +1,14 @@ + +#include "dialoguesubview.hpp" + +CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document, + bool createAndDelete) +: SubView (id) +{ + +} + +void CSVWorld::DialogueSubView::setEditLock (bool locked) +{ + +} \ No newline at end of file diff --git a/apps/opencs/view/world/dialoguesubview.hpp b/apps/opencs/view/world/dialoguesubview.hpp new file mode 100644 index 0000000000..c57dab1084 --- /dev/null +++ b/apps/opencs/view/world/dialoguesubview.hpp @@ -0,0 +1,24 @@ +#ifndef CSV_WORLD_DIALOGUESUBVIEW_H +#define CSV_WORLD_DIALOGUESUBVIEW_H + +#include "../doc/subview.hpp" + +namespace CSMDoc +{ + class Document; +} + +namespace CSVWorld +{ + class DialogueSubView : public CSVDoc::SubView + { + + public: + + DialogueSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document, bool createAndDelete); + + virtual void setEditLock (bool locked); + }; +} + +#endif \ No newline at end of file diff --git a/apps/opencs/view/world/subviews.cpp b/apps/opencs/view/world/subviews.cpp index fdc0cb31d1..080a175ea5 100644 --- a/apps/opencs/view/world/subviews.cpp +++ b/apps/opencs/view/world/subviews.cpp @@ -4,9 +4,13 @@ #include "../doc/subviewfactoryimp.hpp" #include "tablesubview.hpp" +#include "dialoguesubview.hpp" void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) { manager.add (CSMWorld::UniversalId::Type_Globals, new CSVDoc::SubViewFactoryWithCreateFlag (true)); + + manager.add (CSMWorld::UniversalId::Type_Global, + new CSVDoc::SubViewFactoryWithCreateFlag (true)); } \ No newline at end of file diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index 593dc85633..0721ead2c0 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -1,9 +1,8 @@ #include "table.hpp" -#include #include -#include + #include #include #include @@ -14,98 +13,7 @@ #include "../../model/world/idtable.hpp" #include "../../model/world/record.hpp" -namespace CSVWorld -{ - ///< \brief Getting the data out of an editor widget - /// - /// Really, Qt? Really? - class NastyTableModelHack : public QAbstractTableModel - { - QAbstractItemModel& mModel; - QVariant mData; - - public: - - NastyTableModelHack (QAbstractItemModel& model); - - int rowCount (const QModelIndex & parent = QModelIndex()) const; - - int columnCount (const QModelIndex & parent = QModelIndex()) const; - - QVariant data (const QModelIndex & index, int role = Qt::DisplayRole) const; - - bool setData (const QModelIndex &index, const QVariant &value, int role = Qt::EditRole); - - QVariant getData() const; - }; - - ///< \brief Use commands instead of manipulating the model directly - class CommandDelegate : public QStyledItemDelegate - { - QUndoStack& mUndoStack; - bool mEditLock; - - public: - - CommandDelegate (QUndoStack& undoStack, QObject *parent); - - void setModelData (QWidget *editor, QAbstractItemModel *model, const QModelIndex& index) const; - - void setEditLock (bool locked); - }; - -} - -CSVWorld::NastyTableModelHack::NastyTableModelHack (QAbstractItemModel& model) -: mModel (model) -{} - -int CSVWorld::NastyTableModelHack::rowCount (const QModelIndex & parent) const -{ - return mModel.rowCount (parent); -} - -int CSVWorld::NastyTableModelHack::columnCount (const QModelIndex & parent) const -{ - return mModel.columnCount (parent); -} - -QVariant CSVWorld::NastyTableModelHack::data (const QModelIndex & index, int role) const -{ - return mModel.data (index, role); -} - -bool CSVWorld::NastyTableModelHack::setData ( const QModelIndex &index, const QVariant &value, int role) -{ - mData = value; - return true; -} - -QVariant CSVWorld::NastyTableModelHack::getData() const -{ - return mData; -} - -CSVWorld::CommandDelegate::CommandDelegate (QUndoStack& undoStack, QObject *parent) -: QStyledItemDelegate (parent), mUndoStack (undoStack), mEditLock (false) -{} - -void CSVWorld::CommandDelegate::setModelData (QWidget *editor, QAbstractItemModel *model, - const QModelIndex& index) const -{ - if (!mEditLock) - { - NastyTableModelHack hack (*model); - QStyledItemDelegate::setModelData (editor, &hack, index); - mUndoStack.push (new CSMWorld::ModifyCommand (*model, index, hack.getData())); - } - ///< \todo provide some kind of feedback to the user, indicating that editing is currently not possible. -} - -void CSVWorld::CommandDelegate::setEditLock (bool locked) -{ - mEditLock = locked; -} +#include "util.hpp" void CSVWorld::Table::contextMenuEvent (QContextMenuEvent *event) { @@ -176,15 +84,6 @@ CSVWorld::Table::Table (const CSMWorld::UniversalId& id, CSMWorld::Data& data, Q { mModel = &dynamic_cast (*data.getTableModel (id)); - int columns = mModel->columnCount(); - - for (int i=0; isetSourceModel (mModel); @@ -195,6 +94,22 @@ CSVWorld::Table::Table (const CSMWorld::UniversalId& id, CSMWorld::Data& data, Q setSelectionBehavior (QAbstractItemView::SelectRows); setSelectionMode (QAbstractItemView::ExtendedSelection); + int columns = mModel->columnCount(); + + for (int i=0; iheaderData (i, Qt::Horizontal, CSMWorld::ColumnBase::Role_Flags).toInt(); + + if (flags & CSMWorld::ColumnBase::Flag_Table) + { + CommandDelegate *delegate = new CommandDelegate (undoStack, this); + mDelegates.push_back (delegate); + setItemDelegateForColumn (i, delegate); + } + else + hideColumn (i); + } + /// \todo make initial layout fill the whole width of the table if (createAndDelete) @@ -221,6 +136,13 @@ void CSVWorld::Table::setEditLock (bool locked) mEditLock = locked; } +CSMWorld::UniversalId CSVWorld::Table::getUniversalId (int row) const +{ + return CSMWorld::UniversalId ( + static_cast (mProxyModel->data (mProxyModel->index (row, 2)).toInt()), + mProxyModel->data (mProxyModel->index (row, 0)).toString().toStdString()); +} + #include /// \todo remove void CSVWorld::Table::createRecord() { diff --git a/apps/opencs/view/world/table.hpp b/apps/opencs/view/world/table.hpp index b58ba8328a..df0224583e 100644 --- a/apps/opencs/view/world/table.hpp +++ b/apps/opencs/view/world/table.hpp @@ -50,6 +50,8 @@ namespace CSVWorld void setEditLock (bool locked); + CSMWorld::UniversalId getUniversalId (int row) const; + private slots: void createRecord(); diff --git a/apps/opencs/view/world/tablesubview.cpp b/apps/opencs/view/world/tablesubview.cpp index 4abd531d01..bb4bb76c61 100644 --- a/apps/opencs/view/world/tablesubview.cpp +++ b/apps/opencs/view/world/tablesubview.cpp @@ -10,9 +10,16 @@ CSVWorld::TableSubView::TableSubView (const CSMWorld::UniversalId& id, CSMDoc::D : SubView (id) { setWidget (mTable = new Table (id, document.getData(), document.getUndoStack(), createAndDelete)); + + connect (mTable, SIGNAL (doubleClicked (const QModelIndex&)), this, SLOT (rowActivated (const QModelIndex&))); } void CSVWorld::TableSubView::setEditLock (bool locked) { mTable->setEditLock (locked); +} + +void CSVWorld::TableSubView::rowActivated (const QModelIndex& index) +{ + focusId (mTable->getUniversalId (index.row())); } \ No newline at end of file diff --git a/apps/opencs/view/world/tablesubview.hpp b/apps/opencs/view/world/tablesubview.hpp index 9b0785c470..0e7b8aa302 100644 --- a/apps/opencs/view/world/tablesubview.hpp +++ b/apps/opencs/view/world/tablesubview.hpp @@ -3,7 +3,7 @@ #include "../doc/subview.hpp" -class QUndoStack; +class QModelIndex; namespace CSMDoc { @@ -16,6 +16,8 @@ namespace CSVWorld class TableSubView : public CSVDoc::SubView { + Q_OBJECT + Table *mTable; public: @@ -23,6 +25,10 @@ namespace CSVWorld TableSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document, bool createAndDelete); virtual void setEditLock (bool locked); + + private slots: + + void rowActivated (const QModelIndex& index); }; } diff --git a/apps/opencs/view/world/util.cpp b/apps/opencs/view/world/util.cpp new file mode 100644 index 0000000000..7181dd4d17 --- /dev/null +++ b/apps/opencs/view/world/util.cpp @@ -0,0 +1,57 @@ + +#include "util.hpp" + +#include + +#include "../../model/world/commands.hpp" + +CSVWorld::NastyTableModelHack::NastyTableModelHack (QAbstractItemModel& model) +: mModel (model) +{} + +int CSVWorld::NastyTableModelHack::rowCount (const QModelIndex & parent) const +{ + return mModel.rowCount (parent); +} + +int CSVWorld::NastyTableModelHack::columnCount (const QModelIndex & parent) const +{ + return mModel.columnCount (parent); +} + +QVariant CSVWorld::NastyTableModelHack::data (const QModelIndex & index, int role) const +{ + return mModel.data (index, role); +} + +bool CSVWorld::NastyTableModelHack::setData ( const QModelIndex &index, const QVariant &value, int role) +{ + mData = value; + return true; +} + +QVariant CSVWorld::NastyTableModelHack::getData() const +{ + return mData; +} + +CSVWorld::CommandDelegate::CommandDelegate (QUndoStack& undoStack, QObject *parent) +: QStyledItemDelegate (parent), mUndoStack (undoStack), mEditLock (false) +{} + +void CSVWorld::CommandDelegate::setModelData (QWidget *editor, QAbstractItemModel *model, + const QModelIndex& index) const +{ + if (!mEditLock) + { + NastyTableModelHack hack (*model); + QStyledItemDelegate::setModelData (editor, &hack, index); + mUndoStack.push (new CSMWorld::ModifyCommand (*model, index, hack.getData())); + } + ///< \todo provide some kind of feedback to the user, indicating that editing is currently not possible. +} + +void CSVWorld::CommandDelegate::setEditLock (bool locked) +{ + mEditLock = locked; +} \ No newline at end of file diff --git a/apps/opencs/view/world/util.hpp b/apps/opencs/view/world/util.hpp new file mode 100644 index 0000000000..1365831186 --- /dev/null +++ b/apps/opencs/view/world/util.hpp @@ -0,0 +1,50 @@ +#ifndef CSV_WORLD_UTIL_H +#define CSV_WORLD_UTIL_H + +#include +#include + +class QUndoStack; + +namespace CSVWorld +{ + ///< \brief Getting the data out of an editor widget + /// + /// Really, Qt? Really? + class NastyTableModelHack : public QAbstractTableModel + { + QAbstractItemModel& mModel; + QVariant mData; + + public: + + NastyTableModelHack (QAbstractItemModel& model); + + int rowCount (const QModelIndex & parent = QModelIndex()) const; + + int columnCount (const QModelIndex & parent = QModelIndex()) const; + + QVariant data (const QModelIndex & index, int role = Qt::DisplayRole) const; + + bool setData (const QModelIndex &index, const QVariant &value, int role = Qt::EditRole); + + QVariant getData() const; + }; + + ///< \brief Use commands instead of manipulating the model directly + class CommandDelegate : public QStyledItemDelegate + { + QUndoStack& mUndoStack; + bool mEditLock; + + public: + + CommandDelegate (QUndoStack& undoStack, QObject *parent); + + void setModelData (QWidget *editor, QAbstractItemModel *model, const QModelIndex& index) const; + + void setEditLock (bool locked); + }; +} + +#endif