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:
@@ -189,6 +189,7 @@ add_files(
|
||||
utility/messaging/type/MessageLoadProject.h
|
||||
utility/messaging/type/MessageLoadSource.h
|
||||
utility/messaging/type/MessageRefresh.h
|
||||
utility/messaging/type/MessageSearch.h
|
||||
utility/messaging/type/MessageShowFile.h
|
||||
|
||||
utility/messaging/Message.h
|
||||
|
||||
@@ -13,30 +13,6 @@ SearchController::~SearchController()
|
||||
{
|
||||
}
|
||||
|
||||
void SearchController::search(const std::string& s)
|
||||
{
|
||||
LOG_INFO("searching string: \"" + s + "\"");
|
||||
|
||||
std::vector<Id> ids = m_graphAccess->getTokenIdsForQuery(s);
|
||||
if (ids.size())
|
||||
{
|
||||
MessageActivateTokens(ids).dispatch();
|
||||
return;
|
||||
}
|
||||
|
||||
Id nodeId = m_graphAccess->getIdForNodeWithName(s);
|
||||
if (nodeId > 0)
|
||||
{
|
||||
LOG_INFO("Node with name \"" + s + "\" found.");
|
||||
MessageActivateToken message(nodeId);
|
||||
message.dispatch();
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_INFO("Node with name \"" + s + "\" not found.");
|
||||
}
|
||||
}
|
||||
|
||||
void SearchController::handleMessage(MessageActivateToken* message)
|
||||
{
|
||||
getView()->setText(m_graphAccess->getNameForNodeWithId(message->tokenId));
|
||||
@@ -47,16 +23,38 @@ void SearchController::handleMessage(MessageFind* message)
|
||||
getView()->setFocus();
|
||||
}
|
||||
|
||||
void SearchController::handleMessage(MessageFinishedParsing* message)
|
||||
{
|
||||
getView()->setAutocompletionList(m_graphAccess->getNamesForNodesWithNamePrefix(":"));
|
||||
}
|
||||
|
||||
void SearchController::handleMessage(MessageRefresh* message)
|
||||
{
|
||||
getView()->refreshView();
|
||||
}
|
||||
|
||||
void SearchController::handleMessage(MessageSearch* message)
|
||||
{
|
||||
const std::string& query = message->query;
|
||||
|
||||
LOG_INFO("search string: \"" + query + "\"");
|
||||
|
||||
std::vector<Id> ids = m_graphAccess->getTokenIdsForQuery(query);
|
||||
if (ids.size())
|
||||
{
|
||||
MessageActivateTokens(ids).dispatch();
|
||||
return;
|
||||
}
|
||||
|
||||
Id nodeId = m_graphAccess->getIdForNodeWithName(query);
|
||||
if (nodeId > 0)
|
||||
{
|
||||
MessageActivateToken message(nodeId);
|
||||
message.dispatch();
|
||||
}
|
||||
}
|
||||
|
||||
void SearchController::handleMessage(MessageSearchAutocomplete* message)
|
||||
{
|
||||
LOG_INFO("autocomplete string: \"" + message->query + "\"");
|
||||
getView()->setAutocompletionList(m_graphAccess->getAutocompletionMatches(message->query));
|
||||
}
|
||||
|
||||
SearchView* SearchController::getView()
|
||||
{
|
||||
return Controller::getView<SearchView>();
|
||||
|
||||
@@ -7,8 +7,9 @@
|
||||
#include "utility/messaging/MessageListener.h"
|
||||
#include "utility/messaging/type/MessageActivateToken.h"
|
||||
#include "utility/messaging/type/MessageFind.h"
|
||||
#include "utility/messaging/type/MessageFinishedParsing.h"
|
||||
#include "utility/messaging/type/MessageRefresh.h"
|
||||
#include "utility/messaging/type/MessageSearch.h"
|
||||
#include "utility/messaging/type/MessageSearchAutocomplete.h"
|
||||
|
||||
class GraphAccess;
|
||||
class SearchView;
|
||||
@@ -17,21 +18,21 @@ class SearchController
|
||||
: public Controller
|
||||
, public MessageListener<MessageActivateToken>
|
||||
, public MessageListener<MessageFind>
|
||||
, public MessageListener<MessageFinishedParsing>
|
||||
, public MessageListener<MessageRefresh>
|
||||
, public MessageListener<MessageSearch>
|
||||
, public MessageListener<MessageSearchAutocomplete>
|
||||
{
|
||||
public:
|
||||
SearchController(GraphAccess* graphAccess);
|
||||
~SearchController();
|
||||
|
||||
void search(const std::string& s);
|
||||
//void autocomplete(const std::string& s);
|
||||
|
||||
private:
|
||||
virtual void handleMessage(MessageActivateToken* message);
|
||||
virtual void handleMessage(MessageFind* message);
|
||||
virtual void handleMessage(MessageFinishedParsing* message);
|
||||
virtual void handleMessage(MessageRefresh* message);
|
||||
virtual void handleMessage(MessageSearch* message);
|
||||
virtual void handleMessage(MessageSearchAutocomplete* message);
|
||||
|
||||
SearchView* getView();
|
||||
|
||||
GraphAccess* m_graphAccess;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#define SEARCH_VIEW_H
|
||||
|
||||
#include "component/view/View.h"
|
||||
#include "data/SearchIndex.h"
|
||||
|
||||
class SearchController;
|
||||
|
||||
@@ -15,7 +16,7 @@ public:
|
||||
|
||||
virtual void setText(const std::string& s) = 0;
|
||||
virtual void setFocus() = 0;
|
||||
virtual void setAutocompletionList(const std::vector<std::string>& autocompletionList) = 0;
|
||||
virtual void setAutocompletionList(const std::vector<SearchIndex::SearchMatch>& autocompletionList) = 0;
|
||||
|
||||
protected:
|
||||
SearchController* getController();
|
||||
|
||||
@@ -20,6 +20,7 @@ public:
|
||||
virtual ~View();
|
||||
|
||||
virtual std::string getName() const = 0;
|
||||
|
||||
virtual void createWidgetWrapper() = 0;
|
||||
virtual void initView() = 0;
|
||||
virtual void refreshView() = 0;
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
|
||||
#include "data/query/QueryToken.h"
|
||||
#include "utility/logging/logging.h"
|
||||
#include "utility/text/Dictionary.h"
|
||||
#include "utility/utilityString.h"
|
||||
@@ -22,7 +23,7 @@ namespace
|
||||
|
||||
void SearchIndex::SearchMatch::print(std::ostream& ostream) const
|
||||
{
|
||||
ostream << weight << '\t' << node->getFullName() << std::endl << '\t';
|
||||
ostream << weight << '\t' << fullName << std::endl << '\t';
|
||||
size_t i = 0;
|
||||
for (size_t index : indices)
|
||||
{
|
||||
@@ -37,6 +38,23 @@ void SearchIndex::SearchMatch::print(std::ostream& ostream) const
|
||||
ostream << std::endl;
|
||||
}
|
||||
|
||||
std::string SearchIndex::SearchMatch::encodeForQuery() const
|
||||
{
|
||||
if (!tokenIds.size())
|
||||
{
|
||||
return fullName;
|
||||
}
|
||||
|
||||
std::stringstream ss;
|
||||
ss << QueryToken::BOUNDARY << fullName;
|
||||
for (Id tokenId : tokenIds)
|
||||
{
|
||||
ss << QueryToken::DELIMITER << tokenId;
|
||||
}
|
||||
ss << QueryToken::BOUNDARY;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
SearchIndex::SearchNode::SearchNode(SearchNode* parent, const std::string& name, Id nameId)
|
||||
: m_parent(parent)
|
||||
, m_name(name)
|
||||
@@ -284,7 +302,8 @@ std::pair<size_t, size_t> SearchIndex::SearchNode::fuzzyMatch(
|
||||
SearchIndex::SearchMatch SearchIndex::SearchNode::fuzzyMatchData(const std::string& query, const SearchNode* parent) const
|
||||
{
|
||||
SearchMatch data;
|
||||
data.node = this;
|
||||
data.fullName = getFullName();
|
||||
data.tokenIds = m_tokenIds;
|
||||
data.weight = 0;
|
||||
|
||||
size_t pos = 0;
|
||||
|
||||
@@ -19,7 +19,10 @@ public:
|
||||
{
|
||||
void print(std::ostream& ostream) const;
|
||||
|
||||
const SearchIndex::SearchNode* node;
|
||||
std::string encodeForQuery() const;
|
||||
|
||||
std::string fullName;
|
||||
std::set<Id> tokenIds;
|
||||
std::vector<size_t> indices;
|
||||
size_t weight;
|
||||
};
|
||||
|
||||
@@ -336,15 +336,11 @@ std::string Storage::getNameForNodeWithId(Id id) const
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::string> Storage::getNamesForNodesWithNamePrefix(const std::string& prefix) const
|
||||
std::vector<SearchIndex::SearchMatch> Storage::getAutocompletionMatches(const std::string& query) const
|
||||
{
|
||||
std::vector<std::string> names;
|
||||
std::vector<SearchIndex::SearchMatch> matches = m_index.findFuzzyMatches(prefix);
|
||||
for (const SearchIndex::SearchMatch& match : matches)
|
||||
{
|
||||
names.push_back(match.node->getFullName());
|
||||
}
|
||||
return names;
|
||||
std::vector<SearchIndex::SearchMatch> matches = m_index.findFuzzyMatches(query);
|
||||
SearchIndex::logMatches(matches, query);
|
||||
return matches;
|
||||
}
|
||||
|
||||
std::shared_ptr<Graph> Storage::getGraphForActiveTokenIds(const std::vector<Id>& tokenIds) const
|
||||
@@ -444,8 +440,6 @@ std::vector<Id> Storage::getTokenIdsForQuery(std::string query) const
|
||||
|
||||
LOG_INFO_STREAM(<< '\n' << tree << '\n' << outGraph);
|
||||
|
||||
SearchIndex::logMatches(m_index.findFuzzyMatches(query), query);
|
||||
|
||||
return outGraph.getTokenIds();
|
||||
}
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ public:
|
||||
// GraphAccess implementation
|
||||
virtual Id getIdForNodeWithName(const std::string& fullName) const;
|
||||
virtual std::string getNameForNodeWithId(Id id) const;
|
||||
virtual std::vector<std::string> getNamesForNodesWithNamePrefix(const std::string& prefix) const;
|
||||
virtual std::vector<SearchIndex::SearchMatch> getAutocompletionMatches(const std::string& query) const;
|
||||
|
||||
virtual std::shared_ptr<Graph> getGraphForActiveTokenIds(const std::vector<Id>& tokenIds) const;
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include "data/graph/Graph.h"
|
||||
#include "data/SearchIndex.h"
|
||||
#include "utility/types.h"
|
||||
|
||||
class GraphAccess
|
||||
@@ -15,7 +16,7 @@ public:
|
||||
|
||||
virtual Id getIdForNodeWithName(const std::string& name) const = 0;
|
||||
virtual std::string getNameForNodeWithId(Id id) const = 0;
|
||||
virtual std::vector<std::string> getNamesForNodesWithNamePrefix(const std::string& prefix) const = 0;
|
||||
virtual std::vector<SearchIndex::SearchMatch> getAutocompletionMatches(const std::string& query) const = 0;
|
||||
|
||||
virtual std::shared_ptr<Graph> getGraphForActiveTokenIds(const std::vector<Id>& tokenIds) const = 0;
|
||||
|
||||
|
||||
@@ -47,14 +47,14 @@ std::string GraphAccessProxy::getNameForNodeWithId(Id id) const
|
||||
return "";
|
||||
}
|
||||
|
||||
std::vector<std::string> GraphAccessProxy::getNamesForNodesWithNamePrefix(const std::string& prefix) const
|
||||
std::vector<SearchIndex::SearchMatch> GraphAccessProxy::getAutocompletionMatches(const std::string& query) const
|
||||
{
|
||||
if (hasSubject())
|
||||
{
|
||||
return m_subject->getNamesForNodesWithNamePrefix(prefix);
|
||||
return m_subject->getAutocompletionMatches(query);
|
||||
}
|
||||
|
||||
return std::vector<std::string>();
|
||||
return std::vector<SearchIndex::SearchMatch>();
|
||||
}
|
||||
|
||||
std::shared_ptr<Graph> GraphAccessProxy::getGraphForActiveTokenIds(const std::vector<Id>& tokenIds) const
|
||||
|
||||
@@ -15,7 +15,7 @@ public:
|
||||
// GraphAccess implementation
|
||||
virtual Id getIdForNodeWithName(const std::string& name) const;
|
||||
virtual std::string getNameForNodeWithId(Id id) const;
|
||||
virtual std::vector<std::string> getNamesForNodesWithNamePrefix(const std::string& prefix) const;
|
||||
virtual std::vector<SearchIndex::SearchMatch> getAutocompletionMatches(const std::string& query) const;
|
||||
|
||||
virtual std::shared_ptr<Graph> getGraphForActiveTokenIds(const std::vector<Id>& tokenIds) const;
|
||||
|
||||
|
||||
@@ -11,6 +11,16 @@ FilterableGraph::~FilterableGraph()
|
||||
{
|
||||
}
|
||||
|
||||
Token* FilterableGraph::getTokenById(Id id) const
|
||||
{
|
||||
Token* token = getNodeById(id);
|
||||
if (!token)
|
||||
{
|
||||
token = getEdgeById(id);
|
||||
}
|
||||
return token;
|
||||
}
|
||||
|
||||
void FilterableGraph::print(std::ostream& ostream) const
|
||||
{
|
||||
ostream << "Graph:\n";
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
#include <functional>
|
||||
#include <ostream>
|
||||
|
||||
#include "utility/types.h"
|
||||
|
||||
class Edge;
|
||||
class Node;
|
||||
class Token;
|
||||
@@ -29,6 +31,11 @@ public:
|
||||
virtual size_t getNodeCount() const = 0;
|
||||
virtual size_t getEdgeCount() const = 0;
|
||||
|
||||
virtual Node* getNodeById(Id id) const = 0;
|
||||
virtual Edge* getEdgeById(Id id) const = 0;
|
||||
|
||||
Token* getTokenById(Id id) const;
|
||||
|
||||
void print(std::ostream& ostream) const;
|
||||
void printBasic(std::ostream& ostream) const;
|
||||
};
|
||||
|
||||
@@ -75,16 +75,6 @@ size_t Graph::getEdgeCount() const
|
||||
return m_edges.size();
|
||||
}
|
||||
|
||||
const std::map<Id, std::shared_ptr<Node>>& Graph::getNodes() const
|
||||
{
|
||||
return m_nodes;
|
||||
}
|
||||
|
||||
const std::map<Id, std::shared_ptr<Edge>>& Graph::getEdges() const
|
||||
{
|
||||
return m_edges;
|
||||
}
|
||||
|
||||
Node* Graph::getNodeById(Id id) const
|
||||
{
|
||||
std::map<Id, std::shared_ptr<Node>>::const_iterator it = m_nodes.find(id);
|
||||
@@ -105,14 +95,14 @@ Edge* Graph::getEdgeById(Id id) const
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Token* Graph::getTokenById(Id id) const
|
||||
const std::map<Id, std::shared_ptr<Node>>& Graph::getNodes() const
|
||||
{
|
||||
Token* token = getNodeById(id);
|
||||
if (!token)
|
||||
{
|
||||
token = getEdgeById(id);
|
||||
}
|
||||
return token;
|
||||
return m_nodes;
|
||||
}
|
||||
|
||||
const std::map<Id, std::shared_ptr<Edge>>& Graph::getEdges() const
|
||||
{
|
||||
return m_edges;
|
||||
}
|
||||
|
||||
void Graph::removeNode(Node* node)
|
||||
|
||||
@@ -32,13 +32,12 @@ public:
|
||||
virtual size_t getNodeCount() const;
|
||||
virtual size_t getEdgeCount() const;
|
||||
|
||||
virtual Node* getNodeById(Id id) const;
|
||||
virtual Edge* getEdgeById(Id id) const;
|
||||
|
||||
const std::map<Id, std::shared_ptr<Node>>& getNodes() const;
|
||||
const std::map<Id, std::shared_ptr<Edge>>& getEdges() const;
|
||||
|
||||
Node* getNodeById(Id id) const;
|
||||
Edge* getEdgeById(Id id) const;
|
||||
Token* getTokenById(Id id) const;
|
||||
|
||||
void removeNode(Node* node);
|
||||
void removeEdge(Edge* edge);
|
||||
|
||||
|
||||
@@ -71,6 +71,26 @@ size_t SubGraph::getEdgeCount() const
|
||||
return m_edges.size();
|
||||
}
|
||||
|
||||
Node* SubGraph::getNodeById(Id id) const
|
||||
{
|
||||
std::map<Id, Node*>::const_iterator it = m_nodes.find(id);
|
||||
if (it != m_nodes.end())
|
||||
{
|
||||
return it->second;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Edge* SubGraph::getEdgeById(Id id) const
|
||||
{
|
||||
std::map<Id, Edge*>::const_iterator it = m_edges.find(id);
|
||||
if (it != m_edges.end())
|
||||
{
|
||||
return it->second;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::vector<Id> SubGraph::getTokenIds() const
|
||||
{
|
||||
std::vector<Id> ids;
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
#include <vector>
|
||||
|
||||
#include "data/graph/FilterableGraph.h"
|
||||
#include "utility/types.h"
|
||||
|
||||
class Edge;
|
||||
class Node;
|
||||
@@ -35,6 +34,9 @@ public:
|
||||
virtual size_t getNodeCount() const;
|
||||
virtual size_t getEdgeCount() const;
|
||||
|
||||
virtual Node* getNodeById(Id id) const;
|
||||
virtual Edge* getEdgeById(Id id) const;
|
||||
|
||||
std::vector<Id> getTokenIds() const;
|
||||
|
||||
void subtract(const SubGraph& other);
|
||||
|
||||
@@ -174,5 +174,5 @@ void GraphFilterConductor::filterCommandNode(const QueryCommand* node, const Fil
|
||||
|
||||
void GraphFilterConductor::filterTokenNode(const QueryToken* node, const FilterableGraph* in, FilterableGraph* out) const
|
||||
{
|
||||
GraphFilterToken(node->getName()).apply(in, out);
|
||||
GraphFilterToken(node->getTokenName(), node->getTokenIds()).apply(in, out);
|
||||
}
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
#ifndef GRAPH_FILTER_IMPLEMENTATIONS_H
|
||||
#define GRAPH_FILTER_IMPLEMENTATIONS_H
|
||||
|
||||
#include <set>
|
||||
|
||||
#include "data/graph/Edge.h"
|
||||
#include "data/graph/filter/GraphFilter.h"
|
||||
#include "data/graph/FilterableGraph.h"
|
||||
#include "data/graph/Node.h"
|
||||
#include "data/graph/token_component/TokenComponentAbstraction.h"
|
||||
#include "data/graph/token_component/TokenComponentAccess.h"
|
||||
@@ -258,22 +261,43 @@ class GraphFilterToken
|
||||
: public GraphFilter
|
||||
{
|
||||
public:
|
||||
GraphFilterToken(const std::string& name)
|
||||
: m_name(name)
|
||||
GraphFilterToken(const std::string& tokenName, const std::set<Id>& tokenIds)
|
||||
: m_tokenName(tokenName)
|
||||
, m_tokenIds(tokenIds)
|
||||
{
|
||||
}
|
||||
|
||||
void apply(const FilterableGraph* in, FilterableGraph* out)
|
||||
{
|
||||
if (m_tokenIds.size())
|
||||
{
|
||||
for (Id tokenId : m_tokenIds)
|
||||
{
|
||||
Node* node = in->getNodeById(tokenId);
|
||||
if (node)
|
||||
{
|
||||
out->addNode(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
GraphFilter::apply(in, out);
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void visitNode(Node* node)
|
||||
{
|
||||
if (node->getName() == m_name)
|
||||
if (node->getFullName() == m_tokenName)
|
||||
{
|
||||
addNode(node);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
const std::string& m_name;
|
||||
const std::string& m_tokenName;
|
||||
const std::set<Id>& m_tokenIds;
|
||||
};
|
||||
|
||||
#endif // GRAPH_FILTER_IMPLEMENTATIONS_H
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
#ifndef MESSAGE_SEARCH_H
|
||||
#define MESSAGE_SEARCH_H
|
||||
|
||||
#include "utility/messaging/Message.h"
|
||||
#include "utility/types.h"
|
||||
|
||||
class MessageSearch: public Message<MessageSearch>
|
||||
{
|
||||
public:
|
||||
MessageSearch(const std::string& query)
|
||||
: query(query)
|
||||
{
|
||||
}
|
||||
|
||||
static const std::string getStaticType()
|
||||
{
|
||||
return "MessageSearch";
|
||||
}
|
||||
|
||||
const std::string query;
|
||||
};
|
||||
|
||||
#endif // MESSAGE_SEARCH_H
|
||||
@@ -0,0 +1,23 @@
|
||||
#ifndef MESSAGE_SEARCH_AUTOCOMPLETE_H
|
||||
#define MESSAGE_SEARCH_AUTOCOMPLETE_H
|
||||
|
||||
#include "utility/messaging/Message.h"
|
||||
#include "utility/types.h"
|
||||
|
||||
class MessageSearchAutocomplete: public Message<MessageSearchAutocomplete>
|
||||
{
|
||||
public:
|
||||
MessageSearchAutocomplete(const std::string& query)
|
||||
: query(query)
|
||||
{
|
||||
}
|
||||
|
||||
static const std::string getStaticType()
|
||||
{
|
||||
return "MessageSearchAutocomplete";
|
||||
}
|
||||
|
||||
const std::string query;
|
||||
};
|
||||
|
||||
#endif // MESSAGE_SEARCH_AUTOCOMPLETE_H
|
||||
@@ -1,6 +1,7 @@
|
||||
#ifndef UTILITY_STRING_H
|
||||
#define UTILITY_STRING_H
|
||||
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@@ -12,6 +13,12 @@ namespace utility
|
||||
template<typename ContainerType>
|
||||
ContainerType split(const std::string& str, const std::string& delimiter);
|
||||
|
||||
template<typename ContainerType>
|
||||
std::string join(const ContainerType& list, char delimiter);
|
||||
|
||||
template<typename ContainerType>
|
||||
std::string join(const ContainerType& list, const std::string& delimiter);
|
||||
|
||||
template<typename ContainerType>
|
||||
ContainerType tokenize(const std::string& str, char delimiter);
|
||||
|
||||
@@ -53,6 +60,30 @@ ContainerType utility::split(const std::string& str, const std::string& delimite
|
||||
return c;
|
||||
}
|
||||
|
||||
template<typename ContainerType>
|
||||
std::string utility::join(const ContainerType& list, char delimiter)
|
||||
{
|
||||
return join<ContainerType>(list, std::string(1, delimiter));
|
||||
}
|
||||
|
||||
template<typename ContainerType>
|
||||
std::string utility::join(const ContainerType& list, const std::string& delimiter)
|
||||
{
|
||||
std::stringstream ss;
|
||||
bool first = true;
|
||||
for (const std::string& str : list)
|
||||
{
|
||||
if (!first)
|
||||
{
|
||||
ss << delimiter;
|
||||
}
|
||||
first = false;
|
||||
|
||||
ss << str;
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
template<typename ContainerType>
|
||||
ContainerType utility::tokenize(const std::string& str, char delimiter)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user