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:
@@ -9,14 +9,12 @@ add_files(
|
||||
qt/element/QtCodeFile.h
|
||||
qt/element/QtCodeFileList.cpp
|
||||
qt/element/QtCodeFileList.h
|
||||
qt/element/QtButton.cpp
|
||||
qt/element/QtButton.h
|
||||
qt/element/QtCodeSnippet.cpp
|
||||
qt/element/QtCodeSnippet.h
|
||||
qt/element/QtEditBox.cpp
|
||||
qt/element/QtEditBox.h
|
||||
qt/element/QtMainWindow.cpp
|
||||
qt/element/QtMainWindow.h
|
||||
qt/element/QtSearchBox.cpp
|
||||
qt/element/QtSearchBox.h
|
||||
|
||||
qt/utility/QtHighLighter.cpp
|
||||
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 <QAbstractItemView>
|
||||
#include <QCompleter>
|
||||
#include <QFrame>
|
||||
#include <QHBoxLayout>
|
||||
|
||||
#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 "utility/text/TextAccess.h"
|
||||
|
||||
@@ -19,6 +11,8 @@ QtSearchView::QtSearchView(ViewLayout* viewLayout)
|
||||
, m_setFocusFunctor(std::bind(&QtSearchView::doSetFocus, this))
|
||||
, m_setAutocompletionListFunctor(std::bind(&QtSearchView::doSetAutocompletionList, this, std::placeholders::_1))
|
||||
{
|
||||
m_widget = std::make_shared<QtSearchBox>();
|
||||
setStyleSheet();
|
||||
}
|
||||
|
||||
QtSearchView::~QtSearchView()
|
||||
@@ -27,37 +21,11 @@ QtSearchView::~QtSearchView()
|
||||
|
||||
void QtSearchView::createWidgetWrapper()
|
||||
{
|
||||
setWidgetWrapper(std::make_shared<QtViewWidgetWrapper>(std::make_shared<QFrame>()));
|
||||
setWidgetWrapper(std::make_shared<QtViewWidgetWrapper>(m_widget));
|
||||
}
|
||||
|
||||
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()
|
||||
@@ -65,9 +33,9 @@ void QtSearchView::refreshView()
|
||||
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()
|
||||
@@ -75,51 +43,30 @@ void QtSearchView::setFocus()
|
||||
m_setFocusFunctor();
|
||||
}
|
||||
|
||||
void QtSearchView::setAutocompletionList(const std::vector<std::string>& autocompletionList)
|
||||
void QtSearchView::setAutocompletionList(const std::vector<SearchIndex::SearchMatch>& autocompletionList)
|
||||
{
|
||||
m_setAutocompletionListFunctor(autocompletionList);
|
||||
}
|
||||
|
||||
void QtSearchView::onSearchButtonClick()
|
||||
{
|
||||
SearchController* controller = getController();
|
||||
if (controller)
|
||||
{
|
||||
controller->search(m_searchBox->text().toStdString());
|
||||
}
|
||||
}
|
||||
|
||||
void QtSearchView::doRefreshView()
|
||||
{
|
||||
setStyleSheet();
|
||||
}
|
||||
|
||||
void QtSearchView::doSetText(const std::string& s)
|
||||
void QtSearchView::doSetText(const std::string& text)
|
||||
{
|
||||
if (m_searchBox->text() != s.c_str())
|
||||
{
|
||||
m_searchBox->setText(s.c_str());
|
||||
}
|
||||
m_widget->setText(text);
|
||||
}
|
||||
|
||||
void QtSearchView::doSetFocus()
|
||||
{
|
||||
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;
|
||||
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);
|
||||
m_widget->setAutocompletionList(autocompletionList);
|
||||
setStyleSheet();
|
||||
}
|
||||
|
||||
@@ -127,11 +74,10 @@ void QtSearchView::setStyleSheet()
|
||||
{
|
||||
std::string css = TextAccess::createFromFile("data/gui/search_view/search_view.css")->getText();
|
||||
|
||||
QWidget* widget = QtViewWidgetWrapper::getWidgetOfView(this);
|
||||
widget->setStyleSheet(css.c_str());
|
||||
m_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 "component/view/SearchView.h"
|
||||
#include "qt/element/QtSearchBox.h"
|
||||
#include "qt/utility/QtThreadedFunctor.h"
|
||||
|
||||
class QtEditBox;
|
||||
class QtButton;
|
||||
|
||||
class QtSearchView: public SearchView
|
||||
{
|
||||
public:
|
||||
@@ -21,28 +19,24 @@ public:
|
||||
virtual void refreshView();
|
||||
|
||||
// SearchView implementation
|
||||
virtual void setText(const std::string& s);
|
||||
virtual void setText(const std::string& text);
|
||||
virtual void setFocus();
|
||||
virtual void setAutocompletionList(const std::vector<std::string>& autocompletionList);
|
||||
virtual void setAutocompletionList(const std::vector<SearchIndex::SearchMatch>& autocompletionList);
|
||||
|
||||
private:
|
||||
void onSearchButtonClick();
|
||||
|
||||
void doRefreshView();
|
||||
void doSetText(const std::string& s);
|
||||
void doSetText(const std::string& text);
|
||||
void doSetFocus();
|
||||
void doSetAutocompletionList(const std::vector<std::string>& autocompletionList);
|
||||
void doSetAutocompletionList(const std::vector<SearchIndex::SearchMatch>& autocompletionList);
|
||||
|
||||
void setStyleSheet();
|
||||
|
||||
QtEditBox* m_searchBox;
|
||||
QtButton* m_searchButton;
|
||||
QtButton* m_caseSensitiveButton;
|
||||
|
||||
QtThreadedFunctor<> m_refreshViewFunctor;
|
||||
QtThreadedFunctor<const std::string&> m_setTextFunctor;
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user