ui: augmented autocompletion list

This change adds search match information to the autocompletion list:
- matching letters
- color for token or command
- node type as string
This commit is contained in:
Eberhard Graether
2014-11-02 17:21:51 +01:00
parent 250918a4e7
commit e972dbe098
14 changed files with 330 additions and 35 deletions
+188
View File
@@ -0,0 +1,188 @@
#include "qt/element/QtAutocompletionList.h"
#include <QPainter>
QtAutocompletionModel::QtAutocompletionModel(const std::vector<SearchMatch>& matchList, QObject* parent)
: QAbstractTableModel(parent)
, m_matchList(matchList)
{
}
QtAutocompletionModel::~QtAutocompletionModel()
{
}
int QtAutocompletionModel::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent);
return m_matchList.size();
}
int QtAutocompletionModel::columnCount(const QModelIndex &parent) const
{
Q_UNUSED(parent);
return 3;
}
QVariant QtAutocompletionModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid() || index.row() < 0 || size_t(index.row()) >= m_matchList.size() || role != Qt::DisplayRole)
{
return QVariant();
}
const SearchMatch& match = m_matchList[index.row()];
switch (index.column())
{
case 0:
return QString::fromStdString(match.fullName);
case 1:
return QString::fromStdString(match.typeName);
case 2:
{
QList<QVariant> indices;
for (const size_t idx : match.indices)
{
indices.push_back(quint64(idx));
}
return indices;
}
default:
return QVariant();
}
}
const SearchMatch* QtAutocompletionModel::getSearchMatchAt(int idx) const
{
if (idx >= 0 && size_t(idx) < m_matchList.size())
{
return &m_matchList[idx];
}
return nullptr;
}
QtAutocompletionDelegate::QtAutocompletionDelegate(QObject* parent)
: QItemDelegate(parent)
{
}
QtAutocompletionDelegate::~QtAutocompletionDelegate()
{
}
void QtAutocompletionDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const
{
QPen pen = painter->pen();
QFont font = painter->font();
if (option.state & QStyle::State_Selected)
{
QPen highlightPen = pen;
highlightPen.setColor(option.palette.color(QPalette::HighlightedText));
painter->setPen(highlightPen);
painter->fillRect(option.rect, option.palette.color(QPalette::Highlight));
}
else
{
painter->fillRect(option.rect, option.palette.color(QPalette::Base));
}
QFont higlightFont = font;
higlightFont.setWeight(QFont::Bold);
QString name = index.data().toString();
QList<QVariant> indices = index.sibling(index.row(), index.column() + 2).data().toList();
int idx = 0;
int x = 0;
int m = option.fontMetrics.width(QLatin1Char('9'));
for (int i = 0; i < name.size(); i++)
{
if (idx < indices.size() && i == indices[idx])
{
painter->setFont(higlightFont);
idx++;
}
else
{
painter->setFont(font);
}
painter->drawText(option.rect.adjusted(8 + x, 0, 0, 0), Qt::AlignLeft, name.at(i));
x += m;
}
if (font.pixelSize() > 0)
{
QFont typeFont = font;
typeFont.setPixelSize(0.8f * font.pixelSize());
painter->setFont(typeFont);
}
QString type = index.sibling(index.row(), index.column() + 1).data().toString();
QRect rect = option.rect.adjusted(1, 1, 0, -1);
rect.setWidth(5);
if (type.size())
{
painter->fillRect(rect, QColor(153, 22, 165));
painter->drawText(option.rect.adjusted(0, 0, -3, 0), Qt::AlignRight, type);
}
else
{
painter->fillRect(rect, QColor(172, 150, 0));
}
painter->setFont(font);
painter->setPen(pen);
}
QtAutocompletionList::QtAutocompletionList(const std::vector<SearchMatch>& autocompletionList, QWidget* parent)
: QCompleter(parent)
{
m_model = std::make_shared<QtAutocompletionModel>(autocompletionList, this);
setModel(m_model.get());
m_delegate = std::make_shared<QtAutocompletionDelegate>(this);
QListView* list = new QListView(parent);
list->setItemDelegateForColumn(0, m_delegate.get());
list->setObjectName("search_box_popup");
setPopup(list);
setCaseSensitivity(Qt::CaseInsensitive);
connect(this, SIGNAL(highlighted(const QModelIndex&)), this, SLOT(onHighlighted(const QModelIndex&)), Qt::DirectConnection);
connect(this, SIGNAL(activated(const QModelIndex&)), this, SLOT(onActivated(const QModelIndex&)), Qt::DirectConnection);
}
QtAutocompletionList::~QtAutocompletionList()
{
}
const SearchMatch* QtAutocompletionList::getSearchMatchAt(int idx) const
{
return m_model->getSearchMatchAt(idx);
}
void QtAutocompletionList::onHighlighted(const QModelIndex& index)
{
const SearchMatch* match = getSearchMatchAt(index.row());
if (match)
{
emit matchHighlighted(*match);
}
}
void QtAutocompletionList::onActivated(const QModelIndex& index)
{
const SearchMatch* match = getSearchMatchAt(index.row());
if (match)
{
emit matchActivated(*match);
}
}
+70
View File
@@ -0,0 +1,70 @@
#ifndef QT_AUTOCOMPLETION_LIST
#define QT_AUTOCOMPLETION_LIST
#include <memory>
#include <vector>
#include <QAbstractTableModel>
#include <QCompleter>
#include <QItemDelegate>
#include <QListView>
#include "data/search/SearchMatch.h"
class QtAutocompletionModel
: public QAbstractTableModel
{
Q_OBJECT
public:
QtAutocompletionModel(const std::vector<SearchMatch>& matchList, QObject* parent = 0);
virtual ~QtAutocompletionModel();
virtual int rowCount(const QModelIndex& parent) const;
virtual int columnCount(const QModelIndex& parent) const;
virtual QVariant data(const QModelIndex& index, int role) const;
const SearchMatch* getSearchMatchAt(int idx) const;
private:
const std::vector<SearchMatch>& m_matchList;
};
class QtAutocompletionDelegate
: public QItemDelegate
{
public:
explicit QtAutocompletionDelegate(QObject* parent = 0);
virtual ~QtAutocompletionDelegate();
virtual void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const;
};
class QtAutocompletionList
: public QCompleter
{
Q_OBJECT
signals:
void matchHighlighted(const SearchMatch&);
void matchActivated(const SearchMatch&);
public:
QtAutocompletionList(const std::vector<SearchMatch>& autocompletionList, QWidget* parent = 0);
virtual ~QtAutocompletionList();
const SearchMatch* getSearchMatchAt(int idx) const;
private slots:
void onHighlighted(const QModelIndex& index);
void onActivated(const QModelIndex& index);
private:
std::shared_ptr<QtAutocompletionModel> m_model;
std::shared_ptr<QtAutocompletionDelegate> m_delegate;
};
#endif // QT_AUTOCOMPLETION_LIST
+35 -26
View File
@@ -2,18 +2,18 @@
#include <stdlib.h>
#include <QAbstractItemView>
#include <QApplication>
#include <QClipboard>
#include <QCompleter>
#include <QKeyEvent>
#include "data/query/QueryTree.h"
#include "utility/messaging/type/MessageSearch.h"
#include "utility/messaging/type/MessageSearchAutocomplete.h"
#include "utility/text/TextAccess.h"
#include "utility/utilityString.h"
#include "data/query/QueryTree.h"
#include "qt/element/QtAutocompletionList.h"
QtQueryElement::QtQueryElement(const QString& text, QWidget* parent)
: QPushButton(text, parent)
{
@@ -54,29 +54,18 @@ QtSmartSearchBox::~QtSmartSearchBox()
void QtSmartSearchBox::setAutocompletionList(const std::vector<SearchMatch>& autocompletionList)
{
m_matches = autocompletionList;
if (!m_matches.size())
if (!autocompletionList.size())
{
setCompleter(0);
return;
}
QStringList wordList;
for (const SearchMatch& match: autocompletionList)
{
wordList << match.fullName.c_str();
}
QCompleter *completer = new QCompleter(wordList, this);
completer->popup()->setObjectName("search_box_popup");
completer->setCaseSensitivity(Qt::CaseInsensitive);
QCompleter* completer = new QtAutocompletionList(autocompletionList, this);
setCompleter(completer);
completer->complete();
completer->complete(QRect(textMargins().left() + 3, height(), 300, 1));
connect(completer, SIGNAL(highlighted(const QModelIndex&)), this, SLOT(onSearchCompletionHighlighted(const QModelIndex&)), Qt::DirectConnection);
connect(completer, SIGNAL(activated(const QModelIndex&)), this, SLOT(onSearchCompletionActivated(const QModelIndex&)), Qt::DirectConnection);
connect(completer, SIGNAL(matchHighlighted(const SearchMatch&)), this, SLOT(onAutocompletionHighlighted(const SearchMatch&)), Qt::DirectConnection);
connect(completer, SIGNAL(matchActivated(const SearchMatch&)), this, SLOT(onAutocompletionActivated(const SearchMatch&)), Qt::DirectConnection);
completer->popup()->setCurrentIndex(completer->completionModel()->index(0, 0));
}
@@ -96,6 +85,21 @@ void QtSmartSearchBox::setFocus()
selectAllElementsWith(true);
}
bool QtSmartSearchBox::event(QEvent *event)
{
if (event->type() == QEvent::KeyPress)
{
QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
if (keyEvent->key() == Qt::Key_Tab && completer() && completer()->popup()->isVisible())
{
onAutocompletionActivated(m_highlightedMatch);
return true;
}
}
return QWidget::event(event);
}
void QtSmartSearchBox::resizeEvent(QResizeEvent* event)
{
QLineEdit::resizeEvent(event);
@@ -371,19 +375,20 @@ void QtSmartSearchBox::onTextChanged(const QString& text)
updatePlaceholder();
}
void QtSmartSearchBox::onSearchCompletionHighlighted(const QModelIndex& index)
void QtSmartSearchBox::onAutocompletionHighlighted(const SearchMatch& match)
{
m_highlightedMatch = match;
}
void QtSmartSearchBox::onSearchCompletionActivated(const QModelIndex& index)
void QtSmartSearchBox::onAutocompletionActivated(const SearchMatch& match)
{
if (index.row() >= 0 && index.row() < int(m_matches.size()))
if (match.fullName.size())
{
m_oldText.clear();
clearLineEdit();
std::string match = m_matches[index.row()].encodeForQuery();
textToToken(match);
std::string name = match.encodeForQuery();
textToToken(name);
updateElements();
}
@@ -457,9 +462,13 @@ void QtSmartSearchBox::textToToken(std::string text)
return;
}
if (m_matches.size() && utility::equalsCaseInsensitive(text, m_matches.front().fullName))
if (completer())
{
text = m_matches.front().encodeForQuery();
const SearchMatch* match = dynamic_cast<QtAutocompletionList*>(completer())->getSearchMatchAt(0);
if (match && utility::equalsCaseInsensitive(text, match->fullName))
{
text = match->encodeForQuery();
}
}
m_tokens.insert(m_tokens.begin() + m_cursorIndex, text);
+4 -3
View File
@@ -43,6 +43,7 @@ public:
void setFocus();
protected:
virtual bool event(QEvent *event);
virtual void resizeEvent(QResizeEvent* event);
virtual void keyPressEvent(QKeyEvent* event);
virtual void keyReleaseEvent(QKeyEvent* event);
@@ -55,8 +56,8 @@ private slots:
void onTextEdited(const QString& text);
void onTextChanged(const QString& text);
void onSearchCompletionHighlighted(const QModelIndex& index);
void onSearchCompletionActivated(const QModelIndex& index);
void onAutocompletionHighlighted(const SearchMatch& match);
void onAutocompletionActivated(const SearchMatch& match);
void onElementSelected(QtQueryElement* element);
@@ -91,7 +92,7 @@ private:
size_t m_cursorIndex;
std::vector<SearchMatch> m_matches;
SearchMatch m_highlightedMatch;
bool m_shiftKeyDown;
bool m_mousePressed;