2013-04-10 21:20:33 +00:00
|
|
|
/* syntax_line_edit.cpp
|
|
|
|
*
|
|
|
|
* Wireshark - Network traffic analyzer
|
|
|
|
* By Gerald Combs <gerald@wireshark.org>
|
|
|
|
* Copyright 1998 Gerald Combs
|
|
|
|
*
|
2018-04-30 07:47:58 +00:00
|
|
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
*/
|
2013-04-10 21:20:33 +00:00
|
|
|
|
2013-07-17 21:55:38 +00:00
|
|
|
#include "config.h"
|
|
|
|
|
|
|
|
#include <glib.h>
|
|
|
|
|
|
|
|
#include <epan/prefs.h>
|
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
|
|
|
#include <epan/proto.h>
|
|
|
|
#include <epan/dfilter/dfilter.h>
|
2022-08-06 13:31:23 +00:00
|
|
|
#include <epan/column.h>
|
2013-07-17 21:55:38 +00:00
|
|
|
|
2018-12-05 23:37:27 +00:00
|
|
|
#include <wsutil/utf8_entities.h>
|
|
|
|
|
2017-07-25 14:15:18 +00:00
|
|
|
#include <ui/qt/widgets/syntax_line_edit.h>
|
2012-10-08 20:01:59 +00:00
|
|
|
|
2020-02-12 20:34:02 +00:00
|
|
|
#include <ui/qt/utils/qt_ui_utils.h>
|
2017-07-25 14:15:18 +00:00
|
|
|
#include <ui/qt/utils/color_utils.h>
|
2018-12-05 23:37:27 +00:00
|
|
|
#include <ui/qt/utils/stock_icon.h>
|
2012-10-08 20:01:59 +00:00
|
|
|
|
2015-05-19 17:18:54 +00:00
|
|
|
#include <QAbstractItemView>
|
2020-10-05 21:50:29 +00:00
|
|
|
#include <QApplication>
|
2015-05-19 17:18:54 +00:00
|
|
|
#include <QCompleter>
|
|
|
|
#include <QKeyEvent>
|
2018-12-05 23:37:27 +00:00
|
|
|
#include <QPainter>
|
2015-05-19 17:18:54 +00:00
|
|
|
#include <QScrollBar>
|
|
|
|
#include <QStringListModel>
|
2018-12-05 23:37:27 +00:00
|
|
|
#include <QStyleOptionFrame>
|
2015-08-18 06:44:37 +00:00
|
|
|
#include <limits>
|
2015-05-19 17:18:54 +00:00
|
|
|
|
|
|
|
const int max_completion_items_ = 20;
|
|
|
|
|
2012-10-08 20:01:59 +00:00
|
|
|
SyntaxLineEdit::SyntaxLineEdit(QWidget *parent) :
|
2015-05-19 17:18:54 +00:00
|
|
|
QLineEdit(parent),
|
|
|
|
completer_(NULL),
|
2020-07-03 11:15:29 +00:00
|
|
|
completion_model_(NULL),
|
|
|
|
completion_enabled_(false)
|
2012-10-08 20:01:59 +00:00
|
|
|
{
|
2013-07-17 21:55:38 +00:00
|
|
|
setSyntaxState();
|
2015-08-18 06:44:37 +00:00
|
|
|
setMaxLength(std::numeric_limits<quint32>::max());
|
2013-07-17 21:55:38 +00:00
|
|
|
}
|
|
|
|
|
2015-05-19 17:18:54 +00:00
|
|
|
// 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_);
|
2018-12-24 17:11:20 +00:00
|
|
|
QObject::connect(completer_, static_cast<void (QCompleter::*)(const QString &)>(&QCompleter::activated),
|
|
|
|
this, &SyntaxLineEdit::insertFieldCompletion);
|
2020-07-03 11:15:29 +00:00
|
|
|
|
|
|
|
// Auto-completion is turned on.
|
|
|
|
completion_enabled_ = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SyntaxLineEdit::allowCompletion(bool enabled)
|
|
|
|
{
|
|
|
|
completion_enabled_ = enabled;
|
2015-05-19 17:18:54 +00:00
|
|
|
}
|
|
|
|
|
2013-07-17 21:55:38 +00:00
|
|
|
void SyntaxLineEdit::setSyntaxState(SyntaxState state) {
|
|
|
|
syntax_state_ = state;
|
2020-10-05 21:50:29 +00:00
|
|
|
|
2022-07-06 02:34:59 +00:00
|
|
|
// XXX Should we drop the background colors here in favor of ::paintEvent below?
|
2020-10-05 21:50:29 +00:00
|
|
|
QColor valid_bg = ColorUtils::fromColorT(&prefs.gui_text_valid);
|
|
|
|
QColor valid_fg = ColorUtils::contrastingTextColor(valid_bg);
|
|
|
|
QColor invalid_bg = ColorUtils::fromColorT(&prefs.gui_text_invalid);
|
|
|
|
QColor invalid_fg = ColorUtils::contrastingTextColor(invalid_bg);
|
|
|
|
QColor deprecated_bg = ColorUtils::fromColorT(&prefs.gui_text_deprecated);
|
|
|
|
QColor deprecated_fg = ColorUtils::contrastingTextColor(deprecated_bg);
|
|
|
|
|
|
|
|
// Try to matche QLineEdit's placeholder text color (which sets the
|
|
|
|
// alpha channel to 50%, which doesn't work in style sheets).
|
|
|
|
// Setting the foreground color lets us avoid yet another background
|
|
|
|
// color preference and should hopefully make things easier to
|
|
|
|
// distinguish for color blind folk.
|
|
|
|
QColor busy_fg = ColorUtils::alphaBlend(QApplication::palette().text(), QApplication::palette().base(), 0.5);
|
|
|
|
|
2012-10-08 20:01:59 +00:00
|
|
|
state_style_sheet_ = QString(
|
|
|
|
"SyntaxLineEdit[syntaxState=\"%1\"] {"
|
2020-10-05 21:50:29 +00:00
|
|
|
" color: %2;"
|
|
|
|
" background-color: %3;"
|
2012-10-08 20:01:59 +00:00
|
|
|
"}"
|
|
|
|
|
2020-10-05 21:50:29 +00:00
|
|
|
"SyntaxLineEdit[syntaxState=\"%4\"] {"
|
2016-01-07 17:27:13 +00:00
|
|
|
" color: %5;"
|
2020-10-05 21:50:29 +00:00
|
|
|
" background-color: %6;"
|
2012-10-08 20:01:59 +00:00
|
|
|
"}"
|
|
|
|
|
2020-10-05 21:50:29 +00:00
|
|
|
"SyntaxLineEdit[syntaxState=\"%7\"] {"
|
|
|
|
" color: %8;"
|
2016-01-07 17:27:13 +00:00
|
|
|
" background-color: %9;"
|
|
|
|
"}"
|
|
|
|
|
2020-10-05 21:50:29 +00:00
|
|
|
"SyntaxLineEdit[syntaxState=\"%10\"] {"
|
|
|
|
" color: %11;"
|
|
|
|
" background-color: %12;"
|
2012-10-08 20:01:59 +00:00
|
|
|
"}"
|
|
|
|
)
|
2016-01-07 17:27:13 +00:00
|
|
|
|
2020-10-05 21:50:29 +00:00
|
|
|
// CSS selector, foreground, background
|
2013-07-17 21:55:38 +00:00
|
|
|
.arg(Valid)
|
2020-10-05 21:50:29 +00:00
|
|
|
.arg(valid_fg.name())
|
|
|
|
.arg(valid_bg.name())
|
|
|
|
|
2012-10-08 20:01:59 +00:00
|
|
|
.arg(Invalid)
|
2020-10-05 21:50:29 +00:00
|
|
|
.arg(invalid_fg.name())
|
|
|
|
.arg(invalid_bg.name())
|
2016-01-07 17:27:13 +00:00
|
|
|
|
2020-10-05 21:50:29 +00:00
|
|
|
.arg(Deprecated)
|
|
|
|
.arg(deprecated_fg.name())
|
|
|
|
.arg(deprecated_bg.name())
|
2016-01-07 17:27:13 +00:00
|
|
|
|
2020-10-05 21:50:29 +00:00
|
|
|
.arg(Busy)
|
|
|
|
.arg(busy_fg.name())
|
|
|
|
.arg(palette().base().color().name())
|
2012-10-08 20:01:59 +00:00
|
|
|
;
|
|
|
|
setStyleSheet(style_sheet_);
|
|
|
|
}
|
|
|
|
|
2022-08-21 10:46:45 +00:00
|
|
|
QString SyntaxLineEdit::syntaxErrorMessage()
|
|
|
|
{
|
2015-01-18 10:22:19 +00:00
|
|
|
return syntax_error_message_;
|
|
|
|
}
|
|
|
|
|
2022-08-21 10:46:45 +00:00
|
|
|
QString SyntaxLineEdit::syntaxErrorMessageFull()
|
|
|
|
{
|
|
|
|
return syntax_error_message_full_;
|
|
|
|
}
|
|
|
|
|
|
|
|
QString SyntaxLineEdit::createSyntaxErrorMessageFull(
|
|
|
|
const QString &filter, const QString &err_msg,
|
|
|
|
qsizetype loc_start, size_t loc_length)
|
|
|
|
{
|
|
|
|
QString msg = tr("Invalid filter: %1").arg(err_msg);
|
|
|
|
|
|
|
|
if (loc_start >= 0 && loc_length >= 1) {
|
|
|
|
// Add underlined location
|
|
|
|
msg = QString("<p>%1<pre> %2\n %3^%4</pre></p>")
|
|
|
|
.arg(msg)
|
|
|
|
.arg(filter)
|
2022-09-07 12:54:59 +00:00
|
|
|
.arg(QString(' ').repeated(static_cast<int>(loc_start)))
|
|
|
|
.arg(QString('~').repeated(static_cast<int>(loc_length) - 1));
|
2022-08-21 10:46:45 +00:00
|
|
|
}
|
|
|
|
return msg;
|
|
|
|
}
|
|
|
|
|
2012-10-08 20:01:59 +00:00
|
|
|
QString SyntaxLineEdit::styleSheet() const {
|
|
|
|
return style_sheet_;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SyntaxLineEdit::setStyleSheet(const QString &style_sheet) {
|
|
|
|
style_sheet_ = style_sheet;
|
|
|
|
QLineEdit::setStyleSheet(style_sheet_ + state_style_sheet_);
|
|
|
|
}
|
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
|
|
|
|
2015-06-01 23:29:17 +00:00
|
|
|
void SyntaxLineEdit::insertFilter(const QString &filter)
|
|
|
|
{
|
|
|
|
QString padded_filter = filter;
|
|
|
|
|
|
|
|
if (hasSelectedText()) {
|
|
|
|
backspace();
|
|
|
|
}
|
|
|
|
|
|
|
|
int pos = cursorPosition();
|
|
|
|
if (pos > 0 && !text().at(pos - 1).isSpace()) {
|
|
|
|
padded_filter.prepend(" ");
|
|
|
|
}
|
|
|
|
if (pos < text().length() - 1 && !text().at(pos + 1).isSpace()) {
|
|
|
|
padded_filter.append(" ");
|
|
|
|
}
|
|
|
|
insert(padded_filter);
|
|
|
|
}
|
|
|
|
|
2020-08-05 20:42:24 +00:00
|
|
|
bool SyntaxLineEdit::checkDisplayFilter(QString filter)
|
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
|
|
|
{
|
2020-07-03 11:15:29 +00:00
|
|
|
if (!completion_enabled_) {
|
2020-08-05 20:42:24 +00:00
|
|
|
return false;
|
2020-07-03 11:15:29 +00:00
|
|
|
}
|
|
|
|
|
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
|
|
|
if (filter.isEmpty()) {
|
|
|
|
setSyntaxState(SyntaxLineEdit::Empty);
|
2020-08-05 20:42:24 +00:00
|
|
|
return true;
|
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
|
|
|
}
|
|
|
|
|
|
|
|
dfilter_t *dfp = NULL;
|
2022-11-19 19:21:19 +00:00
|
|
|
df_error_t *df_err = NULL;
|
|
|
|
if (dfilter_compile(filter.toUtf8().constData(), &dfp, &df_err)) {
|
2022-12-29 20:06:19 +00:00
|
|
|
GSList *warn;
|
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
|
|
|
GPtrArray *depr = NULL;
|
2022-12-29 20:06:19 +00:00
|
|
|
if (dfp != NULL && (warn = dfilter_get_warnings(dfp)) != NULL) {
|
|
|
|
// FIXME Need to use a different state or rename ::Deprecated
|
|
|
|
setSyntaxState(SyntaxLineEdit::Deprecated);
|
|
|
|
/*
|
|
|
|
* We're being lazy and only printing the first warning.
|
|
|
|
* Would it be better to print all of them?
|
|
|
|
*/
|
|
|
|
syntax_error_message_ = QString(static_cast<gchar *>(warn->data));
|
|
|
|
} else if (dfp != NULL && (depr = dfilter_deprecated_tokens(dfp)) != NULL) {
|
2015-01-18 10:22:19 +00:00
|
|
|
// You keep using that word. I do not think it means what you think it means.
|
2020-02-12 20:34:02 +00:00
|
|
|
// Possible alternatives: ::Troubled, or ::Problematic maybe?
|
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
|
|
|
setSyntaxState(SyntaxLineEdit::Deprecated);
|
2016-01-15 19:35:47 +00:00
|
|
|
/*
|
|
|
|
* We're being lazy and only printing the first "problem" token.
|
|
|
|
* Would it be better to print all of them?
|
|
|
|
*/
|
2020-02-12 20:34:02 +00:00
|
|
|
QString token((const char *)g_ptr_array_index(depr, 0));
|
|
|
|
gchar *token_str = qstring_strdup(token.section('.', 0, 0));
|
|
|
|
header_field_info *hfi = proto_registrar_get_byalias(token_str);
|
|
|
|
if (hfi)
|
|
|
|
syntax_error_message_ = tr("\"%1\" is deprecated in favour of \"%2\". "
|
dfilter: Fix "!=" relation to be free of contradictions
Wireshark defines the relation of equality A == B as
A any_eq B <=> An == Bn for at least one An, Bn.
More accurately I think this is (formally) an equivalence
relation, not true equality.
Whichever definition for "==" we choose we must keep the
definition of "!=" as !(A == B), otherwise it will
lead to logical contradictions like (A == B) AND (A != B)
being true.
Fix the '!=' relation to match the definition of equality:
A != B <=> !(A == B) <=> A all_ne B <=> An != Bn, for
every n.
This has been the recomended way to write "not equal" for a
long time in the documentation, even to the point where != was
deprecated, but it just wasn't implemented consistently in the
language, which has understandably been a persistent source
of confusion. Even a field that is normally well-behaved
with "!=" like "ip.src" or "ip.dst" will produce unexpected
results with encapsulations like IP-over-IP.
The opcode ALL_NE could have been implemented in the compiler
instead using NOT and ANY_EQ but I chose to implement it in
bytecode. It just seemed more elegant and efficient
but the difference was not very significant.
Keep around "~=" for any_ne relation, in case someone depends
on that, and because we don't have an operator for true equality:
A strict_equal B <=> A all_eq B <=> !(A any_ne B).
If there is only one value then any_ne and all_ne are the same
comparison operation.
Implementing this change did not require fixing any tests so it
is unlikely the relation "~=" (any_ne) will be very useful.
Note that the behaviour of the '<' (less than) comparison relation
is a separate, more subtle issue. In the general case the definition
of '<' that is used is only a partial order.
2021-10-18 20:07:06 +00:00
|
|
|
"See Help section 6.4.8 for details.").arg(token_str).arg(hfi->abbrev);
|
2020-02-12 20:34:02 +00:00
|
|
|
else
|
dfilter: Fix "!=" relation to be free of contradictions
Wireshark defines the relation of equality A == B as
A any_eq B <=> An == Bn for at least one An, Bn.
More accurately I think this is (formally) an equivalence
relation, not true equality.
Whichever definition for "==" we choose we must keep the
definition of "!=" as !(A == B), otherwise it will
lead to logical contradictions like (A == B) AND (A != B)
being true.
Fix the '!=' relation to match the definition of equality:
A != B <=> !(A == B) <=> A all_ne B <=> An != Bn, for
every n.
This has been the recomended way to write "not equal" for a
long time in the documentation, even to the point where != was
deprecated, but it just wasn't implemented consistently in the
language, which has understandably been a persistent source
of confusion. Even a field that is normally well-behaved
with "!=" like "ip.src" or "ip.dst" will produce unexpected
results with encapsulations like IP-over-IP.
The opcode ALL_NE could have been implemented in the compiler
instead using NOT and ANY_EQ but I chose to implement it in
bytecode. It just seemed more elegant and efficient
but the difference was not very significant.
Keep around "~=" for any_ne relation, in case someone depends
on that, and because we don't have an operator for true equality:
A strict_equal B <=> A all_eq B <=> !(A any_ne B).
If there is only one value then any_ne and all_ne are the same
comparison operation.
Implementing this change did not require fixing any tests so it
is unlikely the relation "~=" (any_ne) will be very useful.
Note that the behaviour of the '<' (less than) comparison relation
is a separate, more subtle issue. In the general case the definition
of '<' that is used is only a partial order.
2021-10-18 20:07:06 +00:00
|
|
|
// The token_str is the message.
|
|
|
|
syntax_error_message_ = tr("%1").arg(token_str);
|
2020-02-12 20:34:02 +00:00
|
|
|
g_free(token_str);
|
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
|
|
|
} else {
|
2015-01-18 10:22:19 +00:00
|
|
|
setSyntaxState(SyntaxLineEdit::Valid);
|
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
|
|
|
}
|
2015-01-18 10:22:19 +00:00
|
|
|
} else {
|
|
|
|
setSyntaxState(SyntaxLineEdit::Invalid);
|
2022-11-19 19:21:19 +00:00
|
|
|
syntax_error_message_ = QString::fromUtf8(df_err->msg);
|
|
|
|
syntax_error_message_full_ = createSyntaxErrorMessageFull(filter, syntax_error_message_, df_err->loc.col_start, df_err->loc.col_len);
|
2023-04-14 23:18:53 +00:00
|
|
|
df_error_free(&df_err);
|
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
|
|
|
}
|
|
|
|
dfilter_free(dfp);
|
2020-08-05 20:42:24 +00:00
|
|
|
|
|
|
|
return true;
|
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
|
|
|
}
|
|
|
|
|
|
|
|
void SyntaxLineEdit::checkFieldName(QString field)
|
|
|
|
{
|
|
|
|
if (field.isEmpty()) {
|
|
|
|
setSyntaxState(SyntaxLineEdit::Empty);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
char invalid_char = proto_check_field_name(field.toUtf8().constData());
|
|
|
|
if (invalid_char) {
|
|
|
|
setSyntaxState(SyntaxLineEdit::Invalid);
|
|
|
|
} else {
|
|
|
|
checkDisplayFilter(field);
|
|
|
|
}
|
|
|
|
}
|
2015-01-01 19:41:03 +00:00
|
|
|
|
2015-12-11 08:34:08 +00:00
|
|
|
void SyntaxLineEdit::checkCustomColumn(QString fields)
|
|
|
|
{
|
|
|
|
if (fields.isEmpty()) {
|
|
|
|
setSyntaxState(SyntaxLineEdit::Empty);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
columns: Allow any field expression syntax to be used in columns
Allow anything that can be used in a display filter to be used in
columns (with the exception that field references don't work without
a notion of a currently selected frame): display filter functions,
slices, arithmetic calculations, logical tests, raw byte addressing,
the layer modifier, display filter macros, etc., alone or in
combination.
Show the results and generate filters. Note that "resolved" values are
not yet supported. They make conceptual sense for some expressions
(e.g., if the layer modifier only is used) but not for others.
Perhaps resolution could be done as a final step in the filter before
returning values.
It would also be useful to be able to get the expected return type
of an expression, so that the functions for right justifying a column
or sorting numerically could work. Right now the results are treated
as strings even if the return field values are numeric.
Multifield columns (i.e., concatenation of field values) are currently
implemented using the OR operator.For backwards compability, continue to
support that. When a true logical OR would give a different result,
surround the expression in parentheses, which the multifield columns did
not previously support (due to the regex used instead of full filter
grammar parsing.)
Perhaps in the future we should introduce a separate operator for
concatenation, possibly only used in column definitions and nowhere
else.
Update release notes.
Fix #7752. Fix #10154. Fix #15990. Fix #18588. Fix #19076.
Related to #16181 - it's now possibly to define new display filter
functions so that is essentially solved, though I suppose there's
always room for more built-in functions.
2024-02-08 02:13:23 +00:00
|
|
|
#if 0
|
|
|
|
// XXX - Eventually, if the operator we split on is something not supported
|
|
|
|
// in the filter expression syntax (so that we can distinguish multifield
|
|
|
|
// concatenation of column strings from a logical OR), we would split and
|
|
|
|
// then check each split result as a valid display filter.
|
|
|
|
// For now, any expression that is a valid display filter should work.
|
|
|
|
//
|
|
|
|
// We also, for the custom columns, want some of the extra completion
|
|
|
|
// information from DisplayFilterEdit (like the display filter functions),
|
|
|
|
// without all of its integration into the main app, but not every user
|
|
|
|
// of FieldFilterEdit wants that, so perhaps we eventually should have
|
|
|
|
// another class.
|
2015-12-28 23:05:54 +00:00
|
|
|
gchar **splitted_fields = g_regex_split_simple(COL_CUSTOM_PRIME_REGEX,
|
column: Update custom column regex
When splitting a possibly multifield custom column expression
into components, don't match "or" unless it's a word by itself,
i.e. is surrounded by space. "||" by itself is fine as a token.
This is necessary if we allow more complicated filters to match
than just single fields separated by "||" or "or". Also split
at space at the beginning or end of a string (since we don't
always guarantee that whitespace is stripped.)
When spliting into components, only split on "||" and " or " that
are not inside parenthesis. Splitting on operators inside parentheses
results in components which are not fields or valid filter expressions
and has never worked, e.g. splitting "(tcp.srcport or tcp.dstport)"
into "(tcp.srcport" and "tcp.dstport)".
TEST_OR has the lowest possible operator precedence (see
commit 34ad6bb47887fab144c8e2547dce58152111abb0), so this works,
and also justifies using OR instead of AND for multifield custom
columns.
This means that, e.g., "tcp.srcport or tcp.dstport" will be treated
as a multifield custom column expression that returns the values
for both of the fields, whereas "(tcp.srcport or tcp.dstport)" will
be ultimately treated as a single logical test that returns true
if one of the fields exist and false if neither do. Until tests
and other non single-field expressions are supported, the latter
won't work, but it never has worked.
Related to #7752, #10154, #15990, #18588, and #16181.
2024-02-08 01:01:53 +00:00
|
|
|
fields.toUtf8().constData(), (GRegexCompileFlags) G_REGEX_RAW,
|
|
|
|
(GRegexMatchFlags) 0);
|
2015-12-11 08:34:08 +00:00
|
|
|
|
2015-12-28 23:05:54 +00:00
|
|
|
for (guint i = 0; i < g_strv_length(splitted_fields); i++) {
|
|
|
|
if (splitted_fields[i] && *splitted_fields[i]) {
|
|
|
|
if (proto_check_field_name(splitted_fields[i]) != 0) {
|
2015-12-11 08:34:08 +00:00
|
|
|
setSyntaxState(SyntaxLineEdit::Invalid);
|
|
|
|
g_strfreev(splitted_fields);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
g_strfreev(splitted_fields);
|
columns: Allow any field expression syntax to be used in columns
Allow anything that can be used in a display filter to be used in
columns (with the exception that field references don't work without
a notion of a currently selected frame): display filter functions,
slices, arithmetic calculations, logical tests, raw byte addressing,
the layer modifier, display filter macros, etc., alone or in
combination.
Show the results and generate filters. Note that "resolved" values are
not yet supported. They make conceptual sense for some expressions
(e.g., if the layer modifier only is used) but not for others.
Perhaps resolution could be done as a final step in the filter before
returning values.
It would also be useful to be able to get the expected return type
of an expression, so that the functions for right justifying a column
or sorting numerically could work. Right now the results are treated
as strings even if the return field values are numeric.
Multifield columns (i.e., concatenation of field values) are currently
implemented using the OR operator.For backwards compability, continue to
support that. When a true logical OR would give a different result,
surround the expression in parentheses, which the multifield columns did
not previously support (due to the regex used instead of full filter
grammar parsing.)
Perhaps in the future we should introduce a separate operator for
concatenation, possibly only used in column definitions and nowhere
else.
Update release notes.
Fix #7752. Fix #10154. Fix #15990. Fix #18588. Fix #19076.
Related to #16181 - it's now possibly to define new display filter
functions so that is essentially solved, though I suppose there's
always room for more built-in functions.
2024-02-08 02:13:23 +00:00
|
|
|
#endif
|
2015-12-11 08:34:08 +00:00
|
|
|
|
|
|
|
checkDisplayFilter(fields);
|
|
|
|
}
|
|
|
|
|
2015-01-01 19:41:03 +00:00
|
|
|
void SyntaxLineEdit::checkInteger(QString number)
|
|
|
|
{
|
|
|
|
if (number.isEmpty()) {
|
|
|
|
setSyntaxState(SyntaxLineEdit::Empty);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ok;
|
|
|
|
text().toInt(&ok);
|
|
|
|
if (ok) {
|
|
|
|
setSyntaxState(SyntaxLineEdit::Valid);
|
|
|
|
} else {
|
|
|
|
setSyntaxState(SyntaxLineEdit::Invalid);
|
|
|
|
}
|
|
|
|
}
|
2015-05-19 17:18:54 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2016-03-22 23:17:31 +00:00
|
|
|
bool SyntaxLineEdit::event(QEvent *event)
|
|
|
|
{
|
|
|
|
if (event->type() == QEvent::ShortcutOverride) {
|
2016-06-21 23:23:04 +00:00
|
|
|
// You can't set time display formats while the display filter edit
|
|
|
|
// has focus.
|
|
|
|
|
|
|
|
// Keep shortcuts in the main window from stealing keyPressEvents
|
|
|
|
// with Ctrl+Alt modifiers from us. This is a problem for many AltGr
|
|
|
|
// combinations since they are delivered with Ctrl+Alt modifiers
|
|
|
|
// instead of Qt::Key_AltGr and they tend to match the time display
|
|
|
|
// format shortcuts.
|
|
|
|
|
|
|
|
// Uncommenting the qDebug line below prints the following here:
|
|
|
|
//
|
|
|
|
// US Keyboard:
|
|
|
|
// Ctrl+o: 79 QFlags<Qt::KeyboardModifiers>(ControlModifier) "\u000F"
|
|
|
|
// Ctrl+Alt+2: 50 QFlags<Qt::KeyboardModifiers>(ControlModifier|AltModifier) "2"
|
|
|
|
//
|
|
|
|
// Swedish (Sweden) Keyboard:
|
|
|
|
// Ctrl+o: 79 QFlags<Qt::KeyboardModifiers>(ControlModifier) "\u000F"
|
|
|
|
// Ctrl+Alt+2: 64 QFlags<Qt::KeyboardModifiers>(ControlModifier|AltModifier) "@"
|
|
|
|
// AltGr+{: 123 QFlags<Qt::KeyboardModifiers>(ControlModifier|AltModifier) "{"
|
|
|
|
|
|
|
|
QKeyEvent* key_event = static_cast<QKeyEvent*>(event);
|
|
|
|
// qDebug() << "=so" << key_event->key() << key_event->modifiers() << key_event->text();
|
|
|
|
|
|
|
|
if (key_event->modifiers() == Qt::KeyboardModifiers(Qt::ControlModifier|Qt::AltModifier)) {
|
|
|
|
event->accept();
|
|
|
|
return true;
|
|
|
|
}
|
2016-03-22 23:17:31 +00:00
|
|
|
}
|
|
|
|
return QLineEdit::event(event);
|
|
|
|
}
|
|
|
|
|
2015-05-19 17:18:54 +00:00
|
|
|
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:
|
2018-04-06 19:01:06 +00:00
|
|
|
break;
|
2015-05-19 17:18:54 +00:00
|
|
|
case Qt::Key_Tab:
|
2015-09-01 14:37:45 +00:00
|
|
|
focusNextChild();
|
|
|
|
break;
|
|
|
|
case Qt::Key_Escape:
|
2015-05-19 17:18:54 +00:00
|
|
|
case Qt::Key_Backtab:
|
|
|
|
event->ignore();
|
|
|
|
return;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// ...otherwise process the key ourselves.
|
|
|
|
SyntaxLineEdit::keyPressEvent(event);
|
|
|
|
|
2020-07-03 11:15:29 +00:00
|
|
|
if (!completion_enabled_ || !completer_ || !completion_model_ || !prefs.gui_autocomplete_filter) return;
|
2015-05-19 17:18:54 +00:00
|
|
|
|
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
2022-11-19 11:14:57 +00:00
|
|
|
QStringList sentence(splitLineUnderCursor());
|
|
|
|
Q_ASSERT(sentence.size() == 2); // (preamble, token)
|
|
|
|
buildCompletionList(sentence[1] /* token */, sentence[0] /* preamble */);
|
2015-05-19 17:18:54 +00:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2016-06-24 15:59:48 +00:00
|
|
|
void SyntaxLineEdit::focusOutEvent(QFocusEvent *event)
|
|
|
|
{
|
|
|
|
if (completer_ && completer_->popup()->isVisible() && event->reason() == Qt::PopupFocusReason) {
|
|
|
|
// Pretend we still have focus so that we'll draw our cursor.
|
|
|
|
// If cursorRect() were more precise we could just draw the cursor
|
|
|
|
// during a paintEvent.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
QLineEdit::focusOutEvent(event);
|
|
|
|
}
|
|
|
|
|
2018-12-05 23:37:27 +00:00
|
|
|
// Add indicator icons for syntax states in order to make things more clear for
|
|
|
|
// color blind people.
|
|
|
|
void SyntaxLineEdit::paintEvent(QPaintEvent *event)
|
|
|
|
{
|
2022-06-21 02:32:32 +00:00
|
|
|
QStyleOptionFrame opt;
|
|
|
|
initStyleOption(&opt);
|
|
|
|
QRect cr = style()->subElementRect(QStyle::SE_LineEditContents, &opt, this);
|
|
|
|
QPainter painter(this);
|
|
|
|
|
|
|
|
// In my (gcc) testing here, if I add "background: yellow;" to the DisplayFilterCombo
|
|
|
|
// stylesheet, when building with Qt 5.15.2 the combobox background is yellow and the
|
|
|
|
// text entry area (between the bookmark and apply button) is drawn in the correct
|
|
|
|
// base color (white for light mode and black for dark mode), and the correct syntax
|
|
|
|
// color otherwise. When building with Qt 6.2.4 and 6.3.1, the combobox background is
|
|
|
|
// yellow and the text entry area is always yellow, i.e. QLineEdit isn't painting its
|
|
|
|
// background for some reason.
|
|
|
|
//
|
|
|
|
// It's not clear if this is a bug or just how things work under Qt6. Either way, it's
|
|
|
|
// easy to work around.
|
|
|
|
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
|
|
|
// Must match CaptureFilterEdit and DisplayFilterEdit stylesheets.
|
|
|
|
int pad = style()->pixelMetric(QStyle::PM_DefaultFrameWidth) + 1;
|
2023-06-15 07:42:20 +00:00
|
|
|
QRect full_cr = cr.adjusted(-pad, 0, -1, 0);
|
2022-07-06 02:34:59 +00:00
|
|
|
QBrush bg;
|
|
|
|
|
|
|
|
switch (syntax_state_) {
|
|
|
|
case Valid:
|
|
|
|
bg = ColorUtils::fromColorT(&prefs.gui_text_valid);
|
|
|
|
break;
|
|
|
|
case Invalid:
|
|
|
|
bg = ColorUtils::fromColorT(&prefs.gui_text_invalid);
|
|
|
|
break;
|
|
|
|
case Deprecated:
|
|
|
|
bg = ColorUtils::fromColorT(&prefs.gui_text_deprecated);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
bg = palette().base();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
painter.fillRect(full_cr, bg);
|
2022-06-21 02:32:32 +00:00
|
|
|
#endif
|
|
|
|
|
2018-12-05 23:37:27 +00:00
|
|
|
QLineEdit::paintEvent(event);
|
|
|
|
|
|
|
|
QString si_name;
|
|
|
|
|
|
|
|
switch (syntax_state_) {
|
|
|
|
case Invalid:
|
|
|
|
si_name = "x-filter-invalid";
|
|
|
|
break;
|
|
|
|
case Deprecated:
|
|
|
|
si_name = "x-filter-deprecated";
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
QRect sir = QRect(0, 0, 14, 14); // QIcon::paint scales, which is not what we want.
|
2019-06-29 15:02:59 +00:00
|
|
|
int textWidth = fontMetrics().boundingRect(text()).width();
|
|
|
|
// Qt always adds a margin of 6px between the border and text, see
|
|
|
|
// QLineEditPrivate::effectiveLeftTextMargin and
|
|
|
|
// QLineEditPrivate::sideWidgetParameters.
|
|
|
|
int margin = 2 * 6 + 1;
|
2018-12-05 23:37:27 +00:00
|
|
|
|
2019-06-29 15:02:59 +00:00
|
|
|
if (cr.width() - margin - textWidth < sir.width() || cr.height() < sir.height()) {
|
2018-12-05 23:37:27 +00:00
|
|
|
// No space to draw
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
QIcon state_icon = StockIcon(si_name);
|
|
|
|
if (state_icon.isNull()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
int si_off = (cr.height() - sir.height()) / 2;
|
2023-11-08 12:35:06 +00:00
|
|
|
sir.moveTop(cr.top() + si_off);
|
2018-12-05 23:37:27 +00:00
|
|
|
sir.moveRight(cr.right() - si_off);
|
2022-06-21 02:32:32 +00:00
|
|
|
painter.save();
|
2018-12-05 23:37:27 +00:00
|
|
|
painter.setOpacity(0.25);
|
|
|
|
state_icon.paint(&painter, sir);
|
2022-06-21 02:32:32 +00:00
|
|
|
painter.restore();
|
2018-12-05 23:37:27 +00:00
|
|
|
}
|
|
|
|
|
2015-05-19 17:18:54 +00:00
|
|
|
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);
|
2022-03-25 19:22:08 +00:00
|
|
|
setCursorPosition(field_coords.x() + static_cast<int>(completion_text.length()));
|
2016-02-22 21:39:49 +00:00
|
|
|
emit textEdited(new_text);
|
2015-05-19 17:18:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
2022-11-19 11:14:57 +00:00
|
|
|
|
|
|
|
QStringList SyntaxLineEdit::splitLineUnderCursor()
|
|
|
|
{
|
|
|
|
QPoint token_coords(getTokenUnderCursor());
|
|
|
|
|
|
|
|
// Split line into preamble and word under cursor.
|
|
|
|
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
|
|
|
|
QString preamble = text().first(token_coords.x()).trimmed();
|
|
|
|
#else
|
|
|
|
QString preamble = text().mid(0, token_coords.x()).trimmed();
|
|
|
|
#endif
|
|
|
|
// This should be trimmed already
|
|
|
|
QString token_word = text().mid(token_coords.x(), token_coords.y());
|
|
|
|
|
|
|
|
return QStringList{ preamble, token_word };
|
|
|
|
}
|