added numeric value filter node

pull/51/head
Marc Zinnschlag 11 years ago
parent 537ab38985
commit 3cf60da5a7

@ -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

@ -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::Node> 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::Node> CSMFilter::Parser::parseText()
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()
{
mError = true;

@ -32,6 +32,8 @@ namespace CSMFilter
boost::shared_ptr<Node> parseText();
boost::shared_ptr<Node> parseValue();
void error();
public:

@ -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();
}

@ -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…
Cancel
Save