Qt: Enable capture filter bookmarks

Update the code handling capture filter bookmarks and enable the
bookmark button and clear button in CaptureFilterEdit().

Disable the apply button (which starts a capture) for now.

Bug: 11836
Change-Id: Ia33cbb8c9bb839be037112eef26daf744c4ea8f8
Reviewed-on: https://code.wireshark.org/review/13568
Reviewed-by: Stig Bjørlykke <stig@bjorlykke.org>
This commit is contained in:
Stig Bjørlykke 2016-01-27 21:33:24 +01:00
parent 268c0e56fb
commit 3c1d05d5a0
6 changed files with 167 additions and 13 deletions

View File

@ -34,7 +34,7 @@ CaptureFilterCombo::CaptureFilterCombo(QWidget *parent) :
QComboBox(parent), QComboBox(parent),
cf_edit_(NULL) cf_edit_(NULL)
{ {
cf_edit_ = new CaptureFilterEdit(this, true); cf_edit_ = new CaptureFilterEdit(this, false);
setEditable(true); setEditable(true);
// Enabling autocompletion here gives us two simultaneous completions: // Enabling autocompletion here gives us two simultaneous completions:

View File

@ -33,11 +33,14 @@
#include "capture_filter_edit.h" #include "capture_filter_edit.h"
#include "capture_filter_syntax_worker.h" #include "capture_filter_syntax_worker.h"
#include "filter_dialog.h"
#include "stock_icon_tool_button.h" #include "stock_icon_tool_button.h"
#include "wireshark_application.h" #include "wireshark_application.h"
#include <QComboBox> #include <QComboBox>
#include <QCompleter> #include <QCompleter>
#include <QMenu>
#include <QMessageBox>
#include <QPainter> #include <QPainter>
#include <QStringListModel> #include <QStringListModel>
#include <QStyleOptionFrame> #include <QStyleOptionFrame>
@ -110,6 +113,9 @@ CaptureFilterEdit::CaptureFilterEdit(QWidget *parent, bool plain) :
SyntaxLineEdit(parent), SyntaxLineEdit(parent),
plain_(plain), plain_(plain),
field_name_only_(false), field_name_only_(false),
enable_save_action_(false),
save_action_(NULL),
remove_action_(NULL),
bookmark_button_(NULL), bookmark_button_(NULL),
clear_button_(NULL), clear_button_(NULL),
apply_button_(NULL) apply_button_(NULL)
@ -125,11 +131,10 @@ CaptureFilterEdit::CaptureFilterEdit(QWidget *parent, bool plain) :
setPlaceholderText(placeholder_text_); setPlaceholderText(placeholder_text_);
#endif #endif
// These are fully implemented in DisplayFilterEdit but not here.
if (!plain_) { if (!plain_) {
bookmark_button_ = new StockIconToolButton(this, "x-filter-bookmark"); bookmark_button_ = new StockIconToolButton(this, "x-filter-bookmark");
bookmark_button_->setCursor(Qt::ArrowCursor); bookmark_button_->setCursor(Qt::ArrowCursor);
bookmark_button_->setMenu(new QMenu());
bookmark_button_->setPopupMode(QToolButton::InstantPopup); bookmark_button_->setPopupMode(QToolButton::InstantPopup);
bookmark_button_->setToolTip(tr("Manage saved bookmarks.")); bookmark_button_->setToolTip(tr("Manage saved bookmarks."));
bookmark_button_->setIconSize(QSize(14, 14)); bookmark_button_->setIconSize(QSize(14, 14));
@ -162,6 +167,8 @@ CaptureFilterEdit::CaptureFilterEdit(QWidget *parent, bool plain) :
connect(this, SIGNAL(textChanged(const QString&)), this, SLOT(checkFilter(const QString&))); connect(this, SIGNAL(textChanged(const QString&)), this, SLOT(checkFilter(const QString&)));
#if 0
// Disable the apply button for now
if (!plain_) { if (!plain_) {
apply_button_ = new StockIconToolButton(this, "x-filter-apply"); apply_button_ = new StockIconToolButton(this, "x-filter-apply");
apply_button_->setCursor(Qt::ArrowCursor); apply_button_->setCursor(Qt::ArrowCursor);
@ -177,6 +184,7 @@ CaptureFilterEdit::CaptureFilterEdit(QWidget *parent, bool plain) :
); );
connect(apply_button_, SIGNAL(clicked()), this, SLOT(applyCaptureFilter())); connect(apply_button_, SIGNAL(clicked()), this, SLOT(applyCaptureFilter()));
} }
#endif
connect(this, SIGNAL(returnPressed()), this, SLOT(applyCaptureFilter())); connect(this, SIGNAL(returnPressed()), this, SLOT(applyCaptureFilter()));
int frameWidth = style()->pixelMetric(QStyle::PM_DefaultFrameWidth); int frameWidth = style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
@ -203,20 +211,34 @@ CaptureFilterEdit::CaptureFilterEdit(QWidget *parent, bool plain) :
syntax_worker_ = new CaptureFilterSyntaxWorker; syntax_worker_ = new CaptureFilterSyntaxWorker;
syntax_worker_->moveToThread(syntax_thread); syntax_worker_->moveToThread(syntax_thread);
connect(wsApp, SIGNAL(appInitialized()), this, SLOT(initCaptureFilter())); connect(wsApp, SIGNAL(appInitialized()), this, SLOT(initCaptureFilter()));
connect(wsApp, SIGNAL(captureFilterListChanged()), this, SLOT(updateBookmarkMenu()));
connect(syntax_thread, SIGNAL(started()), syntax_worker_, SLOT(start())); connect(syntax_thread, SIGNAL(started()), syntax_worker_, SLOT(start()));
connect(syntax_thread, SIGNAL(started()), this, SLOT(checkFilter())); connect(syntax_thread, SIGNAL(started()), this, SLOT(checkFilter()));
connect(syntax_worker_, SIGNAL(syntaxResult(QString,int,QString)), connect(syntax_worker_, SIGNAL(syntaxResult(QString,int,QString)),
this, SLOT(setFilterSyntaxState(QString,int,QString))); this, SLOT(setFilterSyntaxState(QString,int,QString)));
connect(syntax_thread, SIGNAL(finished()), syntax_worker_, SLOT(deleteLater())); connect(syntax_thread, SIGNAL(finished()), syntax_worker_, SLOT(deleteLater()));
syntax_thread->start(); syntax_thread->start();
checkFilter();
} }
#if QT_VERSION < QT_VERSION_CHECK(4, 7, 0)
void CaptureFilterEdit::paintEvent(QPaintEvent *evt) { void CaptureFilterEdit::paintEvent(QPaintEvent *evt) {
SyntaxLineEdit::paintEvent(evt); SyntaxLineEdit::paintEvent(evt);
if (bookmark_button_) {
// Draw the right border by hand. We could try to do this in the
// style sheet but it's a pain.
#ifdef Q_OS_MAC
QColor divider_color = Qt::gray;
#else
QColor divider_color = palette().shadow().color();
#endif
QPainter painter(this);
painter.setPen(divider_color);
QRect cr = contentsRect();
QSize bksz = bookmark_button_->size();
painter.drawLine(bksz.width(), cr.top(), bksz.width(), cr.bottom());
}
#if QT_VERSION < QT_VERSION_CHECK(4, 7, 0)
// http://wiki.forum.nokia.com/index.php/Custom_QLineEdit // http://wiki.forum.nokia.com/index.php/Custom_QLineEdit
if (text().isEmpty() && ! this->hasFocus()) { if (text().isEmpty() && ! this->hasFocus()) {
QPainter p(this); QPainter p(this);
@ -238,8 +260,8 @@ void CaptureFilterEdit::paintEvent(QPaintEvent *evt) {
} }
// else check filter syntax and set the background accordingly // else check filter syntax and set the background accordingly
// XXX - Should we add little warning/error icons as well? // XXX - Should we add little warning/error icons as well?
}
#endif // QT < 4.7 #endif // QT < 4.7
}
void CaptureFilterEdit::resizeEvent(QResizeEvent *) void CaptureFilterEdit::resizeEvent(QResizeEvent *)
{ {
@ -274,7 +296,35 @@ void CaptureFilterEdit::checkFilter(const QString& filter)
bool empty = filter.isEmpty(); bool empty = filter.isEmpty();
if (bookmark_button_) { if (bookmark_button_) {
bookmark_button_->setEnabled(false); bool match = false;
for (GList *cf_item = get_filter_list_first(CFILTER_LIST); cf_item; cf_item = g_list_next(cf_item)) {
if (!cf_item->data) continue;
filter_def *cf_def = (filter_def *) cf_item->data;
if (!cf_def->name || !cf_def->strval) continue;
if (filter.compare(cf_def->strval) == 0) {
match = true;
}
}
if (match) {
bookmark_button_->setStockIcon("x-filter-matching-bookmark");
if (remove_action_) {
remove_action_->setData(text());
remove_action_->setVisible(true);
}
} else {
bookmark_button_->setStockIcon("x-filter-bookmark");
if (remove_action_) {
remove_action_->setVisible(false);
}
}
enable_save_action_ = (!match && !filter.isEmpty());
if (save_action_) {
save_action_->setEnabled(false);
}
} }
if (apply_button_) { if (apply_button_) {
@ -297,11 +347,46 @@ void CaptureFilterEdit::checkFilter()
checkFilter(text()); checkFilter(text());
} }
void CaptureFilterEdit::updateBookmarkMenu()
{
if (!bookmark_button_)
return;
QMenu *bb_menu = bookmark_button_->menu();
bb_menu->clear();
save_action_ = bb_menu->addAction(tr("Save this filter"));
connect(save_action_, SIGNAL(triggered(bool)), this, SLOT(saveFilter()));
remove_action_ = bb_menu->addAction(tr("Remove this filter"));
connect(remove_action_, SIGNAL(triggered(bool)), this, SLOT(removeFilter()));
QAction *manage_action = bb_menu->addAction(tr("Manage Capture Filters"));
connect(manage_action, SIGNAL(triggered(bool)), this, SLOT(showFilters()));
bb_menu->addSeparator();
for (GList *cf_item = get_filter_list_first(CFILTER_LIST); cf_item; cf_item = g_list_next(cf_item)) {
if (!cf_item->data) continue;
filter_def *cf_def = (filter_def *) cf_item->data;
if (!cf_def->name || !cf_def->strval) continue;
int one_em = bb_menu->fontMetrics().height();
QString prep_text = QString("%1: %2").arg(cf_def->name).arg(cf_def->strval);
prep_text = bb_menu->fontMetrics().elidedText(prep_text, Qt::ElideRight, one_em * 40);
QAction *prep_action = bb_menu->addAction(prep_text);
prep_action->setData(cf_def->strval);
connect(prep_action, SIGNAL(triggered(bool)), this, SLOT(prepareFilter()));
}
checkFilter();
}
void CaptureFilterEdit::initCaptureFilter() void CaptureFilterEdit::initCaptureFilter()
{ {
#ifdef HAVE_LIBPCAP #ifdef HAVE_LIBPCAP
setText(global_capture_opts.default_options.cfilter); setText(global_capture_opts.default_options.cfilter);
#endif // HAVE_LIBPCAP #endif // HAVE_LIBPCAP
updateBookmarkMenu();
} }
void CaptureFilterEdit::setFilterSyntaxState(QString filter, int state, QString err_msg) void CaptureFilterEdit::setFilterSyntaxState(QString filter, int state, QString err_msg)
@ -316,8 +401,8 @@ void CaptureFilterEdit::setFilterSyntaxState(QString filter, int state, QString
bool valid = (state != Invalid); bool valid = (state != Invalid);
if (valid) { if (valid) {
if (bookmark_button_) { if (save_action_) {
bookmark_button_->setEnabled(true); save_action_->setEnabled(enable_save_action_);
} }
if (apply_button_) { if (apply_button_) {
apply_button_->setEnabled(true); apply_button_->setEnabled(true);
@ -381,6 +466,61 @@ void CaptureFilterEdit::applyCaptureFilter()
emit startCapture(); emit startCapture();
} }
void CaptureFilterEdit::saveFilter()
{
FilterDialog capture_filter_dlg(window(), FilterDialog::CaptureFilter, text());
capture_filter_dlg.exec();
}
void CaptureFilterEdit::removeFilter()
{
QAction *ra = qobject_cast<QAction*>(sender());
if (!ra || ra->data().toString().isEmpty()) return;
QString remove_filter = ra->data().toString();
for (GList *cf_item = get_filter_list_first(CFILTER_LIST); cf_item; cf_item = g_list_next(cf_item)) {
if (!cf_item->data) continue;
filter_def *cf_def = (filter_def *) cf_item->data;
if (!cf_def->name || !cf_def->strval) continue;
if (remove_filter.compare(cf_def->strval) == 0) {
remove_from_filter_list(CFILTER_LIST, cf_item);
}
}
char *f_path;
int f_save_errno;
save_filter_list(CFILTER_LIST, &f_path, &f_save_errno);
if (f_path != NULL) {
// We had an error saving the filter.
QString warning_title = tr("Unable to save capture filter settings.");
QString warning_msg = tr("Could not save to your capture filter file\n\"%1\": %2.").arg(f_path).arg(g_strerror(f_save_errno));
QMessageBox::warning(this, warning_title, warning_msg, QMessageBox::Ok);
g_free(f_path);
}
updateBookmarkMenu();
}
void CaptureFilterEdit::showFilters()
{
FilterDialog capture_filter_dlg(window(), FilterDialog::CaptureFilter);
capture_filter_dlg.exec();
}
void CaptureFilterEdit::prepareFilter()
{
QAction *pa = qobject_cast<QAction*>(sender());
if (!pa || pa->data().toString().isEmpty()) return;
QString filter(pa->data().toString());
setText(filter);
emit textEdited(filter);
}
/* /*
* Editor modelines * Editor modelines
* *

View File

@ -36,15 +36,18 @@ public:
explicit CaptureFilterEdit(QWidget *parent = 0, bool plain = false); explicit CaptureFilterEdit(QWidget *parent = 0, bool plain = false);
protected: protected:
#if QT_VERSION < QT_VERSION_CHECK(4, 7, 0)
void paintEvent(QPaintEvent *evt); void paintEvent(QPaintEvent *evt);
#endif
void resizeEvent(QResizeEvent *); void resizeEvent(QResizeEvent *);
void keyPressEvent(QKeyEvent *event) { completionKeyPressEvent(event); } void keyPressEvent(QKeyEvent *event) { completionKeyPressEvent(event); }
void focusInEvent(QFocusEvent *event) { completionFocusInEvent(event); } void focusInEvent(QFocusEvent *event) { completionFocusInEvent(event); }
public slots: public slots:
void checkFilter(); void checkFilter();
void updateBookmarkMenu();
void saveFilter();
void removeFilter();
void showFilters();
void prepareFilter();
private slots: private slots:
void initCaptureFilter(); void initCaptureFilter();
@ -56,7 +59,10 @@ private slots:
private: private:
bool plain_; bool plain_;
bool field_name_only_; bool field_name_only_;
bool enable_save_action_;
QString placeholder_text_; QString placeholder_text_;
QAction *save_action_;
QAction *remove_action_;
StockIconToolButton *bookmark_button_; StockIconToolButton *bookmark_button_;
StockIconToolButton *clear_button_; StockIconToolButton *clear_button_;
StockIconToolButton *apply_button_; StockIconToolButton *apply_button_;

View File

@ -239,7 +239,9 @@ void FilterDialog::on_buttonBox_accepted()
g_free(f_path); g_free(f_path);
} }
if (filter_type_ == DisplayFilter) { if (filter_type_ == CaptureFilter) {
wsApp->emitAppSignal(WiresharkApplication::CaptureFilterListChanged);
} else {
wsApp->emitAppSignal(WiresharkApplication::DisplayFilterListChanged); wsApp->emitAppSignal(WiresharkApplication::DisplayFilterListChanged);
} }
} }

View File

@ -385,6 +385,7 @@ void WiresharkApplication::setConfigurationProfile(const gchar *profile_name)
emit recentFilesRead(); emit recentFilesRead();
emit filterExpressionsChanged(); emit filterExpressionsChanged();
emit checkDisplayFilter(); emit checkDisplayFilter();
emit captureFilterListChanged();
emit displayFilterListChanged(); emit displayFilterListChanged();
/* Enable all protocols and disable from the disabled list */ /* Enable all protocols and disable from the disabled list */
@ -704,6 +705,9 @@ void WiresharkApplication::emitAppSignal(AppSignal signal)
case ColumnsChanged: case ColumnsChanged:
emit columnsChanged(); emit columnsChanged();
break; break;
case CaptureFilterListChanged:
emit captureFilterListChanged();
break;
case DisplayFilterListChanged: case DisplayFilterListChanged:
emit displayFilterListChanged(); emit displayFilterListChanged();
break; break;

View File

@ -63,6 +63,7 @@ public:
enum AppSignal { enum AppSignal {
ColumnsChanged, ColumnsChanged,
CaptureFilterListChanged,
DisplayFilterListChanged, DisplayFilterListChanged,
FilterExpressionsChanged, FilterExpressionsChanged,
PacketDissectionChanged, PacketDissectionChanged,
@ -149,6 +150,7 @@ signals:
void profileNameChanged(const gchar *profile_name); void profileNameChanged(const gchar *profile_name);
void columnsChanged(); // XXX This recreates the packet list. We might want to rename it accordingly. void columnsChanged(); // XXX This recreates the packet list. We might want to rename it accordingly.
void captureFilterListChanged();
void displayFilterListChanged(); void displayFilterListChanged();
void filterExpressionsChanged(); void filterExpressionsChanged();
void packetDissectionChanged(); void packetDissectionChanged();