From 8020be30fd46798aa61017f0ec936806d6495d07 Mon Sep 17 00:00:00 2001 From: Roland Knall Date: Tue, 27 Jun 2017 16:36:19 +0200 Subject: Qt: Drag/Drop Filter buttons to order Allow the ordering of the filter buttons via drag/drop in the toolbar Change-Id: Id8793d6514bae36066a7a23d6890985665e753bd Reviewed-on: https://code.wireshark.org/review/22422 Petri-Dish: Roland Knall Tested-by: Petri Dish Buildbot Reviewed-by: Roland Knall --- epan/uat-int.h | 6 + epan/uat.c | 14 +++ ui/qt/CMakeLists.txt | 2 + ui/qt/Makefile.am | 6 +- ui/qt/main_window.cpp | 6 +- ui/qt/main_window.h | 6 +- ui/qt/main_window_slots.cpp | 20 ++++ ui/qt/widgets/drag_drop_toolbar.cpp | 216 ++++++++++++++++++++++++++++++++++++ ui/qt/widgets/drag_drop_toolbar.h | 70 ++++++++++++ 9 files changed, 342 insertions(+), 4 deletions(-) create mode 100644 ui/qt/widgets/drag_drop_toolbar.cpp create mode 100644 ui/qt/widgets/drag_drop_toolbar.h diff --git a/epan/uat-int.h b/epan/uat-int.h index c36a5c136e..a272c8f209 100644 --- a/epan/uat-int.h +++ b/epan/uat-int.h @@ -111,6 +111,12 @@ void uat_insert_record_idx(uat_t *uat, guint rec_idx, const void *src_record); WS_DLL_PUBLIC void uat_remove_record_idx(uat_t *uat, guint rec_idx); +/** + * Moves the entry from the old position to the new one + */ +WS_DLL_PUBLIC +void uat_move_index(uat_t *uat, guint old_idx, guint new_idx); + /** * Removes and destroys all records from the UAT. */ diff --git a/epan/uat.c b/epan/uat.c index 71403485b7..03f73d2a34 100644 --- a/epan/uat.c +++ b/epan/uat.c @@ -225,6 +225,20 @@ void uat_remove_record_idx(uat_t* uat, guint idx) { g_array_remove_index(uat->valid_data, idx); } +void uat_move_index(uat_t * uat, guint old_idx, guint new_idx) +{ + guint dir = 1; + guint start = old_idx; + if ( old_idx > new_idx ) + dir = -1; + + while ( start != new_idx ) + { + uat_swap(uat, start, start + dir); + start += dir; + } +} + /* The returned filename was g_malloc()'d so the caller must free it */ gchar* uat_get_actual_filename(uat_t* uat, gboolean for_writing) { gchar *pers_fname = NULL; diff --git a/ui/qt/CMakeLists.txt b/ui/qt/CMakeLists.txt index 9addc44d43..8024e3fdab 100644 --- a/ui/qt/CMakeLists.txt +++ b/ui/qt/CMakeLists.txt @@ -174,6 +174,7 @@ set(WIRESHARK_QT_HEADERS wireshark_application.h wireshark_dialog.h wlan_statistics_dialog.h + widgets/drag_drop_toolbar.h ${WIRESHARK_CUSTOM_QT_HEADERS} ) @@ -348,6 +349,7 @@ set(WIRESHARK_QT_SRC wireless_timeline.cpp wireshark_application.cpp wireshark_dialog.cpp + widgets/drag_drop_toolbar.cpp ${WIRESHARK_CUSTOM_QT_SRCS} ) diff --git a/ui/qt/Makefile.am b/ui/qt/Makefile.am index ee9c82a6f1..b8c4720998 100644 --- a/ui/qt/Makefile.am +++ b/ui/qt/Makefile.am @@ -305,7 +305,8 @@ MOC_HDRS = \ wireless_timeline.h \ wireshark_application.h \ wireshark_dialog.h \ - wlan_statistics_dialog.h + wlan_statistics_dialog.h \ + widgets/drag_drop_toolbar.h # # .ui files. @@ -592,7 +593,8 @@ WIRESHARK_QT_SRC = \ wireless_frame.cpp \ wireless_timeline.cpp \ wireshark_application.cpp \ - wireshark_dialog.cpp + wireshark_dialog.cpp \ + widgets/drag_drop_toolbar.cpp WIRESHARK_QT_TAP_SRC = \ expert_info_dialog.cpp \ diff --git a/ui/qt/main_window.cpp b/ui/qt/main_window.cpp index 5d7ac14741..fbbbcf58ba 100644 --- a/ui/qt/main_window.cpp +++ b/ui/qt/main_window.cpp @@ -84,6 +84,8 @@ DIAG_ON(frame-larger-than=) #include "qt_ui_utils.h" +#include + #include #include #include @@ -460,11 +462,13 @@ MainWindow::MainWindow(QWidget *parent) : // Make sure filter expressions overflow into a menu instead of a // larger toolbar. We do this by adding them to a child toolbar. // https://bugreports.qt.io/browse/QTBUG-2472 - filter_expression_toolbar_ = new QToolBar(); + filter_expression_toolbar_ = new DragDropToolBar(); filter_expression_toolbar_->setStyleSheet("QToolBar { background: none; border: none; }"); filter_expression_toolbar_->setContextMenuPolicy(Qt::CustomContextMenu); connect(filter_expression_toolbar_, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(filterToolbarCustomMenuHandler(QPoint))); + connect(filter_expression_toolbar_, SIGNAL(actionMoved(QAction*, int, int)), + this, SLOT(filterToolbarActionMoved(QAction*, int, int))); main_ui_->displayFilterToolBar->addWidget(filter_expression_toolbar_); diff --git a/ui/qt/main_window.h b/ui/qt/main_window.h index 55e3407add..26b76d8317 100644 --- a/ui/qt/main_window.h +++ b/ui/qt/main_window.h @@ -68,6 +68,7 @@ class MainWelcome; class PacketList; class ProtoTree; class WirelessFrame; +class DragDropToolBar; class QAction; class QActionGroup; @@ -165,7 +166,7 @@ private: QWidget *freeze_focus_; QMap td_actions; QMap tp_actions; - QToolBar *filter_expression_toolbar_; + DragDropToolBar *filter_expression_toolbar_; bool was_maximized_; bool capture_stopping_; @@ -195,6 +196,8 @@ private: QAction *update_action_; #endif + QPoint dragStartPosition; + QWidget* getLayoutWidget(layout_pane_content_e type); void freeze(); @@ -350,6 +353,7 @@ private slots: void filterToolbarEditFilter(); void filterToolbarDisableFilter(); void filterToolbarRemoveFilter(); + void filterToolbarActionMoved(QAction * action, int oldPos, int newPos); void startInterfaceCapture(bool valid, const QString capture_filter); diff --git a/ui/qt/main_window_slots.cpp b/ui/qt/main_window_slots.cpp index cf70ad4e07..f41f13b104 100644 --- a/ui/qt/main_window_slots.cpp +++ b/ui/qt/main_window_slots.cpp @@ -64,6 +64,7 @@ DIAG_ON(frame-larger-than=) #include "epan/prefs.h" #include "epan/plugin_if.h" #include "epan/uat.h" +#include "epan/uat-int.h" #include "epan/value_string.h" #ifdef HAVE_LUA @@ -87,6 +88,7 @@ DIAG_ON(frame-larger-than=) #include "ui/qt/simple_dialog.h" #include +#include #ifdef HAVE_SOFTWARE_UPDATE #include "ui/software_update.h" @@ -4112,6 +4114,24 @@ void MainWindow::filterToolbarRemoveFilter() } } +void MainWindow::filterToolbarActionMoved(QAction* action, int oldPos, int newPos) +{ + gchar* err = NULL; + if ( oldPos == newPos ) + return; + + UatModel * uatModel = new UatModel(this, "Display expressions"); + QModelIndex rowIndex = uatModel->findRowForColumnContent(action->data(), 2); + if ( rowIndex.isValid() ) + { + uat_t * table = uat_get_table_by_name("Display expressions"); + uat_move_index(table, oldPos, newPos); + uat_save(table, &err); + + g_free(err); + } +} + #ifdef _MSC_VER #pragma warning(pop) #endif diff --git a/ui/qt/widgets/drag_drop_toolbar.cpp b/ui/qt/widgets/drag_drop_toolbar.cpp new file mode 100644 index 0000000000..04f6c7d096 --- /dev/null +++ b/ui/qt/widgets/drag_drop_toolbar.cpp @@ -0,0 +1,216 @@ +/* drag_drop_toolbar.cpp + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define drag_drop_toolbar_action_ "drag_drop_toolbar_action_" + +DragDropToolBar::DragDropToolBar(const QString &title, QWidget *parent) : + QToolBar(title, parent) +{ + childCounter = 0; + setAcceptDrops(true); +} + +DragDropToolBar::DragDropToolBar(QWidget *parent) : + QToolBar(parent) +{ + childCounter = 0; + setAcceptDrops(true); +} + +DragDropToolBar::~DragDropToolBar() +{ +} + +void DragDropToolBar::childEvent(QChildEvent * event) +{ + /* New action has been added */ + if ( event->type() == QEvent::ChildAdded ) + { + if ( event->child()->isWidgetType() ) + { + ((QWidget *)event->child())->installEventFilter(this); + event->child()->setProperty(drag_drop_toolbar_action_, qVariantFromValue(childCounter)); + childCounter++; + } + } + else if ( event->type() == QEvent::ChildRemoved ) + { + childCounter--; + } +} + +bool DragDropToolBar::eventFilter(QObject * obj, QEvent * event) +{ + if ( ! obj->isWidgetType() ) + return QToolBar::eventFilter(obj, event); + + QWidget * elem = qobject_cast(obj); + + if ( ! elem || ( event->type() != QEvent::MouseButtonPress && event->type() != QEvent::MouseMove ) ) + return QToolBar::eventFilter(obj, event); + + QMouseEvent * ev = (QMouseEvent *)event; + + if ( event->type() == QEvent::MouseButtonPress ) + { + if ( ev->buttons() & Qt::LeftButton ) + dragStartPosition = ev->pos(); + } + else if ( event->type() == QEvent::MouseMove ) + { + if ( ( ev->buttons() & Qt::LeftButton ) && (ev->pos() - dragStartPosition).manhattanLength() + > QApplication::startDragDistance()) + { + QDrag * drag = new QDrag(elem); + QMimeData *mimeData = new QMimeData; + mimeData->setData("application/x-wireshark-toolbar-entry", + elem->property(drag_drop_toolbar_action_).toByteArray()); + drag->setMimeData(mimeData); + + qreal dpr = window()->windowHandle()->devicePixelRatio(); + QPixmap pixmap(elem->size() * dpr); + pixmap.setDevicePixelRatio(dpr); + elem->render(&pixmap); + drag->setPixmap(pixmap); + + Qt::DropAction dropAction = drag->exec(Qt::CopyAction | Qt::MoveAction); + + if (dropAction == Qt::MoveAction) + elem->setVisible(false); + + return true; + } + } + + return QToolBar::eventFilter(obj, event); +} + +void DragDropToolBar::dragEnterEvent(QDragEnterEvent *event) +{ + if (event->mimeData()->hasFormat("application/x-wireshark-toolbar-entry")) + { + if (event->source() == this) { + event->setDropAction(Qt::MoveAction); + event->accept(); + } else { + event->acceptProposedAction(); + } + } else { + event->ignore(); + } +} + +void DragDropToolBar::dragMoveEvent(QDragMoveEvent *event) +{ + if (event->mimeData()->hasFormat("application/x-wireshark-toolbar-entry")) + { + if (event->source() == this) { + event->setDropAction(Qt::MoveAction); + event->accept(); + } else { + event->acceptProposedAction(); + QAction * action = actionAt(event->pos()); + if ( action ) + { + foreach(QAction * act, actions()) + { + if ( widgetForAction(act) ) + widgetForAction(act)->setStyleSheet("QWidget { border: none; };"); + } + + widgetForAction(action)->setStyleSheet("QWidget { border: 2px dotted grey; };"); + } + } + } else { + event->ignore(); + } +} + +void DragDropToolBar::dropEvent(QDropEvent *event) +{ + if (event->mimeData()->hasFormat("application/x-wireshark-toolbar-entry")) + { + int oldPos = event->mimeData()->data("application/x-wireshark-toolbar-entry").toInt(); + int newPos = -1; + QAction * action = actionAt(event->pos()); + if ( action && actions().at(oldPos) ) + { + widgetForAction(action)->setStyleSheet("QWidget { border: none; };"); + newPos = widgetForAction(action)->property(drag_drop_toolbar_action_).toInt(); + moveToolbarItems(oldPos, newPos); + emit actionMoved(actions().at(oldPos), oldPos, newPos); + } + + if (event->source() == this) { + event->setDropAction(Qt::MoveAction); + event->accept(); + } else { + event->acceptProposedAction(); + } + + } else { + event->ignore(); + } +} + +void DragDropToolBar::moveToolbarItems(int fromPos, int newPos) +{ + if ( fromPos == newPos ) + return; + + setUpdatesEnabled(false); + + QList storedActions = actions(); + + clear(); + childCounter = 0; + + storedActions.move(fromPos, newPos); + foreach ( QAction * action, storedActions ) + addAction(action); + + setUpdatesEnabled(true); +} + +/* + * 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: + */ diff --git a/ui/qt/widgets/drag_drop_toolbar.h b/ui/qt/widgets/drag_drop_toolbar.h new file mode 100644 index 0000000000..6de98ef628 --- /dev/null +++ b/ui/qt/widgets/drag_drop_toolbar.h @@ -0,0 +1,70 @@ +/* drag_drop_toolbar.h + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef DRAG_DROP_TOOLBAR_H +#define DRAG_DROP_TOOLBAR_H + +#include +#include + +class DragDropToolBar : public QToolBar +{ + Q_OBJECT +public: + explicit DragDropToolBar(const QString &title, QWidget *parent = Q_NULLPTR); + explicit DragDropToolBar(QWidget *parent = Q_NULLPTR); + ~DragDropToolBar(); + +Q_SIGNALS: + void actionMoved(QAction * action, int oldPos, int newPos); + +protected: + + virtual void childEvent(QChildEvent * event); + + virtual bool eventFilter(QObject * obj, QEvent * ev); + virtual void dragEnterEvent(QDragEnterEvent *event); + virtual void dragMoveEvent(QDragMoveEvent *event); + virtual void dropEvent(QDropEvent *event); + +private: + + QPoint dragStartPosition; + int childCounter; + + void moveToolbarItems(int fromPos, int toPos); + +}; + +#endif // DRAG_DROP_TOOLBAR_H + +/* + * 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: + */ -- cgit v1.2.1