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:
@@ -20,18 +20,35 @@ Storage.cpp INFO: call: main -> A::getCount <input.cc 34:9 34:21>
|
|||||||
Storage.cpp INFO: class: A <input.cc 1:7 1:7>
|
Storage.cpp INFO: class: A <input.cc 1:7 1:7>
|
||||||
Storage.cpp INFO: method: A::A <input.cc 4:2 4:2>
|
Storage.cpp INFO: method: A::A <input.cc 4:2 4:2>
|
||||||
Storage.cpp INFO: global usage: A::A -> A::count <input.cc 5:3 5:7>
|
Storage.cpp INFO: global usage: A::A -> A::count <input.cc 5:3 5:7>
|
||||||
Storage.cpp INFO: method: A::getCount <input.cc 8:13 8:20>
|
Storage.cpp INFO: method: A::A <input.cc 8:2 8:2>
|
||||||
Storage.cpp INFO: global usage: A::getCount -> A::count <input.cc 10:10 10:14>
|
Storage.cpp INFO: global usage: A::A -> A::count <input.cc 9:3 9:7>
|
||||||
Storage.cpp INFO: method: A::process <input.cc 14:15 14:21>
|
Storage.cpp INFO: method: A::getCount <input.cc 12:13 12:20>
|
||||||
Storage.cpp INFO: field: A::count <input.cc 17:13 17:17>
|
Storage.cpp INFO: global usage: A::getCount -> A::count <input.cc 14:10 14:14>
|
||||||
Storage.cpp INFO: class: B <input.cc 20:7 20:7>
|
Storage.cpp INFO: method: A::process <input.cc 18:15 18:21>
|
||||||
Storage.cpp INFO: inheritance: B : A <input.cc 21:4 21:11>
|
Storage.cpp INFO: field: A::count <input.cc 21:13 21:17>
|
||||||
Storage.cpp INFO: method: B::process <input.cc 24:15 24:21>
|
Storage.cpp INFO: class: B <input.cc 24:7 24:7>
|
||||||
Storage.cpp INFO: type usage: B::process -> int <input.cc 26:3 26:5>
|
Storage.cpp INFO: inheritance: B : A <input.cc 25:4 25:11>
|
||||||
Storage.cpp INFO: function: main <input.cc 30:5 30:8>
|
Storage.cpp INFO: method: B::process <input.cc 28:15 28:21>
|
||||||
Storage.cpp INFO: type usage: main -> B <input.cc 32:2 32:2>
|
Storage.cpp INFO: type usage: B::process -> int <input.cc 30:3 30:5>
|
||||||
Storage.cpp INFO: call: main -> B::B <input.cc 32:4 32:4>
|
Storage.cpp INFO: function: main <input.cc 34:5 34:8>
|
||||||
Storage.cpp INFO: call: main -> A::getCount <input.cc 34:9 34:21>
|
Storage.cpp INFO: type usage: main -> B <input.cc 36:2 36:2>
|
||||||
|
Storage.cpp INFO: call: main -> B::B <input.cc 36:4 36:4>
|
||||||
|
Storage.cpp INFO: call: main -> A::getCount <input.cc 38:9 38:21>
|
||||||
|
SearchIndex.cpp INFO:
|
||||||
|
1 matches for "main":
|
||||||
|
474 main
|
||||||
|
^^^^
|
||||||
|
|
||||||
|
SearchIndex.cpp INFO:
|
||||||
|
1 matches for "main":
|
||||||
|
474 main
|
||||||
|
^^^^
|
||||||
|
|
||||||
|
SearchIndex.cpp INFO:
|
||||||
|
1 matches for "A::A":
|
||||||
|
237 A::A
|
||||||
|
^^^^
|
||||||
|
|
||||||
Settings.cpp WARNING: File for Settings not found.
|
Settings.cpp WARNING: File for Settings not found.
|
||||||
ConfigManager.cpp ERROR: value Bool is not present in config.
|
ConfigManager.cpp ERROR: value Bool is not present in config.
|
||||||
ConfigManager.cpp ERROR: value Int is not present in config.
|
ConfigManager.cpp ERROR: value Int is not present in config.
|
||||||
|
|||||||
@@ -9,14 +9,12 @@ add_files(
|
|||||||
qt/element/QtCodeFile.h
|
qt/element/QtCodeFile.h
|
||||||
qt/element/QtCodeFileList.cpp
|
qt/element/QtCodeFileList.cpp
|
||||||
qt/element/QtCodeFileList.h
|
qt/element/QtCodeFileList.h
|
||||||
qt/element/QtButton.cpp
|
|
||||||
qt/element/QtButton.h
|
|
||||||
qt/element/QtCodeSnippet.cpp
|
qt/element/QtCodeSnippet.cpp
|
||||||
qt/element/QtCodeSnippet.h
|
qt/element/QtCodeSnippet.h
|
||||||
qt/element/QtEditBox.cpp
|
|
||||||
qt/element/QtEditBox.h
|
|
||||||
qt/element/QtMainWindow.cpp
|
qt/element/QtMainWindow.cpp
|
||||||
qt/element/QtMainWindow.h
|
qt/element/QtMainWindow.h
|
||||||
|
qt/element/QtSearchBox.cpp
|
||||||
|
qt/element/QtSearchBox.h
|
||||||
|
|
||||||
qt/utility/QtHighLighter.cpp
|
qt/utility/QtHighLighter.cpp
|
||||||
qt/utility/QtHighLighter.h
|
qt/utility/QtHighLighter.h
|
||||||
|
|||||||
@@ -1,27 +0,0 @@
|
|||||||
#include "qt/element/QtButton.h"
|
|
||||||
|
|
||||||
QtButton::QtButton(QWidget *parent)
|
|
||||||
: QPushButton(parent)
|
|
||||||
, m_onClick(nullptr)
|
|
||||||
{
|
|
||||||
setAttribute(Qt::WA_LayoutUsesWidgetRect); // fixes layouting on Mac
|
|
||||||
|
|
||||||
connect(this, SIGNAL(clicked()), this, SLOT(slotOnClick()));
|
|
||||||
}
|
|
||||||
|
|
||||||
QtButton::~QtButton()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void QtButton::setCallbackOnClick(std::function<void(void)> callback)
|
|
||||||
{
|
|
||||||
m_onClick = callback;
|
|
||||||
}
|
|
||||||
|
|
||||||
void QtButton::slotOnClick()
|
|
||||||
{
|
|
||||||
if (m_onClick)
|
|
||||||
{
|
|
||||||
m_onClick();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
#ifndef QT_BUTTON_H
|
|
||||||
#define QT_BUTTON_H
|
|
||||||
|
|
||||||
#include <functional>
|
|
||||||
|
|
||||||
#include <QPushButton>
|
|
||||||
|
|
||||||
class QtButton: public QPushButton
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
QtButton(QWidget *parent);
|
|
||||||
~QtButton();
|
|
||||||
|
|
||||||
void setCallbackOnClick(std::function<void(void)> callback);
|
|
||||||
|
|
||||||
private slots:
|
|
||||||
void slotOnClick();
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::function<void(void)> m_onClick;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // QT_BUTTON_H
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
#include "qt/element/QtEditBox.h"
|
|
||||||
#include "utility/logging/logging.h"
|
|
||||||
|
|
||||||
QtEditBox::QtEditBox(QWidget *parent)
|
|
||||||
: QLineEdit(parent)
|
|
||||||
, m_onReturnPressed(nullptr)
|
|
||||||
, m_onTextEdited(nullptr)
|
|
||||||
{
|
|
||||||
setAttribute(Qt::WA_LayoutUsesWidgetRect); // fixes layouting on Mac
|
|
||||||
|
|
||||||
connect(this, SIGNAL(returnPressed()), this, SLOT(slotOnReturnPressed()));
|
|
||||||
connect(this, SIGNAL(textEdited(const QString&)), this, SLOT(slotOnTextEdited(const QString&)));
|
|
||||||
}
|
|
||||||
|
|
||||||
QtEditBox::~QtEditBox()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void QtEditBox::setCallbackOnReturnPressed(std::function<void(void)> callback)
|
|
||||||
{
|
|
||||||
m_onReturnPressed = callback;
|
|
||||||
}
|
|
||||||
|
|
||||||
void QtEditBox::setCallbackOnTextEdited(std::function<void(const std::string&)> callback)
|
|
||||||
{
|
|
||||||
m_onTextEdited = callback;
|
|
||||||
}
|
|
||||||
|
|
||||||
void QtEditBox::slotOnReturnPressed()
|
|
||||||
{
|
|
||||||
if (m_onReturnPressed)
|
|
||||||
{
|
|
||||||
m_onReturnPressed();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void QtEditBox::slotOnTextEdited(const QString& text)
|
|
||||||
{
|
|
||||||
if (m_onTextEdited)
|
|
||||||
{
|
|
||||||
m_onTextEdited(text.toStdString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
#ifndef QT_EDIT_BOX_H
|
|
||||||
#define QT_EDIT_BOX_H
|
|
||||||
|
|
||||||
#include <functional>
|
|
||||||
|
|
||||||
#include <QLineEdit>
|
|
||||||
|
|
||||||
class QtEditBox: public QLineEdit
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
QtEditBox(QWidget *parent);
|
|
||||||
~QtEditBox();
|
|
||||||
|
|
||||||
void setCallbackOnReturnPressed(std::function<void(void)> callback);
|
|
||||||
void setCallbackOnTextEdited(std::function<void(const std::string&)> callback);
|
|
||||||
|
|
||||||
private slots:
|
|
||||||
void slotOnReturnPressed();
|
|
||||||
void slotOnTextEdited(const QString& text);
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::function<void(void)> m_onReturnPressed;
|
|
||||||
std::function<void(const std::string&)> m_onTextEdited;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // QT_EDIT_BOX_H
|
|
||||||
@@ -0,0 +1,147 @@
|
|||||||
|
#include "qt/element/QtSearchBox.h"
|
||||||
|
|
||||||
|
#include <QCompleter>
|
||||||
|
#include <QHBoxLayout>
|
||||||
|
#include <QLineEdit>
|
||||||
|
#include <QPushButton>
|
||||||
|
|
||||||
|
#include "data/query/QueryTree.h"
|
||||||
|
#include "utility/messaging/type/MessageSearch.h"
|
||||||
|
#include "utility/messaging/type/MessageSearchAutocomplete.h"
|
||||||
|
#include "utility/utilityString.h"
|
||||||
|
|
||||||
|
QtSearchBox::QtSearchBox()
|
||||||
|
: m_preventQueryChange(false)
|
||||||
|
{
|
||||||
|
setObjectName("search_view");
|
||||||
|
|
||||||
|
QBoxLayout* layout = new QHBoxLayout();
|
||||||
|
layout->setSpacing(0);
|
||||||
|
layout->setAlignment(Qt::AlignTop);
|
||||||
|
setLayout(layout);
|
||||||
|
|
||||||
|
m_searchButton = new QPushButton(this);
|
||||||
|
m_searchButton->setObjectName("search_button");
|
||||||
|
m_searchButton->setAttribute(Qt::WA_LayoutUsesWidgetRect); // fixes layouting on Mac
|
||||||
|
connect(m_searchButton, SIGNAL(clicked()), this, SLOT(onSearchButtonClick()));
|
||||||
|
layout->addWidget(m_searchButton);
|
||||||
|
|
||||||
|
m_searchBox = new QLineEdit(this);
|
||||||
|
m_searchBox->setObjectName("search_box");
|
||||||
|
m_searchBox->setPlaceholderText("Please enter your search string.");
|
||||||
|
m_searchBox->setAttribute(Qt::WA_LayoutUsesWidgetRect); // fixes layouting on Mac
|
||||||
|
connect(m_searchBox, SIGNAL(returnPressed()), this, SLOT(onSearchButtonClick()));
|
||||||
|
connect(m_searchBox, SIGNAL(textEdited(const QString&)), this, SLOT(onSearchQueryEdited(const QString&)));
|
||||||
|
connect(m_searchBox, SIGNAL(textChanged(const QString&)), this, SLOT(onSearchQueryChanged(const QString&)));
|
||||||
|
layout->addWidget(m_searchBox);
|
||||||
|
|
||||||
|
m_caseSensitiveButton = new QPushButton(this);
|
||||||
|
m_caseSensitiveButton->setObjectName("case_sensitive_button");
|
||||||
|
m_caseSensitiveButton->setCheckable(true);
|
||||||
|
m_caseSensitiveButton->setToolTip("case sensitive");
|
||||||
|
m_caseSensitiveButton->setAttribute(Qt::WA_LayoutUsesWidgetRect); // fixes layouting on Mac
|
||||||
|
layout->addWidget(m_caseSensitiveButton);
|
||||||
|
}
|
||||||
|
|
||||||
|
QtSearchBox::~QtSearchBox()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void QtSearchBox::setText(const std::string& text)
|
||||||
|
{
|
||||||
|
if (m_searchBox->text() != text.c_str())
|
||||||
|
{
|
||||||
|
m_searchBox->setText(text.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void QtSearchBox::setFocus()
|
||||||
|
{
|
||||||
|
m_searchBox->setFocus(Qt::ShortcutFocusReason);
|
||||||
|
}
|
||||||
|
|
||||||
|
void QtSearchBox::setAutocompletionList(const std::vector<SearchIndex::SearchMatch>& autocompletionList)
|
||||||
|
{
|
||||||
|
m_matches = autocompletionList;
|
||||||
|
|
||||||
|
QStringList wordList;
|
||||||
|
for (const SearchIndex::SearchMatch& match: autocompletionList)
|
||||||
|
{
|
||||||
|
wordList << match.fullName.c_str();
|
||||||
|
}
|
||||||
|
|
||||||
|
QCompleter *completer = new QCompleter(wordList, m_searchBox);
|
||||||
|
completer->popup()->setObjectName("search_box_popup");
|
||||||
|
completer->setCaseSensitivity(Qt::CaseInsensitive);
|
||||||
|
m_searchBox->setCompleter(completer);
|
||||||
|
completer->complete();
|
||||||
|
|
||||||
|
connect(completer, SIGNAL(highlighted(const QModelIndex&)), this, SLOT(onSearchCompletionHighlighted(const QModelIndex&)));
|
||||||
|
connect(completer, SIGNAL(activated(const QString&)), this, SLOT(onSearchCompletionActivated(const QString&)));
|
||||||
|
}
|
||||||
|
|
||||||
|
QAbstractItemView* QtSearchBox::getCompleterPopup()
|
||||||
|
{
|
||||||
|
if (m_searchBox->completer())
|
||||||
|
{
|
||||||
|
return m_searchBox->completer()->popup();
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QtSearchBox::onSearchButtonClick()
|
||||||
|
{
|
||||||
|
m_query = m_searchBox->text().toStdString();
|
||||||
|
MessageSearch(m_query).dispatch();
|
||||||
|
}
|
||||||
|
|
||||||
|
void QtSearchBox::onSearchQueryEdited(const QString& text)
|
||||||
|
{
|
||||||
|
m_query = text.toStdString();
|
||||||
|
m_oldQuery = m_query;
|
||||||
|
|
||||||
|
std::deque<std::string> tokens = QueryTree::tokenizeQuery(text.toStdString());
|
||||||
|
if (tokens.size())
|
||||||
|
{
|
||||||
|
MessageSearchAutocomplete(tokens.back()).dispatch();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void QtSearchBox::onSearchQueryChanged(const QString& text)
|
||||||
|
{
|
||||||
|
if (m_preventQueryChange)
|
||||||
|
{
|
||||||
|
m_preventQueryChange = false;
|
||||||
|
setText(m_query);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void QtSearchBox::onSearchCompletionHighlighted(const QModelIndex& index)
|
||||||
|
{
|
||||||
|
if (index.row() < 0 || index.row() >= int(m_matches.size()))
|
||||||
|
{
|
||||||
|
m_query = m_oldQuery;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::deque<std::string> tokens = QueryTree::tokenizeQuery(m_query);
|
||||||
|
if (tokens.size())
|
||||||
|
{
|
||||||
|
tokens.pop_back();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string match = m_matches[index.row()].encodeForQuery();
|
||||||
|
tokens.push_back(match);
|
||||||
|
|
||||||
|
m_query = utility::join<std::deque<std::string>>(tokens, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
setText(m_query);
|
||||||
|
m_preventQueryChange = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QtSearchBox::onSearchCompletionActivated(const QString& text)
|
||||||
|
{
|
||||||
|
setText(m_query);
|
||||||
|
m_preventQueryChange = true;
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
#ifndef QT_SEARCH_BOX_H
|
||||||
|
#define QT_SEARCH_BOX_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <QAbstractItemView>
|
||||||
|
#include <QFrame>
|
||||||
|
|
||||||
|
#include "data/SearchIndex.h"
|
||||||
|
|
||||||
|
class QLineEdit;
|
||||||
|
class QPushButton;
|
||||||
|
|
||||||
|
class QtSearchBox
|
||||||
|
: public QFrame
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
QtSearchBox();
|
||||||
|
virtual ~QtSearchBox();
|
||||||
|
|
||||||
|
void setText(const std::string& text);
|
||||||
|
void setFocus();
|
||||||
|
void setAutocompletionList(const std::vector<SearchIndex::SearchMatch>& autocompletionList);
|
||||||
|
|
||||||
|
QAbstractItemView* getCompleterPopup();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void onSearchButtonClick();
|
||||||
|
void onSearchQueryEdited(const QString& text);
|
||||||
|
void onSearchQueryChanged(const QString& text);
|
||||||
|
void onSearchCompletionHighlighted(const QModelIndex& index);
|
||||||
|
void onSearchCompletionActivated(const QString& text);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QLineEdit* m_searchBox;
|
||||||
|
QPushButton* m_searchButton;
|
||||||
|
QPushButton* m_caseSensitiveButton;
|
||||||
|
|
||||||
|
std::string m_query;
|
||||||
|
std::string m_oldQuery;
|
||||||
|
bool m_preventQueryChange;
|
||||||
|
|
||||||
|
std::vector<SearchIndex::SearchMatch> m_matches;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // QT_SEARCH_BOX_H
|
||||||
@@ -1,14 +1,6 @@
|
|||||||
#include "qt/view/QtSearchView.h"
|
#include "qt/view/QtSearchView.h"
|
||||||
|
|
||||||
#include <QAbstractItemView>
|
|
||||||
#include <QCompleter>
|
|
||||||
#include <QFrame>
|
|
||||||
#include <QHBoxLayout>
|
|
||||||
|
|
||||||
#include "component/controller/SearchController.h"
|
#include "component/controller/SearchController.h"
|
||||||
#include "qt/element/QtButton.h"
|
|
||||||
#include "qt/element/QtEditBox.h"
|
|
||||||
#include "qt/utility/utilityQt.h"
|
|
||||||
#include "qt/view/QtViewWidgetWrapper.h"
|
#include "qt/view/QtViewWidgetWrapper.h"
|
||||||
#include "utility/text/TextAccess.h"
|
#include "utility/text/TextAccess.h"
|
||||||
|
|
||||||
@@ -19,6 +11,8 @@ QtSearchView::QtSearchView(ViewLayout* viewLayout)
|
|||||||
, m_setFocusFunctor(std::bind(&QtSearchView::doSetFocus, this))
|
, m_setFocusFunctor(std::bind(&QtSearchView::doSetFocus, this))
|
||||||
, m_setAutocompletionListFunctor(std::bind(&QtSearchView::doSetAutocompletionList, this, std::placeholders::_1))
|
, m_setAutocompletionListFunctor(std::bind(&QtSearchView::doSetAutocompletionList, this, std::placeholders::_1))
|
||||||
{
|
{
|
||||||
|
m_widget = std::make_shared<QtSearchBox>();
|
||||||
|
setStyleSheet();
|
||||||
}
|
}
|
||||||
|
|
||||||
QtSearchView::~QtSearchView()
|
QtSearchView::~QtSearchView()
|
||||||
@@ -27,37 +21,11 @@ QtSearchView::~QtSearchView()
|
|||||||
|
|
||||||
void QtSearchView::createWidgetWrapper()
|
void QtSearchView::createWidgetWrapper()
|
||||||
{
|
{
|
||||||
setWidgetWrapper(std::make_shared<QtViewWidgetWrapper>(std::make_shared<QFrame>()));
|
setWidgetWrapper(std::make_shared<QtViewWidgetWrapper>(m_widget));
|
||||||
}
|
}
|
||||||
|
|
||||||
void QtSearchView::initView()
|
void QtSearchView::initView()
|
||||||
{
|
{
|
||||||
QWidget* widget = QtViewWidgetWrapper::getWidgetOfView(this);
|
|
||||||
widget->setObjectName("search_view");
|
|
||||||
|
|
||||||
QBoxLayout* layout = new QHBoxLayout();
|
|
||||||
layout->setSpacing(0);
|
|
||||||
layout->setAlignment(Qt::AlignTop);
|
|
||||||
widget->setLayout(layout);
|
|
||||||
|
|
||||||
m_searchButton = new QtButton(widget);
|
|
||||||
m_searchButton->setObjectName("search_button");
|
|
||||||
m_searchButton->setCallbackOnClick(std::bind(&QtSearchView::onSearchButtonClick, this));
|
|
||||||
widget->layout()->addWidget(m_searchButton);
|
|
||||||
|
|
||||||
m_searchBox = new QtEditBox(widget);
|
|
||||||
m_searchBox->setObjectName("search_box");
|
|
||||||
m_searchBox->setPlaceholderText("Please enter your search string.");
|
|
||||||
m_searchBox->setCallbackOnReturnPressed(std::bind(&QtSearchView::onSearchButtonClick, this));
|
|
||||||
widget->layout()->addWidget(m_searchBox);
|
|
||||||
|
|
||||||
m_caseSensitiveButton = new QtButton(widget);
|
|
||||||
m_caseSensitiveButton->setObjectName("case_sensitive_button");
|
|
||||||
m_caseSensitiveButton->setCheckable(true);
|
|
||||||
m_caseSensitiveButton->setToolTip("case sensitive");
|
|
||||||
widget->layout()->addWidget(m_caseSensitiveButton);
|
|
||||||
|
|
||||||
setStyleSheet();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void QtSearchView::refreshView()
|
void QtSearchView::refreshView()
|
||||||
@@ -65,9 +33,9 @@ void QtSearchView::refreshView()
|
|||||||
m_refreshViewFunctor();
|
m_refreshViewFunctor();
|
||||||
}
|
}
|
||||||
|
|
||||||
void QtSearchView::setText(const std::string& s)
|
void QtSearchView::setText(const std::string& text)
|
||||||
{
|
{
|
||||||
m_setTextFunctor(s);
|
m_setTextFunctor(text);
|
||||||
}
|
}
|
||||||
|
|
||||||
void QtSearchView::setFocus()
|
void QtSearchView::setFocus()
|
||||||
@@ -75,51 +43,30 @@ void QtSearchView::setFocus()
|
|||||||
m_setFocusFunctor();
|
m_setFocusFunctor();
|
||||||
}
|
}
|
||||||
|
|
||||||
void QtSearchView::setAutocompletionList(const std::vector<std::string>& autocompletionList)
|
void QtSearchView::setAutocompletionList(const std::vector<SearchIndex::SearchMatch>& autocompletionList)
|
||||||
{
|
{
|
||||||
m_setAutocompletionListFunctor(autocompletionList);
|
m_setAutocompletionListFunctor(autocompletionList);
|
||||||
}
|
}
|
||||||
|
|
||||||
void QtSearchView::onSearchButtonClick()
|
|
||||||
{
|
|
||||||
SearchController* controller = getController();
|
|
||||||
if (controller)
|
|
||||||
{
|
|
||||||
controller->search(m_searchBox->text().toStdString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void QtSearchView::doRefreshView()
|
void QtSearchView::doRefreshView()
|
||||||
{
|
{
|
||||||
setStyleSheet();
|
setStyleSheet();
|
||||||
}
|
}
|
||||||
|
|
||||||
void QtSearchView::doSetText(const std::string& s)
|
void QtSearchView::doSetText(const std::string& text)
|
||||||
{
|
{
|
||||||
if (m_searchBox->text() != s.c_str())
|
m_widget->setText(text);
|
||||||
{
|
|
||||||
m_searchBox->setText(s.c_str());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void QtSearchView::doSetFocus()
|
void QtSearchView::doSetFocus()
|
||||||
{
|
{
|
||||||
getViewLayout()->showView(this);
|
getViewLayout()->showView(this);
|
||||||
m_searchBox->setFocus(Qt::ShortcutFocusReason);
|
m_widget->setFocus();
|
||||||
}
|
}
|
||||||
|
|
||||||
void QtSearchView::doSetAutocompletionList(const std::vector<std::string>& autocompletionList)
|
void QtSearchView::doSetAutocompletionList(const std::vector<SearchIndex::SearchMatch>& autocompletionList)
|
||||||
{
|
{
|
||||||
QStringList wordList;
|
m_widget->setAutocompletionList(autocompletionList);
|
||||||
for (const std::string& s: autocompletionList)
|
|
||||||
{
|
|
||||||
wordList << s.c_str();
|
|
||||||
}
|
|
||||||
|
|
||||||
QCompleter *completer = new QCompleter(wordList, m_searchBox);
|
|
||||||
completer->popup()->setObjectName("search_box_popup");
|
|
||||||
completer->setCaseSensitivity(Qt::CaseInsensitive);
|
|
||||||
m_searchBox->setCompleter(completer);
|
|
||||||
setStyleSheet();
|
setStyleSheet();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -127,11 +74,10 @@ void QtSearchView::setStyleSheet()
|
|||||||
{
|
{
|
||||||
std::string css = TextAccess::createFromFile("data/gui/search_view/search_view.css")->getText();
|
std::string css = TextAccess::createFromFile("data/gui/search_view/search_view.css")->getText();
|
||||||
|
|
||||||
QWidget* widget = QtViewWidgetWrapper::getWidgetOfView(this);
|
m_widget->setStyleSheet(css.c_str());
|
||||||
widget->setStyleSheet(css.c_str());
|
|
||||||
|
|
||||||
if (m_searchBox->completer())
|
if (m_widget->getCompleterPopup())
|
||||||
{
|
{
|
||||||
m_searchBox->completer()->popup()->setStyleSheet(css.c_str());
|
m_widget->getCompleterPopup()->setStyleSheet(css.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,11 +4,9 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "component/view/SearchView.h"
|
#include "component/view/SearchView.h"
|
||||||
|
#include "qt/element/QtSearchBox.h"
|
||||||
#include "qt/utility/QtThreadedFunctor.h"
|
#include "qt/utility/QtThreadedFunctor.h"
|
||||||
|
|
||||||
class QtEditBox;
|
|
||||||
class QtButton;
|
|
||||||
|
|
||||||
class QtSearchView: public SearchView
|
class QtSearchView: public SearchView
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -21,28 +19,24 @@ public:
|
|||||||
virtual void refreshView();
|
virtual void refreshView();
|
||||||
|
|
||||||
// SearchView implementation
|
// SearchView implementation
|
||||||
virtual void setText(const std::string& s);
|
virtual void setText(const std::string& text);
|
||||||
virtual void setFocus();
|
virtual void setFocus();
|
||||||
virtual void setAutocompletionList(const std::vector<std::string>& autocompletionList);
|
virtual void setAutocompletionList(const std::vector<SearchIndex::SearchMatch>& autocompletionList);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void onSearchButtonClick();
|
|
||||||
|
|
||||||
void doRefreshView();
|
void doRefreshView();
|
||||||
void doSetText(const std::string& s);
|
void doSetText(const std::string& text);
|
||||||
void doSetFocus();
|
void doSetFocus();
|
||||||
void doSetAutocompletionList(const std::vector<std::string>& autocompletionList);
|
void doSetAutocompletionList(const std::vector<SearchIndex::SearchMatch>& autocompletionList);
|
||||||
|
|
||||||
void setStyleSheet();
|
void setStyleSheet();
|
||||||
|
|
||||||
QtEditBox* m_searchBox;
|
|
||||||
QtButton* m_searchButton;
|
|
||||||
QtButton* m_caseSensitiveButton;
|
|
||||||
|
|
||||||
QtThreadedFunctor<> m_refreshViewFunctor;
|
QtThreadedFunctor<> m_refreshViewFunctor;
|
||||||
QtThreadedFunctor<const std::string&> m_setTextFunctor;
|
QtThreadedFunctor<const std::string&> m_setTextFunctor;
|
||||||
QtThreadedFunctor<> m_setFocusFunctor;
|
QtThreadedFunctor<> m_setFocusFunctor;
|
||||||
QtThreadedFunctor<const std::vector<std::string>&> m_setAutocompletionListFunctor;
|
QtThreadedFunctor<const std::vector<SearchIndex::SearchMatch>&> m_setAutocompletionListFunctor;
|
||||||
|
|
||||||
|
std::shared_ptr<QtSearchBox> m_widget;
|
||||||
};
|
};
|
||||||
|
|
||||||
# endif // QT_SEARCH_VIEW_H
|
# endif // QT_SEARCH_VIEW_H
|
||||||
|
|||||||
@@ -189,6 +189,7 @@ add_files(
|
|||||||
utility/messaging/type/MessageLoadProject.h
|
utility/messaging/type/MessageLoadProject.h
|
||||||
utility/messaging/type/MessageLoadSource.h
|
utility/messaging/type/MessageLoadSource.h
|
||||||
utility/messaging/type/MessageRefresh.h
|
utility/messaging/type/MessageRefresh.h
|
||||||
|
utility/messaging/type/MessageSearch.h
|
||||||
utility/messaging/type/MessageShowFile.h
|
utility/messaging/type/MessageShowFile.h
|
||||||
|
|
||||||
utility/messaging/Message.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)
|
void SearchController::handleMessage(MessageActivateToken* message)
|
||||||
{
|
{
|
||||||
getView()->setText(m_graphAccess->getNameForNodeWithId(message->tokenId));
|
getView()->setText(m_graphAccess->getNameForNodeWithId(message->tokenId));
|
||||||
@@ -47,16 +23,38 @@ void SearchController::handleMessage(MessageFind* message)
|
|||||||
getView()->setFocus();
|
getView()->setFocus();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SearchController::handleMessage(MessageFinishedParsing* message)
|
|
||||||
{
|
|
||||||
getView()->setAutocompletionList(m_graphAccess->getNamesForNodesWithNamePrefix(":"));
|
|
||||||
}
|
|
||||||
|
|
||||||
void SearchController::handleMessage(MessageRefresh* message)
|
void SearchController::handleMessage(MessageRefresh* message)
|
||||||
{
|
{
|
||||||
getView()->refreshView();
|
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()
|
SearchView* SearchController::getView()
|
||||||
{
|
{
|
||||||
return Controller::getView<SearchView>();
|
return Controller::getView<SearchView>();
|
||||||
|
|||||||
@@ -7,8 +7,9 @@
|
|||||||
#include "utility/messaging/MessageListener.h"
|
#include "utility/messaging/MessageListener.h"
|
||||||
#include "utility/messaging/type/MessageActivateToken.h"
|
#include "utility/messaging/type/MessageActivateToken.h"
|
||||||
#include "utility/messaging/type/MessageFind.h"
|
#include "utility/messaging/type/MessageFind.h"
|
||||||
#include "utility/messaging/type/MessageFinishedParsing.h"
|
|
||||||
#include "utility/messaging/type/MessageRefresh.h"
|
#include "utility/messaging/type/MessageRefresh.h"
|
||||||
|
#include "utility/messaging/type/MessageSearch.h"
|
||||||
|
#include "utility/messaging/type/MessageSearchAutocomplete.h"
|
||||||
|
|
||||||
class GraphAccess;
|
class GraphAccess;
|
||||||
class SearchView;
|
class SearchView;
|
||||||
@@ -17,21 +18,21 @@ class SearchController
|
|||||||
: public Controller
|
: public Controller
|
||||||
, public MessageListener<MessageActivateToken>
|
, public MessageListener<MessageActivateToken>
|
||||||
, public MessageListener<MessageFind>
|
, public MessageListener<MessageFind>
|
||||||
, public MessageListener<MessageFinishedParsing>
|
|
||||||
, public MessageListener<MessageRefresh>
|
, public MessageListener<MessageRefresh>
|
||||||
|
, public MessageListener<MessageSearch>
|
||||||
|
, public MessageListener<MessageSearchAutocomplete>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SearchController(GraphAccess* graphAccess);
|
SearchController(GraphAccess* graphAccess);
|
||||||
~SearchController();
|
~SearchController();
|
||||||
|
|
||||||
void search(const std::string& s);
|
|
||||||
//void autocomplete(const std::string& s);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
virtual void handleMessage(MessageActivateToken* message);
|
virtual void handleMessage(MessageActivateToken* message);
|
||||||
virtual void handleMessage(MessageFind* message);
|
virtual void handleMessage(MessageFind* message);
|
||||||
virtual void handleMessage(MessageFinishedParsing* message);
|
|
||||||
virtual void handleMessage(MessageRefresh* message);
|
virtual void handleMessage(MessageRefresh* message);
|
||||||
|
virtual void handleMessage(MessageSearch* message);
|
||||||
|
virtual void handleMessage(MessageSearchAutocomplete* message);
|
||||||
|
|
||||||
SearchView* getView();
|
SearchView* getView();
|
||||||
|
|
||||||
GraphAccess* m_graphAccess;
|
GraphAccess* m_graphAccess;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#define SEARCH_VIEW_H
|
#define SEARCH_VIEW_H
|
||||||
|
|
||||||
#include "component/view/View.h"
|
#include "component/view/View.h"
|
||||||
|
#include "data/SearchIndex.h"
|
||||||
|
|
||||||
class SearchController;
|
class SearchController;
|
||||||
|
|
||||||
@@ -15,7 +16,7 @@ public:
|
|||||||
|
|
||||||
virtual void setText(const std::string& s) = 0;
|
virtual void setText(const std::string& s) = 0;
|
||||||
virtual void setFocus() = 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:
|
protected:
|
||||||
SearchController* getController();
|
SearchController* getController();
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ public:
|
|||||||
virtual ~View();
|
virtual ~View();
|
||||||
|
|
||||||
virtual std::string getName() const = 0;
|
virtual std::string getName() const = 0;
|
||||||
|
|
||||||
virtual void createWidgetWrapper() = 0;
|
virtual void createWidgetWrapper() = 0;
|
||||||
virtual void initView() = 0;
|
virtual void initView() = 0;
|
||||||
virtual void refreshView() = 0;
|
virtual void refreshView() = 0;
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cctype>
|
#include <cctype>
|
||||||
|
|
||||||
|
#include "data/query/QueryToken.h"
|
||||||
#include "utility/logging/logging.h"
|
#include "utility/logging/logging.h"
|
||||||
#include "utility/text/Dictionary.h"
|
#include "utility/text/Dictionary.h"
|
||||||
#include "utility/utilityString.h"
|
#include "utility/utilityString.h"
|
||||||
@@ -22,7 +23,7 @@ namespace
|
|||||||
|
|
||||||
void SearchIndex::SearchMatch::print(std::ostream& ostream) const
|
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;
|
size_t i = 0;
|
||||||
for (size_t index : indices)
|
for (size_t index : indices)
|
||||||
{
|
{
|
||||||
@@ -37,6 +38,23 @@ void SearchIndex::SearchMatch::print(std::ostream& ostream) const
|
|||||||
ostream << std::endl;
|
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)
|
SearchIndex::SearchNode::SearchNode(SearchNode* parent, const std::string& name, Id nameId)
|
||||||
: m_parent(parent)
|
: m_parent(parent)
|
||||||
, m_name(name)
|
, 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
|
SearchIndex::SearchMatch SearchIndex::SearchNode::fuzzyMatchData(const std::string& query, const SearchNode* parent) const
|
||||||
{
|
{
|
||||||
SearchMatch data;
|
SearchMatch data;
|
||||||
data.node = this;
|
data.fullName = getFullName();
|
||||||
|
data.tokenIds = m_tokenIds;
|
||||||
data.weight = 0;
|
data.weight = 0;
|
||||||
|
|
||||||
size_t pos = 0;
|
size_t pos = 0;
|
||||||
|
|||||||
@@ -19,7 +19,10 @@ public:
|
|||||||
{
|
{
|
||||||
void print(std::ostream& ostream) const;
|
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;
|
std::vector<size_t> indices;
|
||||||
size_t weight;
|
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(query);
|
||||||
std::vector<SearchIndex::SearchMatch> matches = m_index.findFuzzyMatches(prefix);
|
SearchIndex::logMatches(matches, query);
|
||||||
for (const SearchIndex::SearchMatch& match : matches)
|
return matches;
|
||||||
{
|
|
||||||
names.push_back(match.node->getFullName());
|
|
||||||
}
|
|
||||||
return names;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<Graph> Storage::getGraphForActiveTokenIds(const std::vector<Id>& tokenIds) const
|
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);
|
LOG_INFO_STREAM(<< '\n' << tree << '\n' << outGraph);
|
||||||
|
|
||||||
SearchIndex::logMatches(m_index.findFuzzyMatches(query), query);
|
|
||||||
|
|
||||||
return outGraph.getTokenIds();
|
return outGraph.getTokenIds();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ public:
|
|||||||
// GraphAccess implementation
|
// GraphAccess implementation
|
||||||
virtual Id getIdForNodeWithName(const std::string& fullName) const;
|
virtual Id getIdForNodeWithName(const std::string& fullName) const;
|
||||||
virtual std::string getNameForNodeWithId(Id id) 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;
|
virtual std::shared_ptr<Graph> getGraphForActiveTokenIds(const std::vector<Id>& tokenIds) const;
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "data/graph/Graph.h"
|
#include "data/graph/Graph.h"
|
||||||
|
#include "data/SearchIndex.h"
|
||||||
#include "utility/types.h"
|
#include "utility/types.h"
|
||||||
|
|
||||||
class GraphAccess
|
class GraphAccess
|
||||||
@@ -15,7 +16,7 @@ public:
|
|||||||
|
|
||||||
virtual Id getIdForNodeWithName(const std::string& name) const = 0;
|
virtual Id getIdForNodeWithName(const std::string& name) const = 0;
|
||||||
virtual std::string getNameForNodeWithId(Id id) 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;
|
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 "";
|
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())
|
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
|
std::shared_ptr<Graph> GraphAccessProxy::getGraphForActiveTokenIds(const std::vector<Id>& tokenIds) const
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ public:
|
|||||||
// GraphAccess implementation
|
// GraphAccess implementation
|
||||||
virtual Id getIdForNodeWithName(const std::string& name) const;
|
virtual Id getIdForNodeWithName(const std::string& name) const;
|
||||||
virtual std::string getNameForNodeWithId(Id id) 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;
|
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
|
void FilterableGraph::print(std::ostream& ostream) const
|
||||||
{
|
{
|
||||||
ostream << "Graph:\n";
|
ostream << "Graph:\n";
|
||||||
|
|||||||
@@ -4,6 +4,8 @@
|
|||||||
#include <functional>
|
#include <functional>
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
|
|
||||||
|
#include "utility/types.h"
|
||||||
|
|
||||||
class Edge;
|
class Edge;
|
||||||
class Node;
|
class Node;
|
||||||
class Token;
|
class Token;
|
||||||
@@ -29,6 +31,11 @@ public:
|
|||||||
virtual size_t getNodeCount() const = 0;
|
virtual size_t getNodeCount() const = 0;
|
||||||
virtual size_t getEdgeCount() 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 print(std::ostream& ostream) const;
|
||||||
void printBasic(std::ostream& ostream) const;
|
void printBasic(std::ostream& ostream) const;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -75,16 +75,6 @@ size_t Graph::getEdgeCount() const
|
|||||||
return m_edges.size();
|
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
|
Node* Graph::getNodeById(Id id) const
|
||||||
{
|
{
|
||||||
std::map<Id, std::shared_ptr<Node>>::const_iterator it = m_nodes.find(id);
|
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;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Token* Graph::getTokenById(Id id) const
|
const std::map<Id, std::shared_ptr<Node>>& Graph::getNodes() const
|
||||||
{
|
{
|
||||||
Token* token = getNodeById(id);
|
return m_nodes;
|
||||||
if (!token)
|
}
|
||||||
{
|
|
||||||
token = getEdgeById(id);
|
const std::map<Id, std::shared_ptr<Edge>>& Graph::getEdges() const
|
||||||
}
|
{
|
||||||
return token;
|
return m_edges;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Graph::removeNode(Node* node)
|
void Graph::removeNode(Node* node)
|
||||||
|
|||||||
@@ -32,13 +32,12 @@ public:
|
|||||||
virtual size_t getNodeCount() const;
|
virtual size_t getNodeCount() const;
|
||||||
virtual size_t getEdgeCount() 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<Node>>& getNodes() const;
|
||||||
const std::map<Id, std::shared_ptr<Edge>>& getEdges() 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 removeNode(Node* node);
|
||||||
void removeEdge(Edge* edge);
|
void removeEdge(Edge* edge);
|
||||||
|
|
||||||
|
|||||||
@@ -71,6 +71,26 @@ size_t SubGraph::getEdgeCount() const
|
|||||||
return m_edges.size();
|
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> SubGraph::getTokenIds() const
|
||||||
{
|
{
|
||||||
std::vector<Id> ids;
|
std::vector<Id> ids;
|
||||||
|
|||||||
@@ -6,7 +6,6 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "data/graph/FilterableGraph.h"
|
#include "data/graph/FilterableGraph.h"
|
||||||
#include "utility/types.h"
|
|
||||||
|
|
||||||
class Edge;
|
class Edge;
|
||||||
class Node;
|
class Node;
|
||||||
@@ -35,6 +34,9 @@ public:
|
|||||||
virtual size_t getNodeCount() const;
|
virtual size_t getNodeCount() const;
|
||||||
virtual size_t getEdgeCount() const;
|
virtual size_t getEdgeCount() const;
|
||||||
|
|
||||||
|
virtual Node* getNodeById(Id id) const;
|
||||||
|
virtual Edge* getEdgeById(Id id) const;
|
||||||
|
|
||||||
std::vector<Id> getTokenIds() const;
|
std::vector<Id> getTokenIds() const;
|
||||||
|
|
||||||
void subtract(const SubGraph& other);
|
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
|
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
|
#ifndef GRAPH_FILTER_IMPLEMENTATIONS_H
|
||||||
#define GRAPH_FILTER_IMPLEMENTATIONS_H
|
#define GRAPH_FILTER_IMPLEMENTATIONS_H
|
||||||
|
|
||||||
|
#include <set>
|
||||||
|
|
||||||
#include "data/graph/Edge.h"
|
#include "data/graph/Edge.h"
|
||||||
#include "data/graph/filter/GraphFilter.h"
|
#include "data/graph/filter/GraphFilter.h"
|
||||||
|
#include "data/graph/FilterableGraph.h"
|
||||||
#include "data/graph/Node.h"
|
#include "data/graph/Node.h"
|
||||||
#include "data/graph/token_component/TokenComponentAbstraction.h"
|
#include "data/graph/token_component/TokenComponentAbstraction.h"
|
||||||
#include "data/graph/token_component/TokenComponentAccess.h"
|
#include "data/graph/token_component/TokenComponentAccess.h"
|
||||||
@@ -258,22 +261,43 @@ class GraphFilterToken
|
|||||||
: public GraphFilter
|
: public GraphFilter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
GraphFilterToken(const std::string& name)
|
GraphFilterToken(const std::string& tokenName, const std::set<Id>& tokenIds)
|
||||||
: m_name(name)
|
: 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:
|
protected:
|
||||||
virtual void visitNode(Node* node)
|
virtual void visitNode(Node* node)
|
||||||
{
|
{
|
||||||
if (node->getName() == m_name)
|
if (node->getFullName() == m_tokenName)
|
||||||
{
|
{
|
||||||
addNode(node);
|
addNode(node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const std::string& m_name;
|
const std::string& m_tokenName;
|
||||||
|
const std::set<Id>& m_tokenIds;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // GRAPH_FILTER_IMPLEMENTATIONS_H
|
#endif // GRAPH_FILTER_IMPLEMENTATIONS_H
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ bool QueryCommand::isToken() const
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool QueryCommand::isComplete() const
|
bool QueryCommand::derivedIsComplete() const
|
||||||
{
|
{
|
||||||
return m_type != COMMAND_INVALID;
|
return m_type != COMMAND_INVALID;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ public:
|
|||||||
virtual bool isOperator() const;
|
virtual bool isOperator() const;
|
||||||
virtual bool isToken() 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) const;
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ void QueryNode::print(std::ostream& ostream, int n) const
|
|||||||
ostream << ')';
|
ostream << ')';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!m_isComplete || !isComplete())
|
if (!isComplete())
|
||||||
{
|
{
|
||||||
ostream << " INVALID";
|
ostream << " INVALID";
|
||||||
}
|
}
|
||||||
@@ -47,6 +47,11 @@ void QueryNode::setIsGroup(bool isGroup)
|
|||||||
m_isGroup = isGroup;
|
m_isGroup = isGroup;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool QueryNode::isComplete() const
|
||||||
|
{
|
||||||
|
return m_isComplete && derivedIsComplete();
|
||||||
|
}
|
||||||
|
|
||||||
void QueryNode::setIsComplete(bool isComplete)
|
void QueryNode::setIsComplete(bool isComplete)
|
||||||
{
|
{
|
||||||
m_isComplete = isComplete;
|
m_isComplete = isComplete;
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ public:
|
|||||||
virtual bool isOperator() const = 0;
|
virtual bool isOperator() const = 0;
|
||||||
virtual bool isToken() 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) const = 0;
|
||||||
virtual void print(std::ostream& ostream, int n) const;
|
virtual void print(std::ostream& ostream, int n) const;
|
||||||
@@ -21,6 +21,7 @@ public:
|
|||||||
bool isGroup() const;
|
bool isGroup() const;
|
||||||
void setIsGroup(bool isGroup);
|
void setIsGroup(bool isGroup);
|
||||||
|
|
||||||
|
bool isComplete() const;
|
||||||
void setIsComplete(bool isComplete);
|
void setIsComplete(bool isComplete);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
#include "data/query/QueryOperator.h"
|
#include "data/query/QueryOperator.h"
|
||||||
|
|
||||||
|
#include "data/query/QueryToken.h"
|
||||||
|
|
||||||
const std::map<char, QueryOperator::OperatorType>& QueryOperator::getOperatorTypeMap()
|
const std::map<char, QueryOperator::OperatorType>& QueryOperator::getOperatorTypeMap()
|
||||||
{
|
{
|
||||||
static std::map<char, OperatorType> operatorMap;
|
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_AND);
|
||||||
operatorMap.emplace('|', OPERATOR_OR);
|
operatorMap.emplace('|', OPERATOR_OR);
|
||||||
|
|
||||||
operatorMap.emplace('"', OPERATOR_NAME);
|
operatorMap.emplace(QueryToken::BOUNDARY, OPERATOR_TOKEN);
|
||||||
|
|
||||||
operatorMap.emplace('(', OPERATOR_GROUP_OPEN);
|
operatorMap.emplace('(', OPERATOR_GROUP_OPEN);
|
||||||
operatorMap.emplace(')', OPERATOR_GROUP_CLOSE);
|
operatorMap.emplace(')', OPERATOR_GROUP_CLOSE);
|
||||||
|
|
||||||
@@ -74,7 +77,7 @@ bool QueryOperator::isToken() const
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool QueryOperator::isComplete() const
|
bool QueryOperator::derivedIsComplete() const
|
||||||
{
|
{
|
||||||
if (m_type == OPERATOR_NOT)
|
if (m_type == OPERATOR_NOT)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ public:
|
|||||||
OPERATOR_AND,
|
OPERATOR_AND,
|
||||||
OPERATOR_OR,
|
OPERATOR_OR,
|
||||||
|
|
||||||
OPERATOR_NAME,
|
OPERATOR_TOKEN,
|
||||||
OPERATOR_GROUP_OPEN,
|
OPERATOR_GROUP_OPEN,
|
||||||
OPERATOR_GROUP_CLOSE
|
OPERATOR_GROUP_CLOSE
|
||||||
};
|
};
|
||||||
@@ -36,7 +36,7 @@ public:
|
|||||||
virtual bool isOperator() const;
|
virtual bool isOperator() const;
|
||||||
virtual bool isToken() 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) const;
|
||||||
virtual void print(std::ostream& ostream, int n) const;
|
virtual void print(std::ostream& ostream, int n) const;
|
||||||
|
|||||||
@@ -1,8 +1,29 @@
|
|||||||
#include "data/query/QueryToken.h"
|
#include "data/query/QueryToken.h"
|
||||||
|
|
||||||
|
#include <deque>
|
||||||
|
|
||||||
|
#include "utility/utilityString.h"
|
||||||
|
|
||||||
QueryToken::QueryToken(const std::string& name)
|
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()
|
QueryToken::~QueryToken()
|
||||||
@@ -24,17 +45,30 @@ bool QueryToken::isToken() const
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool QueryToken::isComplete() const
|
bool QueryToken::derivedIsComplete() const
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void QueryToken::print(std::ostream& ostream) const
|
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
|
#ifndef QUERY_TOKEN_H
|
||||||
#define QUERY_TOKEN_H
|
#define QUERY_TOKEN_H
|
||||||
|
|
||||||
|
#include <set>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "data/query/QueryNode.h"
|
#include "data/query/QueryNode.h"
|
||||||
|
#include "utility/types.h"
|
||||||
|
|
||||||
class QueryToken
|
class QueryToken
|
||||||
: public QueryNode
|
: public QueryNode
|
||||||
@@ -15,14 +17,20 @@ public:
|
|||||||
virtual bool isCommand() const;
|
virtual bool isCommand() const;
|
||||||
virtual bool isOperator() const;
|
virtual bool isOperator() const;
|
||||||
virtual bool isToken() 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) 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:
|
private:
|
||||||
const std::string m_name;
|
std::string m_tokenName;
|
||||||
|
std::set<Id> m_tokenIds;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // QUERY_TOKEN_H
|
#endif // QUERY_TOKEN_H
|
||||||
|
|||||||
@@ -6,22 +6,51 @@
|
|||||||
#include "data/query/QueryToken.h"
|
#include "data/query/QueryToken.h"
|
||||||
#include "utility/utilityString.h"
|
#include "utility/utilityString.h"
|
||||||
|
|
||||||
QueryTree::QueryTree(std::string query)
|
std::deque<std::string> QueryTree::tokenizeQuery(const std::string& query)
|
||||||
: m_valid(true)
|
|
||||||
{
|
{
|
||||||
std::deque<std::string> tokens =
|
std::deque<std::string> tokensTmp =
|
||||||
utility::split<std::deque<std::string>>(query, QueryOperator::getOperator(QueryOperator::OPERATOR_NONE));
|
utility::split<std::deque<std::string>>(query, QueryOperator::getOperator(QueryOperator::OPERATOR_NONE));
|
||||||
|
|
||||||
for (const std::pair<char, QueryOperator::OperatorType>& p : QueryOperator::getOperatorTypeMap())
|
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);
|
m_root = buildTree(tokens, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,7 +74,7 @@ void QueryTree::print(std::ostream& ostream) const
|
|||||||
|
|
||||||
if (!m_valid)
|
if (!m_valid)
|
||||||
{
|
{
|
||||||
ostream << "INVALID";
|
ostream << " INVALID";
|
||||||
}
|
}
|
||||||
|
|
||||||
ostream << '\n';
|
ostream << '\n';
|
||||||
@@ -156,18 +185,10 @@ std::shared_ptr<QueryNode> QueryTree::buildGroup(std::deque<std::string>& tokens
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<QueryNode> groupNode;
|
std::shared_ptr<QueryNode> groupNode = buildTree(group, nullptr);
|
||||||
if (closeType == QueryOperator::OPERATOR_NAME)
|
groupNode->setIsGroup(true);
|
||||||
{
|
|
||||||
groupNode = std::make_shared<QueryToken>(name);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
groupNode = buildTree(group, nullptr);
|
|
||||||
groupNode->setIsGroup(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
groupNode->setIsComplete(valid);
|
groupNode->setIsComplete(valid);
|
||||||
|
|
||||||
return groupNode;
|
return groupNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -189,8 +210,9 @@ std::shared_ptr<QueryNode> QueryTree::getNextNode(std::deque<std::string>& token
|
|||||||
case QueryOperator::OPERATOR_OR:
|
case QueryOperator::OPERATOR_OR:
|
||||||
return std::make_shared<QueryOperator>(type);
|
return std::make_shared<QueryOperator>(type);
|
||||||
|
|
||||||
case QueryOperator::OPERATOR_NAME:
|
case QueryOperator::OPERATOR_TOKEN:
|
||||||
return buildGroup(tokens, QueryOperator::OPERATOR_NAME);
|
return createToken(token);
|
||||||
|
|
||||||
case QueryOperator::OPERATOR_GROUP_OPEN:
|
case QueryOperator::OPERATOR_GROUP_OPEN:
|
||||||
return buildGroup(tokens, QueryOperator::OPERATOR_GROUP_CLOSE);
|
return buildGroup(tokens, QueryOperator::OPERATOR_GROUP_CLOSE);
|
||||||
case 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;
|
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);
|
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;
|
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)
|
std::ostream& operator<<(std::ostream& ostream, const QueryTree& tree)
|
||||||
{
|
{
|
||||||
tree.print(ostream);
|
tree.print(ostream);
|
||||||
|
|||||||
@@ -13,7 +13,9 @@ class QueryNode;
|
|||||||
class QueryTree
|
class QueryTree
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
QueryTree(std::string query);
|
static std::deque<std::string> tokenizeQuery(const std::string& query);
|
||||||
|
|
||||||
|
QueryTree(const std::string& query);
|
||||||
~QueryTree();
|
~QueryTree();
|
||||||
|
|
||||||
std::shared_ptr<QueryNode> getRoot() const;
|
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> 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> buildGroup(std::deque<std::string>& tokens, QueryOperator::OperatorType closeType);
|
||||||
std::shared_ptr<QueryNode> getNextNode(std::deque<std::string>& tokens);
|
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::shared_ptr<QueryNode> m_root;
|
||||||
std::string m_query;
|
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
|
#ifndef UTILITY_STRING_H
|
||||||
#define UTILITY_STRING_H
|
#define UTILITY_STRING_H
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@@ -12,6 +13,12 @@ namespace utility
|
|||||||
template<typename ContainerType>
|
template<typename ContainerType>
|
||||||
ContainerType split(const std::string& str, const std::string& delimiter);
|
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>
|
template<typename ContainerType>
|
||||||
ContainerType tokenize(const std::string& str, char delimiter);
|
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;
|
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>
|
template<typename ContainerType>
|
||||||
ContainerType utility::tokenize(const std::string& str, char delimiter)
|
ContainerType utility::tokenize(const std::string& str, char delimiter)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -17,12 +17,69 @@ public:
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void test_token_query_with_id()
|
||||||
|
{
|
||||||
|
std::set<Id> ids = getIdsForNodeWithName("main");
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << "\"main";
|
||||||
|
for (Id id : ids)
|
||||||
|
{
|
||||||
|
ss << ',' << id;
|
||||||
|
}
|
||||||
|
ss << '"';
|
||||||
|
|
||||||
|
TS_ASSERT_EQUALS(
|
||||||
|
printedFilteredTestGraph(ss.str()), // "main,<id>"
|
||||||
|
|
||||||
|
"1 nodes: function:main\n"
|
||||||
|
"0 edges:\n"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_token_query_with_id_and_wrong_name_uses_id()
|
||||||
|
{
|
||||||
|
std::set<Id> ids = getIdsForNodeWithName("main");
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << "\"hello";
|
||||||
|
for (Id id : ids)
|
||||||
|
{
|
||||||
|
ss << ',' << id;
|
||||||
|
}
|
||||||
|
ss << '"';
|
||||||
|
|
||||||
|
TS_ASSERT_EQUALS(
|
||||||
|
printedFilteredTestGraph(ss.str()), // "hello,<id>"
|
||||||
|
|
||||||
|
"1 nodes: function:main\n"
|
||||||
|
"0 edges:\n"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_token_query_with_ids()
|
||||||
|
{
|
||||||
|
std::set<Id> ids = getIdsForNodeWithName("A::A");
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << "\"A::A";
|
||||||
|
for (Id id : ids)
|
||||||
|
{
|
||||||
|
ss << ',' << id;
|
||||||
|
}
|
||||||
|
ss << '"';
|
||||||
|
|
||||||
|
TS_ASSERT_EQUALS(
|
||||||
|
printedFilteredTestGraph(ss.str()), // "A::A,<id1>,<id2>"
|
||||||
|
|
||||||
|
"2 nodes: method:A::A method:A::A\n"
|
||||||
|
"0 edges:\n"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
void test_command_query()
|
void test_command_query()
|
||||||
{
|
{
|
||||||
TS_ASSERT_EQUALS(
|
TS_ASSERT_EQUALS(
|
||||||
printedFilteredTestGraph("method"),
|
printedFilteredTestGraph("method"),
|
||||||
|
|
||||||
"4 nodes: method:A::A method:A::getCount method:A::process method:B::process\n"
|
"5 nodes: method:A::A method:A::A method:A::getCount method:A::process method:B::process\n"
|
||||||
"0 edges:\n"
|
"0 edges:\n"
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -104,6 +161,19 @@ private:
|
|||||||
return ss.str();
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::set<Id> getIdsForNodeWithName(const std::string& name)
|
||||||
|
{
|
||||||
|
createTestStorage();
|
||||||
|
|
||||||
|
std::vector<SearchIndex::SearchMatch> matches = m_storage->getAutocompletionMatches(name);
|
||||||
|
if (matches.size() && matches[0].fullName == name)
|
||||||
|
{
|
||||||
|
return matches[0].tokenIds;
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::set<Id>();
|
||||||
|
}
|
||||||
|
|
||||||
void createTestStorage()
|
void createTestStorage()
|
||||||
{
|
{
|
||||||
if (m_storage)
|
if (m_storage)
|
||||||
@@ -121,6 +191,10 @@ private:
|
|||||||
" count++;\n"
|
" count++;\n"
|
||||||
" }\n"
|
" }\n"
|
||||||
"\n"
|
"\n"
|
||||||
|
" A(int c) {\n"
|
||||||
|
" count += c;\n"
|
||||||
|
" }\n"
|
||||||
|
"\n"
|
||||||
" static int getCount()\n"
|
" static int getCount()\n"
|
||||||
" {\n"
|
" {\n"
|
||||||
" return count;\n"
|
" return count;\n"
|
||||||
|
|||||||
@@ -161,7 +161,7 @@ public:
|
|||||||
|
|
||||||
void test_GraphFilterToken()
|
void test_GraphFilterToken()
|
||||||
{
|
{
|
||||||
GraphFilterToken filter("main");
|
GraphFilterToken filter("main", std::set<Id>());
|
||||||
|
|
||||||
TS_ASSERT_EQUALS(
|
TS_ASSERT_EQUALS(
|
||||||
printedFilteredTestGraph(&filter),
|
printedFilteredTestGraph(&filter),
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ public:
|
|||||||
TS_ASSERT_EQUALS(
|
TS_ASSERT_EQUALS(
|
||||||
printedQueryTree(""),
|
printedQueryTree(""),
|
||||||
|
|
||||||
"INVALID\n"
|
" INVALID\n"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -28,7 +28,7 @@ public:
|
|||||||
TS_ASSERT_EQUALS(
|
TS_ASSERT_EQUALS(
|
||||||
printedQueryTree("class"),
|
printedQueryTree("class"),
|
||||||
|
|
||||||
"class \n"
|
"class\n"
|
||||||
"class\n"
|
"class\n"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -47,7 +47,7 @@ public:
|
|||||||
TS_ASSERT_EQUALS(
|
TS_ASSERT_EQUALS(
|
||||||
printedQueryTree("\"A\""),
|
printedQueryTree("\"A\""),
|
||||||
|
|
||||||
"\" A \" \n"
|
"\"A\"\n"
|
||||||
"\"A\"\n"
|
"\"A\"\n"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -57,14 +57,13 @@ public:
|
|||||||
TS_ASSERT_EQUALS(
|
TS_ASSERT_EQUALS(
|
||||||
printedQueryTree("\"A"),
|
printedQueryTree("\"A"),
|
||||||
|
|
||||||
"\" A INVALID\n"
|
"\"A INVALID\n"
|
||||||
"\"A\" INVALID\n"
|
|
||||||
);
|
);
|
||||||
|
|
||||||
TS_ASSERT_EQUALS(
|
TS_ASSERT_EQUALS(
|
||||||
printedQueryTree("\"\""),
|
printedQueryTree("\"\""),
|
||||||
|
|
||||||
"\" \" INVALID\n"
|
"\"\" INVALID\n"
|
||||||
);
|
);
|
||||||
|
|
||||||
TS_ASSERT_EQUALS(
|
TS_ASSERT_EQUALS(
|
||||||
@@ -74,12 +73,32 @@ public:
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void test_token_query_with_id()
|
||||||
|
{
|
||||||
|
TS_ASSERT_EQUALS(
|
||||||
|
printedQueryTree("\"A,1\""),
|
||||||
|
|
||||||
|
"\"A,1\"\n"
|
||||||
|
"\"A,1\"\n"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_token_query_with_ids()
|
||||||
|
{
|
||||||
|
TS_ASSERT_EQUALS(
|
||||||
|
printedQueryTree("\"A,1,2\""),
|
||||||
|
|
||||||
|
"\"A,1,2\"\n"
|
||||||
|
"\"A,1,2\"\n"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
void test_operator_not_query()
|
void test_operator_not_query()
|
||||||
{
|
{
|
||||||
TS_ASSERT_EQUALS(
|
TS_ASSERT_EQUALS(
|
||||||
printedQueryTree("!field"),
|
printedQueryTree("!field"),
|
||||||
|
|
||||||
"! field \n"
|
"! field\n"
|
||||||
"!\n"
|
"!\n"
|
||||||
" field\n"
|
" field\n"
|
||||||
);
|
);
|
||||||
@@ -87,7 +106,7 @@ public:
|
|||||||
TS_ASSERT_EQUALS(
|
TS_ASSERT_EQUALS(
|
||||||
printedQueryTree("!!field"),
|
printedQueryTree("!!field"),
|
||||||
|
|
||||||
"! ! field \n"
|
"! ! field\n"
|
||||||
"!\n"
|
"!\n"
|
||||||
" !\n"
|
" !\n"
|
||||||
" field\n"
|
" field\n"
|
||||||
@@ -117,7 +136,7 @@ public:
|
|||||||
TS_ASSERT_EQUALS(
|
TS_ASSERT_EQUALS(
|
||||||
printedQueryTree("\"A\".\"B\""),
|
printedQueryTree("\"A\".\"B\""),
|
||||||
|
|
||||||
"\" A \" . \" B \" \n"
|
"\"A\" . \"B\"\n"
|
||||||
" \"A\"\n"
|
" \"A\"\n"
|
||||||
".\n"
|
".\n"
|
||||||
" \"B\"\n"
|
" \"B\"\n"
|
||||||
@@ -129,7 +148,7 @@ public:
|
|||||||
TS_ASSERT_EQUALS(
|
TS_ASSERT_EQUALS(
|
||||||
printedQueryTree("\"A\"."),
|
printedQueryTree("\"A\"."),
|
||||||
|
|
||||||
"\" A \" . INVALID\n"
|
"\"A\" . INVALID\n"
|
||||||
" \"A\"\n"
|
" \"A\"\n"
|
||||||
". INVALID\n"
|
". INVALID\n"
|
||||||
);
|
);
|
||||||
@@ -144,7 +163,7 @@ public:
|
|||||||
TS_ASSERT_EQUALS(
|
TS_ASSERT_EQUALS(
|
||||||
printedQueryTree(".\"A\""),
|
printedQueryTree(".\"A\""),
|
||||||
|
|
||||||
". \" A \" INVALID\n"
|
". \"A\" INVALID\n"
|
||||||
". INVALID\n"
|
". INVALID\n"
|
||||||
" \"A\"\n"
|
" \"A\"\n"
|
||||||
);
|
);
|
||||||
@@ -152,7 +171,7 @@ public:
|
|||||||
TS_ASSERT_EQUALS(
|
TS_ASSERT_EQUALS(
|
||||||
printedQueryTree("\"A\"..\"B\""),
|
printedQueryTree("\"A\"..\"B\""),
|
||||||
|
|
||||||
"\" A \" . . \" B \" INVALID\n"
|
"\"A\" . . \"B\" INVALID\n"
|
||||||
" \"A\"\n"
|
" \"A\"\n"
|
||||||
".\n"
|
".\n"
|
||||||
" . INVALID\n"
|
" . INVALID\n"
|
||||||
@@ -165,7 +184,7 @@ public:
|
|||||||
TS_ASSERT_EQUALS(
|
TS_ASSERT_EQUALS(
|
||||||
printedQueryTree("\"A\":\"B\""),
|
printedQueryTree("\"A\":\"B\""),
|
||||||
|
|
||||||
"\" A \" : \" B \" \n"
|
"\"A\" : \"B\"\n"
|
||||||
" \"A\"\n"
|
" \"A\"\n"
|
||||||
":\n"
|
":\n"
|
||||||
" \"B\"\n"
|
" \"B\"\n"
|
||||||
@@ -177,7 +196,7 @@ public:
|
|||||||
TS_ASSERT_EQUALS(
|
TS_ASSERT_EQUALS(
|
||||||
printedQueryTree("\"A\"&\"B\""),
|
printedQueryTree("\"A\"&\"B\""),
|
||||||
|
|
||||||
"\" A \" & \" B \" \n"
|
"\"A\" & \"B\"\n"
|
||||||
" \"A\"\n"
|
" \"A\"\n"
|
||||||
"&\n"
|
"&\n"
|
||||||
" \"B\"\n"
|
" \"B\"\n"
|
||||||
@@ -189,7 +208,7 @@ public:
|
|||||||
TS_ASSERT_EQUALS(
|
TS_ASSERT_EQUALS(
|
||||||
printedQueryTree("\"A\"|\"B\""),
|
printedQueryTree("\"A\"|\"B\""),
|
||||||
|
|
||||||
"\" A \" | \" B \" \n"
|
"\"A\" | \"B\"\n"
|
||||||
" \"A\"\n"
|
" \"A\"\n"
|
||||||
"|\n"
|
"|\n"
|
||||||
" \"B\"\n"
|
" \"B\"\n"
|
||||||
@@ -201,14 +220,14 @@ public:
|
|||||||
TS_ASSERT_EQUALS(
|
TS_ASSERT_EQUALS(
|
||||||
printedQueryTree("(\"A\")"),
|
printedQueryTree("(\"A\")"),
|
||||||
|
|
||||||
"( \" A \" ) \n"
|
"( \"A\" )\n"
|
||||||
"(\"A\")\n"
|
"(\"A\")\n"
|
||||||
);
|
);
|
||||||
|
|
||||||
TS_ASSERT_EQUALS(
|
TS_ASSERT_EQUALS(
|
||||||
printedQueryTree("(\"A\"|\"B\")"),
|
printedQueryTree("(\"A\"|\"B\")"),
|
||||||
|
|
||||||
"( \" A \" | \" B \" ) \n"
|
"( \"A\" | \"B\" )\n"
|
||||||
" \"A\"\n"
|
" \"A\"\n"
|
||||||
"(|)\n"
|
"(|)\n"
|
||||||
" \"B\"\n"
|
" \"B\"\n"
|
||||||
@@ -226,14 +245,14 @@ public:
|
|||||||
TS_ASSERT_EQUALS(
|
TS_ASSERT_EQUALS(
|
||||||
printedQueryTree("(\"A\""),
|
printedQueryTree("(\"A\""),
|
||||||
|
|
||||||
"( \" A \" INVALID\n"
|
"( \"A\" INVALID\n"
|
||||||
"(\"A\") INVALID\n"
|
"(\"A\") INVALID\n"
|
||||||
);
|
);
|
||||||
|
|
||||||
TS_ASSERT_EQUALS(
|
TS_ASSERT_EQUALS(
|
||||||
printedQueryTree("\"A\")"),
|
printedQueryTree("\"A\")"),
|
||||||
|
|
||||||
"\" A \" ) INVALID\n"
|
"\"A\" ) INVALID\n"
|
||||||
);
|
);
|
||||||
|
|
||||||
TS_ASSERT_EQUALS(
|
TS_ASSERT_EQUALS(
|
||||||
@@ -248,7 +267,7 @@ public:
|
|||||||
TS_ASSERT_EQUALS(
|
TS_ASSERT_EQUALS(
|
||||||
printedQueryTree("\"A\"(\"B\")"),
|
printedQueryTree("\"A\"(\"B\")"),
|
||||||
|
|
||||||
"\" A \" ( \" B \" ) \n"
|
"\"A\" ( \"B\" )\n"
|
||||||
" \"A\"\n"
|
" \"A\"\n"
|
||||||
".\n"
|
".\n"
|
||||||
" (\"B\")\n"
|
" (\"B\")\n"
|
||||||
@@ -260,7 +279,7 @@ public:
|
|||||||
TS_ASSERT_EQUALS(
|
TS_ASSERT_EQUALS(
|
||||||
printedQueryTree("!method.!const"),
|
printedQueryTree("!method.!const"),
|
||||||
|
|
||||||
"! method . ! const \n"
|
"! method . ! const\n"
|
||||||
" !\n"
|
" !\n"
|
||||||
" method\n"
|
" method\n"
|
||||||
".\n"
|
".\n"
|
||||||
@@ -274,7 +293,7 @@ public:
|
|||||||
TS_ASSERT_EQUALS(
|
TS_ASSERT_EQUALS(
|
||||||
printedQueryTree("namespace.class:method"),
|
printedQueryTree("namespace.class:method"),
|
||||||
|
|
||||||
"namespace . class : method \n"
|
"namespace . class : method\n"
|
||||||
" namespace\n"
|
" namespace\n"
|
||||||
" .\n"
|
" .\n"
|
||||||
" class\n"
|
" class\n"
|
||||||
@@ -288,7 +307,7 @@ public:
|
|||||||
TS_ASSERT_EQUALS(
|
TS_ASSERT_EQUALS(
|
||||||
printedQueryTree("class:method|field"),
|
printedQueryTree("class:method|field"),
|
||||||
|
|
||||||
"class : method | field \n"
|
"class : method | field\n"
|
||||||
" class\n"
|
" class\n"
|
||||||
" :\n"
|
" :\n"
|
||||||
" method\n"
|
" method\n"
|
||||||
@@ -302,7 +321,7 @@ public:
|
|||||||
TS_ASSERT_EQUALS(
|
TS_ASSERT_EQUALS(
|
||||||
printedQueryTree("namespace.(class:method)"),
|
printedQueryTree("namespace.(class:method)"),
|
||||||
|
|
||||||
"namespace . ( class : method ) \n"
|
"namespace . ( class : method )\n"
|
||||||
" namespace\n"
|
" namespace\n"
|
||||||
".\n"
|
".\n"
|
||||||
" class\n"
|
" class\n"
|
||||||
@@ -313,7 +332,7 @@ public:
|
|||||||
TS_ASSERT_EQUALS(
|
TS_ASSERT_EQUALS(
|
||||||
printedQueryTree("class:(method|field)"),
|
printedQueryTree("class:(method|field)"),
|
||||||
|
|
||||||
"class : ( method | field ) \n"
|
"class : ( method | field )\n"
|
||||||
" class\n"
|
" class\n"
|
||||||
":\n"
|
":\n"
|
||||||
" method\n"
|
" method\n"
|
||||||
@@ -327,7 +346,7 @@ public:
|
|||||||
TS_ASSERT_EQUALS(
|
TS_ASSERT_EQUALS(
|
||||||
printedQueryTree(" \"Field \":(method | field) .const | public "),
|
printedQueryTree(" \"Field \":(method | field) .const | public "),
|
||||||
|
|
||||||
"\" Field \" : ( method | field ) . const | public \n"
|
"\"Field\" : ( method | field ) . const | public\n"
|
||||||
" \"Field\"\n"
|
" \"Field\"\n"
|
||||||
" :\n"
|
" :\n"
|
||||||
" method\n"
|
" method\n"
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ public:
|
|||||||
std::vector<SearchIndex::SearchMatch> matches = index.findFuzzyMatches("u");
|
std::vector<SearchIndex::SearchMatch> matches = index.findFuzzyMatches("u");
|
||||||
|
|
||||||
TS_ASSERT_EQUALS(1, matches.size());
|
TS_ASSERT_EQUALS(1, matches.size());
|
||||||
TS_ASSERT_EQUALS("util", matches[0].node->getName());
|
TS_ASSERT_EQUALS("util", matches[0].fullName);
|
||||||
|
|
||||||
TS_ASSERT_EQUALS(1, matches[0].indices.size());
|
TS_ASSERT_EQUALS(1, matches[0].indices.size());
|
||||||
TS_ASSERT_EQUALS(0, matches[0].indices[0]);
|
TS_ASSERT_EQUALS(0, matches[0].indices[0]);
|
||||||
@@ -120,14 +120,14 @@ public:
|
|||||||
std::vector<SearchIndex::SearchMatch> matches = index.findFuzzyMatches("t");
|
std::vector<SearchIndex::SearchMatch> matches = index.findFuzzyMatches("t");
|
||||||
|
|
||||||
TS_ASSERT_EQUALS(2, matches.size());
|
TS_ASSERT_EQUALS(2, matches.size());
|
||||||
TS_ASSERT_EQUALS("MATH", matches[0].node->getName());
|
TS_ASSERT_EQUALS("MATH", matches[0].fullName);
|
||||||
TS_ASSERT_EQUALS("util", matches[1].node->getName());
|
TS_ASSERT_EQUALS("util", matches[1].fullName);
|
||||||
|
|
||||||
matches = index.findFuzzyMatches("T");
|
matches = index.findFuzzyMatches("T");
|
||||||
|
|
||||||
TS_ASSERT_EQUALS(2, matches.size());
|
TS_ASSERT_EQUALS(2, matches.size());
|
||||||
TS_ASSERT_EQUALS("MATH", matches[0].node->getName());
|
TS_ASSERT_EQUALS("MATH", matches[0].fullName);
|
||||||
TS_ASSERT_EQUALS("util", matches[1].node->getName());
|
TS_ASSERT_EQUALS("util", matches[1].fullName);
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_fuzzy_matching_wheighs_by_distance_and_alphabet()
|
void test_fuzzy_matching_wheighs_by_distance_and_alphabet()
|
||||||
@@ -140,9 +140,9 @@ public:
|
|||||||
std::vector<SearchIndex::SearchMatch> matches = index.findFuzzyMatches("t");
|
std::vector<SearchIndex::SearchMatch> matches = index.findFuzzyMatches("t");
|
||||||
|
|
||||||
TS_ASSERT_EQUALS(3, matches.size());
|
TS_ASSERT_EQUALS(3, matches.size());
|
||||||
TS_ASSERT_EQUALS("string", matches[0].node->getName());
|
TS_ASSERT_EQUALS("string", matches[0].fullName);
|
||||||
TS_ASSERT_EQUALS("util", matches[1].node->getName());
|
TS_ASSERT_EQUALS("util", matches[1].fullName);
|
||||||
TS_ASSERT_EQUALS("math", matches[2].node->getName());
|
TS_ASSERT_EQUALS("math", matches[2].fullName);
|
||||||
|
|
||||||
TS_ASSERT_EQUALS(1, matches[0].indices.size());
|
TS_ASSERT_EQUALS(1, matches[0].indices.size());
|
||||||
TS_ASSERT_EQUALS(1, matches[0].indices[0]);
|
TS_ASSERT_EQUALS(1, matches[0].indices[0]);
|
||||||
@@ -163,8 +163,8 @@ public:
|
|||||||
std::vector<SearchIndex::SearchMatch> matches = index.findFuzzyMatches("t");
|
std::vector<SearchIndex::SearchMatch> matches = index.findFuzzyMatches("t");
|
||||||
|
|
||||||
TS_ASSERT_EQUALS(2, matches.size());
|
TS_ASSERT_EQUALS(2, matches.size());
|
||||||
TS_ASSERT_EQUALS("uTil", matches[0].node->getName());
|
TS_ASSERT_EQUALS("uTil", matches[0].fullName);
|
||||||
TS_ASSERT_EQUALS("string", matches[1].node->getName());
|
TS_ASSERT_EQUALS("string", matches[1].fullName);
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_fuzzy_matching_wheighs_higher_on_consecutive_letters()
|
void test_fuzzy_matching_wheighs_higher_on_consecutive_letters()
|
||||||
@@ -176,8 +176,8 @@ public:
|
|||||||
std::vector<SearchIndex::SearchMatch> matches = index.findFuzzyMatches("abc");
|
std::vector<SearchIndex::SearchMatch> matches = index.findFuzzyMatches("abc");
|
||||||
|
|
||||||
TS_ASSERT_EQUALS(2, matches.size());
|
TS_ASSERT_EQUALS(2, matches.size());
|
||||||
TS_ASSERT_EQUALS("ocbaabc", matches[0].node->getName());
|
TS_ASSERT_EQUALS("ocbaabc", matches[0].fullName);
|
||||||
TS_ASSERT_EQUALS("oaabbcc", matches[1].node->getName());
|
TS_ASSERT_EQUALS("oaabbcc", matches[1].fullName);
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_fuzzy_matching_in_hierarchy()
|
void test_fuzzy_matching_in_hierarchy()
|
||||||
@@ -190,13 +190,13 @@ public:
|
|||||||
std::vector<SearchIndex::SearchMatch> matches = index.findFuzzyMatches("t");
|
std::vector<SearchIndex::SearchMatch> matches = index.findFuzzyMatches("t");
|
||||||
|
|
||||||
TS_ASSERT_EQUALS(1, matches.size());
|
TS_ASSERT_EQUALS(1, matches.size());
|
||||||
TS_ASSERT_EQUALS("util", matches[0].node->getName());
|
TS_ASSERT_EQUALS("util", matches[0].fullName);
|
||||||
|
|
||||||
matches = index.findFuzzyMatches("uml");
|
matches = index.findFuzzyMatches("uml");
|
||||||
|
|
||||||
TS_ASSERT_EQUALS(2, matches.size());
|
TS_ASSERT_EQUALS(2, matches.size());
|
||||||
TS_ASSERT_EQUALS("floor", matches[0].node->getName());
|
TS_ASSERT_EQUALS("util::math::floor", matches[0].fullName);
|
||||||
TS_ASSERT_EQUALS("ceil", matches[1].node->getName());
|
TS_ASSERT_EQUALS("util::math::ceil", matches[1].fullName);
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_fuzzy_matching_in_hierarchy_respects_collin()
|
void test_fuzzy_matching_in_hierarchy_respects_collin()
|
||||||
@@ -209,13 +209,13 @@ public:
|
|||||||
std::vector<SearchIndex::SearchMatch> matches = index.findFuzzyMatches("u:i");
|
std::vector<SearchIndex::SearchMatch> matches = index.findFuzzyMatches("u:i");
|
||||||
|
|
||||||
TS_ASSERT_EQUALS(2, matches.size());
|
TS_ASSERT_EQUALS(2, matches.size());
|
||||||
TS_ASSERT_EQUALS("string", matches[0].node->getName());
|
TS_ASSERT_EQUALS("util::string", matches[0].fullName);
|
||||||
TS_ASSERT_EQUALS("ceil", matches[1].node->getName());
|
TS_ASSERT_EQUALS("util::math::ceil", matches[1].fullName);
|
||||||
|
|
||||||
matches = index.findFuzzyMatches("u:t:i");
|
matches = index.findFuzzyMatches("u:t:i");
|
||||||
|
|
||||||
TS_ASSERT_EQUALS(1, matches.size());
|
TS_ASSERT_EQUALS(1, matches.size());
|
||||||
TS_ASSERT_EQUALS("ceil", matches[0].node->getName());
|
TS_ASSERT_EQUALS("util::math::ceil", matches[0].fullName);
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_fuzzy_matching_in_hierarchy_weighs_front_letters_higher()
|
void test_fuzzy_matching_in_hierarchy_weighs_front_letters_higher()
|
||||||
@@ -227,8 +227,8 @@ public:
|
|||||||
std::vector<SearchIndex::SearchMatch> matches = index.findFuzzyMatches("g");
|
std::vector<SearchIndex::SearchMatch> matches = index.findFuzzyMatches("g");
|
||||||
|
|
||||||
TS_ASSERT_EQUALS(2, matches.size());
|
TS_ASSERT_EQUALS(2, matches.size());
|
||||||
TS_ASSERT_EQUALS("ghi", matches[0].node->getName());
|
TS_ASSERT_EQUALS("abc::dfe::ghi", matches[0].fullName);
|
||||||
TS_ASSERT_EQUALS("hgi", matches[1].node->getName());
|
TS_ASSERT_EQUALS("abc::hgi", matches[1].fullName);
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_fuzzy_matching_with_defined_start_node()
|
void test_fuzzy_matching_with_defined_start_node()
|
||||||
@@ -241,7 +241,7 @@ public:
|
|||||||
std::vector<SearchIndex::SearchMatch> matches = index.findFuzzyMatches("\"math\"c");
|
std::vector<SearchIndex::SearchMatch> matches = index.findFuzzyMatches("\"math\"c");
|
||||||
|
|
||||||
TS_ASSERT_EQUALS(1, matches.size());
|
TS_ASSERT_EQUALS(1, matches.size());
|
||||||
TS_ASSERT_EQUALS("ceil", matches[0].node->getName());
|
TS_ASSERT_EQUALS("math::ceil", matches[0].fullName);
|
||||||
|
|
||||||
matches = index.findFuzzyMatches("\"mathc");
|
matches = index.findFuzzyMatches("\"mathc");
|
||||||
TS_ASSERT_EQUALS(0, matches.size());
|
TS_ASSERT_EQUALS(0, matches.size());
|
||||||
|
|||||||
@@ -71,6 +71,46 @@ public:
|
|||||||
TS_ASSERT_EQUALS(result[2], "");
|
TS_ASSERT_EQUALS(result[2], "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void test_join_with_char_delimiter()
|
||||||
|
{
|
||||||
|
std::vector<std::string> list;
|
||||||
|
list.push_back("A");
|
||||||
|
list.push_back("B");
|
||||||
|
list.push_back("C");
|
||||||
|
|
||||||
|
std::string result = utility::join<std::vector<std::string> >(list, ',');
|
||||||
|
TS_ASSERT_EQUALS(result, "A,B,C");
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_join_with_string_delimiter()
|
||||||
|
{
|
||||||
|
std::vector<std::string> list;
|
||||||
|
list.push_back("A");
|
||||||
|
list.push_back("B");
|
||||||
|
list.push_back("C");
|
||||||
|
|
||||||
|
std::string result = utility::join<std::vector<std::string> >(list, "==");
|
||||||
|
TS_ASSERT_EQUALS(result, "A==B==C");
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_join_on_empty_list()
|
||||||
|
{
|
||||||
|
std::vector<std::string> list;
|
||||||
|
std::string result = utility::join<std::vector<std::string> >(list, ',');
|
||||||
|
TS_ASSERT_EQUALS(result, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_join_with_empty_strings_in_list()
|
||||||
|
{
|
||||||
|
std::vector<std::string> list;
|
||||||
|
list.push_back("A");
|
||||||
|
list.push_back("");
|
||||||
|
list.push_back("");
|
||||||
|
|
||||||
|
std::string result = utility::join<std::vector<std::string> >(list, ':');
|
||||||
|
TS_ASSERT_EQUALS(result, "A::");
|
||||||
|
}
|
||||||
|
|
||||||
void test_tokenize_with_string()
|
void test_tokenize_with_string()
|
||||||
{
|
{
|
||||||
std::vector<std::string> result = utility::tokenize<std::vector<std::string> >("A->B->C", "->");
|
std::vector<std::string> result = utility::tokenize<std::vector<std::string> >("A->B->C", "->");
|
||||||
|
|||||||
Reference in New Issue
Block a user