From f6226e4859c0a089156a4d4c16e7335ff94c3b79 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 8 Aug 2013 15:55:23 +0200 Subject: [PATCH 01/30] added Creator class for filters --- apps/opencs/CMakeLists.txt | 4 ++ apps/opencs/model/filter/filter.hpp | 12 ++--- apps/opencs/view/filter/filtercreator.cpp | 65 +++++++++++++++++++++++ apps/opencs/view/filter/filtercreator.hpp | 41 ++++++++++++++ apps/opencs/view/world/subviews.cpp | 8 ++- 5 files changed, 123 insertions(+), 7 deletions(-) create mode 100644 apps/opencs/view/filter/filtercreator.cpp create mode 100644 apps/opencs/view/filter/filtercreator.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index f7b7daee49..9f33c862a2 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -111,6 +111,10 @@ opencs_hdrs_noqt (model/filter filter ) +opencs_units (view/filter + filtercreator + ) + set (OPENCS_US ) diff --git a/apps/opencs/model/filter/filter.hpp b/apps/opencs/model/filter/filter.hpp index bddc9cc2d8..7630ad4107 100644 --- a/apps/opencs/model/filter/filter.hpp +++ b/apps/opencs/model/filter/filter.hpp @@ -11,15 +11,15 @@ namespace CSMFilter /// \brief Wrapper for Filter record struct Filter : public ESM::Filter { - enum scope + enum Scope { - Global = 0, - Local = 1, - Session = 2, - Content = 3 + Scope_Global = 0, // per user + Scope_Project = 1, // per project + Scope_Session = 2, // exists only for one editing session; not saved + Scope_Content = 3 // embedded in the edited content file }; - scope mScope; + Scope mScope; }; } diff --git a/apps/opencs/view/filter/filtercreator.cpp b/apps/opencs/view/filter/filtercreator.cpp new file mode 100644 index 0000000000..476eacbe16 --- /dev/null +++ b/apps/opencs/view/filter/filtercreator.cpp @@ -0,0 +1,65 @@ + +#include "filtercreator.hpp" + +#include +#include + +#include "../../model/filter/filter.hpp" + +std::string CSVFilter::FilterCreator::getNamespace() const +{ + switch (mScope->currentIndex()) + { + case CSMFilter::Filter::Scope_Global: return "global::"; + case CSMFilter::Filter::Scope_Project: return "project::"; + case CSMFilter::Filter::Scope_Session: return "session::"; + } + + return ""; +} + +void CSVFilter::FilterCreator::update() +{ + mNamespace->setText (QString::fromUtf8 (getNamespace().c_str())); + GenericCreator::update(); +} + +std::string CSVFilter::FilterCreator::getId() const +{ + return getNamespace() + GenericCreator::getId(); +} + +CSVFilter::FilterCreator::FilterCreator (CSMWorld::Data& data, QUndoStack& undoStack, + const CSMWorld::UniversalId& id) +: GenericCreator (data, undoStack, id) +{ + mNamespace = new QLabel ("::", this); + insertAtBeginning (mNamespace, false); + + mScope = new QComboBox (this); + + mScope->addItem ("Global"); + mScope->addItem ("Project"); + mScope->addItem ("Session"); + /// \ŧodo re-enable for OpenMW 1.1 + // mScope->addItem ("Content"); + + connect (mScope, SIGNAL (currentIndexChanged (int)), this, SLOT (setScope (int))); + + insertAtBeginning (mScope, false); + + QLabel *label = new QLabel ("Scope", this); + insertAtBeginning (label, false); + + mScope->setCurrentIndex (2); +} + +void CSVFilter::FilterCreator::reset() +{ + GenericCreator::reset(); +} + +void CSVFilter::FilterCreator::setScope (int index) +{ + update(); +} diff --git a/apps/opencs/view/filter/filtercreator.hpp b/apps/opencs/view/filter/filtercreator.hpp new file mode 100644 index 0000000000..82d38d22c7 --- /dev/null +++ b/apps/opencs/view/filter/filtercreator.hpp @@ -0,0 +1,41 @@ +#ifndef CSV_FILTER_FILTERCREATOR_H +#define CSV_FILTER_FILTERCREATOR_H + +class QComboBox; +class QLabel; + +#include "../world/genericcreator.hpp" + +namespace CSVFilter +{ + class FilterCreator : public CSVWorld::GenericCreator + { + Q_OBJECT + + QComboBox *mScope; + QLabel *mNamespace; + + private: + + std::string getNamespace() const; + + protected: + + void update(); + + virtual std::string getId() const; + + public: + + FilterCreator (CSMWorld::Data& data, QUndoStack& undoStack, + const CSMWorld::UniversalId& id); + + virtual void reset(); + + private slots: + + void setScope (int index); + }; +} + +#endif diff --git a/apps/opencs/view/world/subviews.cpp b/apps/opencs/view/world/subviews.cpp index 2ca711a598..d22e07d89c 100644 --- a/apps/opencs/view/world/subviews.cpp +++ b/apps/opencs/view/world/subviews.cpp @@ -3,6 +3,8 @@ #include "../doc/subviewfactoryimp.hpp" +#include "../filter/filtercreator.hpp" + #include "tablesubview.hpp" #include "dialoguesubview.hpp" #include "scriptsubview.hpp" @@ -33,7 +35,6 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) CSMWorld::UniversalId::Type_Regions, CSMWorld::UniversalId::Type_Birthsigns, CSMWorld::UniversalId::Type_Spells, - CSMWorld::UniversalId::Type_Filters, CSMWorld::UniversalId::Type_None // end marker }; @@ -56,4 +57,9 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) // Other stuff (combined record tables) manager.add (CSMWorld::UniversalId::Type_RegionMap, new CSVDoc::SubViewFactory); + + manager.add (CSMWorld::UniversalId::Type_Filters, + new CSVDoc::SubViewFactoryWithCreator >); + } \ No newline at end of file From a95715b61dbd52237fc21454e1f639bf2b5d3e47 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 9 Aug 2013 13:45:50 +0200 Subject: [PATCH 02/30] added description field to filter record --- apps/opencs/model/world/data.cpp | 1 + components/esm/filter.cpp | 3 +++ components/esm/filter.hpp | 2 ++ 3 files changed, 6 insertions(+) diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 9c5e13562b..4a5dcb38fb 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -150,6 +150,7 @@ CSMWorld::Data::Data() : mRefs (mCells) mFilters.addColumn (new StringIdColumn); mFilters.addColumn (new RecordStateColumn); + mFilters.addColumn (new DescriptionColumn); addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global); addModel (new IdTable (&mGmsts), UniversalId::Type_Gmsts, UniversalId::Type_Gmst); diff --git a/components/esm/filter.cpp b/components/esm/filter.cpp index 205332f6b5..7d4851a5f6 100644 --- a/components/esm/filter.cpp +++ b/components/esm/filter.cpp @@ -7,14 +7,17 @@ void ESM::Filter::load (ESMReader& esm) { mFilter = esm.getHNString ("FILT"); + mDescription = esm.getHNString ("DESC"); } void ESM::Filter::save (ESMWriter& esm) { esm.writeHNCString ("FILT", mFilter); + esm.writeHNCString ("DESC", mDescription); } void ESM::Filter::blank() { mFilter.clear(); + mDescription.clear(); } diff --git a/components/esm/filter.hpp b/components/esm/filter.hpp index 2dde92fb0e..0fd564361e 100644 --- a/components/esm/filter.hpp +++ b/components/esm/filter.hpp @@ -12,6 +12,8 @@ namespace ESM { std::string mId; + std::string mDescription; + std::string mFilter; void load (ESMReader& esm); From f5b06d5d520573dd612e663131a28f7b6cc3eed5 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 9 Aug 2013 14:49:05 +0200 Subject: [PATCH 03/30] basic filter tree structure --- apps/opencs/CMakeLists.txt | 4 ++ apps/opencs/model/filter/binarynode.cpp | 58 ++++++++++++++++++++++++ apps/opencs/model/filter/binarynode.hpp | 42 +++++++++++++++++ apps/opencs/model/filter/booleannode.cpp | 17 +++++++ apps/opencs/model/filter/booleannode.hpp | 31 +++++++++++++ apps/opencs/model/filter/leafnode.cpp | 22 +++++++++ apps/opencs/model/filter/leafnode.hpp | 29 ++++++++++++ apps/opencs/model/filter/node.cpp | 6 +++ apps/opencs/model/filter/node.hpp | 58 ++++++++++++++++++++++++ apps/opencs/model/filter/unarynode.cpp | 34 ++++++++++++++ apps/opencs/model/filter/unarynode.hpp | 37 +++++++++++++++ 11 files changed, 338 insertions(+) create mode 100644 apps/opencs/model/filter/binarynode.cpp create mode 100644 apps/opencs/model/filter/binarynode.hpp create mode 100644 apps/opencs/model/filter/booleannode.cpp create mode 100644 apps/opencs/model/filter/booleannode.hpp create mode 100644 apps/opencs/model/filter/leafnode.cpp create mode 100644 apps/opencs/model/filter/leafnode.hpp create mode 100644 apps/opencs/model/filter/node.cpp create mode 100644 apps/opencs/model/filter/node.hpp create mode 100644 apps/opencs/model/filter/unarynode.cpp create mode 100644 apps/opencs/model/filter/unarynode.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 9f33c862a2..8e0024ad95 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -107,6 +107,10 @@ opencs_units_noqt (model/settings settingsitem ) +opencs_units_noqt (model/filter + node unarynode binarynode leafnode booleannode + ) + opencs_hdrs_noqt (model/filter filter ) diff --git a/apps/opencs/model/filter/binarynode.cpp b/apps/opencs/model/filter/binarynode.cpp new file mode 100644 index 0000000000..0e86930dbb --- /dev/null +++ b/apps/opencs/model/filter/binarynode.cpp @@ -0,0 +1,58 @@ + +#include "binarynode.hpp" + +CSMFilter::BinaryNode::BinaryNode (std::auto_ptr left, std::auto_ptr right) +: mLeft (left), mRight (right) +{} + +const CSMFilter::Node& CSMFilter::BinaryNode::getLeft() const +{ + return *mLeft; +} + +CSMFilter::Node& CSMFilter::BinaryNode::getLeft() +{ + return *mLeft; +} + +const CSMFilter::Node& CSMFilter::BinaryNode::getRight() const +{ + return *mRight; +} + +CSMFilter::Node& CSMFilter::BinaryNode::getRight() +{ + return *mRight; +} + +std::vector CSMFilter::BinaryNode::getReferencedFilters() const +{ + std::vector left = mLeft->getReferencedFilters(); + + std::vector right = mRight->getReferencedFilters(); + + left.insert (left.end(), right.begin(), right.end()); + + return left; +} + +std::vector CSMFilter::BinaryNode::getReferencedColumns() const +{ + std::vector left = mLeft->getReferencedColumns(); + + std::vector right = mRight->getReferencedColumns(); + + left.insert (left.end(), right.begin(), right.end()); + + return left; +} + +bool CSMFilter::BinaryNode::isSimple() const +{ + return false; +} + +bool CSMFilter::BinaryNode::hasUserValue() const +{ + return mLeft->hasUserValue() || mRight->hasUserValue(); +} diff --git a/apps/opencs/model/filter/binarynode.hpp b/apps/opencs/model/filter/binarynode.hpp new file mode 100644 index 0000000000..18cdad2a9f --- /dev/null +++ b/apps/opencs/model/filter/binarynode.hpp @@ -0,0 +1,42 @@ +#ifndef CSM_FILTER_BINARYNODE_H +#define CSM_FILTER_BINARYNODE_H + +#include + +#include "node.hpp" + +namespace CSMFilter +{ + class BinaryNode : public Node + { + std::auto_ptr mLeft; + std::auto_ptr mRight; + + public: + + BinaryNode (std::auto_ptr left, std::auto_ptr right); + + const Node& getLeft() const; + + Node& getLeft(); + + const Node& getRight() const; + + Node& getRight(); + + virtual std::vector getReferencedFilters() const; + ///< Return a list of filters that are used by this node (and must be passed as + /// otherFilters when calling test). + + virtual std::vector getReferencedColumns() const; + ///< Return a list of the IDs of the columns referenced by this node. The column mapping + /// passed into test as columns must contain all columns listed here. + + virtual bool isSimple() const; + ///< \return Can this filter be displayed in simple mode. + + virtual bool hasUserValue() const; + }; +} + +#endif diff --git a/apps/opencs/model/filter/booleannode.cpp b/apps/opencs/model/filter/booleannode.cpp new file mode 100644 index 0000000000..cea130d241 --- /dev/null +++ b/apps/opencs/model/filter/booleannode.cpp @@ -0,0 +1,17 @@ + +#include "booleannode.hpp" + +CSMFilter::BooleanNode::BooleanNode (bool true_) : mTrue (true) {} + +bool CSMFilter::BooleanNode::test (const CSMWorld::IdTable& table, int row, + const std::map& otherFilters, + const std::map& columns, + const std::string& userValue) const +{ + return mTrue; +} + +std::string CSMFilter::BooleanNode::toString (bool numericColumns) const +{ + return mTrue ? "true" : "false"; +} \ No newline at end of file diff --git a/apps/opencs/model/filter/booleannode.hpp b/apps/opencs/model/filter/booleannode.hpp new file mode 100644 index 0000000000..3578c7f3ff --- /dev/null +++ b/apps/opencs/model/filter/booleannode.hpp @@ -0,0 +1,31 @@ +#ifndef CSM_FILTER_BOOLEANNODE_H +#define CSM_FILTER_BOOLEANNODE_H + +#include "leafnode.hpp" + +namespace CSMFilter +{ + class BooleanNode : public LeafNode + { + bool mTrue; + + public: + + BooleanNode (bool true_); + + virtual bool test (const CSMWorld::IdTable& table, int row, + const std::map& otherFilters, + const std::map& columns, + const std::string& userValue) const; + ///< \return Can the specified table row pass through to filter? + /// \param columns column ID to column index mapping + + virtual std::string toString (bool numericColumns) const; + ///< Return a string that represents this node. + /// + /// \param numericColumns Use numeric IDs instead of string to represent columns. + + }; +} + +#endif \ No newline at end of file diff --git a/apps/opencs/model/filter/leafnode.cpp b/apps/opencs/model/filter/leafnode.cpp new file mode 100644 index 0000000000..5c6d4b0428 --- /dev/null +++ b/apps/opencs/model/filter/leafnode.cpp @@ -0,0 +1,22 @@ + +#include "leafnode.hpp" + +std::vector CSMFilter::LeafNode::getReferencedFilters() const +{ + return std::vector(); +} + +std::vector CSMFilter::LeafNode::getReferencedColumns() const +{ + return std::vector(); +} + +bool CSMFilter::LeafNode::isSimple() const +{ + return true; +} + +bool CSMFilter::LeafNode::hasUserValue() const +{ + return false; +} \ No newline at end of file diff --git a/apps/opencs/model/filter/leafnode.hpp b/apps/opencs/model/filter/leafnode.hpp new file mode 100644 index 0000000000..663083ff98 --- /dev/null +++ b/apps/opencs/model/filter/leafnode.hpp @@ -0,0 +1,29 @@ +#ifndef CSM_FILTER_UNARIYNODE_H +#define CSM_FILTER_UNARIYNODE_H + +#include + +#include "node.hpp" + +namespace CSMFilter +{ + class LeafNode : public Node + { + public: + + virtual std::vector getReferencedFilters() const; + ///< Return a list of filters that are used by this node (and must be passed as + /// otherFilters when calling test). + + virtual std::vector getReferencedColumns() const; + ///< Return a list of the IDs of the columns referenced by this node. The column mapping + /// passed into test as columns must contain all columns listed here. + + virtual bool isSimple() const; + ///< \return Can this filter be displayed in simple mode. + + virtual bool hasUserValue() const; + }; +} + +#endif diff --git a/apps/opencs/model/filter/node.cpp b/apps/opencs/model/filter/node.cpp new file mode 100644 index 0000000000..276861cdc4 --- /dev/null +++ b/apps/opencs/model/filter/node.cpp @@ -0,0 +1,6 @@ + +#include "node.hpp" + +CSMFilter::Node::Node() {} + +CSMFilter::Node::~Node() {} \ No newline at end of file diff --git a/apps/opencs/model/filter/node.hpp b/apps/opencs/model/filter/node.hpp new file mode 100644 index 0000000000..09bc3cd420 --- /dev/null +++ b/apps/opencs/model/filter/node.hpp @@ -0,0 +1,58 @@ +#ifndef CSM_FILTER_NODE_H +#define CSM_FILTER_NODE_H + +#include +#include +#include + +namespace CSMWorld +{ + class IdTable; +} + +namespace CSMFilter +{ + /// \brief Root class for the filter node hierarchy + /// + /// \note When the function documentation for this class mentions "this node", this should be + /// interpreted as "the node and all its children". + class Node + { + // not implemented + Node (const Node&); + Node& operator= (const Node&); + + public: + + Node(); + + virtual ~Node(); + + virtual bool test (const CSMWorld::IdTable& table, int row, + const std::map& otherFilters, + const std::map& columns, + const std::string& userValue) const = 0; + ///< \return Can the specified table row pass through to filter? + /// \param columns column ID to column index mapping + + virtual std::vector getReferencedFilters() const = 0; + ///< Return a list of filters that are used by this node (and must be passed as + /// otherFilters when calling test). + + virtual std::vector getReferencedColumns() const = 0; + ///< Return a list of the IDs of the columns referenced by this node. The column mapping + /// passed into test as columns must contain all columns listed here. + + virtual bool isSimple() const = 0; + ///< \return Can this filter be displayed in simple mode. + + virtual bool hasUserValue() const = 0; + + virtual std::string toString (bool numericColumns) const = 0; + ///< Return a string that represents this node. + /// + /// \param numericColumns Use numeric IDs instead of string to represent columns. + }; +} + +#endif diff --git a/apps/opencs/model/filter/unarynode.cpp b/apps/opencs/model/filter/unarynode.cpp new file mode 100644 index 0000000000..f9cc3fdc83 --- /dev/null +++ b/apps/opencs/model/filter/unarynode.cpp @@ -0,0 +1,34 @@ + +#include "unarynode.hpp" + +CSMFilter::UnaryNode::UnaryNode (std::auto_ptr child) : mChild (child) {} + +const CSMFilter::Node& CSMFilter::UnaryNode::getChild() const +{ + return *mChild; +} + +CSMFilter::Node& CSMFilter::UnaryNode::getChild() +{ + return *mChild; +} + +std::vector CSMFilter::UnaryNode::getReferencedFilters() const +{ + return mChild->getReferencedFilters(); +} + +std::vector CSMFilter::UnaryNode::getReferencedColumns() const +{ + return mChild->getReferencedColumns(); +} + +bool CSMFilter::UnaryNode::isSimple() const +{ + return false; +} + +bool CSMFilter::UnaryNode::hasUserValue() const +{ + return mChild->hasUserValue(); +} diff --git a/apps/opencs/model/filter/unarynode.hpp b/apps/opencs/model/filter/unarynode.hpp new file mode 100644 index 0000000000..6ecad1192e --- /dev/null +++ b/apps/opencs/model/filter/unarynode.hpp @@ -0,0 +1,37 @@ +#ifndef CSM_FILTER_UNARIYNODE_H +#define CSM_FILTER_UNARIYNODE_H + +#include + +#include "node.hpp" + +namespace CSMFilter +{ + class UnaryNode : public Node + { + std::auto_ptr mChild; + + public: + + UnaryNode (std::auto_ptr child); + + const Node& getChild() const; + + Node& getChild(); + + virtual std::vector getReferencedFilters() const; + ///< Return a list of filters that are used by this node (and must be passed as + /// otherFilters when calling test). + + virtual std::vector getReferencedColumns() const; + ///< Return a list of the IDs of the columns referenced by this node. The column mapping + /// passed into test as columns must contain all columns listed here. + + virtual bool isSimple() const; + ///< \return Can this filter be displayed in simple mode. + + virtual bool hasUserValue() const; + }; +} + +#endif From 789a66eaa7e0894e458c39bae8afa993fc392c0e Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 11 Aug 2013 20:39:21 +0200 Subject: [PATCH 04/30] added filter box and basic record filter UI (not functional yet; only supporting on-the-fly filters for now) --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/view/filter/filterbox.cpp | 18 ++++++++++++++++++ apps/opencs/view/filter/filterbox.hpp | 19 +++++++++++++++++++ apps/opencs/view/filter/recordfilterbox.cpp | 20 ++++++++++++++++++++ apps/opencs/view/filter/recordfilterbox.hpp | 21 +++++++++++++++++++++ apps/opencs/view/world/tablesubview.cpp | 4 ++++ 6 files changed, 83 insertions(+), 1 deletion(-) create mode 100644 apps/opencs/view/filter/filterbox.cpp create mode 100644 apps/opencs/view/filter/filterbox.hpp create mode 100644 apps/opencs/view/filter/recordfilterbox.cpp create mode 100644 apps/opencs/view/filter/recordfilterbox.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 8e0024ad95..d363eeedc9 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -116,7 +116,7 @@ opencs_hdrs_noqt (model/filter ) opencs_units (view/filter - filtercreator + filtercreator filterbox recordfilterbox ) set (OPENCS_US diff --git a/apps/opencs/view/filter/filterbox.cpp b/apps/opencs/view/filter/filterbox.cpp new file mode 100644 index 0000000000..f3f17706b8 --- /dev/null +++ b/apps/opencs/view/filter/filterbox.cpp @@ -0,0 +1,18 @@ + +#include "filterbox.hpp" + +#include + +#include "recordfilterbox.hpp" + +CSVFilter::FilterBox::FilterBox (QWidget *parent) +: QWidget (parent) +{ + QHBoxLayout *layout = new QHBoxLayout (this); + + layout->setContentsMargins (0, 0, 0, 0); + + layout->addWidget (new RecordFilterBox (this)); + + setLayout (layout); +} \ No newline at end of file diff --git a/apps/opencs/view/filter/filterbox.hpp b/apps/opencs/view/filter/filterbox.hpp new file mode 100644 index 0000000000..969a43cd72 --- /dev/null +++ b/apps/opencs/view/filter/filterbox.hpp @@ -0,0 +1,19 @@ +#ifndef CSV_FILTER_FILTERBOX_H +#define CSV_FILTER_FILTERBOX_H + +#include + +namespace CSVFilter +{ + class FilterBox : public QWidget + { + Q_OBJECT + + public: + + FilterBox (QWidget *parent = 0); + }; + +} + +#endif diff --git a/apps/opencs/view/filter/recordfilterbox.cpp b/apps/opencs/view/filter/recordfilterbox.cpp new file mode 100644 index 0000000000..b0c1956644 --- /dev/null +++ b/apps/opencs/view/filter/recordfilterbox.cpp @@ -0,0 +1,20 @@ + +#include "recordfilterbox.hpp" + +#include +#include +#include + +CSVFilter::RecordFilterBox::RecordFilterBox (QWidget *parent) +: QWidget (parent) +{ + QHBoxLayout *layout = new QHBoxLayout (this); + + layout->setContentsMargins (0, 0, 0, 0); + + layout->addWidget (new QLabel ("Record Filter", this)); + + layout->addWidget (new QLineEdit (this)); + + setLayout (layout); +} \ No newline at end of file diff --git a/apps/opencs/view/filter/recordfilterbox.hpp b/apps/opencs/view/filter/recordfilterbox.hpp new file mode 100644 index 0000000000..3a411f8084 --- /dev/null +++ b/apps/opencs/view/filter/recordfilterbox.hpp @@ -0,0 +1,21 @@ +#ifndef CSV_FILTER_RECORDFILTERBOX_H +#define CSV_FILTER_RECORDFILTERBOX_H + +#include + +#include + +namespace CSVFilter +{ + class RecordFilterBox : public QWidget + { + Q_OBJECT + + public: + + RecordFilterBox (QWidget *parent = 0); + }; + +} + +#endif \ No newline at end of file diff --git a/apps/opencs/view/world/tablesubview.cpp b/apps/opencs/view/world/tablesubview.cpp index af3d186e85..df95940c9d 100644 --- a/apps/opencs/view/world/tablesubview.cpp +++ b/apps/opencs/view/world/tablesubview.cpp @@ -5,6 +5,8 @@ #include "../../model/doc/document.hpp" +#include "../filter/filterbox.hpp" + #include "table.hpp" #include "tablebottombox.hpp" #include "creator.hpp" @@ -23,6 +25,8 @@ CSVWorld::TableSubView::TableSubView (const CSMWorld::UniversalId& id, CSMDoc::D layout->insertWidget (0, mTable = new Table (id, document.getData(), document.getUndoStack(), mBottom->canCreateAndDelete()), 2); + layout->insertWidget (0, new CSVFilter::FilterBox (this)); + QWidget *widget = new QWidget; widget->setLayout (layout); From 528e047fd53d89b3c28a6074c60f272ec954545a Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 16 Aug 2013 13:57:54 +0200 Subject: [PATCH 05/30] repalced std::auto_ptr with boost::shared_ptr in filter nodes --- apps/opencs/model/filter/binarynode.cpp | 2 +- apps/opencs/model/filter/binarynode.hpp | 8 ++++---- apps/opencs/model/filter/unarynode.cpp | 2 +- apps/opencs/model/filter/unarynode.hpp | 6 +++--- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/apps/opencs/model/filter/binarynode.cpp b/apps/opencs/model/filter/binarynode.cpp index 0e86930dbb..c0c7fde378 100644 --- a/apps/opencs/model/filter/binarynode.cpp +++ b/apps/opencs/model/filter/binarynode.cpp @@ -1,7 +1,7 @@ #include "binarynode.hpp" -CSMFilter::BinaryNode::BinaryNode (std::auto_ptr left, std::auto_ptr right) +CSMFilter::BinaryNode::BinaryNode (boost::shared_ptr left, boost::shared_ptr right) : mLeft (left), mRight (right) {} diff --git a/apps/opencs/model/filter/binarynode.hpp b/apps/opencs/model/filter/binarynode.hpp index 18cdad2a9f..c2b4041d25 100644 --- a/apps/opencs/model/filter/binarynode.hpp +++ b/apps/opencs/model/filter/binarynode.hpp @@ -1,7 +1,7 @@ #ifndef CSM_FILTER_BINARYNODE_H #define CSM_FILTER_BINARYNODE_H -#include +#include #include "node.hpp" @@ -9,12 +9,12 @@ namespace CSMFilter { class BinaryNode : public Node { - std::auto_ptr mLeft; - std::auto_ptr mRight; + boost::shared_ptr mLeft; + boost::shared_ptr mRight; public: - BinaryNode (std::auto_ptr left, std::auto_ptr right); + BinaryNode (boost::shared_ptr left, boost::shared_ptr right); const Node& getLeft() const; diff --git a/apps/opencs/model/filter/unarynode.cpp b/apps/opencs/model/filter/unarynode.cpp index f9cc3fdc83..490d953769 100644 --- a/apps/opencs/model/filter/unarynode.cpp +++ b/apps/opencs/model/filter/unarynode.cpp @@ -1,7 +1,7 @@ #include "unarynode.hpp" -CSMFilter::UnaryNode::UnaryNode (std::auto_ptr child) : mChild (child) {} +CSMFilter::UnaryNode::UnaryNode (boost::shared_ptr child) : mChild (child) {} const CSMFilter::Node& CSMFilter::UnaryNode::getChild() const { diff --git a/apps/opencs/model/filter/unarynode.hpp b/apps/opencs/model/filter/unarynode.hpp index 6ecad1192e..4e1fb0cc29 100644 --- a/apps/opencs/model/filter/unarynode.hpp +++ b/apps/opencs/model/filter/unarynode.hpp @@ -1,7 +1,7 @@ #ifndef CSM_FILTER_UNARIYNODE_H #define CSM_FILTER_UNARIYNODE_H -#include +#include #include "node.hpp" @@ -9,11 +9,11 @@ namespace CSMFilter { class UnaryNode : public Node { - std::auto_ptr mChild; + boost::shared_ptr mChild; public: - UnaryNode (std::auto_ptr child); + UnaryNode (boost::shared_ptr child); const Node& getChild() const; From 236dc9fc43ceec38bed853e8326f828de2dbf87c Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 16 Aug 2013 14:18:31 +0200 Subject: [PATCH 06/30] replaced binary filter node with a n-ary node --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/filter/binarynode.cpp | 58 ------------------ apps/opencs/model/filter/narynode.cpp | 61 +++++++++++++++++++ .../filter/{binarynode.hpp => narynode.hpp} | 21 +++---- 4 files changed, 71 insertions(+), 71 deletions(-) delete mode 100644 apps/opencs/model/filter/binarynode.cpp create mode 100644 apps/opencs/model/filter/narynode.cpp rename apps/opencs/model/filter/{binarynode.hpp => narynode.hpp} (64%) diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index d363eeedc9..8a1949e518 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -108,7 +108,7 @@ opencs_units_noqt (model/settings ) opencs_units_noqt (model/filter - node unarynode binarynode leafnode booleannode + node unarynode narynode leafnode booleannode ) opencs_hdrs_noqt (model/filter diff --git a/apps/opencs/model/filter/binarynode.cpp b/apps/opencs/model/filter/binarynode.cpp deleted file mode 100644 index c0c7fde378..0000000000 --- a/apps/opencs/model/filter/binarynode.cpp +++ /dev/null @@ -1,58 +0,0 @@ - -#include "binarynode.hpp" - -CSMFilter::BinaryNode::BinaryNode (boost::shared_ptr left, boost::shared_ptr right) -: mLeft (left), mRight (right) -{} - -const CSMFilter::Node& CSMFilter::BinaryNode::getLeft() const -{ - return *mLeft; -} - -CSMFilter::Node& CSMFilter::BinaryNode::getLeft() -{ - return *mLeft; -} - -const CSMFilter::Node& CSMFilter::BinaryNode::getRight() const -{ - return *mRight; -} - -CSMFilter::Node& CSMFilter::BinaryNode::getRight() -{ - return *mRight; -} - -std::vector CSMFilter::BinaryNode::getReferencedFilters() const -{ - std::vector left = mLeft->getReferencedFilters(); - - std::vector right = mRight->getReferencedFilters(); - - left.insert (left.end(), right.begin(), right.end()); - - return left; -} - -std::vector CSMFilter::BinaryNode::getReferencedColumns() const -{ - std::vector left = mLeft->getReferencedColumns(); - - std::vector right = mRight->getReferencedColumns(); - - left.insert (left.end(), right.begin(), right.end()); - - return left; -} - -bool CSMFilter::BinaryNode::isSimple() const -{ - return false; -} - -bool CSMFilter::BinaryNode::hasUserValue() const -{ - return mLeft->hasUserValue() || mRight->hasUserValue(); -} diff --git a/apps/opencs/model/filter/narynode.cpp b/apps/opencs/model/filter/narynode.cpp new file mode 100644 index 0000000000..0756f6707f --- /dev/null +++ b/apps/opencs/model/filter/narynode.cpp @@ -0,0 +1,61 @@ + +#include "narynode.hpp" + +CSMFilter::NAryNode::NAryNode (const std::vector >& nodes) +: mNodes (nodes) +{} + +int CSMFilter::NAryNode::getSize() const +{ + return mNodes.size(); +} + +const CSMFilter::Node& CSMFilter::NAryNode::operator[] (int index) const +{ + return *mNodes.at (index); +} + +std::vector CSMFilter::NAryNode::getReferencedFilters() const +{ + std::vector filters; + + for (std::vector >::const_iterator iter (mNodes.begin()); + iter!=mNodes.end(); ++iter) + { + std::vector filters2 = (*iter)->getReferencedFilters(); + + filters.insert (filters.end(), filters2.begin(), filters2.end()); + } + + return filters; +} + +std::vector CSMFilter::NAryNode::getReferencedColumns() const +{ + std::vector columns; + + for (std::vector >::const_iterator iter (mNodes.begin()); + iter!=mNodes.end(); ++iter) + { + std::vector columns2 = (*iter)->getReferencedColumns(); + + columns.insert (columns.end(), columns2.begin(), columns2.end()); + } + + return columns; +} + +bool CSMFilter::NAryNode::isSimple() const +{ + return false; +} + +bool CSMFilter::NAryNode::hasUserValue() const +{ + for (std::vector >::const_iterator iter (mNodes.begin()); + iter!=mNodes.end(); ++iter) + if ((*iter)->hasUserValue()) + return true; + + return false; +} diff --git a/apps/opencs/model/filter/binarynode.hpp b/apps/opencs/model/filter/narynode.hpp similarity index 64% rename from apps/opencs/model/filter/binarynode.hpp rename to apps/opencs/model/filter/narynode.hpp index c2b4041d25..65e12d1ed0 100644 --- a/apps/opencs/model/filter/binarynode.hpp +++ b/apps/opencs/model/filter/narynode.hpp @@ -1,5 +1,7 @@ -#ifndef CSM_FILTER_BINARYNODE_H -#define CSM_FILTER_BINARYNODE_H +#ifndef CSM_FILTER_NARYNODE_H +#define CSM_FILTER_NARYNODE_H + +#include #include @@ -7,22 +9,17 @@ namespace CSMFilter { - class BinaryNode : public Node + class NAryNode : public Node { - boost::shared_ptr mLeft; - boost::shared_ptr mRight; + std::vector > mNodes; public: - BinaryNode (boost::shared_ptr left, boost::shared_ptr right); + NAryNode (const std::vector >& nodes); - const Node& getLeft() const; + int getSize() const; - Node& getLeft(); - - const Node& getRight() const; - - Node& getRight(); + const Node& operator[] (int index) const; virtual std::vector getReferencedFilters() const; ///< Return a list of filters that are used by this node (and must be passed as From c38860fa72936ea956a07d729c29e0ff6c392552 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 18 Aug 2013 14:17:18 +0200 Subject: [PATCH 07/30] added parser and custom filter edit widget (parser not functional yet; always returns a false boolean node) --- apps/opencs/CMakeLists.txt | 4 +-- apps/opencs/model/filter/parser.cpp | 33 +++++++++++++++++ apps/opencs/model/filter/parser.hpp | 39 +++++++++++++++++++++ apps/opencs/view/filter/editwidget.cpp | 20 +++++++++++ apps/opencs/view/filter/editwidget.hpp | 30 ++++++++++++++++ apps/opencs/view/filter/recordfilterbox.cpp | 5 +-- 6 files changed, 127 insertions(+), 4 deletions(-) create mode 100644 apps/opencs/model/filter/parser.cpp create mode 100644 apps/opencs/model/filter/parser.hpp create mode 100644 apps/opencs/view/filter/editwidget.cpp create mode 100644 apps/opencs/view/filter/editwidget.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 8a1949e518..031c650dfa 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -108,7 +108,7 @@ opencs_units_noqt (model/settings ) opencs_units_noqt (model/filter - node unarynode narynode leafnode booleannode + node unarynode narynode leafnode booleannode parser ) opencs_hdrs_noqt (model/filter @@ -116,7 +116,7 @@ opencs_hdrs_noqt (model/filter ) opencs_units (view/filter - filtercreator filterbox recordfilterbox + filtercreator filterbox recordfilterbox editwidget ) set (OPENCS_US diff --git a/apps/opencs/model/filter/parser.cpp b/apps/opencs/model/filter/parser.cpp new file mode 100644 index 0000000000..46052cec67 --- /dev/null +++ b/apps/opencs/model/filter/parser.cpp @@ -0,0 +1,33 @@ + +#include "parser.hpp" + +#include + +#include "booleannode.hpp" + +CSMFilter::Parser::Parser() : mState (State_Begin) {} + +void CSMFilter::Parser::parse (const std::string& filter) +{ + // reset + mState = State_Begin; + mFilter.reset(); + + + // for now we ignore the filter string + mFilter.reset (new BooleanNode (false)); + mState = State_End; +} + +CSMFilter::Parser::State CSMFilter::Parser::getState() const +{ + return mState; +} + +boost::shared_ptr CSMFilter::Parser::getFilter() const +{ + if (mState!=State_End) + throw std::logic_error ("No filter available"); + + return mFilter; +} \ No newline at end of file diff --git a/apps/opencs/model/filter/parser.hpp b/apps/opencs/model/filter/parser.hpp new file mode 100644 index 0000000000..72dc7d507d --- /dev/null +++ b/apps/opencs/model/filter/parser.hpp @@ -0,0 +1,39 @@ +#ifndef CSM_FILTER_PARSER_H +#define CSM_FILTER_PARSER_H + +#include + +#include "node.hpp" + +namespace CSMFilter +{ + class Parser + { + public: + + enum State + { + State_Begin, + State_End + }; + + private: + + State mState; + boost::shared_ptr mFilter; + + public: + + Parser(); + + void parse (const std::string& filter); + ///< Discards any previous calls to parse + + State getState() const; + + boost::shared_ptr getFilter() const; + ///< Throws an exception if getState()!=State_End + }; +} + +#endif diff --git a/apps/opencs/view/filter/editwidget.cpp b/apps/opencs/view/filter/editwidget.cpp new file mode 100644 index 0000000000..8fc4a88aeb --- /dev/null +++ b/apps/opencs/view/filter/editwidget.cpp @@ -0,0 +1,20 @@ + +#include "editwidget.hpp" + +CSVFilter::EditWidget::EditWidget (QWidget *parent) +: QLineEdit (parent) +{ + connect (this, SIGNAL (textChanged (const QString&)), this, SLOT (textChanged (const QString&))); +} + +void CSVFilter::EditWidget::textChanged (const QString& text) +{ + mParser.parse (text.toUtf8().constData()); + + if (mParser.getState()==CSMFilter::Parser::State_End) + emit filterChanged(); + else + { + /// \todo error handling + } +} \ No newline at end of file diff --git a/apps/opencs/view/filter/editwidget.hpp b/apps/opencs/view/filter/editwidget.hpp new file mode 100644 index 0000000000..5959a8b16f --- /dev/null +++ b/apps/opencs/view/filter/editwidget.hpp @@ -0,0 +1,30 @@ +#ifndef CSV_FILTER_EDITWIDGET_H +#define CSV_FILTER_EDITWIDGET_H + +#include + +#include "../../model/filter/parser.hpp" + +namespace CSVFilter +{ + class EditWidget : public QLineEdit + { + Q_OBJECT + + CSMFilter::Parser mParser; + + public: + + EditWidget (QWidget *parent = 0); + + signals: + + void filterChanged(); + + private slots: + + void textChanged (const QString& text); + }; +} + +#endif diff --git a/apps/opencs/view/filter/recordfilterbox.cpp b/apps/opencs/view/filter/recordfilterbox.cpp index b0c1956644..5e297ec386 100644 --- a/apps/opencs/view/filter/recordfilterbox.cpp +++ b/apps/opencs/view/filter/recordfilterbox.cpp @@ -2,9 +2,10 @@ #include "recordfilterbox.hpp" #include -#include #include +#include "editwidget.hpp" + CSVFilter::RecordFilterBox::RecordFilterBox (QWidget *parent) : QWidget (parent) { @@ -14,7 +15,7 @@ CSVFilter::RecordFilterBox::RecordFilterBox (QWidget *parent) layout->addWidget (new QLabel ("Record Filter", this)); - layout->addWidget (new QLineEdit (this)); + layout->addWidget (new EditWidget (this)); setLayout (layout); } \ No newline at end of file From 470f890a9add6916ef6b26160c7063de083c24da Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 18 Aug 2013 16:52:51 +0200 Subject: [PATCH 08/30] fixed BooleanNode constructor --- apps/opencs/model/filter/booleannode.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/model/filter/booleannode.cpp b/apps/opencs/model/filter/booleannode.cpp index cea130d241..2f521ed068 100644 --- a/apps/opencs/model/filter/booleannode.cpp +++ b/apps/opencs/model/filter/booleannode.cpp @@ -1,7 +1,7 @@ #include "booleannode.hpp" -CSMFilter::BooleanNode::BooleanNode (bool true_) : mTrue (true) {} +CSMFilter::BooleanNode::BooleanNode (bool true_) : mTrue (true_) {} bool CSMFilter::BooleanNode::test (const CSMWorld::IdTable& table, int row, const std::map& otherFilters, From ea8b9ce45b76923a4c52a66fe3f1c3b3d9d3d114 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 18 Aug 2013 16:53:28 +0200 Subject: [PATCH 09/30] apply filter to table after filter text change --- apps/opencs/model/filter/node.hpp | 6 +++++ apps/opencs/model/world/idtableproxymodel.cpp | 23 +++++++++++++++++++ apps/opencs/model/world/idtableproxymodel.hpp | 16 ++++++++++++- apps/opencs/view/filter/editwidget.cpp | 2 +- apps/opencs/view/filter/editwidget.hpp | 6 ++++- apps/opencs/view/filter/filterbox.cpp | 8 ++++++- apps/opencs/view/filter/filterbox.hpp | 7 ++++++ apps/opencs/view/filter/recordfilterbox.cpp | 10 ++++++-- apps/opencs/view/filter/recordfilterbox.hpp | 9 ++++++++ apps/opencs/view/world/table.cpp | 6 +++++ apps/opencs/view/world/table.hpp | 4 ++++ apps/opencs/view/world/tablesubview.cpp | 8 ++++++- 12 files changed, 98 insertions(+), 7 deletions(-) diff --git a/apps/opencs/model/filter/node.hpp b/apps/opencs/model/filter/node.hpp index 09bc3cd420..9743034ba0 100644 --- a/apps/opencs/model/filter/node.hpp +++ b/apps/opencs/model/filter/node.hpp @@ -5,6 +5,10 @@ #include #include +#include + +#include + namespace CSMWorld { class IdTable; @@ -55,4 +59,6 @@ namespace CSMFilter }; } +Q_DECLARE_METATYPE (boost::shared_ptr) + #endif diff --git a/apps/opencs/model/world/idtableproxymodel.cpp b/apps/opencs/model/world/idtableproxymodel.cpp index e99e1575ce..e2c8622701 100644 --- a/apps/opencs/model/world/idtableproxymodel.cpp +++ b/apps/opencs/model/world/idtableproxymodel.cpp @@ -1,8 +1,23 @@ #include "idtableproxymodel.hpp" +#include +#include + #include "idtable.hpp" +bool CSMWorld::IdTableProxyModel::filterAcceptsRow (int sourceRow, const QModelIndex& sourceParent) + const +{ + if (!mFilter) + return true; + + std::map otherFilters; /// \todo get other filters; + std::map columns; /// \todo get columns + + return mFilter->test (dynamic_cast (*sourceModel()), sourceRow, otherFilters, columns, mUserValue); +} + CSMWorld::IdTableProxyModel::IdTableProxyModel (QObject *parent) : QSortFilterProxyModel (parent) {} @@ -10,4 +25,12 @@ CSMWorld::IdTableProxyModel::IdTableProxyModel (QObject *parent) QModelIndex CSMWorld::IdTableProxyModel::getModelIndex (const std::string& id, int column) const { return mapFromSource (dynamic_cast (*sourceModel()).getModelIndex (id, column)); +} + +void CSMWorld::IdTableProxyModel::setFilter (const boost::shared_ptr& filter, + const std::string& userValue) +{ + mFilter = filter; + mUserValue = userValue; + invalidateFilter(); } \ No newline at end of file diff --git a/apps/opencs/model/world/idtableproxymodel.hpp b/apps/opencs/model/world/idtableproxymodel.hpp index 200b99fe20..c7dcd345ac 100644 --- a/apps/opencs/model/world/idtableproxymodel.hpp +++ b/apps/opencs/model/world/idtableproxymodel.hpp @@ -1,9 +1,13 @@ #ifndef CSM_WOLRD_IDTABLEPROXYMODEL_H #define CSM_WOLRD_IDTABLEPROXYMODEL_H +#include + +#include + #include -#include +#include "../filter/node.hpp" namespace CSMWorld { @@ -11,11 +15,21 @@ namespace CSMWorld { Q_OBJECT + boost::shared_ptr mFilter; + std::string mUserValue; + + private: + + bool filterAcceptsRow (int sourceRow, const QModelIndex& sourceParent) const; + public: IdTableProxyModel (QObject *parent = 0); virtual QModelIndex getModelIndex (const std::string& id, int column) const; + + void setFilter (const boost::shared_ptr& filter, + const std::string& userValue); }; } diff --git a/apps/opencs/view/filter/editwidget.cpp b/apps/opencs/view/filter/editwidget.cpp index 8fc4a88aeb..b8853ffa35 100644 --- a/apps/opencs/view/filter/editwidget.cpp +++ b/apps/opencs/view/filter/editwidget.cpp @@ -12,7 +12,7 @@ void CSVFilter::EditWidget::textChanged (const QString& text) mParser.parse (text.toUtf8().constData()); if (mParser.getState()==CSMFilter::Parser::State_End) - emit filterChanged(); + emit filterChanged (mParser.getFilter(), ""); else { /// \todo error handling diff --git a/apps/opencs/view/filter/editwidget.hpp b/apps/opencs/view/filter/editwidget.hpp index 5959a8b16f..9c4b1fa161 100644 --- a/apps/opencs/view/filter/editwidget.hpp +++ b/apps/opencs/view/filter/editwidget.hpp @@ -1,9 +1,12 @@ #ifndef CSV_FILTER_EDITWIDGET_H #define CSV_FILTER_EDITWIDGET_H +#include + #include #include "../../model/filter/parser.hpp" +#include "../../model/filter/node.hpp" namespace CSVFilter { @@ -19,7 +22,8 @@ namespace CSVFilter signals: - void filterChanged(); + void filterChanged (boost::shared_ptr filter, + const std::string& userValue); private slots: diff --git a/apps/opencs/view/filter/filterbox.cpp b/apps/opencs/view/filter/filterbox.cpp index f3f17706b8..9da08d3bad 100644 --- a/apps/opencs/view/filter/filterbox.cpp +++ b/apps/opencs/view/filter/filterbox.cpp @@ -12,7 +12,13 @@ CSVFilter::FilterBox::FilterBox (QWidget *parent) layout->setContentsMargins (0, 0, 0, 0); - layout->addWidget (new RecordFilterBox (this)); + RecordFilterBox *recordFilterBox = new RecordFilterBox (this); + + layout->addWidget (recordFilterBox); setLayout (layout); + + connect (recordFilterBox, + SIGNAL (filterChanged (boost::shared_ptr, const std::string&)), + this, SIGNAL (recordFilterChanged (boost::shared_ptr, const std::string&))); } \ No newline at end of file diff --git a/apps/opencs/view/filter/filterbox.hpp b/apps/opencs/view/filter/filterbox.hpp index 969a43cd72..5f260003af 100644 --- a/apps/opencs/view/filter/filterbox.hpp +++ b/apps/opencs/view/filter/filterbox.hpp @@ -3,6 +3,8 @@ #include +#include "../../model/filter/node.hpp" + namespace CSVFilter { class FilterBox : public QWidget @@ -12,6 +14,11 @@ namespace CSVFilter public: FilterBox (QWidget *parent = 0); + + signals: + + void recordFilterChanged (boost::shared_ptr filter, + const std::string& userValue); }; } diff --git a/apps/opencs/view/filter/recordfilterbox.cpp b/apps/opencs/view/filter/recordfilterbox.cpp index 5e297ec386..c4b516f03b 100644 --- a/apps/opencs/view/filter/recordfilterbox.cpp +++ b/apps/opencs/view/filter/recordfilterbox.cpp @@ -15,7 +15,13 @@ CSVFilter::RecordFilterBox::RecordFilterBox (QWidget *parent) layout->addWidget (new QLabel ("Record Filter", this)); - layout->addWidget (new EditWidget (this)); + EditWidget *editWidget = new EditWidget (this); + + layout->addWidget (editWidget); setLayout (layout); -} \ No newline at end of file + + connect ( + editWidget, SIGNAL (filterChanged (boost::shared_ptr, const std::string&)), + this, SIGNAL (filterChanged (boost::shared_ptr, const std::string&))); +} diff --git a/apps/opencs/view/filter/recordfilterbox.hpp b/apps/opencs/view/filter/recordfilterbox.hpp index 3a411f8084..8fc1e263bc 100644 --- a/apps/opencs/view/filter/recordfilterbox.hpp +++ b/apps/opencs/view/filter/recordfilterbox.hpp @@ -1,10 +1,14 @@ #ifndef CSV_FILTER_RECORDFILTERBOX_H #define CSV_FILTER_RECORDFILTERBOX_H +#include + #include #include +#include "../../model/filter/node.hpp" + namespace CSVFilter { class RecordFilterBox : public QWidget @@ -14,6 +18,11 @@ namespace CSVFilter public: RecordFilterBox (QWidget *parent = 0); + + signals: + + void filterChanged (boost::shared_ptr filter, + const std::string& userValue); }; } diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index 4ae25d10b3..cc84e612d0 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -292,4 +292,10 @@ void CSVWorld::Table::requestFocus (const std::string& id) if (index.isValid()) scrollTo (index, QAbstractItemView::PositionAtTop); +} + +void CSVWorld::Table::recordFilterChanged (boost::shared_ptr filter, + const std::string& userValue) +{ + mProxyModel->setFilter (filter, userValue); } \ No newline at end of file diff --git a/apps/opencs/view/world/table.hpp b/apps/opencs/view/world/table.hpp index 0c24e7b54c..2e24e46a56 100644 --- a/apps/opencs/view/world/table.hpp +++ b/apps/opencs/view/world/table.hpp @@ -6,6 +6,8 @@ #include +#include "../../model/filter/node.hpp" + class QUndoStack; class QAction; @@ -85,6 +87,8 @@ namespace CSVWorld void requestFocus (const std::string& id); + void recordFilterChanged (boost::shared_ptr filter, + const std::string& userValue); }; } diff --git a/apps/opencs/view/world/tablesubview.cpp b/apps/opencs/view/world/tablesubview.cpp index df95940c9d..cb6f430c1c 100644 --- a/apps/opencs/view/world/tablesubview.cpp +++ b/apps/opencs/view/world/tablesubview.cpp @@ -25,7 +25,9 @@ CSVWorld::TableSubView::TableSubView (const CSMWorld::UniversalId& id, CSMDoc::D layout->insertWidget (0, mTable = new Table (id, document.getData(), document.getUndoStack(), mBottom->canCreateAndDelete()), 2); - layout->insertWidget (0, new CSVFilter::FilterBox (this)); + CSVFilter::FilterBox *filterBox = new CSVFilter::FilterBox (this); + + layout->insertWidget (0, filterBox); QWidget *widget = new QWidget; @@ -48,6 +50,10 @@ CSVWorld::TableSubView::TableSubView (const CSMWorld::UniversalId& id, CSMDoc::D connect (mBottom, SIGNAL (requestFocus (const std::string&)), mTable, SLOT (requestFocus (const std::string&))); + + connect (filterBox, + SIGNAL (recordFilterChanged (boost::shared_ptr, const std::string&)), + mTable, SLOT (recordFilterChanged (boost::shared_ptr, const std::string&))); } void CSVWorld::TableSubView::setEditLock (bool locked) From c7e97a83e195891c758fd8175f80986d9b4f42a5 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 18 Aug 2013 17:28:04 +0200 Subject: [PATCH 10/30] automatically build column map on filter change --- apps/opencs/model/world/idtableproxymodel.cpp | 22 ++++++++++++++++--- apps/opencs/model/world/idtableproxymodel.hpp | 5 +++++ 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/apps/opencs/model/world/idtableproxymodel.cpp b/apps/opencs/model/world/idtableproxymodel.cpp index e2c8622701..4bb440ce78 100644 --- a/apps/opencs/model/world/idtableproxymodel.cpp +++ b/apps/opencs/model/world/idtableproxymodel.cpp @@ -1,11 +1,26 @@ #include "idtableproxymodel.hpp" -#include #include #include "idtable.hpp" +void CSMWorld::IdTableProxyModel::updateColumnMap() +{ + mColumnMap.clear(); + + if (mFilter) + { + std::vector columns = mFilter->getReferencedColumns(); + + const IdTable& table = dynamic_cast (*sourceModel()); + + for (std::vector::const_iterator iter (columns.begin()); iter!=columns.end(); ++iter) + mColumnMap.insert (std::make_pair (*iter, + table.searchColumnIndex (static_cast (*iter)))); + } +} + bool CSMWorld::IdTableProxyModel::filterAcceptsRow (int sourceRow, const QModelIndex& sourceParent) const { @@ -13,9 +28,9 @@ bool CSMWorld::IdTableProxyModel::filterAcceptsRow (int sourceRow, const QModelI return true; std::map otherFilters; /// \todo get other filters; - std::map columns; /// \todo get columns - return mFilter->test (dynamic_cast (*sourceModel()), sourceRow, otherFilters, columns, mUserValue); + return mFilter->test ( + dynamic_cast (*sourceModel()), sourceRow, otherFilters, mColumnMap, mUserValue); } CSMWorld::IdTableProxyModel::IdTableProxyModel (QObject *parent) @@ -32,5 +47,6 @@ void CSMWorld::IdTableProxyModel::setFilter (const boost::shared_ptr +#include + #include #include "../filter/node.hpp" @@ -17,9 +19,12 @@ namespace CSMWorld boost::shared_ptr mFilter; std::string mUserValue; + std::map mColumnMap; // column ID, column index in this model (or -1) private: + void updateColumnMap(); + bool filterAcceptsRow (int sourceRow, const QModelIndex& sourceParent) const; public: From c87a2794449b69eec4489b5f291188938e8e3d3c Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 18 Aug 2013 17:54:18 +0200 Subject: [PATCH 11/30] added error reporting in the filter edit widget (change the text colour for now) --- apps/opencs/model/filter/parser.cpp | 50 ++++++++++++++++++++++++-- apps/opencs/model/filter/parser.hpp | 8 +++++ apps/opencs/view/filter/editwidget.cpp | 10 +++++- apps/opencs/view/filter/editwidget.hpp | 2 ++ 4 files changed, 66 insertions(+), 4 deletions(-) diff --git a/apps/opencs/model/filter/parser.cpp b/apps/opencs/model/filter/parser.cpp index 46052cec67..06a974bbe8 100644 --- a/apps/opencs/model/filter/parser.cpp +++ b/apps/opencs/model/filter/parser.cpp @@ -5,6 +5,37 @@ #include "booleannode.hpp" +namespace CSMFilter +{ + struct Token + { + enum Type + { + Type_EOS, + Type_None + }; + + Type mType; + + Token (Type type); + }; + + Token::Token (Type type) : mType (type) {} +} + +CSMFilter::Token CSMFilter::Parser::getNextToken (const std::string& filter, int& index) const +{ + if (index>=static_cast (filter.size())) + return Token (Token::Type_EOS); + + return Token (Token::Type_None); +} + +bool CSMFilter::Parser::isEndState() const +{ + return mState==State_End || mState==State_UnexpectedCharacter; +} + CSMFilter::Parser::Parser() : mState (State_Begin) {} void CSMFilter::Parser::parse (const std::string& filter) @@ -12,11 +43,24 @@ void CSMFilter::Parser::parse (const std::string& filter) // reset mState = State_Begin; mFilter.reset(); + int index = 0; + while (!isEndState()) + { + Token token = getNextToken (filter, index); - // for now we ignore the filter string - mFilter.reset (new BooleanNode (false)); - mState = State_End; + switch (token.mType) + { + case Token::Type_None: mState = State_UnexpectedCharacter; break; + case Token::Type_EOS: mState = State_End; break; + } + } + + if (mState==State_End && !mFilter) + { + // Empty filter string equals to filter "true". + mFilter.reset (new BooleanNode (true)); + } } CSMFilter::Parser::State CSMFilter::Parser::getState() const diff --git a/apps/opencs/model/filter/parser.hpp b/apps/opencs/model/filter/parser.hpp index 72dc7d507d..2d616b9e1b 100644 --- a/apps/opencs/model/filter/parser.hpp +++ b/apps/opencs/model/filter/parser.hpp @@ -7,6 +7,8 @@ namespace CSMFilter { + struct Token; + class Parser { public: @@ -14,6 +16,7 @@ namespace CSMFilter enum State { State_Begin, + State_UnexpectedCharacter, State_End }; @@ -22,6 +25,11 @@ namespace CSMFilter State mState; boost::shared_ptr mFilter; + Token getNextToken (const std::string& filter, int& index) const; + + bool isEndState() const; + ///< This includes error states. + public: Parser(); diff --git a/apps/opencs/view/filter/editwidget.cpp b/apps/opencs/view/filter/editwidget.cpp index b8853ffa35..79cbc1dcea 100644 --- a/apps/opencs/view/filter/editwidget.cpp +++ b/apps/opencs/view/filter/editwidget.cpp @@ -4,6 +4,7 @@ CSVFilter::EditWidget::EditWidget (QWidget *parent) : QLineEdit (parent) { + mPalette = palette(); connect (this, SIGNAL (textChanged (const QString&)), this, SLOT (textChanged (const QString&))); } @@ -12,9 +13,16 @@ void CSVFilter::EditWidget::textChanged (const QString& text) mParser.parse (text.toUtf8().constData()); if (mParser.getState()==CSMFilter::Parser::State_End) + { + setPalette (mPalette); emit filterChanged (mParser.getFilter(), ""); + } else { - /// \todo error handling + QPalette palette (mPalette); + palette.setColor (QPalette::Text, Qt::red); + setPalette (palette); + + /// \todo improve error reporting; mark only the faulty part } } \ No newline at end of file diff --git a/apps/opencs/view/filter/editwidget.hpp b/apps/opencs/view/filter/editwidget.hpp index 9c4b1fa161..4e692fc4d8 100644 --- a/apps/opencs/view/filter/editwidget.hpp +++ b/apps/opencs/view/filter/editwidget.hpp @@ -4,6 +4,7 @@ #include #include +#include #include "../../model/filter/parser.hpp" #include "../../model/filter/node.hpp" @@ -15,6 +16,7 @@ namespace CSVFilter Q_OBJECT CSMFilter::Parser mParser; + QPalette mPalette; public: From a61215dab1c6b486feec67d420a8fe199287e8aa Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 20 Aug 2013 16:04:06 +0200 Subject: [PATCH 12/30] some general filter parser cleanup --- apps/opencs/model/filter/parser.cpp | 244 +++++++++++++++++++++---- apps/opencs/model/filter/parser.hpp | 38 ++-- apps/opencs/view/filter/editwidget.cpp | 4 +- 3 files changed, 231 insertions(+), 55 deletions(-) diff --git a/apps/opencs/model/filter/parser.cpp b/apps/opencs/model/filter/parser.cpp index 06a974bbe8..305bf7a7d0 100644 --- a/apps/opencs/model/filter/parser.cpp +++ b/apps/opencs/model/filter/parser.cpp @@ -1,7 +1,11 @@ #include "parser.hpp" +#include #include +#include + +#include #include "booleannode.hpp" @@ -12,65 +16,239 @@ namespace CSMFilter enum Type { Type_EOS, - Type_None + Type_None, + Type_String, + Type_Number, + Type_Open, + Type_Close, + Type_OpenSquare, + Type_CloseSquare, + Type_Comma, + Type_Keyword_True, ///< \attention Keyword enums must be arranged continuously. + Type_Keyword_False, + Type_Keyword_And, + Type_Keyword_Or, + Type_Keyword_Not }; Type mType; + std::string mString; + double mNumber; Token (Type type); + + Token (const std::string& string); + + Token (double number); + + operator bool() const; }; Token::Token (Type type) : mType (type) {} -} -CSMFilter::Token CSMFilter::Parser::getNextToken (const std::string& filter, int& index) const -{ - if (index>=static_cast (filter.size())) - return Token (Token::Type_EOS); + Token::Token (const std::string& string) : mType (Type_String), mString (string) {} - return Token (Token::Type_None); -} + Token::Token (double number) : mType (Type_Number), mNumber (number) {} -bool CSMFilter::Parser::isEndState() const -{ - return mState==State_End || mState==State_UnexpectedCharacter; -} - -CSMFilter::Parser::Parser() : mState (State_Begin) {} - -void CSMFilter::Parser::parse (const std::string& filter) -{ - // reset - mState = State_Begin; - mFilter.reset(); - int index = 0; - - while (!isEndState()) + Token::operator bool() const { - Token token = getNextToken (filter, index); + return mType!=Type_None; + } - switch (token.mType) + bool operator== (const Token& left, const Token& right) + { + if (left.mType!=right.mType) + return false; + + switch (left.mType) { - case Token::Type_None: mState = State_UnexpectedCharacter; break; - case Token::Type_EOS: mState = State_End; break; + case Token::Type_String: return left.mString==right.mString; + case Token::Type_Number: return left.mNumber==right.mNumber; + + default: return true; + } + } +} + +CSMFilter::Token CSMFilter::Parser::getStringToken() +{ + std::string string; + + int size = static_cast (mInput.size()); + + for (; mIndex1) + { + ++mIndex; + break; + } + }; + + if (!string.empty()) + { + if (string[0]=='"' && (string[string.size()-1]!='"' || string.size()<2) ) + { + error(); + return Token (Token::Type_None); + } + + if (string[0]!='"' && string[string.size()-1]=='"') + { + error(); + return Token (Token::Type_None); } } - if (mState==State_End && !mFilter) + return checkKeywords (string); +} + +CSMFilter::Token CSMFilter::Parser::getNumberToken() +{ + std::string string; + + int size = static_cast (mInput.size()); + + bool hasDecimalPoint = false; + bool hasDigit = false; + + for (; mIndex> value; + + return value; +} + +CSMFilter::Token CSMFilter::Parser::checkKeywords (const Token& token) +{ + static const char *sKeywords[] = + { + "true", "false", + "and", "or", "not", + 0 + }; + + std::string string = Misc::StringUtils::lowerCase (token.mString); + + for (int i=0; sKeywords[i]; ++i) + if (sKeywords[i]==string) + return Token (static_cast (i+Token::Type_Keyword_True)); + + return token; +} + +CSMFilter::Token CSMFilter::Parser::getNextToken() +{ + int size = static_cast (mInput.size()); + + char c = 0; + + for (; mIndex=size) + return Token (Token::Type_EOS); + + switch (c) + { + case '(': ++mIndex; return Token (Token::Type_Open); + case ')': ++mIndex; return Token (Token::Type_Close); + case '[': ++mIndex; return Token (Token::Type_OpenSquare); + case ']': ++mIndex; return Token (Token::Type_CloseSquare); + case ',': ++mIndex; return Token (Token::Type_Comma); + } + + if (c=='"' || c=='_' || std::isalpha (c)) + return getStringToken(); + + if (c=='-' || c=='.' || std::isdigit (c)) + return getNumberToken(); + + error(); + return Token (Token::Type_None); +} + +boost::shared_ptr CSMFilter::Parser::parseImp() +{ + + + + return boost::shared_ptr(); +} + +void CSMFilter::Parser::error() +{ + mError = true; +} + +CSMFilter::Parser::Parser() : mIndex (0), mError (false) {} + +bool CSMFilter::Parser::parse (const std::string& filter) +{ + // reset + mFilter.reset(); + mError = false; + mInput = filter; + mIndex = 0; + + boost::shared_ptr node = parseImp(); + + if (mError) + return false; + + if (node) + mFilter = node; + else { // Empty filter string equals to filter "true". mFilter.reset (new BooleanNode (true)); } -} -CSMFilter::Parser::State CSMFilter::Parser::getState() const -{ - return mState; + return true; } boost::shared_ptr CSMFilter::Parser::getFilter() const { - if (mState!=State_End) + if (mError) throw std::logic_error ("No filter available"); return mFilter; diff --git a/apps/opencs/model/filter/parser.hpp b/apps/opencs/model/filter/parser.hpp index 2d616b9e1b..4341fae9fd 100644 --- a/apps/opencs/model/filter/parser.hpp +++ b/apps/opencs/model/filter/parser.hpp @@ -11,36 +11,36 @@ namespace CSMFilter class Parser { - public: - - enum State - { - State_Begin, - State_UnexpectedCharacter, - State_End - }; - - private: - - State mState; boost::shared_ptr mFilter; + std::string mInput; + int mIndex; + bool mError; - Token getNextToken (const std::string& filter, int& index) const; + Token getStringToken(); - bool isEndState() const; - ///< This includes error states. + Token getNumberToken(); + + Token getNextToken(); + + Token checkKeywords (const Token& token); + ///< Turn string token into keyword token, if possible. + + boost::shared_ptr parseImp(); + ///< Will return a null-pointer, if there is nothing more to parse. + + void error(); public: Parser(); - void parse (const std::string& filter); + bool parse (const std::string& filter); ///< Discards any previous calls to parse - - State getState() const; + /// + /// \return Success? boost::shared_ptr getFilter() const; - ///< Throws an exception if getState()!=State_End + ///< Throws an exception if the last call to parse did not return true. }; } diff --git a/apps/opencs/view/filter/editwidget.cpp b/apps/opencs/view/filter/editwidget.cpp index 79cbc1dcea..793e0504ed 100644 --- a/apps/opencs/view/filter/editwidget.cpp +++ b/apps/opencs/view/filter/editwidget.cpp @@ -10,9 +10,7 @@ CSVFilter::EditWidget::EditWidget (QWidget *parent) void CSVFilter::EditWidget::textChanged (const QString& text) { - mParser.parse (text.toUtf8().constData()); - - if (mParser.getState()==CSMFilter::Parser::State_End) + if (mParser.parse (text.toUtf8().constData())) { setPalette (mPalette); emit filterChanged (mParser.getFilter(), ""); From 2e8b0cf5023e70c6ca26484582efa8aa14622a66 Mon Sep 17 00:00:00 2001 From: Marc Bouvier Date: Wed, 21 Aug 2013 17:14:29 -0500 Subject: [PATCH 13/30] Remove Directory Paths in Qt Classes Includes Qt recommends that the path location not be used when including a class. Also, this is how other files include Qt classes in the OpenCS app. This change is for consistency only. --- apps/opencs/editor.cpp | 2 +- apps/opencs/main.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index 082fa376c6..e05ebcdeb2 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -1,7 +1,7 @@ #include "editor.hpp" -#include +#include #include "model/doc/document.hpp" #include "model/world/data.hpp" diff --git a/apps/opencs/main.cpp b/apps/opencs/main.cpp index aa315804b2..7f6f9302ed 100644 --- a/apps/opencs/main.cpp +++ b/apps/opencs/main.cpp @@ -4,7 +4,7 @@ #include #include -#include +#include #include class Application : public QApplication From 50041fc2112f4bc12e17ffdcda2d36cd236ad61c Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 22 Aug 2013 09:17:57 +0200 Subject: [PATCH 14/30] simplified filter system by taking out filter references and user values for now (these are post-1.0 features anyway) --- apps/opencs/model/filter/booleannode.cpp | 4 +--- apps/opencs/model/filter/booleannode.hpp | 4 +--- apps/opencs/model/filter/leafnode.cpp | 10 -------- apps/opencs/model/filter/leafnode.hpp | 6 ----- apps/opencs/model/filter/narynode.cpp | 24 ------------------- apps/opencs/model/filter/narynode.hpp | 5 ---- apps/opencs/model/filter/node.hpp | 10 +------- apps/opencs/model/filter/unarynode.cpp | 9 ------- apps/opencs/model/filter/unarynode.hpp | 5 ---- apps/opencs/model/world/idtableproxymodel.cpp | 8 ++----- apps/opencs/model/world/idtableproxymodel.hpp | 4 +--- apps/opencs/view/world/table.cpp | 5 ++-- apps/opencs/view/world/table.hpp | 3 +-- 13 files changed, 9 insertions(+), 88 deletions(-) diff --git a/apps/opencs/model/filter/booleannode.cpp b/apps/opencs/model/filter/booleannode.cpp index 2f521ed068..267e06a64a 100644 --- a/apps/opencs/model/filter/booleannode.cpp +++ b/apps/opencs/model/filter/booleannode.cpp @@ -4,9 +4,7 @@ CSMFilter::BooleanNode::BooleanNode (bool true_) : mTrue (true_) {} bool CSMFilter::BooleanNode::test (const CSMWorld::IdTable& table, int row, - const std::map& otherFilters, - const std::map& columns, - const std::string& userValue) const + const std::map& columns) const { return mTrue; } diff --git a/apps/opencs/model/filter/booleannode.hpp b/apps/opencs/model/filter/booleannode.hpp index 3578c7f3ff..d19219e352 100644 --- a/apps/opencs/model/filter/booleannode.hpp +++ b/apps/opencs/model/filter/booleannode.hpp @@ -14,9 +14,7 @@ namespace CSMFilter BooleanNode (bool true_); virtual bool test (const CSMWorld::IdTable& table, int row, - const std::map& otherFilters, - const std::map& columns, - const std::string& userValue) const; + const std::map& columns) const; ///< \return Can the specified table row pass through to filter? /// \param columns column ID to column index mapping diff --git a/apps/opencs/model/filter/leafnode.cpp b/apps/opencs/model/filter/leafnode.cpp index 5c6d4b0428..a1330f9dc3 100644 --- a/apps/opencs/model/filter/leafnode.cpp +++ b/apps/opencs/model/filter/leafnode.cpp @@ -1,11 +1,6 @@ #include "leafnode.hpp" -std::vector CSMFilter::LeafNode::getReferencedFilters() const -{ - return std::vector(); -} - std::vector CSMFilter::LeafNode::getReferencedColumns() const { return std::vector(); @@ -15,8 +10,3 @@ bool CSMFilter::LeafNode::isSimple() const { return true; } - -bool CSMFilter::LeafNode::hasUserValue() const -{ - return false; -} \ No newline at end of file diff --git a/apps/opencs/model/filter/leafnode.hpp b/apps/opencs/model/filter/leafnode.hpp index 663083ff98..2b0163065f 100644 --- a/apps/opencs/model/filter/leafnode.hpp +++ b/apps/opencs/model/filter/leafnode.hpp @@ -11,18 +11,12 @@ namespace CSMFilter { public: - virtual std::vector getReferencedFilters() const; - ///< Return a list of filters that are used by this node (and must be passed as - /// otherFilters when calling test). - virtual std::vector getReferencedColumns() const; ///< Return a list of the IDs of the columns referenced by this node. The column mapping /// passed into test as columns must contain all columns listed here. virtual bool isSimple() const; ///< \return Can this filter be displayed in simple mode. - - virtual bool hasUserValue() const; }; } diff --git a/apps/opencs/model/filter/narynode.cpp b/apps/opencs/model/filter/narynode.cpp index 0756f6707f..cc131d8aca 100644 --- a/apps/opencs/model/filter/narynode.cpp +++ b/apps/opencs/model/filter/narynode.cpp @@ -15,21 +15,6 @@ const CSMFilter::Node& CSMFilter::NAryNode::operator[] (int index) const return *mNodes.at (index); } -std::vector CSMFilter::NAryNode::getReferencedFilters() const -{ - std::vector filters; - - for (std::vector >::const_iterator iter (mNodes.begin()); - iter!=mNodes.end(); ++iter) - { - std::vector filters2 = (*iter)->getReferencedFilters(); - - filters.insert (filters.end(), filters2.begin(), filters2.end()); - } - - return filters; -} - std::vector CSMFilter::NAryNode::getReferencedColumns() const { std::vector columns; @@ -50,12 +35,3 @@ bool CSMFilter::NAryNode::isSimple() const return false; } -bool CSMFilter::NAryNode::hasUserValue() const -{ - for (std::vector >::const_iterator iter (mNodes.begin()); - iter!=mNodes.end(); ++iter) - if ((*iter)->hasUserValue()) - return true; - - return false; -} diff --git a/apps/opencs/model/filter/narynode.hpp b/apps/opencs/model/filter/narynode.hpp index 65e12d1ed0..5d8d5653b1 100644 --- a/apps/opencs/model/filter/narynode.hpp +++ b/apps/opencs/model/filter/narynode.hpp @@ -21,10 +21,6 @@ namespace CSMFilter const Node& operator[] (int index) const; - virtual std::vector getReferencedFilters() const; - ///< Return a list of filters that are used by this node (and must be passed as - /// otherFilters when calling test). - virtual std::vector getReferencedColumns() const; ///< Return a list of the IDs of the columns referenced by this node. The column mapping /// passed into test as columns must contain all columns listed here. @@ -32,7 +28,6 @@ namespace CSMFilter virtual bool isSimple() const; ///< \return Can this filter be displayed in simple mode. - virtual bool hasUserValue() const; }; } diff --git a/apps/opencs/model/filter/node.hpp b/apps/opencs/model/filter/node.hpp index 9743034ba0..6783c3b5ec 100644 --- a/apps/opencs/model/filter/node.hpp +++ b/apps/opencs/model/filter/node.hpp @@ -33,16 +33,10 @@ namespace CSMFilter virtual ~Node(); virtual bool test (const CSMWorld::IdTable& table, int row, - const std::map& otherFilters, - const std::map& columns, - const std::string& userValue) const = 0; + const std::map& columns) const = 0; ///< \return Can the specified table row pass through to filter? /// \param columns column ID to column index mapping - virtual std::vector getReferencedFilters() const = 0; - ///< Return a list of filters that are used by this node (and must be passed as - /// otherFilters when calling test). - virtual std::vector getReferencedColumns() const = 0; ///< Return a list of the IDs of the columns referenced by this node. The column mapping /// passed into test as columns must contain all columns listed here. @@ -50,8 +44,6 @@ namespace CSMFilter virtual bool isSimple() const = 0; ///< \return Can this filter be displayed in simple mode. - virtual bool hasUserValue() const = 0; - virtual std::string toString (bool numericColumns) const = 0; ///< Return a string that represents this node. /// diff --git a/apps/opencs/model/filter/unarynode.cpp b/apps/opencs/model/filter/unarynode.cpp index 490d953769..d687b6468d 100644 --- a/apps/opencs/model/filter/unarynode.cpp +++ b/apps/opencs/model/filter/unarynode.cpp @@ -13,11 +13,6 @@ CSMFilter::Node& CSMFilter::UnaryNode::getChild() return *mChild; } -std::vector CSMFilter::UnaryNode::getReferencedFilters() const -{ - return mChild->getReferencedFilters(); -} - std::vector CSMFilter::UnaryNode::getReferencedColumns() const { return mChild->getReferencedColumns(); @@ -28,7 +23,3 @@ bool CSMFilter::UnaryNode::isSimple() const return false; } -bool CSMFilter::UnaryNode::hasUserValue() const -{ - return mChild->hasUserValue(); -} diff --git a/apps/opencs/model/filter/unarynode.hpp b/apps/opencs/model/filter/unarynode.hpp index 4e1fb0cc29..6483a730f4 100644 --- a/apps/opencs/model/filter/unarynode.hpp +++ b/apps/opencs/model/filter/unarynode.hpp @@ -19,10 +19,6 @@ namespace CSMFilter Node& getChild(); - virtual std::vector getReferencedFilters() const; - ///< Return a list of filters that are used by this node (and must be passed as - /// otherFilters when calling test). - virtual std::vector getReferencedColumns() const; ///< Return a list of the IDs of the columns referenced by this node. The column mapping /// passed into test as columns must contain all columns listed here. @@ -30,7 +26,6 @@ namespace CSMFilter virtual bool isSimple() const; ///< \return Can this filter be displayed in simple mode. - virtual bool hasUserValue() const; }; } diff --git a/apps/opencs/model/world/idtableproxymodel.cpp b/apps/opencs/model/world/idtableproxymodel.cpp index 4bb440ce78..2b757adfe5 100644 --- a/apps/opencs/model/world/idtableproxymodel.cpp +++ b/apps/opencs/model/world/idtableproxymodel.cpp @@ -27,10 +27,8 @@ bool CSMWorld::IdTableProxyModel::filterAcceptsRow (int sourceRow, const QModelI if (!mFilter) return true; - std::map otherFilters; /// \todo get other filters; - return mFilter->test ( - dynamic_cast (*sourceModel()), sourceRow, otherFilters, mColumnMap, mUserValue); + dynamic_cast (*sourceModel()), sourceRow, mColumnMap); } CSMWorld::IdTableProxyModel::IdTableProxyModel (QObject *parent) @@ -42,11 +40,9 @@ QModelIndex CSMWorld::IdTableProxyModel::getModelIndex (const std::string& id, i return mapFromSource (dynamic_cast (*sourceModel()).getModelIndex (id, column)); } -void CSMWorld::IdTableProxyModel::setFilter (const boost::shared_ptr& filter, - const std::string& userValue) +void CSMWorld::IdTableProxyModel::setFilter (const boost::shared_ptr& filter) { mFilter = filter; - mUserValue = userValue; updateColumnMap(); invalidateFilter(); } \ No newline at end of file diff --git a/apps/opencs/model/world/idtableproxymodel.hpp b/apps/opencs/model/world/idtableproxymodel.hpp index 40bf6d4d9a..b63dccd5e2 100644 --- a/apps/opencs/model/world/idtableproxymodel.hpp +++ b/apps/opencs/model/world/idtableproxymodel.hpp @@ -18,7 +18,6 @@ namespace CSMWorld Q_OBJECT boost::shared_ptr mFilter; - std::string mUserValue; std::map mColumnMap; // column ID, column index in this model (or -1) private: @@ -33,8 +32,7 @@ namespace CSMWorld virtual QModelIndex getModelIndex (const std::string& id, int column) const; - void setFilter (const boost::shared_ptr& filter, - const std::string& userValue); + void setFilter (const boost::shared_ptr& filter); }; } diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index cc84e612d0..75cbddc2a7 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -294,8 +294,7 @@ void CSVWorld::Table::requestFocus (const std::string& id) scrollTo (index, QAbstractItemView::PositionAtTop); } -void CSVWorld::Table::recordFilterChanged (boost::shared_ptr filter, - const std::string& userValue) +void CSVWorld::Table::recordFilterChanged (boost::shared_ptr filter) { - mProxyModel->setFilter (filter, userValue); + mProxyModel->setFilter (filter); } \ No newline at end of file diff --git a/apps/opencs/view/world/table.hpp b/apps/opencs/view/world/table.hpp index 2e24e46a56..d931090563 100644 --- a/apps/opencs/view/world/table.hpp +++ b/apps/opencs/view/world/table.hpp @@ -87,8 +87,7 @@ namespace CSVWorld void requestFocus (const std::string& id); - void recordFilterChanged (boost::shared_ptr filter, - const std::string& userValue); + void recordFilterChanged (boost::shared_ptr filter); }; } From 806e9a28880a9379c5bcc4c3a906dbc1538b6a4b Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 22 Aug 2013 13:14:35 +0200 Subject: [PATCH 15/30] added and and or filter nodes --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/filter/andnode.cpp | 20 +++++ apps/opencs/model/filter/andnode.hpp | 23 ++++++ apps/opencs/model/filter/narynode.cpp | 31 +++++++- apps/opencs/model/filter/narynode.hpp | 9 ++- apps/opencs/model/filter/ornode.cpp | 20 +++++ apps/opencs/model/filter/ornode.hpp | 23 ++++++ apps/opencs/model/filter/parser.cpp | 82 +++++++++++++++++++++ apps/opencs/model/filter/parser.hpp | 2 + apps/opencs/view/filter/editwidget.cpp | 2 +- apps/opencs/view/filter/editwidget.hpp | 3 +- apps/opencs/view/filter/filterbox.cpp | 4 +- apps/opencs/view/filter/filterbox.hpp | 3 +- apps/opencs/view/filter/recordfilterbox.cpp | 4 +- apps/opencs/view/filter/recordfilterbox.hpp | 3 +- apps/opencs/view/world/tablesubview.cpp | 4 +- 16 files changed, 218 insertions(+), 17 deletions(-) create mode 100644 apps/opencs/model/filter/andnode.cpp create mode 100644 apps/opencs/model/filter/andnode.hpp create mode 100644 apps/opencs/model/filter/ornode.cpp create mode 100644 apps/opencs/model/filter/ornode.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 031c650dfa..9fb6c1be3e 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -108,7 +108,7 @@ opencs_units_noqt (model/settings ) opencs_units_noqt (model/filter - node unarynode narynode leafnode booleannode parser + node unarynode narynode leafnode booleannode parser andnode ornode ) opencs_hdrs_noqt (model/filter diff --git a/apps/opencs/model/filter/andnode.cpp b/apps/opencs/model/filter/andnode.cpp new file mode 100644 index 0000000000..dfaa56e782 --- /dev/null +++ b/apps/opencs/model/filter/andnode.cpp @@ -0,0 +1,20 @@ + +#include "andnode.hpp" + +#include + +CSMFilter::AndNode::AndNode (const std::vector >& nodes) +: NAryNode (nodes, "and") +{} + +bool CSMFilter::AndNode::test (const CSMWorld::IdTable& table, int row, + const std::map& columns) const +{ + int size = getSize(); + + for (int i=0; i >& nodes); + + virtual bool test (const CSMWorld::IdTable& table, int row, + const std::map& columns) const; + ///< \return Can the specified table row pass through to filter? + /// \param columns column ID to column index mapping + }; +} + +#endif diff --git a/apps/opencs/model/filter/narynode.cpp b/apps/opencs/model/filter/narynode.cpp index cc131d8aca..b96e7d4b2e 100644 --- a/apps/opencs/model/filter/narynode.cpp +++ b/apps/opencs/model/filter/narynode.cpp @@ -1,8 +1,11 @@ #include "narynode.hpp" -CSMFilter::NAryNode::NAryNode (const std::vector >& nodes) -: mNodes (nodes) +#include + +CSMFilter::NAryNode::NAryNode (const std::vector >& nodes, + const std::string& name) +: mNodes (nodes), mName (name) {} int CSMFilter::NAryNode::getSize() const @@ -30,6 +33,30 @@ std::vector CSMFilter::NAryNode::getReferencedColumns() const return columns; } +std::string CSMFilter::NAryNode::toString (bool numericColumns) const +{ + std::ostringstream stream; + + stream << mName << " ("; + + bool first = true; + int size = getSize(); + + for (int i=0; i +#include #include @@ -12,10 +13,11 @@ namespace CSMFilter class NAryNode : public Node { std::vector > mNodes; + std::string mName; public: - NAryNode (const std::vector >& nodes); + NAryNode (const std::vector >& nodes, const std::string& name); int getSize() const; @@ -25,6 +27,11 @@ namespace CSMFilter ///< Return a list of the IDs of the columns referenced by this node. The column mapping /// passed into test as columns must contain all columns listed here. + virtual std::string toString (bool numericColumns) const; + ///< Return a string that represents this node. + /// + /// \param numericColumns Use numeric IDs instead of string to represent columns. + virtual bool isSimple() const; ///< \return Can this filter be displayed in simple mode. diff --git a/apps/opencs/model/filter/ornode.cpp b/apps/opencs/model/filter/ornode.cpp new file mode 100644 index 0000000000..4fc34e1d5a --- /dev/null +++ b/apps/opencs/model/filter/ornode.cpp @@ -0,0 +1,20 @@ + +#include "ornode.hpp" + +#include + +CSMFilter::OrNode::OrNode (const std::vector >& nodes) +: NAryNode (nodes, "or") +{} + +bool CSMFilter::OrNode::test (const CSMWorld::IdTable& table, int row, + const std::map& columns) const +{ + int size = getSize(); + + for (int i=0; i >& nodes); + + virtual bool test (const CSMWorld::IdTable& table, int row, + const std::map& columns) const; + ///< \return Can the specified table row pass through to filter? + /// \param columns column ID to column index mapping + }; +} + +#endif diff --git a/apps/opencs/model/filter/parser.cpp b/apps/opencs/model/filter/parser.cpp index 305bf7a7d0..a35c4bdfdf 100644 --- a/apps/opencs/model/filter/parser.cpp +++ b/apps/opencs/model/filter/parser.cpp @@ -8,6 +8,8 @@ #include #include "booleannode.hpp" +#include "ornode.hpp" +#include "andnode.hpp" namespace CSMFilter { @@ -209,12 +211,89 @@ CSMFilter::Token CSMFilter::Parser::getNextToken() boost::shared_ptr CSMFilter::Parser::parseImp() { + if (Token token = getNextToken()) + { + switch (token.mType) + { + case Token::Type_Keyword_True: + return boost::shared_ptr (new BooleanNode (true)); + case Token::Type_Keyword_False: + + return boost::shared_ptr (new BooleanNode (false)); + + case Token::Type_Keyword_And: + case Token::Type_Keyword_Or: + + return parseNAry (token); + + case Token::Type_EOS: + + return boost::shared_ptr(); + + default: + + error(); + } + } return boost::shared_ptr(); } +boost::shared_ptr CSMFilter::Parser::parseNAry (const Token& keyword) +{ + std::vector > nodes; + + Token token = getNextToken(); + + if (!token || token.mType!=Token::Type_Open) + { + error(); + return boost::shared_ptr(); + } + + for (;;) + { + boost::shared_ptr node = parseImp(); + + if (mError) + return boost::shared_ptr(); + + if (!node.get()) + { + error(); + return boost::shared_ptr(); + } + + nodes.push_back (node); + + Token token = getNextToken(); + + if (!token || (token.mType!=Token::Type_Close && token.mType!=Token::Type_Comma)) + { + error(); + return boost::shared_ptr(); + } + + if (token.mType==Token::Type_Close) + break; + } + + if (nodes.empty()) + { + error(); + return boost::shared_ptr(); + } + + switch (keyword.mType) + { + case Token::Type_Keyword_And: return boost::shared_ptr (new AndNode (nodes)); + case Token::Type_Keyword_Or: return boost::shared_ptr (new OrNode (nodes)); + default: error(); return boost::shared_ptr(); + } +} + void CSMFilter::Parser::error() { mError = true; @@ -235,6 +314,9 @@ bool CSMFilter::Parser::parse (const std::string& filter) if (mError) return false; + if (getNextToken()!=Token (Token::Type_EOS)) + return false; + if (node) mFilter = node; else diff --git a/apps/opencs/model/filter/parser.hpp b/apps/opencs/model/filter/parser.hpp index 4341fae9fd..d9f14b5d9a 100644 --- a/apps/opencs/model/filter/parser.hpp +++ b/apps/opencs/model/filter/parser.hpp @@ -28,6 +28,8 @@ namespace CSMFilter boost::shared_ptr parseImp(); ///< Will return a null-pointer, if there is nothing more to parse. + boost::shared_ptr parseNAry (const Token& keyword); + void error(); public: diff --git a/apps/opencs/view/filter/editwidget.cpp b/apps/opencs/view/filter/editwidget.cpp index 793e0504ed..b691a5e169 100644 --- a/apps/opencs/view/filter/editwidget.cpp +++ b/apps/opencs/view/filter/editwidget.cpp @@ -13,7 +13,7 @@ void CSVFilter::EditWidget::textChanged (const QString& text) if (mParser.parse (text.toUtf8().constData())) { setPalette (mPalette); - emit filterChanged (mParser.getFilter(), ""); + emit filterChanged (mParser.getFilter()); } else { diff --git a/apps/opencs/view/filter/editwidget.hpp b/apps/opencs/view/filter/editwidget.hpp index 4e692fc4d8..76b484de96 100644 --- a/apps/opencs/view/filter/editwidget.hpp +++ b/apps/opencs/view/filter/editwidget.hpp @@ -24,8 +24,7 @@ namespace CSVFilter signals: - void filterChanged (boost::shared_ptr filter, - const std::string& userValue); + void filterChanged (boost::shared_ptr filter); private slots: diff --git a/apps/opencs/view/filter/filterbox.cpp b/apps/opencs/view/filter/filterbox.cpp index 9da08d3bad..495abf8713 100644 --- a/apps/opencs/view/filter/filterbox.cpp +++ b/apps/opencs/view/filter/filterbox.cpp @@ -19,6 +19,6 @@ CSVFilter::FilterBox::FilterBox (QWidget *parent) setLayout (layout); connect (recordFilterBox, - SIGNAL (filterChanged (boost::shared_ptr, const std::string&)), - this, SIGNAL (recordFilterChanged (boost::shared_ptr, const std::string&))); + SIGNAL (filterChanged (boost::shared_ptr)), + this, SIGNAL (recordFilterChanged (boost::shared_ptr))); } \ No newline at end of file diff --git a/apps/opencs/view/filter/filterbox.hpp b/apps/opencs/view/filter/filterbox.hpp index 5f260003af..d3806876df 100644 --- a/apps/opencs/view/filter/filterbox.hpp +++ b/apps/opencs/view/filter/filterbox.hpp @@ -17,8 +17,7 @@ namespace CSVFilter signals: - void recordFilterChanged (boost::shared_ptr filter, - const std::string& userValue); + void recordFilterChanged (boost::shared_ptr filter); }; } diff --git a/apps/opencs/view/filter/recordfilterbox.cpp b/apps/opencs/view/filter/recordfilterbox.cpp index c4b516f03b..3b5f73f474 100644 --- a/apps/opencs/view/filter/recordfilterbox.cpp +++ b/apps/opencs/view/filter/recordfilterbox.cpp @@ -22,6 +22,6 @@ CSVFilter::RecordFilterBox::RecordFilterBox (QWidget *parent) setLayout (layout); connect ( - editWidget, SIGNAL (filterChanged (boost::shared_ptr, const std::string&)), - this, SIGNAL (filterChanged (boost::shared_ptr, const std::string&))); + editWidget, SIGNAL (filterChanged (boost::shared_ptr)), + this, SIGNAL (filterChanged (boost::shared_ptr))); } diff --git a/apps/opencs/view/filter/recordfilterbox.hpp b/apps/opencs/view/filter/recordfilterbox.hpp index 8fc1e263bc..64c1848a85 100644 --- a/apps/opencs/view/filter/recordfilterbox.hpp +++ b/apps/opencs/view/filter/recordfilterbox.hpp @@ -21,8 +21,7 @@ namespace CSVFilter signals: - void filterChanged (boost::shared_ptr filter, - const std::string& userValue); + void filterChanged (boost::shared_ptr filter); }; } diff --git a/apps/opencs/view/world/tablesubview.cpp b/apps/opencs/view/world/tablesubview.cpp index cb6f430c1c..a43ae2dacb 100644 --- a/apps/opencs/view/world/tablesubview.cpp +++ b/apps/opencs/view/world/tablesubview.cpp @@ -52,8 +52,8 @@ CSVWorld::TableSubView::TableSubView (const CSMWorld::UniversalId& id, CSMDoc::D mTable, SLOT (requestFocus (const std::string&))); connect (filterBox, - SIGNAL (recordFilterChanged (boost::shared_ptr, const std::string&)), - mTable, SLOT (recordFilterChanged (boost::shared_ptr, const std::string&))); + SIGNAL (recordFilterChanged (boost::shared_ptr)), + mTable, SLOT (recordFilterChanged (boost::shared_ptr))); } void CSVWorld::TableSubView::setEditLock (bool locked) From ba6edc55d457f62c9f85850f48278ee49d787187 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 22 Aug 2013 13:45:50 +0200 Subject: [PATCH 16/30] added not filter node --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/filter/notnode.cpp | 10 ++++++++++ apps/opencs/model/filter/notnode.hpp | 21 +++++++++++++++++++++ apps/opencs/model/filter/parser.cpp | 24 ++++++++++++++++-------- apps/opencs/model/filter/parser.hpp | 2 +- apps/opencs/model/filter/unarynode.cpp | 8 +++++++- apps/opencs/model/filter/unarynode.hpp | 11 ++++++++--- 7 files changed, 64 insertions(+), 14 deletions(-) create mode 100644 apps/opencs/model/filter/notnode.cpp create mode 100644 apps/opencs/model/filter/notnode.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 9fb6c1be3e..c74f0db22c 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -108,7 +108,7 @@ opencs_units_noqt (model/settings ) opencs_units_noqt (model/filter - node unarynode narynode leafnode booleannode parser andnode ornode + node unarynode narynode leafnode booleannode parser andnode ornode notnode ) opencs_hdrs_noqt (model/filter diff --git a/apps/opencs/model/filter/notnode.cpp b/apps/opencs/model/filter/notnode.cpp new file mode 100644 index 0000000000..1b22ea7a6a --- /dev/null +++ b/apps/opencs/model/filter/notnode.cpp @@ -0,0 +1,10 @@ + +#include "notnode.hpp" + +CSMFilter::NotNode::NotNode (boost::shared_ptr child) : UnaryNode (child, "not") {} + +bool CSMFilter::NotNode::test (const CSMWorld::IdTable& table, int row, + const std::map& columns) const +{ + return !getChild().test (table, row, columns); +} \ No newline at end of file diff --git a/apps/opencs/model/filter/notnode.hpp b/apps/opencs/model/filter/notnode.hpp new file mode 100644 index 0000000000..b9e80b8c6d --- /dev/null +++ b/apps/opencs/model/filter/notnode.hpp @@ -0,0 +1,21 @@ +#ifndef CSM_FILTER_NOTNODE_H +#define CSM_FILTER_NOTNODE_H + +#include "unarynode.hpp" + +namespace CSMFilter +{ + class NotNode : public UnaryNode + { + public: + + NotNode (boost::shared_ptr child); + + virtual bool test (const CSMWorld::IdTable& table, int row, + const std::map& columns) const; + ///< \return Can the specified table row pass through to filter? + /// \param columns column ID to column index mapping + }; +} + +#endif diff --git a/apps/opencs/model/filter/parser.cpp b/apps/opencs/model/filter/parser.cpp index a35c4bdfdf..5dd0392e8c 100644 --- a/apps/opencs/model/filter/parser.cpp +++ b/apps/opencs/model/filter/parser.cpp @@ -10,6 +10,7 @@ #include "booleannode.hpp" #include "ornode.hpp" #include "andnode.hpp" +#include "notnode.hpp" namespace CSMFilter { @@ -209,7 +210,7 @@ CSMFilter::Token CSMFilter::Parser::getNextToken() return Token (Token::Type_None); } -boost::shared_ptr CSMFilter::Parser::parseImp() +boost::shared_ptr CSMFilter::Parser::parseImp (bool allowEmpty) { if (Token token = getNextToken()) { @@ -228,8 +229,21 @@ boost::shared_ptr CSMFilter::Parser::parseImp() return parseNAry (token); + case Token::Type_Keyword_Not: + { + boost::shared_ptr node = parseImp(); + + if (mError) + return boost::shared_ptr(); + + return boost::shared_ptr (new NotNode (node)); + } + case Token::Type_EOS: + if (!allowEmpty) + error(); + return boost::shared_ptr(); default: @@ -260,12 +274,6 @@ boost::shared_ptr CSMFilter::Parser::parseNAry (const Token& ke if (mError) return boost::shared_ptr(); - if (!node.get()) - { - error(); - return boost::shared_ptr(); - } - nodes.push_back (node); Token token = getNextToken(); @@ -309,7 +317,7 @@ bool CSMFilter::Parser::parse (const std::string& filter) mInput = filter; mIndex = 0; - boost::shared_ptr node = parseImp(); + boost::shared_ptr node = parseImp (true); if (mError) return false; diff --git a/apps/opencs/model/filter/parser.hpp b/apps/opencs/model/filter/parser.hpp index d9f14b5d9a..13c77b09a5 100644 --- a/apps/opencs/model/filter/parser.hpp +++ b/apps/opencs/model/filter/parser.hpp @@ -25,7 +25,7 @@ namespace CSMFilter Token checkKeywords (const Token& token); ///< Turn string token into keyword token, if possible. - boost::shared_ptr parseImp(); + boost::shared_ptr parseImp (bool allowEmpty = false); ///< Will return a null-pointer, if there is nothing more to parse. boost::shared_ptr parseNAry (const Token& keyword); diff --git a/apps/opencs/model/filter/unarynode.cpp b/apps/opencs/model/filter/unarynode.cpp index d687b6468d..d1897f4b7a 100644 --- a/apps/opencs/model/filter/unarynode.cpp +++ b/apps/opencs/model/filter/unarynode.cpp @@ -1,7 +1,9 @@ #include "unarynode.hpp" -CSMFilter::UnaryNode::UnaryNode (boost::shared_ptr child) : mChild (child) {} +CSMFilter::UnaryNode::UnaryNode (boost::shared_ptr child, const std::string& name) +: mChild (child), mName (name) +{} const CSMFilter::Node& CSMFilter::UnaryNode::getChild() const { @@ -23,3 +25,7 @@ bool CSMFilter::UnaryNode::isSimple() const return false; } +std::string CSMFilter::UnaryNode::toString (bool numericColumns) const +{ + return mName + " " + mChild->toString (numericColumns); +} \ No newline at end of file diff --git a/apps/opencs/model/filter/unarynode.hpp b/apps/opencs/model/filter/unarynode.hpp index 6483a730f4..9fd5faf3f7 100644 --- a/apps/opencs/model/filter/unarynode.hpp +++ b/apps/opencs/model/filter/unarynode.hpp @@ -1,5 +1,5 @@ -#ifndef CSM_FILTER_UNARIYNODE_H -#define CSM_FILTER_UNARIYNODE_H +#ifndef CSM_FILTER_UNARYNODE_H +#define CSM_FILTER_UNARYNODE_H #include @@ -10,10 +10,11 @@ namespace CSMFilter class UnaryNode : public Node { boost::shared_ptr mChild; + std::string mName; public: - UnaryNode (boost::shared_ptr child); + UnaryNode (boost::shared_ptr child, const std::string& name); const Node& getChild() const; @@ -26,6 +27,10 @@ namespace CSMFilter virtual bool isSimple() const; ///< \return Can this filter be displayed in simple mode. + virtual std::string toString (bool numericColumns) const; + ///< Return a string that represents this node. + /// + /// \param numericColumns Use numeric IDs instead of string to represent columns. }; } From decd826208ef06553fe72fd374d50b3af9627742 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 22 Aug 2013 14:00:55 +0200 Subject: [PATCH 17/30] fixed an include guard --- apps/opencs/model/filter/leafnode.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/filter/leafnode.hpp b/apps/opencs/model/filter/leafnode.hpp index 2b0163065f..a9790d01d2 100644 --- a/apps/opencs/model/filter/leafnode.hpp +++ b/apps/opencs/model/filter/leafnode.hpp @@ -1,5 +1,5 @@ -#ifndef CSM_FILTER_UNARIYNODE_H -#define CSM_FILTER_UNARIYNODE_H +#ifndef CSM_FILTER_LEAFNODE_H +#define CSM_FILTER_LEAFNODE_H #include From de956737fe06a2ef516943ef3d48b847f6adddc5 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 22 Aug 2013 14:50:42 +0200 Subject: [PATCH 18/30] added text filter node --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/filter/parser.cpp | 77 ++++++++++++++++++++++++++- apps/opencs/model/filter/parser.hpp | 2 + apps/opencs/model/filter/textnode.cpp | 61 +++++++++++++++++++++ apps/opencs/model/filter/textnode.hpp | 33 ++++++++++++ 5 files changed, 172 insertions(+), 3 deletions(-) create mode 100644 apps/opencs/model/filter/textnode.cpp create mode 100644 apps/opencs/model/filter/textnode.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index c74f0db22c..ea78135b9b 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -108,7 +108,7 @@ opencs_units_noqt (model/settings ) opencs_units_noqt (model/filter - node unarynode narynode leafnode booleannode parser andnode ornode notnode + node unarynode narynode leafnode booleannode parser andnode ornode notnode textnode ) opencs_hdrs_noqt (model/filter diff --git a/apps/opencs/model/filter/parser.cpp b/apps/opencs/model/filter/parser.cpp index 5dd0392e8c..c2562ad1e1 100644 --- a/apps/opencs/model/filter/parser.cpp +++ b/apps/opencs/model/filter/parser.cpp @@ -7,10 +7,13 @@ #include +#include "../world/columns.hpp" + #include "booleannode.hpp" #include "ornode.hpp" #include "andnode.hpp" #include "notnode.hpp" +#include "textnode.hpp" namespace CSMFilter { @@ -31,7 +34,8 @@ namespace CSMFilter Type_Keyword_False, Type_Keyword_And, Type_Keyword_Or, - Type_Keyword_Not + Type_Keyword_Not, + Type_Keyword_Text }; Type mType; @@ -162,6 +166,7 @@ CSMFilter::Token CSMFilter::Parser::checkKeywords (const Token& token) { "true", "false", "and", "or", "not", + "text", 0 }; @@ -239,6 +244,10 @@ boost::shared_ptr CSMFilter::Parser::parseImp (bool allowEmpty) return boost::shared_ptr (new NotNode (node)); } + case Token::Type_Keyword_Text: + + return parseText(); + case Token::Type_EOS: if (!allowEmpty) @@ -261,7 +270,7 @@ boost::shared_ptr CSMFilter::Parser::parseNAry (const Token& ke Token token = getNextToken(); - if (!token || token.mType!=Token::Type_Open) + if (token.mType!=Token::Type_Open) { error(); return boost::shared_ptr(); @@ -302,6 +311,70 @@ boost::shared_ptr CSMFilter::Parser::parseNAry (const Token& ke } } +boost::shared_ptr CSMFilter::Parser::parseText() +{ + Token token = getNextToken(); + + if (token.mType!=Token::Type_Open) + { + error(); + return boost::shared_ptr(); + } + + token = getNextToken(); + + if (!token) + return boost::shared_ptr(); + + // parse column ID + int columnId = -1; + + if (token.mType==Token::Type_Number) + { + if (static_cast (token.mNumber)==token.mNumber) + columnId = static_cast (token.mNumber); + } + else if (token.mType==Token::Type_String) + { + columnId = CSMWorld::Columns::getId (token.mString); + } + + if (columnId<0) + { + error(); + return boost::shared_ptr(); + } + + token = getNextToken(); + + if (token.mType!=Token::Type_Comma) + { + error(); + return boost::shared_ptr(); + } + + // parse text pattern + token = getNextToken(); + + if (token.mType!=Token::Type_String) + { + error(); + return boost::shared_ptr(); + } + + std::string text = token.mString; + + token = getNextToken(); + + if (token.mType!=Token::Type_Close) + { + error(); + return boost::shared_ptr(); + } + + return boost::shared_ptr (new TextNode (columnId, text)); +} + void CSMFilter::Parser::error() { mError = true; diff --git a/apps/opencs/model/filter/parser.hpp b/apps/opencs/model/filter/parser.hpp index 13c77b09a5..2512de1411 100644 --- a/apps/opencs/model/filter/parser.hpp +++ b/apps/opencs/model/filter/parser.hpp @@ -30,6 +30,8 @@ namespace CSMFilter boost::shared_ptr parseNAry (const Token& keyword); + boost::shared_ptr parseText(); + void error(); public: diff --git a/apps/opencs/model/filter/textnode.cpp b/apps/opencs/model/filter/textnode.cpp new file mode 100644 index 0000000000..f95c1ce284 --- /dev/null +++ b/apps/opencs/model/filter/textnode.cpp @@ -0,0 +1,61 @@ + +#include "textnode.hpp" + +#include +#include + +#include + +#include "../world/columns.hpp" +#include "../world/idtable.hpp" + +CSMFilter::TextNode::TextNode (int columnId, const std::string& text) +: mColumnId (columnId), mText (text) +{} + +bool CSMFilter::TextNode::test (const CSMWorld::IdTable& table, int row, + const std::map& columns) const +{ + const std::map::const_iterator iter = columns.find (mColumnId); + + if (iter==columns.end()) + throw std::logic_error ("invalid column in test node test"); + + if (iter->second==-1) + return true; + + QModelIndex index = table.index (row, iter->second); + + QVariant data = table.data (index); + + if (data.type()!=QVariant::String) + return false; + + QRegExp regExp(QString::fromUtf8 (mText.c_str())); /// \todo make pattern syntax configurable + + return regExp.exactMatch (data.toString()); +} + +std::vector CSMFilter::TextNode::getReferencedColumns() const +{ + return std::vector (1, mColumnId); +} + +std::string CSMFilter::TextNode::toString (bool numericColumns) const +{ + std::ostringstream stream; + + stream << "text ("; + + if (numericColumns) + stream << mColumnId; + else + stream + << "\"" + << CSMWorld::Columns::getName (static_cast (mColumnId)) + << "\""; + + stream << ", \"" << mText << "\")"; + + return stream.str(); +} \ No newline at end of file diff --git a/apps/opencs/model/filter/textnode.hpp b/apps/opencs/model/filter/textnode.hpp new file mode 100644 index 0000000000..663fa7382a --- /dev/null +++ b/apps/opencs/model/filter/textnode.hpp @@ -0,0 +1,33 @@ +#ifndef CSM_FILTER_TEXTNODE_H +#define CSM_FILTER_TEXTNODE_H + +#include "leafnode.hpp" + +namespace CSMFilter +{ + class TextNode : public LeafNode + { + int mColumnId; + std::string mText; + + public: + + TextNode (int columnId, const std::string& text); + + virtual bool test (const CSMWorld::IdTable& table, int row, + const std::map& columns) const; + ///< \return Can the specified table row pass through to filter? + /// \param columns column ID to column index mapping + + virtual std::vector getReferencedColumns() const; + ///< Return a list of the IDs of the columns referenced by this node. The column mapping + /// passed into test as columns must contain all columns listed here. + + virtual std::string toString (bool numericColumns) const; + ///< Return a string that represents this node. + /// + /// \param numericColumns Use numeric IDs instead of string to represent columns. + }; +} + +#endif From f615a9397bd85643804a332cd0d71b0a65a514ea Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 22 Aug 2013 15:16:22 +0200 Subject: [PATCH 19/30] made text node filter case-insensitive --- apps/opencs/model/filter/textnode.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/filter/textnode.cpp b/apps/opencs/model/filter/textnode.cpp index f95c1ce284..ec654267bf 100644 --- a/apps/opencs/model/filter/textnode.cpp +++ b/apps/opencs/model/filter/textnode.cpp @@ -31,7 +31,8 @@ bool CSMFilter::TextNode::test (const CSMWorld::IdTable& table, int row, if (data.type()!=QVariant::String) return false; - QRegExp regExp(QString::fromUtf8 (mText.c_str())); /// \todo make pattern syntax configurable + /// \todo make pattern syntax configurable + QRegExp regExp (QString::fromUtf8 (mText.c_str()), Qt::CaseInsensitive); return regExp.exactMatch (data.toString()); } From 63b1df85e75fb0f9418993be50b3c1b30fce4b2d Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 22 Aug 2013 15:22:39 +0200 Subject: [PATCH 20/30] fixed string parsing --- apps/opencs/model/filter/parser.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/opencs/model/filter/parser.cpp b/apps/opencs/model/filter/parser.cpp index c2562ad1e1..7c8f9d7682 100644 --- a/apps/opencs/model/filter/parser.cpp +++ b/apps/opencs/model/filter/parser.cpp @@ -113,6 +113,9 @@ CSMFilter::Token CSMFilter::Parser::getStringToken() error(); return Token (Token::Type_None); } + + if (string[0]=='"') + string = string.substr (1, string.size()-2); } return checkKeywords (string); From c56007cceb18662f090ee2f350bb2b69ec7c937c Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 23 Aug 2013 14:11:33 +0200 Subject: [PATCH 21/30] fixed a record counting bug (was using the wrong model) --- apps/opencs/view/world/table.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index 75cbddc2a7..72e78c738e 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -257,9 +257,9 @@ void CSVWorld::Table::tableSizeUpdate() int deleted = 0; int modified = 0; - if (mModel->columnCount()>0) + if (mProxyModel->columnCount()>0) { - int rows = mModel->rowCount(); + int rows = mProxyModel->rowCount(); for (int i=0; i Date: Fri, 23 Aug 2013 14:49:41 +0200 Subject: [PATCH 22/30] fixed type in error message --- apps/opencs/model/filter/textnode.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/model/filter/textnode.cpp b/apps/opencs/model/filter/textnode.cpp index ec654267bf..9987c66d22 100644 --- a/apps/opencs/model/filter/textnode.cpp +++ b/apps/opencs/model/filter/textnode.cpp @@ -19,7 +19,7 @@ bool CSMFilter::TextNode::test (const CSMWorld::IdTable& table, int row, const std::map::const_iterator iter = columns.find (mColumnId); if (iter==columns.end()) - throw std::logic_error ("invalid column in test node test"); + throw std::logic_error ("invalid column in text node test"); if (iter->second==-1) return true; From f5d03a16c1dede5e7ddc3a4f2af38917740d66b4 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 23 Aug 2013 07:01:30 -0700 Subject: [PATCH 23/30] Rename getFacedObject and getFacedHandle for melee hits --- apps/openmw/mwbase/world.hpp | 7 ++++--- apps/openmw/mwclass/npc.cpp | 3 ++- apps/openmw/mwworld/physicssystem.cpp | 5 ++++- apps/openmw/mwworld/physicssystem.hpp | 7 ++++--- apps/openmw/mwworld/worldimp.cpp | 9 +++++---- apps/openmw/mwworld/worldimp.hpp | 7 ++++--- 6 files changed, 23 insertions(+), 15 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index aa5a38e6d6..6ca900a4d3 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -220,9 +220,10 @@ namespace MWBase virtual MWWorld::Ptr getFacedObject() = 0; ///< Return pointer to the object the player is looking at, if it is within activation range - /// Returns a pointer to the object the provided object is facing (if within the - /// specified distance). This will attempt to use the "Bip01 Head" node as a basis. - virtual MWWorld::Ptr getFacedObject(const MWWorld::Ptr &ptr, float distance) = 0; + /// Returns a pointer to the object the provided object would hit (if within the + /// specified distance), and the point where the hit occurs. This will attempt to + /// use the "Head" node as a basis. + virtual std::pair getHitContact(const MWWorld::Ptr &ptr, float distance) = 0; virtual void adjustPosition (const MWWorld::Ptr& ptr) = 0; ///< Adjust position after load to be on ground. Must be called after model load. diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index d9c1da77bf..073d1b1b92 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -332,7 +332,8 @@ namespace MWClass float dist = 100.0f * (!weapon.isEmpty() ? weapon.get()->mBase->mData.mReach : gmst.find("fHandToHandReach")->getFloat()); - MWWorld::Ptr victim = world->getFacedObject(ptr, dist); + // TODO: Use second to work out the hit angle and where to spawn the blood effect + MWWorld::Ptr victim = world->getHitContact(ptr, dist).first; if(victim.isEmpty()) // Didn't hit anything return; diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 33ba7101eb..9fa8db782a 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -311,7 +311,10 @@ namespace MWWorld return results; } - std::pair PhysicsSystem::getFacedHandle(const Ogre::Vector3 &origin_, const Ogre::Quaternion &orient_, float queryDistance) + std::pair PhysicsSystem::getHitContact(const std::string &name, + const Ogre::Vector3 &origin_, + const Ogre::Quaternion &orient_, + float queryDistance) { btVector3 origin(origin_.x, origin_.y, origin_.z); diff --git a/apps/openmw/mwworld/physicssystem.hpp b/apps/openmw/mwworld/physicssystem.hpp index 669eb74bd6..f76b4d29c7 100644 --- a/apps/openmw/mwworld/physicssystem.hpp +++ b/apps/openmw/mwworld/physicssystem.hpp @@ -57,9 +57,10 @@ namespace MWWorld Ogre::Vector3 traceDown(const MWWorld::Ptr &ptr); std::pair getFacedHandle (MWWorld::World& world, float queryDistance); - std::pair getFacedHandle(const Ogre::Vector3 &origin, - const Ogre::Quaternion &orientation, - float queryDistance); + std::pair getHitContact(const std::string &name, + const Ogre::Vector3 &origin, + const Ogre::Quaternion &orientation, + float queryDistance); std::vector < std::pair > getFacedHandles (float queryDistance); std::vector < std::pair > getFacedHandles (float mouseX, float mouseY, float queryDistance); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 950f005659..eee9c7a199 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -784,7 +784,7 @@ namespace MWWorld return object; } - MWWorld::Ptr World::getFacedObject(const MWWorld::Ptr &ptr, float distance) + std::pair World::getHitContact(const MWWorld::Ptr &ptr, float distance) { const ESM::Position &posdata = ptr.getRefData().getPosition(); Ogre::Vector3 pos(posdata.pos); @@ -799,11 +799,12 @@ namespace MWWorld pos += node->_getDerivedPosition(); } - std::pair result = mPhysics->getFacedHandle(pos, rot, distance); + std::pair result = mPhysics->getHitContact(ptr.getRefData().getHandle(), + pos, rot, distance); if(result.first.empty()) - return MWWorld::Ptr(); + return std::make_pair(MWWorld::Ptr(), Ogre::Vector3(0.0f)); - return searchPtrViaHandle(result.first); + return std::make_pair(searchPtrViaHandle(result.first), result.second); } void World::deleteObject (const Ptr& ptr) diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index b8a9a4e829..71391239b3 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -252,9 +252,10 @@ namespace MWWorld virtual MWWorld::Ptr getFacedObject(); ///< Return pointer to the object the player is looking at, if it is within activation range - /// Returns a pointer to the object the provided object is facing (if within the - /// specified distance). This will attempt to use the "Bip01 Head" node as a basis. - virtual MWWorld::Ptr getFacedObject(const MWWorld::Ptr &ptr, float distance); + /// Returns a pointer to the object the provided object would hit (if within the + /// specified distance), and the point where the hit occurs. This will attempt to + /// use the "Head" node as a basis. + virtual std::pair getHitContact(const MWWorld::Ptr &ptr, float distance); virtual void deleteObject (const Ptr& ptr); From 3fa65f21ddc3cdbb9e116eea5b61315944a7adf8 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 23 Aug 2013 12:25:57 -0700 Subject: [PATCH 24/30] Use a proper cone shape with a contact test to check for melee hits --- apps/openmw/mwworld/physicssystem.cpp | 39 +++++---- libs/openengine/bullet/physic.cpp | 117 ++++++++++++++------------ libs/openengine/bullet/physic.hpp | 8 +- 3 files changed, 92 insertions(+), 72 deletions(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 9fa8db782a..761e5111c5 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -312,28 +312,31 @@ namespace MWWorld } std::pair PhysicsSystem::getHitContact(const std::string &name, - const Ogre::Vector3 &origin_, - const Ogre::Quaternion &orient_, + const Ogre::Vector3 &origin, + const Ogre::Quaternion &orient, float queryDistance) { - btVector3 origin(origin_.x, origin_.y, origin_.z); + const MWWorld::Store &store = MWBase::Environment::get().getWorld()->getStore().get(); - std::pair result = mEngine->sphereTest(queryDistance,origin); - if(result.first == "") return std::make_pair("",0); - btVector3 a = result.second - origin; - Ogre::Vector3 a_ = Ogre::Vector3(a.x(),a.y(),a.z()); - a_ = orient_.Inverse()*a_; - Ogre::Vector2 a_xy = Ogre::Vector2(a_.x,a_.y); - Ogre::Vector2 a_yz = Ogre::Vector2(a_xy.length(),a_.z); - float axy = a_xy.angleBetween(Ogre::Vector2::UNIT_Y).valueDegrees(); - float az = a_yz.angleBetween(Ogre::Vector2::UNIT_X).valueDegrees(); + btConeShape shape(Ogre::Degree(store.find("fCombatAngleXY")->getFloat()/2.0f).valueRadians(), + queryDistance); + shape.setLocalScaling(btVector3(1, 1, Ogre::Degree(store.find("fCombatAngleZ")->getFloat()/2.0f).valueRadians() / + shape.getRadius())); - float fCombatAngleXY = MWBase::Environment::get().getWorld()->getStore().get().find("fCombatAngleXY")->getFloat(); - float fCombatAngleZ = MWBase::Environment::get().getWorld()->getStore().get().find("fCombatAngleZ")->getFloat(); - if(abs(axy) < fCombatAngleXY && abs(az) < fCombatAngleZ) - return std::make_pair (result.first,result.second.length()); - else - return std::make_pair("",0); + // The shape origin is its center, so we have to move it forward by half the length. The + // real origin will be provided to getFilteredContact to find the closest. + Ogre::Vector3 center = origin + (orient * Ogre::Vector3(0.0f, queryDistance*0.5f, 0.0f)); + + btCollisionObject object; + object.setCollisionShape(&shape); + object.setWorldTransform(btTransform(btQuaternion(orient.x, orient.y, orient.z, orient.w), + btVector3(center.x, center.y, center.z))); + + std::pair result = mEngine->getFilteredContact( + name, btVector3(origin.x, origin.y, origin.z), &object); + if(!result.first) + return std::make_pair(std::string(), Ogre::Vector3(&result.second[0])); + return std::make_pair(result.first->mName, Ogre::Vector3(&result.second[0])); } diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index e488d6e991..e33edda183 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -543,62 +543,64 @@ namespace Physic #endif }; - struct AabbResultCallback : public btBroadphaseAabbCallback { - std::vector hits; - //AabbResultCallback(){} - virtual bool process(const btBroadphaseProxy* proxy) { - RigidBody* collisionObject = static_cast(proxy->m_clientObject); - if(proxy->m_collisionFilterGroup == CollisionType_Actor && (collisionObject->mName != "player")) - this->hits.push_back(collisionObject); - return true; + class DeepestNotMeContactTestResultCallback : public btCollisionWorld::ContactResultCallback + { + const std::string &mFilter; + // Store the real origin, since the shape's origin is its center + btVector3 mOrigin; + + public: + const RigidBody *mObject; + btVector3 mContactPoint; + btScalar mLeastDistSqr; + + DeepestNotMeContactTestResultCallback(const std::string &filter, const btVector3 &origin) + : mFilter(filter), mOrigin(origin), mObject(0), mContactPoint(0,0,0), + mLeastDistSqr(std::numeric_limits::max()) + { } + +#if defined(BT_COLLISION_OBJECT_WRAPPER_H) + virtual btScalar addSingleResult(btManifoldPoint& cp, + const btCollisionObjectWrapper* col0Wrap,int partId0,int index0, + const btCollisionObjectWrapper* col1Wrap,int partId1,int index1) + { + const RigidBody* body = dynamic_cast(col1Wrap->m_collisionObject); + if(body && body->mName != mFilter) + { + btScalar distsqr = mOrigin.distance2(cp.getPositionWorldOnA()); + if(!mObject || distsqr < mLeastDistSqr) + { + mObject = body; + mLeastDistSqr = distsqr; + mContactPoint = cp.getPositionWorldOnA(); + } + } + + return 0.f; } +#else + virtual btScalar addSingleResult(btManifoldPoint& cp, + const btCollisionObject* col0, int partId0, int index0, + const btCollisionObject* col1, int partId1, int index1) + { + const RigidBody* body = dynamic_cast(col1); + if(body && body->mName != mFilter) + { + btScalar distsqr = mOrigin.distance2(cp.getPositionWorldOnA()); + if(!mObject || distsqr < mLeastDistSqr) + { + mObject = body; + mLeastDistSqr = distsqr; + mContactPoint = cp.getPositionWorldOnA(); + } + } + + return 0.f; + } +#endif }; - std::pair PhysicEngine::sphereTest(float radius,btVector3& pos) - { - AabbResultCallback callback; - /*btDefaultMotionState* newMotionState = - new btDefaultMotionState(btTransform(btQuaternion(0,0,0,1),pos)); - btCollisionShape * shape = new btSphereShape(radius); - btRigidBody::btRigidBodyConstructionInfo CI = btRigidBody::btRigidBodyConstructionInfo - (0,newMotionState, shape); - RigidBody* body = new RigidBody(CI,"hitDetectionShpere__"); - btTransform tr = body->getWorldTransform(); - tr.setOrigin(pos); - body->setWorldTransform(tr); - dynamicsWorld->addRigidBody(body,CollisionType_Actor,CollisionType_World|CollisionType_World); - body->setWorldTransform(tr);*/ - - btVector3 aabbMin = pos - radius*btVector3(1.0f, 1.0f, 1.0f); - btVector3 aabbMax = pos + radius*btVector3(1.0f, 1.0f, 1.0f); - - broadphase->aabbTest(aabbMin,aabbMax,callback); - for(int i=0;i (callback.hits.size()); ++i) - { - float d = (callback.hits[i]->getWorldTransform().getOrigin()-pos).length(); - if(d rayResult = this->rayTest(pos,callback.hits[i]->getWorldTransform().getOrigin()); - if(rayResult.second>d || rayResult.first == callback.hits[i]->mName) - return std::make_pair(callback.hits[i]->mName,callback.hits[i]->getWorldTransform().getOrigin()); - } - } - //ContactTestResultCallback callback; - //dynamicsWorld->contactTest(body, callback); - //dynamicsWorld->removeRigidBody(body); - //delete body; - //delete shape; - //if(callback.mResultName.empty()) return std::make_pair(std::string(""),btVector3(0,0,0)); - /*for(int i=0;i(callback.mResultName[i],callback.mResultContact[i]); - */ - return std::make_pair(std::string(""),btVector3(0,0,0)); - } - std::vector PhysicEngine::getCollisions(const std::string& name) { RigidBody* body = getRigidBody(name); @@ -607,6 +609,17 @@ namespace Physic return callback.mResult; } + + std::pair PhysicEngine::getFilteredContact(const std::string &filter, + const btVector3 &origin, + btCollisionObject *object) + { + DeepestNotMeContactTestResultCallback callback(filter, origin); + dynamicsWorld->contactTest(object, callback); + return std::make_pair(callback.mObject, callback.mContactPoint); + } + + void PhysicEngine::stepSimulation(double deltaT) { // This seems to be needed for character controller objects diff --git a/libs/openengine/bullet/physic.hpp b/libs/openengine/bullet/physic.hpp index 46dafda769..f28f95ccb8 100644 --- a/libs/openengine/bullet/physic.hpp +++ b/libs/openengine/bullet/physic.hpp @@ -321,10 +321,14 @@ public: std::pair sphereCast (float radius, btVector3& from, btVector3& to); ///< @return (hit, relative distance) - std::pair sphereTest(float radius,btVector3& pos); - std::vector getCollisions(const std::string& name); + // Get the nearest object that's inside the given object, filtering out objects of the + // provided name + std::pair getFilteredContact(const std::string &filter, + const btVector3 &origin, + btCollisionObject *object); + //event list of non player object std::list NPEventList; From ca24a809fc416bc3b5566e4cfd790e3e9c109a67 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 23 Aug 2013 13:38:26 -0700 Subject: [PATCH 25/30] Use the position of the actor to determine if they're swimming --- apps/openmw/mwworld/physicssystem.cpp | 33 ++++++++++++--------------- 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 761e5111c5..97aa7dffe5 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -107,8 +107,7 @@ namespace MWWorld } static Ogre::Vector3 move(const MWWorld::Ptr &ptr, const Ogre::Vector3 &movement, float time, - bool isSwimming, bool isFlying, float waterlevel, - OEngine::Physic::PhysicEngine *engine) + bool isFlying, float waterlevel, OEngine::Physic::PhysicEngine *engine) { const ESM::Position &refpos = ptr.getRefData().getPosition(); Ogre::Vector3 position(refpos.pos); @@ -135,11 +134,11 @@ namespace MWWorld bool isOnGround = false; Ogre::Vector3 inertia(0.0f); Ogre::Vector3 velocity; - if(isSwimming || isFlying) + if(position.z < waterlevel || isFlying) { - velocity = (Ogre::Quaternion(Ogre::Radian( -refpos.rot[2]), Ogre::Vector3::UNIT_Z)* - Ogre::Quaternion(Ogre::Radian( -refpos.rot[1]), Ogre::Vector3::UNIT_Y)* - Ogre::Quaternion(Ogre::Radian( refpos.rot[0]), Ogre::Vector3::UNIT_X)) * + velocity = (Ogre::Quaternion(Ogre::Radian(-refpos.rot[2]), Ogre::Vector3::UNIT_Z)* + Ogre::Quaternion(Ogre::Radian(-refpos.rot[1]), Ogre::Vector3::UNIT_Y)* + Ogre::Quaternion(Ogre::Radian( refpos.rot[0]), Ogre::Vector3::UNIT_X)) * movement; } else @@ -173,7 +172,7 @@ namespace MWWorld { Ogre::Vector3 nextpos = newPosition + velocity*remainingTime; - if(isSwimming && !isFlying && + if(newPosition.z < waterlevel && !isFlying && nextpos.z > waterlevel && newPosition.z <= waterlevel) { const Ogre::Vector3 down(0,0,-1); @@ -197,7 +196,7 @@ namespace MWWorld // We hit something. Try to step up onto it. if(stepMove(colobj, newPosition, velocity, remainingTime, engine)) - isOnGround = !(isSwimming || isFlying); // Only on the ground if there's gravity + isOnGround = !(newPosition.z < waterlevel || isFlying); // Only on the ground if there's gravity else { // Can't move this way, try to find another spot along the plane @@ -208,7 +207,7 @@ namespace MWWorld // Do not allow sliding upward if there is gravity. Stepping will have taken // care of that. - if(!(isSwimming || isFlying)) + if(!(newPosition.z < waterlevel || isFlying)) velocity.z = std::min(velocity.z, 0.0f); } } @@ -225,7 +224,7 @@ namespace MWWorld isOnGround = false; } - if(isOnGround || isSwimming || isFlying) + if(isOnGround || newPosition.z < waterlevel || isFlying) physicActor->setInertialForce(Ogre::Vector3(0.0f)); else { @@ -590,15 +589,13 @@ namespace MWWorld for(;iter != mMovementQueue.end();iter++) { float waterlevel = -std::numeric_limits::max(); - const MWWorld::CellStore *cellstore = iter->first.getCell(); - if(cellstore->mCell->hasWater()) - waterlevel = cellstore->mCell->mWater; + const ESM::Cell *cell = iter->first.getCell()->mCell; + if(cell->hasWater()) + waterlevel = cell->mWater; - Ogre::Vector3 newpos; - newpos = MovementSolver::move(iter->first, iter->second, mTimeAccum, - world->isSwimming(iter->first), - world->isFlying(iter->first), - waterlevel, mEngine); + Ogre::Vector3 newpos = MovementSolver::move(iter->first, iter->second, mTimeAccum, + world->isFlying(iter->first), + waterlevel, mEngine); mMovementResults.push_back(std::make_pair(iter->first, newpos)); } From 3cf60da5a70a8b7fa294756dc0fbb982e21ef5c9 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 24 Aug 2013 14:43:38 +0200 Subject: [PATCH 26/30] added numeric value filter node --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/filter/parser.cpp | 127 ++++++++++++++++++++++++- apps/opencs/model/filter/parser.hpp | 2 + apps/opencs/model/filter/valuenode.cpp | 71 ++++++++++++++ apps/opencs/model/filter/valuenode.hpp | 37 +++++++ 5 files changed, 236 insertions(+), 3 deletions(-) create mode 100644 apps/opencs/model/filter/valuenode.cpp create mode 100644 apps/opencs/model/filter/valuenode.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index ea78135b9b..ad7b5b19c7 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -108,7 +108,7 @@ opencs_units_noqt (model/settings ) opencs_units_noqt (model/filter - node unarynode narynode leafnode booleannode parser andnode ornode notnode textnode + node unarynode narynode leafnode booleannode parser andnode ornode notnode textnode valuenode ) opencs_hdrs_noqt (model/filter diff --git a/apps/opencs/model/filter/parser.cpp b/apps/opencs/model/filter/parser.cpp index 7c8f9d7682..5e580b6e15 100644 --- a/apps/opencs/model/filter/parser.cpp +++ b/apps/opencs/model/filter/parser.cpp @@ -14,6 +14,7 @@ #include "andnode.hpp" #include "notnode.hpp" #include "textnode.hpp" +#include "valuenode.hpp" namespace CSMFilter { @@ -35,7 +36,8 @@ namespace CSMFilter Type_Keyword_And, Type_Keyword_Or, Type_Keyword_Not, - Type_Keyword_Text + Type_Keyword_Text, + Type_Keyword_Value }; Type mType; @@ -169,7 +171,7 @@ CSMFilter::Token CSMFilter::Parser::checkKeywords (const Token& token) { "true", "false", "and", "or", "not", - "text", + "text", "value", 0 }; @@ -251,6 +253,10 @@ boost::shared_ptr CSMFilter::Parser::parseImp (bool allowEmpty) return parseText(); + case Token::Type_Keyword_Value: + + return parseValue(); + case Token::Type_EOS: if (!allowEmpty) @@ -378,6 +384,123 @@ boost::shared_ptr CSMFilter::Parser::parseText() return boost::shared_ptr (new TextNode (columnId, text)); } +boost::shared_ptr CSMFilter::Parser::parseValue() +{ + Token token = getNextToken(); + + if (token.mType!=Token::Type_Open) + { + error(); + return boost::shared_ptr(); + } + + token = getNextToken(); + + if (!token) + return boost::shared_ptr(); + + // parse column ID + int columnId = -1; + + if (token.mType==Token::Type_Number) + { + if (static_cast (token.mNumber)==token.mNumber) + columnId = static_cast (token.mNumber); + } + else if (token.mType==Token::Type_String) + { + columnId = CSMWorld::Columns::getId (token.mString); + } + + if (columnId<0) + { + error(); + return boost::shared_ptr(); + } + + token = getNextToken(); + + if (token.mType!=Token::Type_Comma) + { + error(); + return boost::shared_ptr(); + } + + // parse value + double lower = 0; + double upper = 0; + bool min = false; + bool max = false; + + token = getNextToken(); + + if (token.mType==Token::Type_Number) + { + // single value + min = max = true; + lower = upper = token.mNumber; + } + else + { + // interval + if (token.mType==Token::Type_OpenSquare) + min = true; + else if (token.mType!=Token::Type_CloseSquare && token.mType!=Token::Type_Open) + { + error(); + return boost::shared_ptr(); + } + + token = getNextToken(); + + if (token.mType!=Token::Type_Number) + { + error(); + return boost::shared_ptr(); + } + + lower = token.mNumber; + + token = getNextToken(); + + if (token.mType!=Token::Type_Comma) + { + error(); + return boost::shared_ptr(); + } + + token = getNextToken(); + + if (token.mType!=Token::Type_Number) + { + error(); + return boost::shared_ptr(); + } + + upper = token.mNumber; + + token = getNextToken(); + + if (token.mType==Token::Type_CloseSquare) + max = true; + else if (token.mType!=Token::Type_OpenSquare && token.mType!=Token::Type_Close) + { + error(); + return boost::shared_ptr(); + } + } + + token = getNextToken(); + + if (token.mType!=Token::Type_Close) + { + error(); + return boost::shared_ptr(); + } + + return boost::shared_ptr (new ValueNode (columnId, lower, upper, min, max)); +} + void CSMFilter::Parser::error() { mError = true; diff --git a/apps/opencs/model/filter/parser.hpp b/apps/opencs/model/filter/parser.hpp index 2512de1411..1600992b72 100644 --- a/apps/opencs/model/filter/parser.hpp +++ b/apps/opencs/model/filter/parser.hpp @@ -32,6 +32,8 @@ namespace CSMFilter boost::shared_ptr parseText(); + boost::shared_ptr parseValue(); + void error(); public: diff --git a/apps/opencs/model/filter/valuenode.cpp b/apps/opencs/model/filter/valuenode.cpp new file mode 100644 index 0000000000..f6cb20e4cb --- /dev/null +++ b/apps/opencs/model/filter/valuenode.cpp @@ -0,0 +1,71 @@ + +#include "valuenode.hpp" + +#include +#include + +#include "../world/columns.hpp" +#include "../world/idtable.hpp" + +CSMFilter::ValueNode::ValueNode (int columnId, + double lower, double upper, bool min, bool max) +: mColumnId (columnId), mLower (lower), mUpper (upper), mMin (min), mMax (max) +{} + +bool CSMFilter::ValueNode::test (const CSMWorld::IdTable& table, int row, + const std::map& columns) const +{ + const std::map::const_iterator iter = columns.find (mColumnId); + + if (iter==columns.end()) + throw std::logic_error ("invalid column in test value test"); + + if (iter->second==-1) + return true; + + QModelIndex index = table.index (row, iter->second); + + QVariant data = table.data (index); + + if (data.type()!=QVariant::Double && data.type()!=QVariant::Bool && data.type()!=QVariant::Int && + data.type()!=QVariant::UInt) + return false; + + double value = data.toDouble(); + + if (mLower==mUpper && mMin && mMax) + return value==mLower; + + return (mMin ? value>=mLower : value>mLower) && (mMax ? value<=mUpper : value CSMFilter::ValueNode::getReferencedColumns() const +{ + return std::vector (1, mColumnId); +} + +std::string CSMFilter::ValueNode::toString (bool numericColumns) const +{ + std::ostringstream stream; + + stream << "value ("; + + if (numericColumns) + stream << mColumnId; + else + stream + << "\"" + << CSMWorld::Columns::getName (static_cast (mColumnId)) + << "\""; + + stream << ", \""; + + if (mLower==mUpper && mMin && mMax) + stream << mLower; + else + stream << (mMin ? "[" : "(") << mLower << ", " << mUpper << (mMax ? "]" : ")"); + + stream << ")"; + + return stream.str(); +} \ No newline at end of file diff --git a/apps/opencs/model/filter/valuenode.hpp b/apps/opencs/model/filter/valuenode.hpp new file mode 100644 index 0000000000..faaa1e2ff6 --- /dev/null +++ b/apps/opencs/model/filter/valuenode.hpp @@ -0,0 +1,37 @@ +#ifndef CSM_FILTER_VALUENODE_H +#define CSM_FILTER_VALUENODE_H + +#include "leafnode.hpp" + +namespace CSMFilter +{ + class ValueNode : public LeafNode + { + int mColumnId; + std::string mText; + double mLower; + double mUpper; + bool mMin; + bool mMax; + + public: + + ValueNode (int columnId, double lower, double upper, bool min, bool max); + + virtual bool test (const CSMWorld::IdTable& table, int row, + const std::map& columns) const; + ///< \return Can the specified table row pass through to filter? + /// \param columns column ID to column index mapping + + virtual std::vector getReferencedColumns() const; + ///< Return a list of the IDs of the columns referenced by this node. The column mapping + /// passed into test as columns must contain all columns listed here. + + virtual std::string toString (bool numericColumns) const; + ///< Return a string that represents this node. + /// + /// \param numericColumns Use numeric IDs instead of string to represent columns. + }; +} + +#endif From cf58670c85619ab33745a6c7f28e6e9228431919 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 24 Aug 2013 14:46:42 +0200 Subject: [PATCH 27/30] removed global filter scope (would have caused sync problems between projects) --- apps/opencs/model/filter/filter.hpp | 7 +++---- apps/opencs/view/filter/filtercreator.cpp | 4 +--- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/apps/opencs/model/filter/filter.hpp b/apps/opencs/model/filter/filter.hpp index 7630ad4107..62170ca802 100644 --- a/apps/opencs/model/filter/filter.hpp +++ b/apps/opencs/model/filter/filter.hpp @@ -13,10 +13,9 @@ namespace CSMFilter { enum Scope { - Scope_Global = 0, // per user - Scope_Project = 1, // per project - Scope_Session = 2, // exists only for one editing session; not saved - Scope_Content = 3 // embedded in the edited content file + Scope_Project = 0, // per project + Scope_Session = 1, // exists only for one editing session; not saved + Scope_Content = 2 // embedded in the edited content file }; Scope mScope; diff --git a/apps/opencs/view/filter/filtercreator.cpp b/apps/opencs/view/filter/filtercreator.cpp index 476eacbe16..47925ea57a 100644 --- a/apps/opencs/view/filter/filtercreator.cpp +++ b/apps/opencs/view/filter/filtercreator.cpp @@ -10,7 +10,6 @@ std::string CSVFilter::FilterCreator::getNamespace() const { switch (mScope->currentIndex()) { - case CSMFilter::Filter::Scope_Global: return "global::"; case CSMFilter::Filter::Scope_Project: return "project::"; case CSMFilter::Filter::Scope_Session: return "session::"; } @@ -38,7 +37,6 @@ CSVFilter::FilterCreator::FilterCreator (CSMWorld::Data& data, QUndoStack& undoS mScope = new QComboBox (this); - mScope->addItem ("Global"); mScope->addItem ("Project"); mScope->addItem ("Session"); /// \ŧodo re-enable for OpenMW 1.1 @@ -51,7 +49,7 @@ CSVFilter::FilterCreator::FilterCreator (CSMWorld::Data& data, QUndoStack& undoS QLabel *label = new QLabel ("Scope", this); insertAtBeginning (label, false); - mScope->setCurrentIndex (2); + mScope->setCurrentIndex (1); } void CSVFilter::FilterCreator::reset() From 78c7de440d94492490e260777b28030377c64e56 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 24 Aug 2013 14:49:05 +0200 Subject: [PATCH 28/30] simplified filter nodes even more --- apps/opencs/model/filter/leafnode.cpp | 4 ---- apps/opencs/model/filter/leafnode.hpp | 3 --- apps/opencs/model/filter/narynode.cpp | 4 ---- apps/opencs/model/filter/narynode.hpp | 4 ---- apps/opencs/model/filter/node.hpp | 3 --- apps/opencs/model/filter/unarynode.cpp | 5 ----- apps/opencs/model/filter/unarynode.hpp | 3 --- 7 files changed, 26 deletions(-) diff --git a/apps/opencs/model/filter/leafnode.cpp b/apps/opencs/model/filter/leafnode.cpp index a1330f9dc3..055a1747cc 100644 --- a/apps/opencs/model/filter/leafnode.cpp +++ b/apps/opencs/model/filter/leafnode.cpp @@ -6,7 +6,3 @@ std::vector CSMFilter::LeafNode::getReferencedColumns() const return std::vector(); } -bool CSMFilter::LeafNode::isSimple() const -{ - return true; -} diff --git a/apps/opencs/model/filter/leafnode.hpp b/apps/opencs/model/filter/leafnode.hpp index a9790d01d2..2f3d910708 100644 --- a/apps/opencs/model/filter/leafnode.hpp +++ b/apps/opencs/model/filter/leafnode.hpp @@ -14,9 +14,6 @@ namespace CSMFilter virtual std::vector getReferencedColumns() const; ///< Return a list of the IDs of the columns referenced by this node. The column mapping /// passed into test as columns must contain all columns listed here. - - virtual bool isSimple() const; - ///< \return Can this filter be displayed in simple mode. }; } diff --git a/apps/opencs/model/filter/narynode.cpp b/apps/opencs/model/filter/narynode.cpp index b96e7d4b2e..98f706c875 100644 --- a/apps/opencs/model/filter/narynode.cpp +++ b/apps/opencs/model/filter/narynode.cpp @@ -57,8 +57,4 @@ std::string CSMFilter::NAryNode::toString (bool numericColumns) const return stream.str(); } -bool CSMFilter::NAryNode::isSimple() const -{ - return false; -} diff --git a/apps/opencs/model/filter/narynode.hpp b/apps/opencs/model/filter/narynode.hpp index 421847fae4..aa501d0095 100644 --- a/apps/opencs/model/filter/narynode.hpp +++ b/apps/opencs/model/filter/narynode.hpp @@ -31,10 +31,6 @@ namespace CSMFilter ///< Return a string that represents this node. /// /// \param numericColumns Use numeric IDs instead of string to represent columns. - - virtual bool isSimple() const; - ///< \return Can this filter be displayed in simple mode. - }; } diff --git a/apps/opencs/model/filter/node.hpp b/apps/opencs/model/filter/node.hpp index 6783c3b5ec..ef18353a48 100644 --- a/apps/opencs/model/filter/node.hpp +++ b/apps/opencs/model/filter/node.hpp @@ -41,9 +41,6 @@ namespace CSMFilter ///< Return a list of the IDs of the columns referenced by this node. The column mapping /// passed into test as columns must contain all columns listed here. - virtual bool isSimple() const = 0; - ///< \return Can this filter be displayed in simple mode. - virtual std::string toString (bool numericColumns) const = 0; ///< Return a string that represents this node. /// diff --git a/apps/opencs/model/filter/unarynode.cpp b/apps/opencs/model/filter/unarynode.cpp index d1897f4b7a..43a24b76a1 100644 --- a/apps/opencs/model/filter/unarynode.cpp +++ b/apps/opencs/model/filter/unarynode.cpp @@ -20,11 +20,6 @@ std::vector CSMFilter::UnaryNode::getReferencedColumns() const return mChild->getReferencedColumns(); } -bool CSMFilter::UnaryNode::isSimple() const -{ - return false; -} - std::string CSMFilter::UnaryNode::toString (bool numericColumns) const { return mName + " " + mChild->toString (numericColumns); diff --git a/apps/opencs/model/filter/unarynode.hpp b/apps/opencs/model/filter/unarynode.hpp index 9fd5faf3f7..6bbc960920 100644 --- a/apps/opencs/model/filter/unarynode.hpp +++ b/apps/opencs/model/filter/unarynode.hpp @@ -24,9 +24,6 @@ namespace CSMFilter ///< Return a list of the IDs of the columns referenced by this node. The column mapping /// passed into test as columns must contain all columns listed here. - virtual bool isSimple() const; - ///< \return Can this filter be displayed in simple mode. - virtual std::string toString (bool numericColumns) const; ///< Return a string that represents this node. /// From 51fbb0f3f46b3292849bddb2686f14b669248142 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 24 Aug 2013 15:33:46 +0200 Subject: [PATCH 29/30] fixed a segfault when opening views for tables that do not allow the creation of new records --- apps/opencs/view/world/tablebottombox.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/apps/opencs/view/world/tablebottombox.cpp b/apps/opencs/view/world/tablebottombox.cpp index 6cf21a1322..3edf9af317 100644 --- a/apps/opencs/view/world/tablebottombox.cpp +++ b/apps/opencs/view/world/tablebottombox.cpp @@ -63,12 +63,15 @@ CSVWorld::TableBottomBox::TableBottomBox (const CreatorFactoryBase& creatorFacto mCreator = creatorFactory.makeCreator (data, undoStack, id); - mLayout->addWidget (mCreator); + if (mCreator) + { + mLayout->addWidget (mCreator); - connect (mCreator, SIGNAL (done()), this, SLOT (createRequestDone())); + connect (mCreator, SIGNAL (done()), this, SLOT (createRequestDone())); - connect (mCreator, SIGNAL (requestFocus (const std::string&)), - this, SIGNAL (requestFocus (const std::string&))); + connect (mCreator, SIGNAL (requestFocus (const std::string&)), + this, SIGNAL (requestFocus (const std::string&))); + } } void CSVWorld::TableBottomBox::setEditLock (bool locked) From 7aee1da5c6453d0c9a68eec3dbd56c2a4695eba8 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 24 Aug 2013 16:51:49 +0200 Subject: [PATCH 30/30] fixed some columns --- apps/opencs/model/world/columnimp.hpp | 6 +++--- apps/opencs/model/world/columns.cpp | 9 +++++---- apps/opencs/model/world/columns.hpp | 3 ++- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index 8a1595a30e..6c31fddf39 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -257,7 +257,7 @@ namespace CSMWorld int mIndex; UseValueColumn (int index) - : Column (Columns::ColumnId_UseValue1 + index - 1, ColumnBase::Display_Float), + : Column (Columns::ColumnId_UseValue1 + index, ColumnBase::Display_Float), mIndex (index) {} @@ -339,7 +339,7 @@ namespace CSMWorld int mIndex; AttributesColumn (int index) - : Column (Columns::ColumnId_Attribute1 + index - 1, ColumnBase::Display_Attribute), + : Column (Columns::ColumnId_Attribute1 + index, ColumnBase::Display_Attribute), mIndex (index) {} @@ -372,7 +372,7 @@ namespace CSMWorld SkillsColumn (int index, bool typePrefix = false, bool major = false) : Column ((typePrefix ? ( major ? Columns::ColumnId_MajorSkill1 : Columns::ColumnId_MinorSkill1) : - Columns::ColumnId_Skill1) + index - 1, ColumnBase::Display_String), + Columns::ColumnId_Skill1) + index, ColumnBase::Display_String), mIndex (index), mMajor (major) {} diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index 2198d1b0cc..f6eb8fe34e 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -166,10 +166,11 @@ namespace CSMWorld { ColumnId_MinorSkill5, "Minor Skill 5" }, { ColumnId_Skill1, "Skill 1" }, - { ColumnId_Skill1, "Skill 2" }, - { ColumnId_Skill1, "Skill 3" }, - { ColumnId_Skill1, "Skill 4" }, - { ColumnId_Skill1, "Skill 5" }, + { ColumnId_Skill2, "Skill 2" }, + { ColumnId_Skill3, "Skill 3" }, + { ColumnId_Skill4, "Skill 4" }, + { ColumnId_Skill5, "Skill 5" }, + { ColumnId_Skill6, "Skill 6" }, { -1, 0 } // end marker }; diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index adde80dc92..28da60e938 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -171,7 +171,8 @@ namespace CSMWorld ColumnId_Skill2 = 0x50001, ColumnId_Skill3 = 0x50002, ColumnId_Skill4 = 0x50003, - ColumnId_Skill5 = 0x50004 + ColumnId_Skill5 = 0x50004, + ColumnId_Skill6 = 0x50005 }; std::string getName (ColumnId column);