forked from mirror/openmw-tes3mp
added numeric value filter node
This commit is contained in:
parent
537ab38985
commit
3cf60da5a7
5 changed files with 236 additions and 3 deletions
|
@ -108,7 +108,7 @@ opencs_units_noqt (model/settings
|
||||||
)
|
)
|
||||||
|
|
||||||
opencs_units_noqt (model/filter
|
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
|
opencs_hdrs_noqt (model/filter
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include "andnode.hpp"
|
#include "andnode.hpp"
|
||||||
#include "notnode.hpp"
|
#include "notnode.hpp"
|
||||||
#include "textnode.hpp"
|
#include "textnode.hpp"
|
||||||
|
#include "valuenode.hpp"
|
||||||
|
|
||||||
namespace CSMFilter
|
namespace CSMFilter
|
||||||
{
|
{
|
||||||
|
@ -35,7 +36,8 @@ namespace CSMFilter
|
||||||
Type_Keyword_And,
|
Type_Keyword_And,
|
||||||
Type_Keyword_Or,
|
Type_Keyword_Or,
|
||||||
Type_Keyword_Not,
|
Type_Keyword_Not,
|
||||||
Type_Keyword_Text
|
Type_Keyword_Text,
|
||||||
|
Type_Keyword_Value
|
||||||
};
|
};
|
||||||
|
|
||||||
Type mType;
|
Type mType;
|
||||||
|
@ -169,7 +171,7 @@ CSMFilter::Token CSMFilter::Parser::checkKeywords (const Token& token)
|
||||||
{
|
{
|
||||||
"true", "false",
|
"true", "false",
|
||||||
"and", "or", "not",
|
"and", "or", "not",
|
||||||
"text",
|
"text", "value",
|
||||||
0
|
0
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -251,6 +253,10 @@ boost::shared_ptr<CSMFilter::Node> CSMFilter::Parser::parseImp (bool allowEmpty)
|
||||||
|
|
||||||
return parseText();
|
return parseText();
|
||||||
|
|
||||||
|
case Token::Type_Keyword_Value:
|
||||||
|
|
||||||
|
return parseValue();
|
||||||
|
|
||||||
case Token::Type_EOS:
|
case Token::Type_EOS:
|
||||||
|
|
||||||
if (!allowEmpty)
|
if (!allowEmpty)
|
||||||
|
@ -378,6 +384,123 @@ boost::shared_ptr<CSMFilter::Node> CSMFilter::Parser::parseText()
|
||||||
return boost::shared_ptr<Node> (new TextNode (columnId, text));
|
return boost::shared_ptr<Node> (new TextNode (columnId, text));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boost::shared_ptr<CSMFilter::Node> CSMFilter::Parser::parseValue()
|
||||||
|
{
|
||||||
|
Token token = getNextToken();
|
||||||
|
|
||||||
|
if (token.mType!=Token::Type_Open)
|
||||||
|
{
|
||||||
|
error();
|
||||||
|
return boost::shared_ptr<Node>();
|
||||||
|
}
|
||||||
|
|
||||||
|
token = getNextToken();
|
||||||
|
|
||||||
|
if (!token)
|
||||||
|
return boost::shared_ptr<Node>();
|
||||||
|
|
||||||
|
// parse column ID
|
||||||
|
int columnId = -1;
|
||||||
|
|
||||||
|
if (token.mType==Token::Type_Number)
|
||||||
|
{
|
||||||
|
if (static_cast<int> (token.mNumber)==token.mNumber)
|
||||||
|
columnId = static_cast<int> (token.mNumber);
|
||||||
|
}
|
||||||
|
else if (token.mType==Token::Type_String)
|
||||||
|
{
|
||||||
|
columnId = CSMWorld::Columns::getId (token.mString);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (columnId<0)
|
||||||
|
{
|
||||||
|
error();
|
||||||
|
return boost::shared_ptr<Node>();
|
||||||
|
}
|
||||||
|
|
||||||
|
token = getNextToken();
|
||||||
|
|
||||||
|
if (token.mType!=Token::Type_Comma)
|
||||||
|
{
|
||||||
|
error();
|
||||||
|
return boost::shared_ptr<Node>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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<Node>();
|
||||||
|
}
|
||||||
|
|
||||||
|
token = getNextToken();
|
||||||
|
|
||||||
|
if (token.mType!=Token::Type_Number)
|
||||||
|
{
|
||||||
|
error();
|
||||||
|
return boost::shared_ptr<Node>();
|
||||||
|
}
|
||||||
|
|
||||||
|
lower = token.mNumber;
|
||||||
|
|
||||||
|
token = getNextToken();
|
||||||
|
|
||||||
|
if (token.mType!=Token::Type_Comma)
|
||||||
|
{
|
||||||
|
error();
|
||||||
|
return boost::shared_ptr<Node>();
|
||||||
|
}
|
||||||
|
|
||||||
|
token = getNextToken();
|
||||||
|
|
||||||
|
if (token.mType!=Token::Type_Number)
|
||||||
|
{
|
||||||
|
error();
|
||||||
|
return boost::shared_ptr<Node>();
|
||||||
|
}
|
||||||
|
|
||||||
|
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<Node>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
token = getNextToken();
|
||||||
|
|
||||||
|
if (token.mType!=Token::Type_Close)
|
||||||
|
{
|
||||||
|
error();
|
||||||
|
return boost::shared_ptr<Node>();
|
||||||
|
}
|
||||||
|
|
||||||
|
return boost::shared_ptr<Node> (new ValueNode (columnId, lower, upper, min, max));
|
||||||
|
}
|
||||||
|
|
||||||
void CSMFilter::Parser::error()
|
void CSMFilter::Parser::error()
|
||||||
{
|
{
|
||||||
mError = true;
|
mError = true;
|
||||||
|
|
|
@ -32,6 +32,8 @@ namespace CSMFilter
|
||||||
|
|
||||||
boost::shared_ptr<Node> parseText();
|
boost::shared_ptr<Node> parseText();
|
||||||
|
|
||||||
|
boost::shared_ptr<Node> parseValue();
|
||||||
|
|
||||||
void error();
|
void error();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
71
apps/opencs/model/filter/valuenode.cpp
Normal file
71
apps/opencs/model/filter/valuenode.cpp
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
|
||||||
|
#include "valuenode.hpp"
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
#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<int, int>& columns) const
|
||||||
|
{
|
||||||
|
const std::map<int, int>::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<mUpper);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<int> CSMFilter::ValueNode::getReferencedColumns() const
|
||||||
|
{
|
||||||
|
return std::vector<int> (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<CSMWorld::Columns::ColumnId> (mColumnId))
|
||||||
|
<< "\"";
|
||||||
|
|
||||||
|
stream << ", \"";
|
||||||
|
|
||||||
|
if (mLower==mUpper && mMin && mMax)
|
||||||
|
stream << mLower;
|
||||||
|
else
|
||||||
|
stream << (mMin ? "[" : "(") << mLower << ", " << mUpper << (mMax ? "]" : ")");
|
||||||
|
|
||||||
|
stream << ")";
|
||||||
|
|
||||||
|
return stream.str();
|
||||||
|
}
|
37
apps/opencs/model/filter/valuenode.hpp
Normal file
37
apps/opencs/model/filter/valuenode.hpp
Normal file
|
@ -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<int, int>& columns) const;
|
||||||
|
///< \return Can the specified table row pass through to filter?
|
||||||
|
/// \param columns column ID to column index mapping
|
||||||
|
|
||||||
|
virtual std::vector<int> 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
|
Loading…
Reference in a new issue