File indexing completed on 2024-05-05 09:12:43
0001 /* This file is part of the KDE libraries 0002 SPDX-FileCopyrightText: 2003 Stephan Binner <binner@kde.org> 0003 SPDX-FileCopyrightText: 2003 Zack Rusin <zack@kde.org> 0004 SPDX-FileCopyrightText: 2009 Urs Wolfer <uwolfer @ kde.org> 0005 0006 SPDX-License-Identifier: LGPL-2.0-or-later 0007 */ 0008 0009 #include "ktabbar.h" 0010 0011 #include <QTimer> 0012 #include <QApplication> 0013 #include <QCursor> 0014 #include <QMouseEvent> 0015 0016 class Q_DECL_HIDDEN KTabBar::Private 0017 { 0018 public: 0019 Private() 0020 : 0021 mDragSwitchTab(-1), 0022 mActivateDragSwitchTabTimer(nullptr), 0023 mMiddleMouseTabMoveInProgress(false) 0024 { 0025 } 0026 0027 QPoint mDragStart; 0028 int mDragSwitchTab; 0029 QTimer *mActivateDragSwitchTabTimer; 0030 0031 bool mMiddleMouseTabMoveInProgress : 1; 0032 0033 }; 0034 0035 KTabBar::KTabBar(QWidget *parent) 0036 : QTabBar(parent), 0037 d(new Private) 0038 { 0039 setAcceptDrops(true); 0040 setMouseTracking(true); 0041 0042 d->mActivateDragSwitchTabTimer = new QTimer(this); 0043 d->mActivateDragSwitchTabTimer->setSingleShot(true); 0044 connect(d->mActivateDragSwitchTabTimer, SIGNAL(timeout()), SLOT(activateDragSwitchTab())); 0045 } 0046 0047 KTabBar::~KTabBar() 0048 { 0049 delete d; 0050 } 0051 0052 void KTabBar::mouseDoubleClickEvent(QMouseEvent *event) 0053 { 0054 if (event->button() != Qt::LeftButton) { 0055 return; 0056 } 0057 0058 int tab = selectTab(event->pos()); 0059 0060 if (tab == -1) { 0061 emit newTabRequest(); 0062 } else { 0063 emit tabDoubleClicked(tab); 0064 } 0065 0066 QTabBar::mouseDoubleClickEvent(event); 0067 } 0068 0069 void KTabBar::mousePressEvent(QMouseEvent *event) 0070 { 0071 if (event->button() == Qt::LeftButton) { 0072 d->mDragStart = event->pos(); 0073 } else if (event->button() == Qt::RightButton) { 0074 int tab = selectTab(event->pos()); 0075 if (tab != -1) { 0076 emit contextMenu(tab, mapToGlobal(event->pos())); 0077 } else { 0078 emit emptyAreaContextMenu(mapToGlobal(event->pos())); 0079 } 0080 return; 0081 } 0082 0083 QTabBar::mousePressEvent(event); 0084 } 0085 0086 void KTabBar::mouseMoveEvent(QMouseEvent *event) 0087 { 0088 if (event->buttons() == Qt::LeftButton && !isMovable()) { 0089 int tab = selectTab(event->pos()); 0090 if (d->mDragSwitchTab && tab != d->mDragSwitchTab) { 0091 d->mActivateDragSwitchTabTimer->stop(); 0092 d->mDragSwitchTab = 0; 0093 } 0094 0095 int delay = QApplication::startDragDistance(); 0096 QPoint newPos = event->pos(); 0097 if (newPos.x() > d->mDragStart.x() + delay || newPos.x() < d->mDragStart.x() - delay || 0098 newPos.y() > d->mDragStart.y() + delay || newPos.y() < d->mDragStart.y() - delay) { 0099 if (tab != -1) { 0100 emit initiateDrag(tab); 0101 return; 0102 } 0103 } 0104 } 0105 0106 QTabBar::mouseMoveEvent(event); 0107 } 0108 0109 void KTabBar::activateDragSwitchTab() 0110 { 0111 int tab = selectTab(mapFromGlobal(QCursor::pos())); 0112 if (tab != -1 && d->mDragSwitchTab == tab) { 0113 setCurrentIndex(d->mDragSwitchTab); 0114 } 0115 0116 d->mDragSwitchTab = 0; 0117 } 0118 0119 void KTabBar::dragEnterEvent(QDragEnterEvent *event) 0120 { 0121 int tab = selectTab(event->pos()); 0122 if (tab != -1) { 0123 bool accept = false; 0124 // The receivers of the testCanDecode() signal has to adjust 0125 // 'accept' accordingly. 0126 emit testCanDecode(event, accept); 0127 if (accept && tab != currentIndex()) { 0128 d->mDragSwitchTab = tab; 0129 d->mActivateDragSwitchTabTimer->start(QApplication::doubleClickInterval() * 2); 0130 } 0131 0132 event->setAccepted(accept); 0133 return; 0134 } 0135 0136 QTabBar::dragEnterEvent(event); 0137 } 0138 0139 void KTabBar::dragMoveEvent(QDragMoveEvent *event) 0140 { 0141 int tab = selectTab(event->pos()); 0142 if (tab != -1) { 0143 bool accept = false; 0144 // The receivers of the testCanDecode() signal has to adjust 0145 // 'accept' accordingly. 0146 emit testCanDecode(event, accept); 0147 if (accept && tab != currentIndex()) { 0148 d->mDragSwitchTab = tab; 0149 d->mActivateDragSwitchTabTimer->start(QApplication::doubleClickInterval() * 2); 0150 } 0151 0152 event->setAccepted(accept); 0153 return; 0154 } 0155 0156 QTabBar::dragMoveEvent(event); 0157 } 0158 0159 void KTabBar::dropEvent(QDropEvent *event) 0160 { 0161 int tab = selectTab(event->pos()); 0162 if (tab != -1) { 0163 d->mActivateDragSwitchTabTimer->stop(); 0164 d->mDragSwitchTab = 0; 0165 emit receivedDropEvent(tab, event); 0166 return; 0167 } 0168 0169 QTabBar::dropEvent(event); 0170 } 0171 0172 #ifndef QT_NO_WHEELEVENT 0173 void KTabBar::wheelEvent(QWheelEvent *event) 0174 { 0175 if (event->angleDelta().y() != 0) { 0176 if (receivers(SIGNAL(wheelDelta(int)))) { 0177 emit(wheelDelta(event->angleDelta().y())); 0178 return; 0179 } 0180 int lastIndex = count() - 1; 0181 //Set an invalid index as base case 0182 int targetIndex = -1; 0183 bool forward = event->angleDelta().y() < 0; 0184 if (forward && lastIndex == currentIndex()) { 0185 targetIndex = 0; 0186 } else if (!forward && 0 == currentIndex()) { 0187 targetIndex = lastIndex; 0188 } 0189 //Will not move when targetIndex is invalid 0190 setCurrentIndex(targetIndex); 0191 //If it has not moved yet (targetIndex == -1), or if it moved but current tab is disabled 0192 if (targetIndex != currentIndex() || !isTabEnabled(targetIndex)) { 0193 QTabBar::wheelEvent(event); 0194 } 0195 event->accept(); 0196 } else { 0197 event->ignore(); 0198 } 0199 } 0200 #endif 0201 0202 void KTabBar::tabLayoutChange() 0203 { 0204 d->mActivateDragSwitchTabTimer->stop(); 0205 d->mDragSwitchTab = 0; 0206 } 0207 0208 int KTabBar::selectTab(const QPoint &pos) const 0209 { 0210 const int tabCount = count(); 0211 for (int i = 0; i < tabCount; ++i) 0212 if (tabRect(i).contains(pos)) { 0213 return i; 0214 } 0215 0216 return -1; 0217 } 0218