2012-01-04 22:13:01 +00:00
|
|
|
/* display_filter_edit.cpp
|
|
|
|
*
|
|
|
|
* Wireshark - Network traffic analyzer
|
|
|
|
* By Gerald Combs <gerald@wireshark.org>
|
|
|
|
* Copyright 1998 Gerald Combs
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
|
|
|
* of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
2012-06-28 22:56:06 +00:00
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
2012-01-04 22:13:01 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
|
|
|
#include <glib.h>
|
|
|
|
|
2013-12-03 23:08:46 +00:00
|
|
|
#include <epan/dfilter/dfilter.h>
|
2012-01-04 22:13:01 +00:00
|
|
|
|
2014-12-20 22:13:05 +00:00
|
|
|
#include <filter_files.h>
|
2015-05-18 23:56:57 +00:00
|
|
|
|
2015-10-04 17:10:29 +00:00
|
|
|
#include <wsutil/utf8_entities.h>
|
2015-03-03 20:27:10 +00:00
|
|
|
|
2012-01-04 22:13:01 +00:00
|
|
|
#include "display_filter_edit.h"
|
2015-09-02 21:51:33 +00:00
|
|
|
#include "filter_dialog.h"
|
2015-09-10 21:42:07 +00:00
|
|
|
#include "stock_icon_tool_button.h"
|
2012-10-08 20:01:59 +00:00
|
|
|
#include "syntax_line_edit.h"
|
2012-01-04 22:13:01 +00:00
|
|
|
|
2015-09-02 21:51:33 +00:00
|
|
|
#include <QAction>
|
2015-03-03 20:27:10 +00:00
|
|
|
#include <QAbstractItemView>
|
|
|
|
#include <QComboBox>
|
|
|
|
#include <QCompleter>
|
|
|
|
#include <QEvent>
|
2015-09-02 21:51:33 +00:00
|
|
|
#include <QMenu>
|
2016-01-27 20:30:52 +00:00
|
|
|
#include <QMessageBox>
|
2012-12-05 19:04:59 +00:00
|
|
|
#include <QPainter>
|
2015-03-03 20:27:10 +00:00
|
|
|
#include <QStringListModel>
|
2012-12-05 19:04:59 +00:00
|
|
|
|
2015-10-04 17:10:29 +00:00
|
|
|
#include <wsutil/utf8_entities.h>
|
2012-01-04 22:13:01 +00:00
|
|
|
|
2015-03-03 20:27:10 +00:00
|
|
|
// To do:
|
2015-09-02 21:51:33 +00:00
|
|
|
// - Get rid of shortcuts and replace them with "n most recently applied filters"?
|
2015-03-03 20:27:10 +00:00
|
|
|
// - We need simplified (button- and dropdown-free) versions for use in dialogs and field-only checking.
|
2015-05-13 16:25:41 +00:00
|
|
|
// - Add a separator or otherwise distinguish between recent items and fields
|
|
|
|
// in the completion dropdown.
|
2012-01-04 22:13:01 +00:00
|
|
|
|
2013-04-24 11:07:25 +00:00
|
|
|
#if defined(Q_OS_MAC) && 0
|
2012-01-04 22:13:01 +00:00
|
|
|
// http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/ApplicationKit/Classes/NSImage_Class/Reference/Reference.html
|
|
|
|
// http://www.virtualbox.org/svn/vbox/trunk/src/VBox/Frontends/VirtualBox/src/platform/darwin/UICocoaSpecialControls.mm
|
|
|
|
|
|
|
|
class UIMiniCancelButton: public QAbstractButton
|
|
|
|
{
|
|
|
|
Q_OBJECT;
|
|
|
|
|
|
|
|
public:
|
|
|
|
UIMiniCancelButton(QWidget *pParent = 0);
|
|
|
|
|
|
|
|
void setText(const QString &strText) { m_pButton->setText(strText); }
|
|
|
|
void setToolTip(const QString &strTip) { m_pButton->setToolTip(strTip); }
|
|
|
|
void removeBorder() {}
|
|
|
|
|
|
|
|
protected:
|
|
|
|
void paintEvent(QPaintEvent * /* pEvent */) {}
|
|
|
|
void resizeEvent(QResizeEvent *pEvent);
|
|
|
|
|
|
|
|
private:
|
|
|
|
UICocoaButton *m_pButton;
|
|
|
|
};
|
|
|
|
|
|
|
|
UIMiniCancelButton::UIMiniCancelButton(QWidget *pParent /* = 0 */)
|
|
|
|
: QAbstractButton(pParent)
|
|
|
|
{
|
|
|
|
setShortcut(QKeySequence(Qt::Key_Escape));
|
|
|
|
m_pButton = new UICocoaButton(UICocoaButton::CancelButton, this);
|
|
|
|
connect(m_pButton, SIGNAL(clicked()),
|
|
|
|
this, SIGNAL(clicked()));
|
|
|
|
setFixedSize(m_pButton->size());
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef __APPLE__
|
2015-03-03 20:27:10 +00:00
|
|
|
#define DEFAULT_MODIFIER UTF8_PLACE_OF_INTEREST_SIGN
|
2012-01-04 22:13:01 +00:00
|
|
|
#else
|
|
|
|
#define DEFAULT_MODIFIER "Ctrl-"
|
|
|
|
#endif
|
|
|
|
|
2015-05-13 16:25:41 +00:00
|
|
|
// proto.c:fld_abbrev_chars
|
|
|
|
static const QString fld_abbrev_chars_ = "-.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz";
|
|
|
|
|
2015-11-16 19:00:32 +00:00
|
|
|
DisplayFilterEdit::DisplayFilterEdit(QWidget *parent, DisplayFilterEditType type) :
|
2012-10-08 20:01:59 +00:00
|
|
|
SyntaxLineEdit(parent),
|
2015-11-16 19:00:32 +00:00
|
|
|
type_(type),
|
2016-01-27 20:30:52 +00:00
|
|
|
save_action_(NULL),
|
|
|
|
remove_action_(NULL),
|
2015-06-01 23:29:17 +00:00
|
|
|
bookmark_button_(NULL),
|
|
|
|
clear_button_(NULL),
|
2015-05-19 17:18:54 +00:00
|
|
|
apply_button_(NULL)
|
2012-01-04 22:13:01 +00:00
|
|
|
{
|
2012-03-07 10:16:33 +00:00
|
|
|
setAccessibleName(tr("Display filter entry"));
|
2012-01-04 22:13:01 +00:00
|
|
|
|
2015-03-03 20:27:10 +00:00
|
|
|
completion_model_ = new QStringListModel(this);
|
2015-05-19 17:18:54 +00:00
|
|
|
setCompleter(new QCompleter(completion_model_, this));
|
|
|
|
setCompletionTokenChars(fld_abbrev_chars_);
|
2015-03-03 20:27:10 +00:00
|
|
|
|
2015-11-16 19:00:32 +00:00
|
|
|
setDefaultPlaceholderText();
|
2012-07-21 01:21:41 +00:00
|
|
|
|
2012-01-04 22:13:01 +00:00
|
|
|
// DFCombo
|
2015-09-02 21:51:33 +00:00
|
|
|
// Bookmark
|
2015-11-16 19:00:32 +00:00
|
|
|
// DisplayFilterEdit
|
2012-01-04 22:13:01 +00:00
|
|
|
// Clear button
|
2015-09-02 21:51:33 +00:00
|
|
|
// Apply (right arrow)
|
2013-02-06 18:22:54 +00:00
|
|
|
// Combo drop-down
|
2012-01-04 22:13:01 +00:00
|
|
|
|
2015-11-16 19:00:32 +00:00
|
|
|
if (type_ == DisplayFilterToApply) {
|
2016-01-30 00:45:04 +00:00
|
|
|
bookmark_button_ = new StockIconToolButton(this, "x-display-filter-bookmark");
|
2015-06-01 23:29:17 +00:00
|
|
|
bookmark_button_->setCursor(Qt::ArrowCursor);
|
2015-09-02 21:51:33 +00:00
|
|
|
bookmark_button_->setMenu(new QMenu());
|
|
|
|
bookmark_button_->setPopupMode(QToolButton::InstantPopup);
|
2015-09-06 23:47:50 +00:00
|
|
|
bookmark_button_->setToolTip(tr("Manage saved bookmarks."));
|
2015-09-02 21:51:33 +00:00
|
|
|
bookmark_button_->setIconSize(QSize(14, 14));
|
|
|
|
bookmark_button_->setStyleSheet(
|
|
|
|
"QToolButton {"
|
|
|
|
" border: none;"
|
|
|
|
" background: transparent;" // Disables platform style on Windows.
|
|
|
|
" padding: 0 0 0 0;"
|
2015-06-01 23:29:17 +00:00
|
|
|
"}"
|
2015-09-02 21:51:33 +00:00
|
|
|
"QToolButton::menu-indicator { image: none; }"
|
2015-06-01 23:29:17 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2015-11-16 19:00:32 +00:00
|
|
|
if (type_ == DisplayFilterToApply) {
|
2015-09-02 21:51:33 +00:00
|
|
|
clear_button_ = new StockIconToolButton(this, "x-filter-clear");
|
2015-06-01 23:29:17 +00:00
|
|
|
clear_button_->setCursor(Qt::ArrowCursor);
|
2015-09-06 23:47:50 +00:00
|
|
|
clear_button_->setToolTip(QString());
|
2015-09-02 21:51:33 +00:00
|
|
|
clear_button_->setIconSize(QSize(14, 14));
|
2015-06-01 23:29:17 +00:00
|
|
|
clear_button_->setStyleSheet(
|
|
|
|
"QToolButton {"
|
|
|
|
" border: none;"
|
2015-09-02 21:51:33 +00:00
|
|
|
" background: transparent;" // Disables platform style on Windows.
|
|
|
|
" padding: 0 0 0 0;"
|
|
|
|
" margin-left: 1px;"
|
2015-06-01 23:29:17 +00:00
|
|
|
"}"
|
|
|
|
);
|
|
|
|
connect(clear_button_, SIGNAL(clicked()), this, SLOT(clearFilter()));
|
|
|
|
}
|
|
|
|
|
2012-01-04 22:13:01 +00:00
|
|
|
connect(this, SIGNAL(textChanged(const QString&)), this, SLOT(checkFilter(const QString&)));
|
|
|
|
|
2015-11-16 19:00:32 +00:00
|
|
|
if (type_ == DisplayFilterToApply) {
|
2015-09-02 21:51:33 +00:00
|
|
|
apply_button_ = new StockIconToolButton(this, "x-filter-apply");
|
2012-08-23 02:59:31 +00:00
|
|
|
apply_button_->setCursor(Qt::ArrowCursor);
|
2012-12-07 01:46:20 +00:00
|
|
|
apply_button_->setEnabled(false);
|
2015-09-06 23:47:50 +00:00
|
|
|
apply_button_->setToolTip(tr("Apply this filter string to the display."));
|
2015-09-02 21:51:33 +00:00
|
|
|
apply_button_->setIconSize(QSize(24, 14));
|
2012-08-23 02:59:31 +00:00
|
|
|
apply_button_->setStyleSheet(
|
2015-09-02 21:51:33 +00:00
|
|
|
"QToolButton {"
|
|
|
|
" border: none;"
|
|
|
|
" background: transparent;" // Disables platform style on Windows.
|
|
|
|
" padding: 0 0 0 0;"
|
2013-02-06 18:22:54 +00:00
|
|
|
"}"
|
2012-07-21 01:21:41 +00:00
|
|
|
);
|
2012-08-23 02:59:31 +00:00
|
|
|
connect(apply_button_, SIGNAL(clicked()), this, SLOT(applyDisplayFilter()));
|
2012-07-21 01:21:41 +00:00
|
|
|
connect(this, SIGNAL(returnPressed()), this, SLOT(applyDisplayFilter()));
|
|
|
|
}
|
2012-01-04 22:13:01 +00:00
|
|
|
|
|
|
|
int frameWidth = style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
|
2015-06-01 23:29:17 +00:00
|
|
|
QSize bksz;
|
|
|
|
if (bookmark_button_) {
|
|
|
|
bksz = bookmark_button_->sizeHint();
|
|
|
|
}
|
|
|
|
QSize cbsz;
|
|
|
|
if (clear_button_) {
|
|
|
|
cbsz = clear_button_->sizeHint();
|
|
|
|
}
|
2012-07-21 01:21:41 +00:00
|
|
|
QSize apsz;
|
2012-08-23 02:59:31 +00:00
|
|
|
if (apply_button_) {
|
|
|
|
apsz = apply_button_->sizeHint();
|
2012-07-21 01:21:41 +00:00
|
|
|
}
|
2012-10-08 20:01:59 +00:00
|
|
|
setStyleSheet(QString(
|
2012-01-04 22:13:01 +00:00
|
|
|
"DisplayFilterEdit {"
|
|
|
|
" padding-left: %1px;"
|
|
|
|
" margin-left: %2px;"
|
|
|
|
" margin-right: %3px;"
|
|
|
|
"}"
|
|
|
|
)
|
|
|
|
.arg(frameWidth + 1)
|
|
|
|
.arg(bksz.width())
|
|
|
|
.arg(cbsz.width() + apsz.width() + frameWidth + 1)
|
2015-03-03 20:27:10 +00:00
|
|
|
);
|
2016-01-27 20:30:52 +00:00
|
|
|
|
|
|
|
connect(wsApp, SIGNAL(appInitialized()), this, SLOT(updateBookmarkMenu()));
|
|
|
|
connect(wsApp, SIGNAL(displayFilterListChanged()), this, SLOT(updateBookmarkMenu()));
|
2015-03-03 20:27:10 +00:00
|
|
|
}
|
|
|
|
|
2015-11-16 19:00:32 +00:00
|
|
|
void DisplayFilterEdit::setDefaultPlaceholderText()
|
|
|
|
{
|
|
|
|
switch (type_) {
|
|
|
|
|
|
|
|
case DisplayFilterToApply:
|
|
|
|
placeholder_text_ = QString(tr("Apply a display filter %1 <%2/>")).arg(UTF8_HORIZONTAL_ELLIPSIS)
|
|
|
|
.arg(DEFAULT_MODIFIER);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DisplayFilterToEnter:
|
|
|
|
placeholder_text_ = QString(tr("Enter a display filter %1")).arg(UTF8_HORIZONTAL_ELLIPSIS);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ReadFilterToApply:
|
|
|
|
placeholder_text_ = QString(tr("Apply a read filter %1")).arg(UTF8_HORIZONTAL_ELLIPSIS);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)
|
|
|
|
setPlaceholderText(placeholder_text_);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2012-01-04 22:13:01 +00:00
|
|
|
void DisplayFilterEdit::paintEvent(QPaintEvent *evt) {
|
2012-10-08 20:01:59 +00:00
|
|
|
SyntaxLineEdit::paintEvent(evt);
|
2012-01-04 22:13:01 +00:00
|
|
|
|
2015-09-02 21:51:33 +00:00
|
|
|
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)
|
2012-01-04 22:13:01 +00:00
|
|
|
// http://wiki.forum.nokia.com/index.php/Custom_QLineEdit
|
|
|
|
if (text().isEmpty() && ! this->hasFocus()) {
|
|
|
|
QPainter p(this);
|
|
|
|
QFont f = font();
|
|
|
|
f.setItalic(true);
|
|
|
|
p.setFont(f);
|
|
|
|
|
|
|
|
QColor color(palette().color(foregroundRole()));
|
|
|
|
color.setAlphaF(0.5);
|
|
|
|
p.setPen(color);
|
|
|
|
|
|
|
|
QStyleOptionFrame opt;
|
|
|
|
initStyleOption(&opt);
|
|
|
|
QRect cr = style()->subElementRect(QStyle::SE_LineEditContents, &opt, this);
|
|
|
|
cr.setLeft(cr.left() + 2);
|
|
|
|
cr.setRight(cr.right() - 2);
|
|
|
|
|
2015-03-03 20:27:10 +00:00
|
|
|
p.drawText(cr, Qt::AlignLeft|Qt::AlignVCenter, placeholder_text_);
|
2012-01-04 22:13:01 +00:00
|
|
|
}
|
|
|
|
// else check filter syntax and set the background accordingly
|
|
|
|
// XXX - Should we add little warning/error icons as well?
|
2015-03-03 20:27:10 +00:00
|
|
|
#endif // QT < 4.7
|
2015-09-02 21:51:33 +00:00
|
|
|
}
|
2012-01-04 22:13:01 +00:00
|
|
|
|
|
|
|
void DisplayFilterEdit::resizeEvent(QResizeEvent *)
|
|
|
|
{
|
2015-06-01 23:29:17 +00:00
|
|
|
QSize cbsz;
|
|
|
|
if (clear_button_) {
|
|
|
|
cbsz = clear_button_->sizeHint();
|
|
|
|
}
|
2012-07-21 01:21:41 +00:00
|
|
|
QSize apsz;
|
2012-08-23 02:59:31 +00:00
|
|
|
if (apply_button_) {
|
|
|
|
apsz = apply_button_->sizeHint();
|
2012-07-21 01:21:41 +00:00
|
|
|
} else {
|
|
|
|
apsz.setHeight(0); apsz.setWidth(0);
|
|
|
|
}
|
2012-01-04 22:13:01 +00:00
|
|
|
int frameWidth = style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
|
2015-06-01 23:29:17 +00:00
|
|
|
if (clear_button_) {
|
|
|
|
clear_button_->move(contentsRect().right() - frameWidth - cbsz.width() - apsz.width(),
|
|
|
|
contentsRect().top());
|
2015-09-02 21:51:33 +00:00
|
|
|
clear_button_->setMinimumHeight(contentsRect().height());
|
2015-06-01 23:29:17 +00:00
|
|
|
clear_button_->setMaximumHeight(contentsRect().height());
|
|
|
|
}
|
2012-08-23 02:59:31 +00:00
|
|
|
if (apply_button_) {
|
2012-12-07 21:22:16 +00:00
|
|
|
apply_button_->move(contentsRect().right() - frameWidth - apsz.width(),
|
2012-12-07 21:32:19 +00:00
|
|
|
contentsRect().top());
|
2015-09-02 21:51:33 +00:00
|
|
|
apply_button_->setMinimumHeight(contentsRect().height());
|
2012-12-07 21:32:19 +00:00
|
|
|
apply_button_->setMaximumHeight(contentsRect().height());
|
2012-07-21 01:21:41 +00:00
|
|
|
}
|
2015-06-01 23:29:17 +00:00
|
|
|
if (bookmark_button_) {
|
2015-09-02 21:51:33 +00:00
|
|
|
bookmark_button_->setMinimumHeight(contentsRect().height());
|
2015-06-01 23:29:17 +00:00
|
|
|
bookmark_button_->setMaximumHeight(contentsRect().height());
|
|
|
|
}
|
2012-01-04 22:13:01 +00:00
|
|
|
}
|
|
|
|
|
2015-05-19 17:18:54 +00:00
|
|
|
void DisplayFilterEdit::focusOutEvent(QFocusEvent *event)
|
2015-05-14 22:37:55 +00:00
|
|
|
{
|
|
|
|
if (syntaxState() == Valid)
|
|
|
|
emit popFilterSyntaxStatus();
|
2015-05-19 17:18:54 +00:00
|
|
|
SyntaxLineEdit::focusOutEvent(event);
|
2015-05-14 22:37:55 +00:00
|
|
|
}
|
|
|
|
|
2015-08-18 19:15:27 +00:00
|
|
|
bool DisplayFilterEdit::checkFilter()
|
|
|
|
{
|
|
|
|
checkFilter(text());
|
|
|
|
|
2015-08-20 17:05:39 +00:00
|
|
|
return syntaxState() != Invalid;
|
2015-08-18 19:15:27 +00:00
|
|
|
}
|
|
|
|
|
2015-09-02 21:51:33 +00:00
|
|
|
void DisplayFilterEdit::checkFilter(const QString& filter_text)
|
2012-01-04 22:13:01 +00:00
|
|
|
{
|
2015-06-01 23:29:17 +00:00
|
|
|
if (clear_button_) {
|
2015-09-02 21:51:33 +00:00
|
|
|
clear_button_->setVisible(!filter_text.isEmpty());
|
2015-06-01 23:29:17 +00:00
|
|
|
}
|
2012-01-04 22:13:01 +00:00
|
|
|
|
2012-01-14 00:16:16 +00:00
|
|
|
popFilterSyntaxStatus();
|
2015-09-02 21:51:33 +00:00
|
|
|
checkDisplayFilter(filter_text);
|
Add a Qt I/O Graph dialog.
For each graph you can set:
- Its visibility
- A name
- A display filter
- Color, from a fixed list
- Plot style: Line, Impulse, Bar, Stacked Bar, Dot, Square, Diamond
- Basic Y Axes (packets/s, bytes/s, bits/s)
- Computed Y Axes (SUM, MIN, AVG, MAX)
- Smoothing
You can pan and zoom using the mouse and keyboard. Clicking on a graph
selects the last packet for that interval. If all graphs have the same Y
axis a single label is shown, otherwise a legend is shown.
The time scale (X axis) can be toggled between relative seconds and the
time of day.
Graphs can be saved as PDF, PNG, BMP, and JPEG. Settings are "sticky"
via the io_graphs UAT.
To do:
- Minimize graph drawing delays.
- Figure out why smoothing differs from GTK+
- Everything else at the top of io_graph_dialog.cpp
- Fix empty resets.
A fair amount of code was copied from TCPStreamDialog. We might want to
subclass QCustomPlot and place the shared code there.
Move common syntax checking to SyntaxLineEdit.
Move some common code from ui/gtk/io_stat.c to ui/io_graph_item.[ch] and
use it in both GTK+ and Qt.
Make the io_graph_item_t array allocation in io_stat.c static. The
behavior should be identical and this gives us additional compile-time
checks.
Change-Id: I9a3d544469b7048f0761fdbf7bcf20f44ae76577
Reviewed-on: https://code.wireshark.org/review/435
Reviewed-by: Gerald Combs <gerald@wireshark.org>
Tested-by: Gerald Combs <gerald@wireshark.org>
2014-02-12 00:07:10 +00:00
|
|
|
|
|
|
|
switch (syntaxState()) {
|
|
|
|
case Deprecated:
|
|
|
|
{
|
2016-01-15 19:35:47 +00:00
|
|
|
emit pushFilterSyntaxWarning(syntaxErrorMessage());
|
Add a Qt I/O Graph dialog.
For each graph you can set:
- Its visibility
- A name
- A display filter
- Color, from a fixed list
- Plot style: Line, Impulse, Bar, Stacked Bar, Dot, Square, Diamond
- Basic Y Axes (packets/s, bytes/s, bits/s)
- Computed Y Axes (SUM, MIN, AVG, MAX)
- Smoothing
You can pan and zoom using the mouse and keyboard. Clicking on a graph
selects the last packet for that interval. If all graphs have the same Y
axis a single label is shown, otherwise a legend is shown.
The time scale (X axis) can be toggled between relative seconds and the
time of day.
Graphs can be saved as PDF, PNG, BMP, and JPEG. Settings are "sticky"
via the io_graphs UAT.
To do:
- Minimize graph drawing delays.
- Figure out why smoothing differs from GTK+
- Everything else at the top of io_graph_dialog.cpp
- Fix empty resets.
A fair amount of code was copied from TCPStreamDialog. We might want to
subclass QCustomPlot and place the shared code there.
Move common syntax checking to SyntaxLineEdit.
Move some common code from ui/gtk/io_stat.c to ui/io_graph_item.[ch] and
use it in both GTK+ and Qt.
Make the io_graph_item_t array allocation in io_stat.c static. The
behavior should be identical and this gives us additional compile-time
checks.
Change-Id: I9a3d544469b7048f0761fdbf7bcf20f44ae76577
Reviewed-on: https://code.wireshark.org/review/435
Reviewed-by: Gerald Combs <gerald@wireshark.org>
Tested-by: Gerald Combs <gerald@wireshark.org>
2014-02-12 00:07:10 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case Invalid:
|
|
|
|
{
|
2015-01-18 10:22:19 +00:00
|
|
|
QString invalidMsg(tr("Invalid filter: "));
|
|
|
|
invalidMsg.append(syntaxErrorMessage());
|
2012-01-14 00:16:16 +00:00
|
|
|
emit pushFilterSyntaxStatus(invalidMsg);
|
Add a Qt I/O Graph dialog.
For each graph you can set:
- Its visibility
- A name
- A display filter
- Color, from a fixed list
- Plot style: Line, Impulse, Bar, Stacked Bar, Dot, Square, Diamond
- Basic Y Axes (packets/s, bytes/s, bits/s)
- Computed Y Axes (SUM, MIN, AVG, MAX)
- Smoothing
You can pan and zoom using the mouse and keyboard. Clicking on a graph
selects the last packet for that interval. If all graphs have the same Y
axis a single label is shown, otherwise a legend is shown.
The time scale (X axis) can be toggled between relative seconds and the
time of day.
Graphs can be saved as PDF, PNG, BMP, and JPEG. Settings are "sticky"
via the io_graphs UAT.
To do:
- Minimize graph drawing delays.
- Figure out why smoothing differs from GTK+
- Everything else at the top of io_graph_dialog.cpp
- Fix empty resets.
A fair amount of code was copied from TCPStreamDialog. We might want to
subclass QCustomPlot and place the shared code there.
Move common syntax checking to SyntaxLineEdit.
Move some common code from ui/gtk/io_stat.c to ui/io_graph_item.[ch] and
use it in both GTK+ and Qt.
Make the io_graph_item_t array allocation in io_stat.c static. The
behavior should be identical and this gives us additional compile-time
checks.
Change-Id: I9a3d544469b7048f0761fdbf7bcf20f44ae76577
Reviewed-on: https://code.wireshark.org/review/435
Reviewed-by: Gerald Combs <gerald@wireshark.org>
Tested-by: Gerald Combs <gerald@wireshark.org>
2014-02-12 00:07:10 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
break;
|
2012-01-04 22:13:01 +00:00
|
|
|
}
|
|
|
|
|
2015-06-01 23:29:17 +00:00
|
|
|
if (bookmark_button_) {
|
2015-09-02 21:51:33 +00:00
|
|
|
bool enable_save_action = false;
|
|
|
|
bool match = false;
|
|
|
|
|
|
|
|
for (GList *df_item = get_filter_list_first(DFILTER_LIST); df_item; df_item = g_list_next(df_item)) {
|
|
|
|
if (!df_item->data) continue;
|
|
|
|
filter_def *df_def = (filter_def *) df_item->data;
|
|
|
|
if (!df_def->name || !df_def->strval) continue;
|
|
|
|
|
|
|
|
if (filter_text.compare(df_def->strval) == 0) {
|
|
|
|
match = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (match) {
|
|
|
|
bookmark_button_->setStockIcon("x-filter-matching-bookmark");
|
2016-01-27 20:30:52 +00:00
|
|
|
if (remove_action_) {
|
|
|
|
remove_action_->setData(text());
|
|
|
|
remove_action_->setVisible(true);
|
|
|
|
}
|
2015-09-02 21:51:33 +00:00
|
|
|
} else {
|
2016-01-30 00:45:04 +00:00
|
|
|
bookmark_button_->setStockIcon("x-display-filter-bookmark");
|
2016-01-27 20:30:52 +00:00
|
|
|
if (remove_action_) {
|
|
|
|
remove_action_->setVisible(false);
|
|
|
|
}
|
2015-09-02 21:51:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!match && (syntaxState() == Valid || syntaxState() == Deprecated) && !filter_text.isEmpty()) {
|
|
|
|
enable_save_action = true;
|
|
|
|
}
|
2016-01-27 20:30:52 +00:00
|
|
|
if (save_action_) {
|
|
|
|
save_action_->setEnabled(enable_save_action);
|
|
|
|
}
|
2015-06-01 23:29:17 +00:00
|
|
|
}
|
2012-08-23 02:59:31 +00:00
|
|
|
if (apply_button_) {
|
2015-08-20 17:05:39 +00:00
|
|
|
apply_button_->setEnabled(syntaxState() != Invalid);
|
2012-07-21 01:21:41 +00:00
|
|
|
}
|
2012-01-04 22:13:01 +00:00
|
|
|
}
|
|
|
|
|
2016-01-27 20:30:52 +00:00
|
|
|
void DisplayFilterEdit::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 Display Filters"));
|
|
|
|
connect(manage_action, SIGNAL(triggered(bool)), this, SLOT(showFilters()));
|
|
|
|
QAction *expr_action = bb_menu->addAction(tr("Manage Filter Expressions"));
|
|
|
|
connect(expr_action, SIGNAL(triggered(bool)), this, SLOT(showExpressionPrefs()));
|
|
|
|
bb_menu->addSeparator();
|
|
|
|
|
|
|
|
for (GList *df_item = get_filter_list_first(DFILTER_LIST); df_item; df_item = g_list_next(df_item)) {
|
|
|
|
if (!df_item->data) continue;
|
|
|
|
filter_def *df_def = (filter_def *) df_item->data;
|
|
|
|
if (!df_def->name || !df_def->strval) continue;
|
|
|
|
|
|
|
|
int one_em = bb_menu->fontMetrics().height();
|
|
|
|
QString prep_text = QString("%1: %2").arg(df_def->name).arg(df_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(df_def->strval);
|
|
|
|
connect(prep_action, SIGNAL(triggered(bool)), this, SLOT(prepareFilter()));
|
|
|
|
}
|
|
|
|
|
|
|
|
checkFilter();
|
|
|
|
}
|
|
|
|
|
2015-03-03 20:27:10 +00:00
|
|
|
// GTK+ behavior:
|
|
|
|
// - Operates on words (proto.c:fld_abbrev_chars).
|
|
|
|
// - Popup appears when you enter or remove text.
|
|
|
|
|
|
|
|
// Our behavior:
|
|
|
|
// - Operates on words (fld_abbrev_chars_).
|
|
|
|
// - Popup appears when you enter or remove text.
|
|
|
|
// - Popup appears when you move the cursor.
|
|
|
|
// - Popup does not appear when text is selected.
|
2015-05-18 23:56:57 +00:00
|
|
|
// - Recent and saved display filters in popup when editing first word.
|
2015-03-03 20:27:10 +00:00
|
|
|
|
|
|
|
// ui/gtk/filter_autocomplete.c:build_autocompletion_list
|
|
|
|
void DisplayFilterEdit::buildCompletionList(const QString &field_word)
|
|
|
|
{
|
2015-05-11 22:21:38 +00:00
|
|
|
// Push a hint about the current field.
|
|
|
|
if (syntaxState() == Valid) {
|
|
|
|
emit popFilterSyntaxStatus();
|
|
|
|
|
|
|
|
header_field_info *hfinfo = proto_registrar_get_byname(field_word.toUtf8().constData());
|
|
|
|
if (hfinfo) {
|
|
|
|
QString cursor_field_msg = QString("%1: %2")
|
|
|
|
.arg(hfinfo->name)
|
|
|
|
.arg(ftype_pretty_name(hfinfo->type));
|
|
|
|
emit pushFilterSyntaxStatus(cursor_field_msg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-18 23:56:57 +00:00
|
|
|
if (field_word.length() < 1) {
|
|
|
|
completion_model_->setStringList(QStringList());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Grab matching display filters from our parent combo and from the
|
|
|
|
// saved display filters file. Skip ones that look like single fields
|
|
|
|
// and assume they will be added below.
|
|
|
|
QStringList complex_list;
|
2015-03-03 20:27:10 +00:00
|
|
|
QComboBox *df_combo = qobject_cast<QComboBox *>(parent());
|
|
|
|
if (df_combo) {
|
|
|
|
for (int i = 0; i < df_combo->count() ; i++) {
|
2015-05-13 16:25:41 +00:00
|
|
|
QString recent_filter = df_combo->itemText(i);
|
|
|
|
|
2015-05-18 23:56:57 +00:00
|
|
|
if (isComplexFilter(recent_filter)) {
|
|
|
|
complex_list << recent_filter;
|
2015-03-03 20:27:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-05-18 23:56:57 +00:00
|
|
|
for (const GList *df_item = get_filter_list_first(DFILTER_LIST); df_item; df_item = g_list_next(df_item)) {
|
|
|
|
const filter_def *df_def = (filter_def *) df_item->data;
|
|
|
|
if (!df_def || !df_def->strval) continue;
|
|
|
|
QString saved_filter = df_def->strval;
|
2015-03-03 20:27:10 +00:00
|
|
|
|
2015-05-18 23:56:57 +00:00
|
|
|
if (isComplexFilter(saved_filter) && !complex_list.contains(saved_filter)) {
|
|
|
|
complex_list << saved_filter;
|
|
|
|
}
|
2015-03-03 20:27:10 +00:00
|
|
|
}
|
2015-05-18 23:56:57 +00:00
|
|
|
completion_model_->setStringList(complex_list);
|
|
|
|
completer()->setCompletionPrefix(field_word);
|
2015-03-03 20:27:10 +00:00
|
|
|
|
|
|
|
void *proto_cookie;
|
|
|
|
QStringList field_list;
|
2015-05-12 19:35:54 +00:00
|
|
|
int field_dots = field_word.count('.'); // Some protocol names (_ws.expert) contain periods.
|
2015-03-03 20:27:10 +00:00
|
|
|
for (int proto_id = proto_get_first_protocol(&proto_cookie); proto_id != -1; proto_id = proto_get_next_protocol(&proto_cookie)) {
|
|
|
|
protocol_t *protocol = find_protocol_by_id(proto_id);
|
|
|
|
if (!proto_is_protocol_enabled(protocol)) continue;
|
|
|
|
|
|
|
|
// Don't complete the current word.
|
2015-05-11 23:42:52 +00:00
|
|
|
const QString pfname = proto_get_protocol_filter_name(proto_id);
|
2015-05-12 19:35:54 +00:00
|
|
|
if (field_word.compare(pfname)) field_list << pfname;
|
|
|
|
|
|
|
|
// Add fields only if we're past the protocol name and only for the
|
|
|
|
// current protocol.
|
2015-05-14 22:00:07 +00:00
|
|
|
if (field_dots > pfname.count('.')) {
|
2015-03-03 20:27:10 +00:00
|
|
|
void *field_cookie;
|
2015-05-14 22:00:07 +00:00
|
|
|
const QByteArray fw_ba = field_word.toUtf8(); // or toLatin1 or toStdString?
|
|
|
|
const char *fw_utf8 = fw_ba.constData();
|
2015-05-14 22:12:12 +00:00
|
|
|
gsize fw_len = (gsize) strlen(fw_utf8);
|
2015-03-03 20:27:10 +00:00
|
|
|
for (header_field_info *hfinfo = proto_get_first_protocol_field(proto_id, &field_cookie); hfinfo; hfinfo = proto_get_next_protocol_field(proto_id, &field_cookie)) {
|
2015-05-13 16:25:41 +00:00
|
|
|
if (hfinfo->same_name_prev_id != -1) continue; // Ignore duplicate names.
|
2015-03-03 20:27:10 +00:00
|
|
|
|
2015-05-14 22:12:12 +00:00
|
|
|
if (!g_ascii_strncasecmp(fw_utf8, hfinfo->abbrev, fw_len)) {
|
|
|
|
if ((gsize) strlen(hfinfo->abbrev) != fw_len) field_list << hfinfo->abbrev;
|
|
|
|
}
|
2015-03-03 20:27:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
field_list.sort();
|
|
|
|
|
2015-05-18 23:56:57 +00:00
|
|
|
completion_model_->setStringList(complex_list + field_list);
|
2015-03-03 20:27:10 +00:00
|
|
|
completer()->setCompletionPrefix(field_word);
|
|
|
|
}
|
|
|
|
|
2014-03-11 04:27:50 +00:00
|
|
|
void DisplayFilterEdit::clearFilter()
|
|
|
|
{
|
|
|
|
clear();
|
|
|
|
QString new_filter;
|
|
|
|
emit filterPackets(new_filter, true);
|
|
|
|
}
|
|
|
|
|
2012-01-04 22:13:01 +00:00
|
|
|
void DisplayFilterEdit::applyDisplayFilter()
|
|
|
|
{
|
2015-08-20 17:05:39 +00:00
|
|
|
if (syntaxState() == Invalid) {
|
2012-01-04 22:13:01 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-12-07 01:46:20 +00:00
|
|
|
QString new_filter = text();
|
|
|
|
emit filterPackets(new_filter, true);
|
|
|
|
}
|
2012-01-04 22:13:01 +00:00
|
|
|
|
2012-12-07 01:46:20 +00:00
|
|
|
void DisplayFilterEdit::displayFilterSuccess(bool success)
|
|
|
|
{
|
|
|
|
apply_button_->setEnabled(!success);
|
2012-01-04 22:13:01 +00:00
|
|
|
}
|
2012-09-04 08:18:31 +00:00
|
|
|
|
2013-12-21 16:55:43 +00:00
|
|
|
void DisplayFilterEdit::changeEvent(QEvent* event)
|
|
|
|
{
|
|
|
|
if (0 != event)
|
|
|
|
{
|
|
|
|
switch (event->type())
|
|
|
|
{
|
|
|
|
case QEvent::LanguageChange:
|
2015-11-16 19:00:32 +00:00
|
|
|
setDefaultPlaceholderText();
|
2013-12-21 16:55:43 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
SyntaxLineEdit::changeEvent(event);
|
|
|
|
}
|
|
|
|
|
2015-09-02 21:51:33 +00:00
|
|
|
void DisplayFilterEdit::saveFilter()
|
|
|
|
{
|
|
|
|
FilterDialog display_filter_dlg(window(), FilterDialog::DisplayFilter, text());
|
|
|
|
display_filter_dlg.exec();
|
|
|
|
}
|
|
|
|
|
|
|
|
void DisplayFilterEdit::removeFilter()
|
|
|
|
{
|
|
|
|
QAction *ra = qobject_cast<QAction*>(sender());
|
|
|
|
if (!ra || ra->data().toString().isEmpty()) return;
|
|
|
|
|
|
|
|
QString remove_filter = ra->data().toString();
|
|
|
|
|
|
|
|
for (GList *df_item = get_filter_list_first(DFILTER_LIST); df_item; df_item = g_list_next(df_item)) {
|
|
|
|
if (!df_item->data) continue;
|
|
|
|
filter_def *df_def = (filter_def *) df_item->data;
|
|
|
|
if (!df_def->name || !df_def->strval) continue;
|
|
|
|
|
|
|
|
if (remove_filter.compare(df_def->strval) == 0) {
|
|
|
|
remove_from_filter_list(DFILTER_LIST, df_item);
|
|
|
|
}
|
|
|
|
}
|
2016-01-27 20:30:52 +00:00
|
|
|
|
|
|
|
char *f_path;
|
|
|
|
int f_save_errno;
|
|
|
|
|
|
|
|
save_filter_list(DFILTER_LIST, &f_path, &f_save_errno);
|
|
|
|
if (f_path != NULL) {
|
|
|
|
// We had an error saving the filter.
|
|
|
|
QString warning_title = tr("Unable to save display filter settings.");
|
|
|
|
QString warning_msg = tr("Could not save to your display 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();
|
2015-09-02 21:51:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void DisplayFilterEdit::showFilters()
|
|
|
|
{
|
|
|
|
FilterDialog display_filter_dlg(window(), FilterDialog::DisplayFilter);
|
|
|
|
display_filter_dlg.exec();
|
|
|
|
}
|
|
|
|
|
2015-10-27 16:52:51 +00:00
|
|
|
void DisplayFilterEdit::showExpressionPrefs()
|
|
|
|
{
|
|
|
|
emit showPreferencesDialog(PreferencesDialog::ppFilterExpressions);
|
|
|
|
}
|
|
|
|
|
2015-09-02 21:51:33 +00:00
|
|
|
void DisplayFilterEdit::prepareFilter()
|
|
|
|
{
|
|
|
|
QAction *pa = qobject_cast<QAction*>(sender());
|
|
|
|
if (!pa || pa->data().toString().isEmpty()) return;
|
|
|
|
|
|
|
|
setText(pa->data().toString());
|
|
|
|
}
|
|
|
|
|
2012-09-04 08:18:31 +00:00
|
|
|
/*
|
|
|
|
* Editor modelines
|
|
|
|
*
|
|
|
|
* Local Variables:
|
|
|
|
* c-basic-offset: 4
|
|
|
|
* tab-width: 8
|
|
|
|
* indent-tabs-mode: nil
|
|
|
|
* End:
|
|
|
|
*
|
|
|
|
* ex: set shiftwidth=4 tabstop=8 expandtab:
|
|
|
|
* :indentSize=4:tabSize=8:noTabs=true:
|
|
|
|
*/
|