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:
Eberhard Graether
2014-09-11 14:53:03 +02:00
parent 760e5ffafd
commit fec7abbc9b
48 changed files with 786 additions and 391 deletions
+1 -1
View File
@@ -80,7 +80,7 @@ bool QueryCommand::isToken() const
return false;
}
bool QueryCommand::isComplete() const
bool QueryCommand::derivedIsComplete() const
{
return m_type != COMMAND_INVALID;
}
+1 -1
View File
@@ -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;
+6 -1
View File
@@ -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;
+2 -1
View File
@@ -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:
+5 -2
View File
@@ -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)
{
+2 -2
View File
@@ -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;
+39 -5
View File
@@ -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 = '"';
+11 -3
View File
@@ -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
+54 -21
View File
@@ -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);
+5 -2
View File
@@ -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;