ui: integrated autocompletion and filtering into SearchView

- QtSearchView was split into QtSearchView and QtSearchBox.
- QtSearchBox contains all Qt elements and can use them purely
- QtSearchView forwards calls from the SearchController to QtSearchBox
- Searching is initiated with MessageSearch to the SearchController
- Autocompletion is initiated with MessageSearchAutocomplete to the SearchController
- The search field is able to create filter queries by only giving autocompletions for the last token in the query
- For named tokens the search field adds their token ids to the query in the form of "A,25" for faster lookup

bug id = #21
This commit is contained in:
Eberhard Graether
2014-09-11 14:53:03 +02:00
parent 760e5ffafd
commit fec7abbc9b
48 changed files with 786 additions and 391 deletions
-27
View File
@@ -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();
}
}
-25
View File
@@ -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
-43
View File
@@ -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());
}
}
-28
View File
@@ -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
+147
View File
@@ -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;
}
+48
View File
@@ -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