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"