File indexing completed on 2024-04-21 14:55:59

0001 /* This file is part of the KDE libraries
0002     Copyright (C) 2003 Stephan Binner <binner@kde.org>
0003     Copyright (C) 2003 Zack Rusin <zack@kde.org>
0004     Copyright (C) 2009 Urs Wolfer <uwolfer @ kde.org>
0005 
0006     This library is free software; you can redistribute it and/or
0007     modify it under the terms of the GNU Library General Public
0008     License as published by the Free Software Foundation; either
0009     version 2 of the License, or (at your option) any later version.
0010 
0011     This library is distributed in the hope that it will be useful,
0012     but WITHOUT ANY WARRANTY; without even the implied warranty of
0013     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0014     Library General Public License for more details.
0015 
0016     You should have received a copy of the GNU Library General Public License
0017     along with this library; see the file COPYING.LIB.  If not, write to
0018     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0019     Boston, MA 02110-1301, USA.
0020 */
0021 
0022 #include "ktabbar.h"
0023 
0024 #include <QTimer>
0025 #include <QApplication>
0026 #include <QCursor>
0027 #include <QMouseEvent>
0028 
0029 class Q_DECL_HIDDEN KTabBar::Private
0030 {
0031 public:
0032     Private()
0033         : mReorderStartTab(-1),
0034           mReorderPreviousTab(-1),
0035           mDragSwitchTab(-1),
0036           mActivateDragSwitchTabTimer(nullptr),
0037           mTabReorderingEnabled(false),
0038           mMiddleMouseTabMoveInProgress(false)
0039     {
0040     }
0041 
0042     QPoint mDragStart;
0043     int mReorderStartTab;
0044     int mReorderPreviousTab;
0045     int mDragSwitchTab;
0046     QTimer *mActivateDragSwitchTabTimer;
0047 
0048     bool mTabReorderingEnabled : 1;
0049     bool mMiddleMouseTabMoveInProgress : 1;
0050 
0051 };
0052 
0053 KTabBar::KTabBar(QWidget *parent)
0054     : QTabBar(parent),
0055       d(new Private)
0056 {
0057     setAcceptDrops(true);
0058     setMouseTracking(true);
0059 
0060     d->mActivateDragSwitchTabTimer = new QTimer(this);
0061     d->mActivateDragSwitchTabTimer->setSingleShot(true);
0062     connect(d->mActivateDragSwitchTabTimer, SIGNAL(timeout()), SLOT(activateDragSwitchTab()));
0063 #ifndef KDELIBS4SUPPORT_NO_DEPRECATED
0064     connect(this, SIGNAL(tabCloseRequested(int)), this, SIGNAL(closeRequest(int)));  // just for backward compatibility, KDE5 remove
0065 #endif
0066 
0067     //connect( this, SIGNAL(layoutChanged()), SLOT(onLayoutChange()) );
0068 }
0069 
0070 KTabBar::~KTabBar()
0071 {
0072     delete d;
0073 }
0074 
0075 void KTabBar::mouseDoubleClickEvent(QMouseEvent *event)
0076 {
0077     if (event->button() != Qt::LeftButton) {
0078         return;
0079     }
0080 
0081     int tab = selectTab(event->pos());
0082 
0083     if (tab == -1) {
0084         emit newTabRequest();
0085     } else {
0086 #ifndef KDELIBS4SUPPORT_NO_DEPRECATED
0087         emit mouseDoubleClick(tab);   //deprecated
0088 #endif
0089         emit tabDoubleClicked(tab);
0090     }
0091 
0092     QTabBar::mouseDoubleClickEvent(event);
0093 }
0094 
0095 void KTabBar::mousePressEvent(QMouseEvent *event)
0096 {
0097     if (event->button() == Qt::LeftButton) {
0098         d->mDragStart = event->pos();
0099     } else if (event->button() == Qt::RightButton) {
0100         int tab = selectTab(event->pos());
0101         if (tab != -1) {
0102             emit contextMenu(tab, mapToGlobal(event->pos()));
0103         } else {
0104             emit emptyAreaContextMenu(mapToGlobal(event->pos()));
0105         }
0106         return;
0107     }
0108 
0109     QTabBar::mousePressEvent(event);
0110 }
0111 
0112 void KTabBar::mouseMoveEvent(QMouseEvent *event)
0113 {
0114     if (event->buttons() == Qt::LeftButton && !isMovable()) {
0115         int tab = selectTab(event->pos());
0116         if (d->mDragSwitchTab && tab != d->mDragSwitchTab) {
0117             d->mActivateDragSwitchTabTimer->stop();
0118             d->mDragSwitchTab = 0;
0119         }
0120 
0121         int delay = QApplication::startDragDistance();
0122         QPoint newPos = event->pos();
0123         if (newPos.x() > d->mDragStart.x() + delay || newPos.x() < d->mDragStart.x() - delay ||
0124                 newPos.y() > d->mDragStart.y() + delay || newPos.y() < d->mDragStart.y() - delay) {
0125             if (tab != -1) {
0126                 emit initiateDrag(tab);
0127                 return;
0128             }
0129         }
0130     } else if (event->buttons() == Qt::MidButton && !isMovable()) {
0131         if (d->mReorderStartTab == -1) {
0132             int delay = QApplication::startDragDistance();
0133             QPoint newPos = event->pos();
0134 
0135             if (newPos.x() > d->mDragStart.x() + delay || newPos.x() < d->mDragStart.x() - delay ||
0136                     newPos.y() > d->mDragStart.y() + delay || newPos.y() < d->mDragStart.y() - delay) {
0137                 int tab = selectTab(event->pos());
0138                 if (tab != -1 && d->mTabReorderingEnabled) {
0139                     d->mReorderStartTab = tab;
0140                     grabMouse(Qt::SizeAllCursor);
0141                     return;
0142                 }
0143             }
0144         } else {
0145             int tab = selectTab(event->pos());
0146             if (tab != -1) {
0147                 int reorderStopTab = tab;
0148                 if (d->mReorderStartTab != reorderStopTab && d->mReorderPreviousTab != reorderStopTab) {
0149                     emit moveTab(d->mReorderStartTab, reorderStopTab);
0150 
0151                     d->mReorderPreviousTab = d->mReorderStartTab;
0152                     d->mReorderStartTab = reorderStopTab;
0153 
0154                     return;
0155                 }
0156             }
0157         }
0158     } else if (event->button() == Qt::NoButton && event->buttons() == Qt::MidButton && isMovable()) {
0159         // compatibility feature for old middle mouse tab moving
0160         event->accept();
0161         if (d->mMiddleMouseTabMoveInProgress == false) {
0162             QMouseEvent fakedMouseEvent(QEvent::MouseButtonPress, event->pos(), Qt::LeftButton, Qt::LeftButton, event->modifiers());
0163             QCoreApplication::sendEvent(this, &fakedMouseEvent);
0164         }
0165         d->mMiddleMouseTabMoveInProgress = true;
0166         QMouseEvent fakedMouseEvent(event->type(), event->pos(), event->button(), Qt::LeftButton, event->modifiers());
0167         QCoreApplication::sendEvent(this, &fakedMouseEvent);
0168         return;
0169     }
0170 
0171     QTabBar::mouseMoveEvent(event);
0172 }
0173 
0174 #ifndef KDELIBS4SUPPORT_NO_DEPRECATED
0175 void KTabBar::closeButtonClicked()
0176 {
0177     // deprecated
0178 }
0179 #endif
0180 
0181 #ifndef KDELIBS4SUPPORT_NO_DEPRECATED
0182 void KTabBar::enableCloseButton()
0183 {
0184     // deprecated
0185 }
0186 #endif
0187 
0188 void KTabBar::activateDragSwitchTab()
0189 {
0190     int tab = selectTab(mapFromGlobal(QCursor::pos()));
0191     if (tab != -1 && d->mDragSwitchTab == tab) {
0192         setCurrentIndex(d->mDragSwitchTab);
0193     }
0194 
0195     d->mDragSwitchTab = 0;
0196 }
0197 
0198 void KTabBar::mouseReleaseEvent(QMouseEvent *event)
0199 {
0200     switch (event->button()) {
0201     case Qt::LeftButton:
0202         break;
0203 
0204     case Qt::MidButton:
0205         if (d->mMiddleMouseTabMoveInProgress && QTabBar::isMovable()) {
0206             // compatibility feature for old middle mouse tab moving
0207             d->mMiddleMouseTabMoveInProgress = false;
0208             event->accept();
0209             QMouseEvent fakedMouseEvent(event->type(), event->pos(), Qt::LeftButton, Qt::LeftButton, event->modifiers());
0210             QCoreApplication::sendEvent(this, &fakedMouseEvent);
0211             return;
0212         }
0213         if (d->mReorderStartTab == -1) {
0214             int tab = selectTab(event->pos());
0215             if (tab != -1) {
0216                 event->accept();
0217                 if (QTabBar::isMovable()) {
0218                     QMouseEvent fakedMouseEvent(event->type(), event->pos(), Qt::LeftButton, Qt::LeftButton, event->modifiers());
0219                     QCoreApplication::sendEvent(this, &fakedMouseEvent);
0220                 }
0221                 if (tabsClosable()) {
0222                     emit tabCloseRequested(tab);
0223                 } else {
0224                     emit mouseMiddleClick(tab);
0225                 }
0226                 return;
0227             }
0228         } else {
0229             releaseMouse();
0230             setCursor(Qt::ArrowCursor);
0231             d->mReorderStartTab = -1;
0232             d->mReorderPreviousTab = -1;
0233         }
0234         break;
0235 
0236     default:
0237         break;
0238     }
0239 
0240     QTabBar::mouseReleaseEvent(event);
0241 }
0242 
0243 void KTabBar::dragEnterEvent(QDragEnterEvent *event)
0244 {
0245     int tab = selectTab(event->pos());
0246     if (tab != -1) {
0247         bool accept = false;
0248         // The receivers of the testCanDecode() signal has to adjust
0249         // 'accept' accordingly.
0250         emit testCanDecode(event, accept);
0251         if (accept && tab != currentIndex()) {
0252             d->mDragSwitchTab = tab;
0253             d->mActivateDragSwitchTabTimer->start(QApplication::doubleClickInterval() * 2);
0254         }
0255 
0256         event->setAccepted(accept);
0257         return;
0258     }
0259 
0260     QTabBar::dragEnterEvent(event);
0261 }
0262 
0263 void KTabBar::dragMoveEvent(QDragMoveEvent *event)
0264 {
0265     int tab = selectTab(event->pos());
0266     if (tab != -1) {
0267         bool accept = false;
0268         // The receivers of the testCanDecode() signal has to adjust
0269         // 'accept' accordingly.
0270         emit testCanDecode(event, accept);
0271         if (accept && tab != currentIndex()) {
0272             d->mDragSwitchTab = tab;
0273             d->mActivateDragSwitchTabTimer->start(QApplication::doubleClickInterval() * 2);
0274         }
0275 
0276         event->setAccepted(accept);
0277         return;
0278     }
0279 
0280     QTabBar::dragMoveEvent(event);
0281 }
0282 
0283 void KTabBar::dropEvent(QDropEvent *event)
0284 {
0285     int tab = selectTab(event->pos());
0286     if (tab != -1) {
0287         d->mActivateDragSwitchTabTimer->stop();
0288         d->mDragSwitchTab = 0;
0289         emit receivedDropEvent(tab, event);
0290         return;
0291     }
0292 
0293     QTabBar::dropEvent(event);
0294 }
0295 
0296 void KTabBar::paintEvent(QPaintEvent *event)
0297 {
0298     QTabBar::paintEvent(event);
0299 }
0300 
0301 void KTabBar::leaveEvent(QEvent *event)
0302 {
0303     QTabBar::leaveEvent(event);
0304 }
0305 
0306 QSize KTabBar::tabSizeHint(int index) const
0307 {
0308     QSize size = QTabBar::tabSizeHint(index);
0309 
0310     return size;
0311 }
0312 
0313 #ifndef QT_NO_WHEELEVENT
0314 void KTabBar::wheelEvent(QWheelEvent *event)
0315 {
0316     if (!(event->orientation() == Qt::Horizontal)) {
0317         if (receivers(SIGNAL(wheelDelta(int)))) {
0318             emit(wheelDelta(event->delta()));
0319             return;
0320         }
0321         int lastIndex = count() - 1;
0322         //Set an invalid index as base case
0323         int targetIndex = -1;
0324         bool forward = event->delta() < 0;
0325         if (forward && lastIndex == currentIndex()) {
0326             targetIndex = 0;
0327         } else if (!forward && 0 == currentIndex()) {
0328             targetIndex = lastIndex;
0329         }
0330         //Will not move when targetIndex is invalid
0331         setCurrentIndex(targetIndex);
0332         //If it has not moved yet (targetIndex == -1), or if it moved but current tab is disabled
0333         if (targetIndex != currentIndex() || !isTabEnabled(targetIndex)) {
0334             QTabBar::wheelEvent(event);
0335         }
0336         event->accept();
0337     } else {
0338         event->ignore();
0339     }
0340 }
0341 #endif
0342 
0343 #ifndef KDELIBS4SUPPORT_NO_DEPRECATED
0344 bool KTabBar::isTabReorderingEnabled() const
0345 {
0346     return d->mTabReorderingEnabled;
0347 }
0348 #endif
0349 
0350 #ifndef KDELIBS4SUPPORT_NO_DEPRECATED
0351 void KTabBar::setTabReorderingEnabled(bool on)
0352 {
0353     d->mTabReorderingEnabled = on;
0354 }
0355 #endif
0356 
0357 #ifndef KDELIBS4SUPPORT_NO_DEPRECATED
0358 bool KTabBar::tabCloseActivatePrevious() const
0359 {
0360     return selectionBehaviorOnRemove() == QTabBar::SelectPreviousTab;
0361 }
0362 #endif
0363 
0364 #ifndef KDELIBS4SUPPORT_NO_DEPRECATED
0365 void KTabBar::setTabCloseActivatePrevious(bool on)
0366 {
0367     setSelectionBehaviorOnRemove(on ? QTabBar::SelectPreviousTab : QTabBar::SelectRightTab);
0368 }
0369 #endif
0370 
0371 #ifndef KDELIBS4SUPPORT_NO_DEPRECATED
0372 void KTabBar::setHoverCloseButton(bool button)
0373 {
0374     // deprecated
0375     setTabsClosable(button);
0376 }
0377 #endif
0378 
0379 #ifndef KDELIBS4SUPPORT_NO_DEPRECATED
0380 bool KTabBar::hoverCloseButton() const
0381 {
0382     // deprecated
0383     return tabsClosable();
0384 }
0385 #endif
0386 
0387 #ifndef KDELIBS4SUPPORT_NO_DEPRECATED
0388 void KTabBar::setHoverCloseButtonDelayed(bool delayed)
0389 {
0390     // deprecated
0391     Q_UNUSED(delayed);
0392 }
0393 #endif
0394 
0395 #ifndef KDELIBS4SUPPORT_NO_DEPRECATED
0396 bool KTabBar::hoverCloseButtonDelayed() const
0397 {
0398     // deprecated
0399     return false;
0400 }
0401 #endif
0402 
0403 #ifndef KDELIBS4SUPPORT_NO_DEPRECATED
0404 void KTabBar::setCloseButtonEnabled(bool enable)
0405 {
0406     QTabBar::setTabsClosable(enable);
0407 }
0408 #endif
0409 
0410 #ifndef KDELIBS4SUPPORT_NO_DEPRECATED
0411 bool KTabBar::isCloseButtonEnabled() const
0412 {
0413     return QTabBar::tabsClosable();
0414 }
0415 #endif
0416 
0417 void KTabBar::tabLayoutChange()
0418 {
0419     d->mActivateDragSwitchTabTimer->stop();
0420     d->mDragSwitchTab = 0;
0421 }
0422 
0423 int KTabBar::selectTab(const QPoint &pos) const
0424 {
0425     const int tabCount = count();
0426     for (int i = 0; i < tabCount; ++i)
0427         if (tabRect(i).contains(pos)) {
0428             return i;
0429         }
0430 
0431     return -1;
0432 }
0433 
0434 QPoint KTabBar::closeButtonPos(int tabIndex) const
0435 {
0436     Q_UNUSED(tabIndex);
0437     return QPoint();
0438 }
0439 
0440 QRect KTabBar::closeButtonRect(int tabIndex) const
0441 {
0442     Q_UNUSED(tabIndex);
0443     return QRect();
0444 }
0445 
0446 #include "moc_ktabbar.cpp"