summaryrefslogtreecommitdiff
path: root/ui/qt/syntax_line_edit.cpp
diff options
context:
space:
mode:
authorGerald Combs <gerald@wireshark.org>2015-05-19 10:18:54 -0700
committerGerald Combs <gerald@wireshark.org>2015-05-20 03:03:58 +0000
commitaf054591c31fdccd8661c87bb3d28cdeb3077db3 (patch)
treea115ca9125de66b8764c6ce3e284cee4c40dd021 /ui/qt/syntax_line_edit.cpp
parentfd985194f590225d4a41a8291cf9afae12f1b013 (diff)
downloadwireshark-af054591c31fdccd8661c87bb3d28cdeb3077db3.tar.gz
Add capture filter autocompletion.
Autocomplete on recent and saved capture filters along with the primitives in gencode.l in the libpcap sources. Move common autocomplete code to SyntaxLineEdit. Change-Id: I0931a6775bacf9c917c294befbbdaade51d19b93 Reviewed-on: https://code.wireshark.org/review/8542 Petri-Dish: Gerald Combs <gerald@wireshark.org> Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org> Reviewed-by: Gerald Combs <gerald@wireshark.org>
Diffstat (limited to 'ui/qt/syntax_line_edit.cpp')
-rw-r--r--ui/qt/syntax_line_edit.cpp139
1 files changed, 138 insertions, 1 deletions
diff --git a/ui/qt/syntax_line_edit.cpp b/ui/qt/syntax_line_edit.cpp
index 867c01d38a..ac1b029a9f 100644
--- a/ui/qt/syntax_line_edit.cpp
+++ b/ui/qt/syntax_line_edit.cpp
@@ -31,12 +31,43 @@
#include "color_utils.h"
+#include <QAbstractItemView>
+#include <QCompleter>
+#include <QKeyEvent>
+#include <QScrollBar>
+#include <QStringListModel>
+
+const int max_completion_items_ = 20;
+
SyntaxLineEdit::SyntaxLineEdit(QWidget *parent) :
- QLineEdit(parent)
+ QLineEdit(parent),
+ completer_(NULL),
+ completion_model_(NULL)
{
setSyntaxState();
}
+// Override setCompleter so that we don't clobber the filter text on activate.
+void SyntaxLineEdit::setCompleter(QCompleter *c)
+{
+ if (completer_)
+ QObject::disconnect(completer_, 0, this, 0);
+
+ completer_ = c;
+
+ if (!completer_)
+ return;
+
+ completer_->setWidget(this);
+ completer_->setCompletionMode(QCompleter::PopupCompletion);
+ completer_->setCaseSensitivity(Qt::CaseInsensitive);
+ // Completion items are not guaranteed to be sorted (recent filters +
+ // fields), so no setModelSorting.
+ completer_->setMaxVisibleItems(max_completion_items_);
+ QObject::connect(completer_, SIGNAL(activated(QString)),
+ this, SLOT(insertFieldCompletion(QString)));
+}
+
void SyntaxLineEdit::setSyntaxState(SyntaxState state) {
syntax_state_ = state;
state_style_sheet_ = QString(
@@ -144,3 +175,109 @@ void SyntaxLineEdit::checkInteger(QString number)
setSyntaxState(SyntaxLineEdit::Invalid);
}
}
+
+bool SyntaxLineEdit::isComplexFilter(const QString &filter)
+{
+ bool is_complex = false;
+ for (int i = 0; i < filter.length(); i++) {
+ if (!token_chars_.contains(filter.at(i))) {
+ is_complex = true;
+ break;
+ }
+ }
+ // Don't complete the current filter.
+ if (is_complex && filter.startsWith(text()) && filter.compare(text())) {
+ return true;
+ }
+ return false;
+}
+
+void SyntaxLineEdit::completionKeyPressEvent(QKeyEvent *event)
+{
+ // Forward to the completer if needed...
+ if (completer_ && completer_->popup()->isVisible()) {
+ switch (event->key()) {
+ case Qt::Key_Enter:
+ case Qt::Key_Return:
+ case Qt::Key_Escape:
+ case Qt::Key_Tab:
+ case Qt::Key_Backtab:
+ event->ignore();
+ return;
+ default:
+ break;
+ }
+ }
+
+ // ...otherwise process the key ourselves.
+ SyntaxLineEdit::keyPressEvent(event);
+
+ if (!completer_ || !completion_model_) return;
+
+ // Do nothing on bare shift.
+ if ((event->modifiers() & Qt::ShiftModifier) && event->text().isEmpty()) return;
+
+ if (event->modifiers() & (Qt::ControlModifier | Qt::AltModifier | Qt::MetaModifier)) {
+ completer_->popup()->hide();
+ return;
+ }
+
+ QPoint token_coords(getTokenUnderCursor());
+
+ QString token_word = text().mid(token_coords.x(), token_coords.y());
+ buildCompletionList(token_word);
+
+ if (completion_model_->stringList().length() < 1) {
+ completer_->popup()->hide();
+ return;
+ }
+
+ QRect cr = cursorRect();
+ cr.setWidth(completer_->popup()->sizeHintForColumn(0)
+ + completer_->popup()->verticalScrollBar()->sizeHint().width());
+ completer_->complete(cr);
+}
+
+void SyntaxLineEdit::completionFocusInEvent(QFocusEvent *event)
+{
+ if (completer_)
+ completer_->setWidget(this);
+ SyntaxLineEdit::focusInEvent(event);
+}
+
+void SyntaxLineEdit::insertFieldCompletion(const QString &completion_text)
+{
+ if (!completer_) return;
+
+ QPoint field_coords(getTokenUnderCursor());
+
+ // Insert only if we have a matching field or if the entry is empty
+ if (field_coords.y() < 1 && !text().isEmpty()) {
+ completer_->popup()->hide();
+ return;
+ }
+
+ QString new_text = text().replace(field_coords.x(), field_coords.y(), completion_text);
+ setText(new_text);
+ setCursorPosition(field_coords.x() + completion_text.length());
+}
+
+QPoint SyntaxLineEdit::getTokenUnderCursor()
+{
+ if (selectionStart() >= 0) return (QPoint(0,0));
+
+ int pos = cursorPosition();
+ int start = pos;
+ int len = 0;
+
+ while (start > 0 && token_chars_.contains(text().at(start -1))) {
+ start--;
+ len++;
+ }
+ while (pos < text().length() && token_chars_.contains(text().at(pos))) {
+ pos++;
+ len++;
+ }
+
+ return QPoint(start, len);
+}