aboutsummaryrefslogtreecommitdiffstats
path: root/ui
diff options
context:
space:
mode:
authorRoland Knall <rknall@gmail.com>2020-04-19 14:56:35 +0200
committerRoland Knall <rknall@gmail.com>2020-04-21 11:05:44 +0000
commit9c75c1dc18199ea6b282177e21fe1d445af5bbb3 (patch)
tree48ed797d06402301dbcf074f7dfa314e5cc4de90 /ui
parentd10817ce02c837765a050c006904765275d15e8d (diff)
Qt: Allow folders for filter buttons
Filter buttons can be sorted into folders, by separating different depths by the parent separator "&&". Context menu for filter buttons work also in submenus, and the depth of submenus is only limited by the character limit for the label Bug: 16498 Change-Id: I9c784a36e8c46eede11f679a4c1ac830213de7ce Reviewed-on: https://code.wireshark.org/review/36885 Petri-Dish: Roland Knall <rknall@gmail.com> Tested-by: Petri Dish Buildbot Reviewed-by: Roland Knall <rknall@gmail.com>
Diffstat (limited to 'ui')
-rw-r--r--ui/qt/widgets/filter_expression_toolbar.cpp194
-rw-r--r--ui/qt/widgets/filter_expression_toolbar.h27
2 files changed, 172 insertions, 49 deletions
diff --git a/ui/qt/widgets/filter_expression_toolbar.cpp b/ui/qt/widgets/filter_expression_toolbar.cpp
index 94f5dc665d..29d8b3b1d0 100644
--- a/ui/qt/widgets/filter_expression_toolbar.cpp
+++ b/ui/qt/widgets/filter_expression_toolbar.cpp
@@ -21,10 +21,16 @@
#include <QApplication>
#include <QFrame>
#include <QMenu>
+#include <QEvent>
+#include <QContextMenuEvent>
+#include <QToolButton>
static const char *dfe_property_ = "display filter expression"; //TODO : Fix Translate
static const char *dfe_property_label_ = "display_filter_expression_label";
static const char *dfe_property_expression_ = "display_filter_expression_expr";
+static const char *dfe_menu_ = "filter_menu";
+
+#define PARENT_SEPARATOR "&&"
struct filter_expression_data
{
@@ -32,13 +38,14 @@ struct filter_expression_data
bool actions_added;
};
-
FilterExpressionToolBar::FilterExpressionToolBar(QWidget * parent) :
DragDropToolBar(parent)
{
updateStyleSheet();
setContextMenuPolicy(Qt::CustomContextMenu);
+ /* Give minimum space to the bar, so that drops on an empty bar will work */
+ setMinimumWidth(10);
connect (this, &QWidget::customContextMenuRequested, this, &FilterExpressionToolBar::onCustomMenuHandler);
connect(this, &DragDropToolBar::actionMoved, this, &FilterExpressionToolBar::onActionMoved);
@@ -70,36 +77,45 @@ void FilterExpressionToolBar::onCustomMenuHandler(const QPoint& pos)
if (! filterAction)
return;
- QMenu * filterMenu = new QMenu(this);
-
- QString filterText = filterAction->property(dfe_property_expression_).toString();
- filterMenu->addMenu(FilterAction::createFilterMenu(FilterAction::ActionApply, filterText, true, this));
- filterMenu->addMenu(FilterAction::createFilterMenu(FilterAction::ActionPrepare, filterText, true, this));
- filterMenu->addSeparator();
- filterMenu->addAction(FilterAction::copyFilterAction(filterText, this));
- filterMenu->addSeparator();
- QAction * actEdit = filterMenu->addAction(tr("Edit"));
- connect(actEdit, &QAction::triggered, this, &FilterExpressionToolBar::editFilter);
- actEdit->setProperty(dfe_property_label_, filterAction->property(dfe_property_label_));
- actEdit->setProperty(dfe_property_expression_, filterAction->property(dfe_property_expression_));
- actEdit->setData(filterAction->data());
- QAction * actDisable = filterMenu->addAction(tr("Disable"));
- connect(actDisable, &QAction::triggered, this, &FilterExpressionToolBar::disableFilter);
- actDisable->setProperty(dfe_property_label_, filterAction->property(dfe_property_label_));
- actDisable->setProperty(dfe_property_expression_, filterAction->property(dfe_property_expression_));
- actDisable->setData(filterAction->data());
- QAction * actRemove = filterMenu->addAction(tr("Remove"));
- connect(actRemove, &QAction::triggered, this, &FilterExpressionToolBar::removeFilter);
- actRemove->setProperty(dfe_property_label_, filterAction->property(dfe_property_label_));
- actRemove->setProperty(dfe_property_expression_, filterAction->property(dfe_property_expression_));
- actRemove->setData(filterAction->data());
- filterMenu->addSeparator();
+ customMenu(this, filterAction, pos);
+}
+
+void FilterExpressionToolBar::customMenu(FilterExpressionToolBar * target, QAction * filterAction, const QPoint& pos)
+{
+ QMenu * filterMenu = new QMenu(target);
+
+ /* Only display context menu for actual filter actions */
+ QString filterText = filterAction->property(dfe_property_expression_).toString().trimmed();
+
+ if (!filterText.isEmpty())
+ {
+ filterMenu->addMenu(FilterAction::createFilterMenu(FilterAction::ActionApply, filterText, true, target));
+ filterMenu->addMenu(FilterAction::createFilterMenu(FilterAction::ActionPrepare, filterText, true, target));
+ filterMenu->addSeparator();
+ filterMenu->addAction(FilterAction::copyFilterAction(filterText, target));
+ filterMenu->addSeparator();
+ QAction * actEdit = filterMenu->addAction(tr("Edit"));
+ connect(actEdit, &QAction::triggered, target, &FilterExpressionToolBar::editFilter);
+ actEdit->setProperty(dfe_property_label_, filterAction->property(dfe_property_label_));
+ actEdit->setProperty(dfe_property_expression_, filterAction->property(dfe_property_expression_));
+ actEdit->setData(filterAction->data());
+ QAction * actDisable = filterMenu->addAction(tr("Disable"));
+ connect(actDisable, &QAction::triggered, target, &FilterExpressionToolBar::disableFilter);
+ actDisable->setProperty(dfe_property_label_, filterAction->property(dfe_property_label_));
+ actDisable->setProperty(dfe_property_expression_, filterAction->property(dfe_property_expression_));
+ actDisable->setData(filterAction->data());
+ QAction * actRemove = filterMenu->addAction(tr("Remove"));
+ connect(actRemove, &QAction::triggered, target, &FilterExpressionToolBar::removeFilter);
+ actRemove->setProperty(dfe_property_label_, filterAction->property(dfe_property_label_));
+ actRemove->setProperty(dfe_property_expression_, filterAction->property(dfe_property_expression_));
+ actRemove->setData(filterAction->data());
+ filterMenu->addSeparator();
+ }
QAction *actFilter = filterMenu->addAction(tr("Filter Button Preferences..."));
- connect(actFilter, &QAction::triggered, this, &FilterExpressionToolBar::toolBarShowPreferences);
- actFilter->setProperty(dfe_property_label_, filterAction->property(dfe_property_label_));
- actFilter->setProperty(dfe_property_expression_, filterAction->property(dfe_property_expression_));
- actFilter->setData(filterAction->data());
+ connect(actFilter, &QAction::triggered, target, &FilterExpressionToolBar::toolBarShowPreferences);
+ /* Forcing the menus to get closed, no matter which action has been triggered */
+ connect(filterMenu, &QMenu::triggered, this, &FilterExpressionToolBar::closeMenu);
filterMenu->exec(mapToGlobal(pos));
}
@@ -203,6 +219,8 @@ void FilterExpressionToolBar::editFilter()
if (! sender())
return;
+ closeMenu(qobject_cast<QAction *>(sender()));
+
QString label = ((QAction *)sender())->property(dfe_property_label_).toString();
QString expr = ((QAction *)sender())->property(dfe_property_expression_).toString();
@@ -233,16 +251,10 @@ void FilterExpressionToolBar::updateStyleSheet()
{
// Try to draw 1-pixel-wide separator lines from the button label
// ascent to its baseline.
- int sep_margin = (fontMetrics().height() * 0.5) - 1;
- QColor sep_color = ColorUtils::alphaBlend(palette().text(), palette().base(), 0.3);
setStyleSheet(QString(
"QToolBar { background: none; border: none; spacing: 1px; }"
- "QFrame {"
- " min-width: 1px; max-width: 1px;"
- " margin: %1px 0 %2px 0; padding: 0;"
- " background-color: %3;"
- "}"
- ).arg(sep_margin).arg(sep_margin - 1).arg(sep_color.name()));
+ "QFrame { background: none; min-width: 1px; max-width: 1px; }"
+ ));
}
int FilterExpressionToolBar::uatRowIndexForFilter(QString label, QString expression)
@@ -280,6 +292,95 @@ int FilterExpressionToolBar::uatRowIndexForFilter(QString label, QString express
return result;
}
+bool FilterExpressionToolBar::eventFilter(QObject *obj, QEvent *event)
+{
+ if (event->type() == QEvent::ContextMenu)
+ {
+ QMenu * qm = qobject_cast<QMenu *>(obj);
+
+ if (qm && qm->property(dfe_menu_).toBool()) {
+ QContextMenuEvent *ctx = static_cast<QContextMenuEvent *>(event);
+ QAction * filterAction = qm->actionAt(ctx->pos());
+
+ if (filterAction)
+ customMenu(this, filterAction, ctx->pos());
+ return true;
+ }
+ }
+
+ return QToolBar::eventFilter(obj, event);
+}
+
+void FilterExpressionToolBar::closeMenu(QAction */*sender*/)
+{
+ foreach(QAction * entry, actions())
+ {
+ QWidget * widget = widgetForAction(entry);
+ QToolButton * tb = qobject_cast<QToolButton *>(widget);
+ if (tb && tb->menu())
+ tb->menu()->close();
+ }
+}
+
+QMenu * FilterExpressionToolBar::findParentMenu(const QStringList tree, void *fed_data, QMenu *parent )
+{
+ if (!fed_data)
+ return Q_NULLPTR;
+
+ struct filter_expression_data* data = (filter_expression_data*)fed_data;
+ if (!data->toolbar)
+ return Q_NULLPTR;
+
+ if (! tree.isEmpty())
+ {
+ if (!parent)
+ {
+ /* Searching existing main menus */
+ foreach(QAction * entry, data->toolbar->actions())
+ {
+ QWidget * widget = data->toolbar->widgetForAction(entry);
+ QToolButton * tb = qobject_cast<QToolButton *>(widget);
+ if (tb && tb->menu() && tb->text().compare(tree.at(0).trimmed()) == 0)
+ return findParentMenu(tree.mid(1), fed_data, tb->menu());
+ }
+ }
+ else if (parent)
+ {
+ QString menuName = tree.at(0).trimmed();
+ /* Iterate to see, if we next have to jump into another submenu */
+ foreach(QAction *entry, parent->actions())
+ {
+ if (entry->menu() && entry->text().compare(menuName) == 0)
+ return findParentMenu(tree.mid(1), fed_data, entry->menu());
+ }
+
+ /* Submenu not found, creating */
+ QMenu * subMenu = new QMenu(menuName);
+ subMenu->installEventFilter(data->toolbar);
+ subMenu->setProperty(dfe_menu_, QVariant::fromValue(true));
+ parent->addMenu(subMenu);
+ return findParentMenu(tree.mid(1), fed_data, subMenu);
+ }
+
+ /* No menu has been found, create one */
+ QString parentName = tree.at(0).trimmed();
+ QToolButton * menuButton = new QToolButton();
+ menuButton->setText(parentName);
+ menuButton->setPopupMode(QToolButton::InstantPopup);
+ QMenu * parentMenu = new QMenu(menuButton);
+ parentMenu->installEventFilter(data->toolbar);
+ parentMenu->setProperty(dfe_menu_, QVariant::fromValue(true));
+ menuButton->setMenu(parentMenu);
+ data->toolbar->addWidget(menuButton);
+
+ return findParentMenu(tree.mid(1), fed_data, parentMenu);
+ }
+ else if (parent)
+ return parent;
+
+ return Q_NULLPTR;
+}
+
gboolean FilterExpressionToolBar::filter_expression_add_action(const void *key _U_, void *value, void *user_data)
{
filter_expression_t* fe = (filter_expression_t*)value;
@@ -288,7 +389,17 @@ gboolean FilterExpressionToolBar::filter_expression_add_action(const void *key _
if (!fe->enabled)
return FALSE;
- QAction *dfb_action = new QAction(fe->label, data->toolbar);
+ QString label = QString(fe->label);
+
+ /* Search for parent menu and create if not found */
+ QStringList tree = label.split(PARENT_SEPARATOR);
+ if (!tree.isEmpty())
+ tree.removeLast();
+ QMenu * parentMenu = findParentMenu(tree, data);
+ if (parentMenu)
+ label = label.mid(label.lastIndexOf(PARENT_SEPARATOR) + QString(PARENT_SEPARATOR).length()).trimmed();
+
+ QAction *dfb_action = new QAction(label, data->toolbar);
if (strlen(fe->comment) > 0)
{
QString tooltip = QString("%1\n%2").arg(fe->comment).arg(fe->expression);
@@ -308,7 +419,12 @@ gboolean FilterExpressionToolBar::filter_expression_add_action(const void *key _
sep->setEnabled(false);
data->toolbar->addWidget(sep);
}
- data->toolbar->addAction(dfb_action);
+
+ if (parentMenu)
+ parentMenu->addAction(dfb_action);
+ else
+ data->toolbar->addAction(dfb_action);
+
connect(dfb_action, &QAction::triggered, data->toolbar, &FilterExpressionToolBar::filterClicked);
data->actions_added = true;
return FALSE;
diff --git a/ui/qt/widgets/filter_expression_toolbar.h b/ui/qt/widgets/filter_expression_toolbar.h
index 1e59532d89..58bbbe504c 100644
--- a/ui/qt/widgets/filter_expression_toolbar.h
+++ b/ui/qt/widgets/filter_expression_toolbar.h
@@ -11,6 +11,8 @@
#include <glib.h>
+#include <QMenu>
+
#ifndef FILTER_EXPRESSION_TOOLBAR_H
#define FILTER_EXPRESSION_TOOLBAR_H
@@ -21,9 +23,9 @@ public:
explicit FilterExpressionToolBar(QWidget * parent = Q_NULLPTR);
protected:
- virtual bool event(QEvent *event);
+ virtual bool event(QEvent *event) override;
+ virtual bool eventFilter(QObject *obj, QEvent *ev) override;
-protected:
virtual WiresharkMimeData * createMimeData(QString name, int position);
public slots:
@@ -40,17 +42,22 @@ protected slots:
void onFilterDropped(QString description, QString filter);
private slots:
- void removeFilter();
- void disableFilter();
- void editFilter();
- void filterClicked();
- void toolBarShowPreferences();
+ void removeFilter();
+ void disableFilter();
+ void editFilter();
+ void filterClicked();
+ void toolBarShowPreferences();
+
+ void closeMenu(QAction *);
private:
- void updateStyleSheet();
- int uatRowIndexForFilter(QString label, QString expression);
+ void updateStyleSheet();
+ int uatRowIndexForFilter(QString label, QString expression);
+
+ void customMenu(FilterExpressionToolBar * target, QAction * filterAction, const QPoint& pos);
- static gboolean filter_expression_add_action(const void *key, void *value, void *user_data);
+ static gboolean filter_expression_add_action(const void *key, void *value, void *user_data);
+ static QMenu * findParentMenu(const QStringList tree, void *fed_data, QMenu *parent = Q_NULLPTR);
};
#endif //FILTER_EXPRESSION_TOOLBAR_H