ui: integrated autocompletion and filtering into SearchView
- QtSearchView was split into QtSearchView and QtSearchBox. - QtSearchBox contains all Qt elements and can use them purely - QtSearchView forwards calls from the SearchController to QtSearchBox - Searching is initiated with MessageSearch to the SearchController - Autocompletion is initiated with MessageSearchAutocomplete to the SearchController - The search field is able to create filter queries by only giving autocompletions for the last token in the query - For named tokens the search field adds their token ids to the query in the form of "A,25" for faster lookup bug id = #21
This commit is contained in:
@@ -80,7 +80,7 @@ bool QueryCommand::isToken() const
|
||||
return false;
|
||||
}
|
||||
|
||||
bool QueryCommand::isComplete() const
|
||||
bool QueryCommand::derivedIsComplete() const
|
||||
{
|
||||
return m_type != COMMAND_INVALID;
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ public:
|
||||
virtual bool isOperator() const;
|
||||
virtual bool isToken() const;
|
||||
|
||||
virtual bool isComplete() const;
|
||||
virtual bool derivedIsComplete() const;
|
||||
|
||||
virtual void print(std::ostream& ostream) const;
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ void QueryNode::print(std::ostream& ostream, int n) const
|
||||
ostream << ')';
|
||||
}
|
||||
|
||||
if (!m_isComplete || !isComplete())
|
||||
if (!isComplete())
|
||||
{
|
||||
ostream << " INVALID";
|
||||
}
|
||||
@@ -47,6 +47,11 @@ void QueryNode::setIsGroup(bool isGroup)
|
||||
m_isGroup = isGroup;
|
||||
}
|
||||
|
||||
bool QueryNode::isComplete() const
|
||||
{
|
||||
return m_isComplete && derivedIsComplete();
|
||||
}
|
||||
|
||||
void QueryNode::setIsComplete(bool isComplete)
|
||||
{
|
||||
m_isComplete = isComplete;
|
||||
|
||||
@@ -13,7 +13,7 @@ public:
|
||||
virtual bool isOperator() const = 0;
|
||||
virtual bool isToken() const = 0;
|
||||
|
||||
virtual bool isComplete() const = 0;
|
||||
virtual bool derivedIsComplete() const = 0;
|
||||
|
||||
virtual void print(std::ostream& ostream) const = 0;
|
||||
virtual void print(std::ostream& ostream, int n) const;
|
||||
@@ -21,6 +21,7 @@ public:
|
||||
bool isGroup() const;
|
||||
void setIsGroup(bool isGroup);
|
||||
|
||||
bool isComplete() const;
|
||||
void setIsComplete(bool isComplete);
|
||||
|
||||
private:
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#include "data/query/QueryOperator.h"
|
||||
|
||||
#include "data/query/QueryToken.h"
|
||||
|
||||
const std::map<char, QueryOperator::OperatorType>& QueryOperator::getOperatorTypeMap()
|
||||
{
|
||||
static std::map<char, OperatorType> operatorMap;
|
||||
@@ -17,7 +19,8 @@ const std::map<char, QueryOperator::OperatorType>& QueryOperator::getOperatorTyp
|
||||
operatorMap.emplace('&', OPERATOR_AND);
|
||||
operatorMap.emplace('|', OPERATOR_OR);
|
||||
|
||||
operatorMap.emplace('"', OPERATOR_NAME);
|
||||
operatorMap.emplace(QueryToken::BOUNDARY, OPERATOR_TOKEN);
|
||||
|
||||
operatorMap.emplace('(', OPERATOR_GROUP_OPEN);
|
||||
operatorMap.emplace(')', OPERATOR_GROUP_CLOSE);
|
||||
|
||||
@@ -74,7 +77,7 @@ bool QueryOperator::isToken() const
|
||||
return false;
|
||||
}
|
||||
|
||||
bool QueryOperator::isComplete() const
|
||||
bool QueryOperator::derivedIsComplete() const
|
||||
{
|
||||
if (m_type == OPERATOR_NOT)
|
||||
{
|
||||
|
||||
@@ -20,7 +20,7 @@ public:
|
||||
OPERATOR_AND,
|
||||
OPERATOR_OR,
|
||||
|
||||
OPERATOR_NAME,
|
||||
OPERATOR_TOKEN,
|
||||
OPERATOR_GROUP_OPEN,
|
||||
OPERATOR_GROUP_CLOSE
|
||||
};
|
||||
@@ -36,7 +36,7 @@ public:
|
||||
virtual bool isOperator() const;
|
||||
virtual bool isToken() const;
|
||||
|
||||
virtual bool isComplete() const;
|
||||
virtual bool derivedIsComplete() const;
|
||||
|
||||
virtual void print(std::ostream& ostream) const;
|
||||
virtual void print(std::ostream& ostream, int n) const;
|
||||
|
||||
@@ -1,8 +1,29 @@
|
||||
#include "data/query/QueryToken.h"
|
||||
|
||||
#include <deque>
|
||||
|
||||
#include "utility/utilityString.h"
|
||||
|
||||
QueryToken::QueryToken(const std::string& name)
|
||||
: m_name(name)
|
||||
{
|
||||
std::deque<std::string> names = utility::split<std::deque<std::string>>(name, DELIMITER);
|
||||
|
||||
m_tokenName = names.front();
|
||||
names.pop_front();
|
||||
|
||||
while (names.size())
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << names.front();
|
||||
names.pop_front();
|
||||
|
||||
Id tokenId = 0;
|
||||
ss >> tokenId;
|
||||
if (tokenId)
|
||||
{
|
||||
m_tokenIds.insert(tokenId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QueryToken::~QueryToken()
|
||||
@@ -24,17 +45,30 @@ bool QueryToken::isToken() const
|
||||
return true;
|
||||
}
|
||||
|
||||
bool QueryToken::isComplete() const
|
||||
bool QueryToken::derivedIsComplete() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void QueryToken::print(std::ostream& ostream) const
|
||||
{
|
||||
ostream << '"' << m_name << '"';
|
||||
ostream << BOUNDARY << m_tokenName;
|
||||
for (Id tokenId : m_tokenIds)
|
||||
{
|
||||
ostream << DELIMITER << tokenId;
|
||||
}
|
||||
ostream << BOUNDARY;
|
||||
}
|
||||
|
||||
const std::string& QueryToken::getName() const
|
||||
const std::string& QueryToken::getTokenName() const
|
||||
{
|
||||
return m_name;
|
||||
return m_tokenName;
|
||||
}
|
||||
|
||||
const std::set<Id>& QueryToken::getTokenIds() const
|
||||
{
|
||||
return m_tokenIds;
|
||||
}
|
||||
|
||||
const char QueryToken::DELIMITER = ',';
|
||||
const char QueryToken::BOUNDARY = '"';
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
#ifndef QUERY_TOKEN_H
|
||||
#define QUERY_TOKEN_H
|
||||
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
#include "data/query/QueryNode.h"
|
||||
#include "utility/types.h"
|
||||
|
||||
class QueryToken
|
||||
: public QueryNode
|
||||
@@ -15,14 +17,20 @@ public:
|
||||
virtual bool isCommand() const;
|
||||
virtual bool isOperator() const;
|
||||
virtual bool isToken() const;
|
||||
virtual bool isComplete() const;
|
||||
|
||||
virtual bool derivedIsComplete() const;
|
||||
|
||||
virtual void print(std::ostream& ostream) const;
|
||||
|
||||
const std::string& getName() const;
|
||||
const std::string& getTokenName() const;
|
||||
const std::set<Id>& getTokenIds() const;
|
||||
|
||||
static const char DELIMITER;
|
||||
static const char BOUNDARY;
|
||||
|
||||
private:
|
||||
const std::string m_name;
|
||||
std::string m_tokenName;
|
||||
std::set<Id> m_tokenIds;
|
||||
};
|
||||
|
||||
#endif // QUERY_TOKEN_H
|
||||
|
||||
@@ -6,22 +6,51 @@
|
||||
#include "data/query/QueryToken.h"
|
||||
#include "utility/utilityString.h"
|
||||
|
||||
QueryTree::QueryTree(std::string query)
|
||||
: m_valid(true)
|
||||
std::deque<std::string> QueryTree::tokenizeQuery(const std::string& query)
|
||||
{
|
||||
std::deque<std::string> tokens =
|
||||
std::deque<std::string> tokensTmp =
|
||||
utility::split<std::deque<std::string>>(query, QueryOperator::getOperator(QueryOperator::OPERATOR_NONE));
|
||||
|
||||
for (const std::pair<char, QueryOperator::OperatorType>& p : QueryOperator::getOperatorTypeMap())
|
||||
{
|
||||
tokens = utility::tokenize<std::deque<std::string>>(tokens, p.first);
|
||||
tokensTmp = utility::tokenize<std::deque<std::string>>(tokensTmp, p.first);
|
||||
}
|
||||
|
||||
for (std::string str : tokens)
|
||||
char operatorToken = QueryOperator::getOperator(QueryOperator::OPERATOR_TOKEN);
|
||||
bool isToken = false;
|
||||
|
||||
std::string token;
|
||||
std::deque<std::string> tokens;
|
||||
|
||||
while (tokensTmp.size())
|
||||
{
|
||||
m_query += str + ' ';
|
||||
std::string tokenTmp = tokensTmp.front();
|
||||
tokensTmp.pop_front();
|
||||
|
||||
token += tokenTmp;
|
||||
|
||||
if (tokenTmp.size() == 1 && tokenTmp[0] == operatorToken)
|
||||
{
|
||||
isToken = !isToken;
|
||||
}
|
||||
|
||||
if (!isToken || (!tokensTmp.size() && token.size()))
|
||||
{
|
||||
tokens.push_back(token);
|
||||
token.clear();
|
||||
}
|
||||
}
|
||||
|
||||
return tokens;
|
||||
}
|
||||
|
||||
QueryTree::QueryTree(const std::string& query)
|
||||
: m_valid(true)
|
||||
{
|
||||
std::deque<std::string> tokens = tokenizeQuery(query);
|
||||
|
||||
m_query = utility::join<std::deque<std::string>>(tokens, ' ');
|
||||
|
||||
m_root = buildTree(tokens, nullptr);
|
||||
}
|
||||
|
||||
@@ -45,7 +74,7 @@ void QueryTree::print(std::ostream& ostream) const
|
||||
|
||||
if (!m_valid)
|
||||
{
|
||||
ostream << "INVALID";
|
||||
ostream << " INVALID";
|
||||
}
|
||||
|
||||
ostream << '\n';
|
||||
@@ -156,18 +185,10 @@ std::shared_ptr<QueryNode> QueryTree::buildGroup(std::deque<std::string>& tokens
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<QueryNode> groupNode;
|
||||
if (closeType == QueryOperator::OPERATOR_NAME)
|
||||
{
|
||||
groupNode = std::make_shared<QueryToken>(name);
|
||||
}
|
||||
else
|
||||
{
|
||||
groupNode = buildTree(group, nullptr);
|
||||
groupNode->setIsGroup(true);
|
||||
}
|
||||
|
||||
std::shared_ptr<QueryNode> groupNode = buildTree(group, nullptr);
|
||||
groupNode->setIsGroup(true);
|
||||
groupNode->setIsComplete(valid);
|
||||
|
||||
return groupNode;
|
||||
}
|
||||
|
||||
@@ -189,8 +210,9 @@ std::shared_ptr<QueryNode> QueryTree::getNextNode(std::deque<std::string>& token
|
||||
case QueryOperator::OPERATOR_OR:
|
||||
return std::make_shared<QueryOperator>(type);
|
||||
|
||||
case QueryOperator::OPERATOR_NAME:
|
||||
return buildGroup(tokens, QueryOperator::OPERATOR_NAME);
|
||||
case QueryOperator::OPERATOR_TOKEN:
|
||||
return createToken(token);
|
||||
|
||||
case QueryOperator::OPERATOR_GROUP_OPEN:
|
||||
return buildGroup(tokens, QueryOperator::OPERATOR_GROUP_CLOSE);
|
||||
case QueryOperator::OPERATOR_GROUP_CLOSE:
|
||||
@@ -205,7 +227,7 @@ std::shared_ptr<QueryNode> QueryTree::getNextNode(std::deque<std::string>& token
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<QueryNode> QueryTree::createCommand(std::string name)
|
||||
std::shared_ptr<QueryNode> QueryTree::createCommand(const std::string& name)
|
||||
{
|
||||
std::shared_ptr<QueryCommand> node = std::make_shared<QueryCommand>(name);
|
||||
|
||||
@@ -218,6 +240,17 @@ std::shared_ptr<QueryNode> QueryTree::createCommand(std::string name)
|
||||
return node;
|
||||
}
|
||||
|
||||
std::shared_ptr<QueryNode> QueryTree::createToken(const std::string& name)
|
||||
{
|
||||
if (name.size() < 3 || name.front() != QueryToken::BOUNDARY || name.back() != QueryToken::BOUNDARY)
|
||||
{
|
||||
m_valid = false;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return std::make_shared<QueryToken>(name.substr(1, name.size() - 2));
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& ostream, const QueryTree& tree)
|
||||
{
|
||||
tree.print(ostream);
|
||||
|
||||
@@ -13,7 +13,9 @@ class QueryNode;
|
||||
class QueryTree
|
||||
{
|
||||
public:
|
||||
QueryTree(std::string query);
|
||||
static std::deque<std::string> tokenizeQuery(const std::string& query);
|
||||
|
||||
QueryTree(const std::string& query);
|
||||
~QueryTree();
|
||||
|
||||
std::shared_ptr<QueryNode> getRoot() const;
|
||||
@@ -26,7 +28,8 @@ private:
|
||||
std::shared_ptr<QueryNode> buildTree(std::deque<std::string>& tokens, std::shared_ptr<QueryNode> frontNode);
|
||||
std::shared_ptr<QueryNode> buildGroup(std::deque<std::string>& tokens, QueryOperator::OperatorType closeType);
|
||||
std::shared_ptr<QueryNode> getNextNode(std::deque<std::string>& tokens);
|
||||
std::shared_ptr<QueryNode> createCommand(std::string name);
|
||||
std::shared_ptr<QueryNode> createCommand(const std::string& name);
|
||||
std::shared_ptr<QueryNode> createToken(const std::string& name);
|
||||
|
||||
std::shared_ptr<QueryNode> m_root;
|
||||
std::string m_query;
|
||||
|
||||
Reference in New Issue
Block a user