From 50d61a5b6e057c194f4fddb4d12ee910e1295cda Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 17 Feb 2013 17:27:25 +0100 Subject: [PATCH] proper implementation of gmst type column --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/world/columnbase.hpp | 3 +- apps/opencs/model/world/columns.hpp | 5 +- apps/opencs/view/doc/viewmanager.cpp | 5 + apps/opencs/view/world/enumdelegate.cpp | 101 ++++++++++++++++++++ apps/opencs/view/world/enumdelegate.hpp | 57 ++++++++++++ apps/opencs/view/world/util.cpp | 25 ++++- apps/opencs/view/world/util.hpp | 12 ++- apps/opencs/view/world/vartypedelegate.cpp | 103 +++++++++++++++++++++ apps/opencs/view/world/vartypedelegate.hpp | 38 ++++++++ 10 files changed, 342 insertions(+), 9 deletions(-) create mode 100644 apps/opencs/view/world/enumdelegate.cpp create mode 100644 apps/opencs/view/world/enumdelegate.hpp create mode 100644 apps/opencs/view/world/vartypedelegate.cpp create mode 100644 apps/opencs/view/world/vartypedelegate.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 8cee3f0f4..083aa9630 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -59,7 +59,7 @@ opencs_units (view/world ) opencs_units_noqt (view/world - dialoguesubview util subviews + dialoguesubview util subviews enumdelegate vartypedelegate ) diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index f1871a6a9..40581972e 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -29,7 +29,8 @@ namespace CSMWorld Display_String, Display_Integer, Display_Float, - Display_Var + Display_Var, + Display_VarType }; std::string mTitle; diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index cfbd804a5..2d81a24e9 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -79,7 +79,7 @@ namespace CSMWorld int mType; FixedRecordTypeColumn (int type) - : Column ("Type", ColumnBase::Display_Integer, 0), mType (type) {} + : Column ("Record Type", ColumnBase::Display_Integer, 0), mType (type) {} virtual QVariant get (const Record& record) const { @@ -92,10 +92,11 @@ namespace CSMWorld } }; + /// \attention A var type column must be immediately followed by a suitable value column. template struct VarTypeColumn : public Column { - VarTypeColumn() : Column ("Type", ColumnBase::Display_Integer) {} + VarTypeColumn() : Column ("Type", ColumnBase::Display_VarType) {} virtual QVariant get (const Record& record) const { diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index 2a6309da1..473049999 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -7,6 +7,8 @@ #include "../../model/doc/document.hpp" #include "../world/util.hpp" +#include "../world/enumdelegate.hpp" +#include "../world/vartypedelegate.hpp" #include "view.hpp" @@ -32,6 +34,9 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager) : mDocumentManager (documentManager) { mDelegateFactories = new CSVWorld::CommandDelegateFactoryCollection; + + mDelegateFactories->add (CSMWorld::ColumnBase::Display_VarType, + new CSVWorld::VarTypeDelegateFactory (ESM::VT_None, ESM::VT_String, ESM::VT_Int, ESM::VT_Float)); } CSVDoc::ViewManager::~ViewManager() diff --git a/apps/opencs/view/world/enumdelegate.cpp b/apps/opencs/view/world/enumdelegate.cpp new file mode 100644 index 000000000..7a8b45373 --- /dev/null +++ b/apps/opencs/view/world/enumdelegate.cpp @@ -0,0 +1,101 @@ + +#include "enumdelegate.hpp" + +#include + +#include +#include +#include + +#include "../../model/world/commands.hpp" + +void CSVWorld::EnumDelegate::setModelDataImp (QWidget *editor, QAbstractItemModel *model, + const QModelIndex& index) const +{ + if (QComboBox *comboBox = dynamic_cast (editor)) + { + QString value = comboBox->currentText(); + + for (std::vector >::const_iterator iter (mValues.begin()); + iter!=mValues.end(); ++iter) + if (iter->second==value) + { + addCommands (model, index, iter->first); + break; + } + } +} + +void CSVWorld::EnumDelegate::addCommands (QAbstractItemModel *model, + const QModelIndex& index, int type) const +{ + getUndoStack().push (new CSMWorld::ModifyCommand (*model, index, type)); +} + + +CSVWorld::EnumDelegate::EnumDelegate (const std::vector >& values, + QUndoStack& undoStack, QObject *parent) +: CommandDelegate (undoStack, parent), mValues (values) +{ + +} + +QWidget *CSVWorld::EnumDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem& option, + const QModelIndex& index) const +{ + QComboBox *comboBox = new QComboBox (parent); + + for (std::vector >::const_iterator iter (mValues.begin()); + iter!=mValues.end(); ++iter) + comboBox->addItem (iter->second); + + return comboBox; +} + +void CSVWorld::EnumDelegate::setEditorData (QWidget *editor, const QModelIndex& index) const +{ + if (QComboBox *comboBox = dynamic_cast (editor)) + { + int value = index.data (Qt::EditRole).toInt(); + + std::size_t size = mValues.size(); + + for (std::size_t i=0; isetCurrentIndex (i); + break; + } + } +} + +void CSVWorld::EnumDelegate::paint (QPainter *painter, const QStyleOptionViewItem& option, + const QModelIndex& index) const +{ + QStyleOptionViewItemV4 option2 (option); + + int value = index.data().toInt(); + + for (std::vector >::const_iterator iter (mValues.begin()); + iter!=mValues.end(); ++iter) + if (iter->first==value) + { + option2.text = iter->second; + + QApplication::style()->drawControl (QStyle::CE_ItemViewItem, &option2, painter); + + break; + } +} + + +CSVWorld::CommandDelegate *CSVWorld::EnumDelegateFactory::makeDelegate (QUndoStack& undoStack, + QObject *parent) const +{ + return new EnumDelegate (mValues, undoStack, parent); +} + +void CSVWorld::EnumDelegateFactory::add (int value, const QString& name) +{ + mValues.push_back (std::make_pair (value, name)); +} diff --git a/apps/opencs/view/world/enumdelegate.hpp b/apps/opencs/view/world/enumdelegate.hpp new file mode 100644 index 000000000..f11252371 --- /dev/null +++ b/apps/opencs/view/world/enumdelegate.hpp @@ -0,0 +1,57 @@ +#ifndef CSV_WORLD_ENUMDELEGATE_H +#define CSV_WORLD_ENUMDELEGATE_H + +#include + +#include + +#include + +#include "util.hpp" + +namespace CSVWorld +{ + /// \brief Integer value that represents an enum and is interacted with via a combobox + class EnumDelegate : public CommandDelegate + { + std::vector > mValues; + + private: + + virtual void setModelDataImp (QWidget *editor, QAbstractItemModel *model, + const QModelIndex& index) const; + + virtual void addCommands (QAbstractItemModel *model, + const QModelIndex& index, int type) const; + + public: + + EnumDelegate (const std::vector >& values, + QUndoStack& undoStack, QObject *parent); + + virtual QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem& option, + const QModelIndex& index) const; + + virtual void setEditorData (QWidget *editor, const QModelIndex& index) const; + + virtual void paint (QPainter *painter, const QStyleOptionViewItem& option, + const QModelIndex& index) const; + + }; + + class EnumDelegateFactory : public CommandDelegateFactory + { + std::vector > mValues; + + public: + + virtual CommandDelegate *makeDelegate (QUndoStack& undoStack, QObject *parent) const; + ///< The ownership of the returned CommandDelegate is transferred to the caller. + + void add (int value, const QString& name); + }; + + +} + +#endif \ No newline at end of file diff --git a/apps/opencs/view/world/util.cpp b/apps/opencs/view/world/util.cpp index 85fda2dad..5ada1d84f 100644 --- a/apps/opencs/view/world/util.cpp +++ b/apps/opencs/view/world/util.cpp @@ -88,6 +88,19 @@ const CSVWorld::CommandDelegateFactoryCollection& CSVWorld::CommandDelegateFacto } +QUndoStack& CSVWorld::CommandDelegate::getUndoStack() const +{ + return mUndoStack; +} + +void CSVWorld::CommandDelegate::setModelDataImp (QWidget *editor, QAbstractItemModel *model, + const QModelIndex& index) const +{ + NastyTableModelHack hack (*model); + QStyledItemDelegate::setModelData (editor, &hack, index); + mUndoStack.push (new CSMWorld::ModifyCommand (*model, index, hack.getData())); +} + CSVWorld::CommandDelegate::CommandDelegate (QUndoStack& undoStack, QObject *parent) : QStyledItemDelegate (parent), mUndoStack (undoStack), mEditLock (false) {} @@ -97,14 +110,18 @@ void CSVWorld::CommandDelegate::setModelData (QWidget *editor, QAbstractItemMode { if (!mEditLock) { - NastyTableModelHack hack (*model); - QStyledItemDelegate::setModelData (editor, &hack, index); - mUndoStack.push (new CSMWorld::ModifyCommand (*model, index, hack.getData())); + setModelDataImp (editor, model, index); } + ///< \todo provide some kind of feedback to the user, indicating that editing is currently not possible. } -void CSVWorld::CommandDelegate::setEditLock (bool locked) +void CSVWorld::CommandDelegate::setEditLock (bool locked) { mEditLock = locked; +} + +bool CSVWorld::CommandDelegate::isEditLocked() const +{ + return mEditLock; } \ No newline at end of file diff --git a/apps/opencs/view/world/util.hpp b/apps/opencs/view/world/util.hpp index 79f30da2c..5334abf9c 100644 --- a/apps/opencs/view/world/util.hpp +++ b/apps/opencs/view/world/util.hpp @@ -85,13 +85,23 @@ namespace CSVWorld QUndoStack& mUndoStack; bool mEditLock; + protected: + + QUndoStack& getUndoStack() const; + + virtual void setModelDataImp (QWidget *editor, QAbstractItemModel *model, + const QModelIndex& index) const; + public: CommandDelegate (QUndoStack& undoStack, QObject *parent); - void setModelData (QWidget *editor, QAbstractItemModel *model, const QModelIndex& index) const; + virtual void setModelData (QWidget *editor, QAbstractItemModel *model, + const QModelIndex& index) const; void setEditLock (bool locked); + + bool isEditLocked() const; }; } diff --git a/apps/opencs/view/world/vartypedelegate.cpp b/apps/opencs/view/world/vartypedelegate.cpp new file mode 100644 index 000000000..3ee759ef2 --- /dev/null +++ b/apps/opencs/view/world/vartypedelegate.cpp @@ -0,0 +1,103 @@ + +#include "vartypedelegate.hpp" + +#include + +#include "../../model/world/commands.hpp" + +void CSVWorld::VarTypeDelegate::addCommands (QAbstractItemModel *model, const QModelIndex& index, int type) + const +{ + QModelIndex next = model->index (index.row(), index.column()+1); + + QVariant old = model->data (next); + + QVariant value; + + switch (type) + { + case ESM::VT_Short: + case ESM::VT_Int: + case ESM::VT_Long: + + value = old.toInt(); + break; + + case ESM::VT_Float: + + value = old.toFloat(); + break; + + case ESM::VT_String: + + value = old.toString(); + break; + + default: break; // ignore the rest + } + + getUndoStack().beginMacro ( + "Modify " + model->headerData (index.column(), Qt::Horizontal, Qt::DisplayRole).toString()); + + getUndoStack().push (new CSMWorld::ModifyCommand (*model, index, type)); + getUndoStack().push (new CSMWorld::ModifyCommand (*model, next, value)); + + getUndoStack().endMacro(); +} + +CSVWorld::VarTypeDelegate::VarTypeDelegate (const std::vector >& values, + QUndoStack& undoStack, QObject *parent) +: EnumDelegate (values, undoStack, parent) +{} + + +CSVWorld::VarTypeDelegateFactory::VarTypeDelegateFactory (ESM::VarType type0, + ESM::VarType type1, ESM::VarType type2, ESM::VarType type3) +{ + if (type0!=ESM::VT_Unknown) + add (type0); + + if (type1!=ESM::VT_Unknown) + add (type1); + + if (type2!=ESM::VT_Unknown) + add (type2); + + if (type3!=ESM::VT_Unknown) + add (type3); +} + +CSVWorld::CommandDelegate *CSVWorld::VarTypeDelegateFactory::makeDelegate (QUndoStack& undoStack, + QObject *parent) const +{ + return new VarTypeDelegate (mValues, undoStack, parent); +} + +void CSVWorld::VarTypeDelegateFactory::add (ESM::VarType type) +{ + struct Name + { + ESM::VarType mType; + const char *mName; + }; + + static const Name sNames[] = + { + { ESM::VT_None, "empty" }, + { ESM::VT_Short, "short" }, + { ESM::VT_Int, "long" }, + { ESM::VT_Long, "long" }, + { ESM::VT_Float, "float" }, + { ESM::VT_String, "string" }, + { ESM::VT_Unknown, 0 } // end marker + }; + + for (int i=0; sNames[i].mName; ++i) + if (sNames[i].mType==type) + { + mValues.push_back (std::make_pair (type, sNames[i].mName)); + return; + } + + throw std::logic_error ("Unsupported variable type"); +} diff --git a/apps/opencs/view/world/vartypedelegate.hpp b/apps/opencs/view/world/vartypedelegate.hpp new file mode 100644 index 000000000..621dd316b --- /dev/null +++ b/apps/opencs/view/world/vartypedelegate.hpp @@ -0,0 +1,38 @@ +#ifndef CSV_WORLD_VARTYPEDELEGATE_H +#define CSV_WORLD_VARTYPEDELEGATE_H + +#include "enumdelegate.hpp" + +namespace CSVWorld +{ + class VarTypeDelegate : public EnumDelegate + { + private: + + virtual void addCommands (QAbstractItemModel *model, + const QModelIndex& index, int type) const; + + public: + + VarTypeDelegate (const std::vector >& values, + QUndoStack& undoStack, QObject *parent); + }; + + class VarTypeDelegateFactory : public CommandDelegateFactory + { + std::vector > mValues; + + public: + + VarTypeDelegateFactory (ESM::VarType type0 = ESM::VT_Unknown, + ESM::VarType type1 = ESM::VT_Unknown, ESM::VarType type2 = ESM::VT_Unknown, + ESM::VarType type3 = ESM::VT_Unknown); + + virtual CommandDelegate *makeDelegate (QUndoStack& undoStack, QObject *parent) const; + ///< The ownership of the returned CommandDelegate is transferred to the caller. + + void add (ESM::VarType type); + }; +} + +#endif