/* drag_drop_toolbar.cpp * * Wireshark - Network traffic analyzer * By Gerald Combs * Copyright 1998 Gerald Combs * * SPDX-License-Identifier: GPL-2.0+*/ #include #include #include #include #include #include #include #include #include #include #include #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) #include #endif #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() ) { /* Reset if it has moved underneath lower limit */ if ( childCounter < 0 ) childCounter = 0; ((QWidget *)event->child())->installEventFilter(this); event->child()->setProperty(drag_drop_toolbar_action_, QVariant::fromValue(childCounter)); childCounter++; } } else if ( event->type() == QEvent::ChildRemoved ) { childCounter--; } else if ( event->type() == QEvent::ChildPolished ) { /* Polish is called every time a child is added or removed. This is implemented by adding * all childs again as hidden elements, and afterwards removing the existing ones. Therefore * we have to reset child counter here, if a widget is being polished. If this is not being * done, crashes will occur after an item has been removed and other items are moved afterwards */ if ( event->child()->isWidgetType() ) childCounter = 0; } } void DragDropToolBar::clear() { QToolBar::clear(); childCounter = 0; } 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()) { ToolbarEntryMimeData * temd = new ToolbarEntryMimeData(((QToolButton *)elem)->text(), elem->property(drag_drop_toolbar_action_).toInt()); DragLabel * lbl = new DragLabel(temd->labelText(), this); QDrag * drag = new QDrag(this); drag->setMimeData(temd); #if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0) qreal dpr = window()->windowHandle()->devicePixelRatio(); QPixmap pixmap(lbl->size() * dpr); pixmap.setDevicePixelRatio(dpr); #else QPixmap pixmap(lbl->size()); #endif lbl->render(&pixmap); drag->setPixmap(pixmap); drag->exec(Qt::CopyAction | Qt::MoveAction); return true; } } return QToolBar::eventFilter(obj, event); } void DragDropToolBar::dragEnterEvent(QDragEnterEvent *event) { if ( ! event ) return; if (qobject_cast(event->mimeData())) { if (event->source() == this) { event->setDropAction(Qt::MoveAction); event->accept(); } else { event->acceptProposedAction(); } } else if (qobject_cast(event->mimeData())) { if ( event->source() != this ) { event->setDropAction(Qt::CopyAction); event->accept(); } else { event->acceptProposedAction(); } } else { event->ignore(); } } void DragDropToolBar::dragMoveEvent(QDragMoveEvent *event) { if ( ! event ) return; if (qobject_cast(event->mimeData())) { QAction * actionAtPos = actionAt(event->pos() ); if ( actionAtPos ) { QWidget * widget = widgetForAction(actionAtPos); if ( widget ) { bool success = false; widget->property(drag_drop_toolbar_action_).toInt(&success); if ( ! success ) { event->ignore(); return; } } } if (event->source() == this) { event->setDropAction(Qt::MoveAction); event->accept(); } else { event->acceptProposedAction(); } } else if (qobject_cast(event->mimeData())) { if ( event->source() != this ) { event->setDropAction(Qt::CopyAction); event->accept(); } else { event->acceptProposedAction(); } } else { event->ignore(); } } void DragDropToolBar::dropEvent(QDropEvent *event) { if ( ! event ) return; /* Moving items around */ if (qobject_cast(event->mimeData())) { const ToolbarEntryMimeData * data = qobject_cast(event->mimeData()); int oldPos = data->position(); 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); QAction * moveAction = actions().at(oldPos); emit actionMoved(moveAction, oldPos, newPos); } if (event->source() == this) { event->setDropAction(Qt::MoveAction); event->accept(); } else { event->acceptProposedAction(); } } else if (qobject_cast(event->mimeData())) { const DisplayFilterMimeData * data = qobject_cast(event->mimeData()); if ( event->source() != this ) { event->setDropAction(Qt::CopyAction); event->accept(); emit newFilterDropped(data->description(), data->filter()); } 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: */