File indexing completed on 2024-03-24 17:22:45

0001 /*
0002  * SPDX-FileCopyrightText: 2014 Emmanuel Pescosta <emmanuelpescosta099@gmail.com>
0003  *
0004  * SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 
0007 #include "dolphintabbar.h"
0008 
0009 #include <KLocalizedString>
0010 
0011 #include <QDragEnterEvent>
0012 #include <QMenu>
0013 #include <QMimeData>
0014 #include <QTimer>
0015 
0016 class PreventFocusWhileHidden : public QObject
0017 {
0018 public:
0019     PreventFocusWhileHidden(QObject *parent)
0020         : QObject(parent){};
0021 
0022 protected:
0023     bool eventFilter(QObject *obj, QEvent *ev) override
0024     {
0025         switch (ev->type()) {
0026         case QEvent::Hide:
0027             static_cast<QWidget *>(obj)->setFocusPolicy(Qt::NoFocus);
0028             return false;
0029         case QEvent::Show:
0030             static_cast<QWidget *>(obj)->setFocusPolicy(Qt::TabFocus);
0031             return false;
0032         default:
0033             return false;
0034         }
0035     };
0036 };
0037 
0038 DolphinTabBar::DolphinTabBar(QWidget *parent)
0039     : QTabBar(parent)
0040     , m_autoActivationIndex(-1)
0041     , m_tabToBeClosedOnMiddleMouseButtonRelease(-1)
0042 {
0043     setAcceptDrops(true);
0044     setSelectionBehaviorOnRemove(QTabBar::SelectPreviousTab);
0045     setMovable(true);
0046     setTabsClosable(true);
0047 
0048     setFocusPolicy(Qt::NoFocus);
0049     installEventFilter(new PreventFocusWhileHidden(this));
0050 
0051     m_autoActivationTimer = new QTimer(this);
0052     m_autoActivationTimer->setSingleShot(true);
0053     m_autoActivationTimer->setInterval(800);
0054     connect(m_autoActivationTimer, &QTimer::timeout, this, &DolphinTabBar::slotAutoActivationTimeout);
0055 }
0056 
0057 void DolphinTabBar::dragEnterEvent(QDragEnterEvent *event)
0058 {
0059     const QMimeData *mimeData = event->mimeData();
0060     const int index = tabAt(event->position().toPoint());
0061 
0062     if (mimeData->hasUrls()) {
0063         event->acceptProposedAction();
0064         updateAutoActivationTimer(index);
0065     }
0066 
0067     QTabBar::dragEnterEvent(event);
0068 }
0069 
0070 void DolphinTabBar::dragLeaveEvent(QDragLeaveEvent *event)
0071 {
0072     updateAutoActivationTimer(-1);
0073 
0074     QTabBar::dragLeaveEvent(event);
0075 }
0076 
0077 void DolphinTabBar::dragMoveEvent(QDragMoveEvent *event)
0078 {
0079     const QMimeData *mimeData = event->mimeData();
0080     const int index = tabAt(event->position().toPoint());
0081 
0082     if (mimeData->hasUrls()) {
0083         updateAutoActivationTimer(index);
0084     }
0085 
0086     QTabBar::dragMoveEvent(event);
0087 }
0088 
0089 void DolphinTabBar::dropEvent(QDropEvent *event)
0090 {
0091     // Disable the auto activation timer
0092     updateAutoActivationTimer(-1);
0093 
0094     const QMimeData *mimeData = event->mimeData();
0095     const int index = tabAt(event->position().toPoint());
0096 
0097     if (mimeData->hasUrls()) {
0098         Q_EMIT tabDropEvent(index, event);
0099     }
0100 
0101     QTabBar::dropEvent(event);
0102 }
0103 
0104 void DolphinTabBar::mousePressEvent(QMouseEvent *event)
0105 {
0106     const int index = tabAt(event->pos());
0107 
0108     if (index >= 0 && event->button() == Qt::MiddleButton) {
0109         m_tabToBeClosedOnMiddleMouseButtonRelease = index;
0110         return;
0111     }
0112 
0113     QTabBar::mousePressEvent(event);
0114 }
0115 
0116 void DolphinTabBar::mouseReleaseEvent(QMouseEvent *event)
0117 {
0118     const int index = tabAt(event->pos());
0119 
0120     if (index >= 0 && index == m_tabToBeClosedOnMiddleMouseButtonRelease && event->button() == Qt::MiddleButton) {
0121         // Mouse middle click on a tab closes this tab.
0122         Q_EMIT tabCloseRequested(index);
0123         return;
0124     }
0125 
0126     QTabBar::mouseReleaseEvent(event);
0127 }
0128 
0129 void DolphinTabBar::mouseDoubleClickEvent(QMouseEvent *event)
0130 {
0131     if (event->buttons() & Qt::LeftButton) {
0132         int index = tabAt(event->pos());
0133 
0134         if (index < 0) {
0135             // empty tabbar area case
0136             index = currentIndex();
0137         }
0138         // Double left click on the tabbar opens a new activated tab
0139         // with the url from the doubleclicked tab or currentTab otherwise.
0140         Q_EMIT openNewActivatedTab(index);
0141     }
0142 
0143     QTabBar::mouseDoubleClickEvent(event);
0144 }
0145 
0146 void DolphinTabBar::contextMenuEvent(QContextMenuEvent *event)
0147 {
0148     const int index = tabAt(event->pos());
0149 
0150     if (index >= 0) {
0151         // Tab context menu
0152         QMenu menu(this);
0153 
0154         QAction *newTabAction = menu.addAction(QIcon::fromTheme(QStringLiteral("tab-new")), i18nc("@action:inmenu", "New Tab"));
0155         QAction *detachTabAction = menu.addAction(QIcon::fromTheme(QStringLiteral("tab-detach")), i18nc("@action:inmenu", "Detach Tab"));
0156         QAction *closeOtherTabsAction = menu.addAction(QIcon::fromTheme(QStringLiteral("tab-close-other")), i18nc("@action:inmenu", "Close Other Tabs"));
0157         QAction *closeTabAction = menu.addAction(QIcon::fromTheme(QStringLiteral("tab-close")), i18nc("@action:inmenu", "Close Tab"));
0158 
0159         QAction *selectedAction = menu.exec(event->globalPos());
0160         if (selectedAction == newTabAction) {
0161             Q_EMIT openNewActivatedTab(index);
0162         } else if (selectedAction == detachTabAction) {
0163             Q_EMIT tabDetachRequested(index);
0164         } else if (selectedAction == closeOtherTabsAction) {
0165             const int tabCount = count();
0166             for (int i = 0; i < index; i++) {
0167                 Q_EMIT tabCloseRequested(0);
0168             }
0169             for (int i = index + 1; i < tabCount; i++) {
0170                 Q_EMIT tabCloseRequested(1);
0171             }
0172         } else if (selectedAction == closeTabAction) {
0173             Q_EMIT tabCloseRequested(index);
0174         }
0175 
0176         return;
0177     }
0178 
0179     QTabBar::contextMenuEvent(event);
0180 }
0181 
0182 void DolphinTabBar::slotAutoActivationTimeout()
0183 {
0184     if (m_autoActivationIndex >= 0) {
0185         setCurrentIndex(m_autoActivationIndex);
0186         updateAutoActivationTimer(-1);
0187     }
0188 }
0189 
0190 void DolphinTabBar::updateAutoActivationTimer(const int index)
0191 {
0192     if (m_autoActivationIndex != index) {
0193         m_autoActivationIndex = index;
0194 
0195         if (m_autoActivationIndex < 0) {
0196             m_autoActivationTimer->stop();
0197         } else {
0198             m_autoActivationTimer->start();
0199         }
0200     }
0201 }
0202 
0203 #include "moc_dolphintabbar.cpp"