File indexing completed on 2024-04-28 05:50:53

0001 /*
0002     SPDX-FileCopyrightText: 2018 Tomaz Canabrava <tcanabrava@kde.org>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "DetachableTabBar.h"
0008 #include "KonsoleSettings.h"
0009 #include "widgets/ViewContainer.h"
0010 
0011 #include <QApplication>
0012 #include <QMimeData>
0013 #include <QMouseEvent>
0014 
0015 #include <KAcceleratorManager>
0016 
0017 #include <QColor>
0018 #include <QPainter>
0019 
0020 namespace Konsole
0021 {
0022 DetachableTabBar::DetachableTabBar(QWidget *parent)
0023     : QTabBar(parent)
0024     , dragType(DragType::NONE)
0025     , _originalCursor(cursor())
0026     , tabId(-1)
0027 {
0028     setAcceptDrops(true);
0029     setElideMode(Qt::TextElideMode::ElideLeft);
0030     KAcceleratorManager::setNoAccel(this);
0031 }
0032 
0033 void DetachableTabBar::setColor(int idx, const QColor &color)
0034 {
0035     setTabData(idx, color);
0036 }
0037 
0038 void DetachableTabBar::removeColor(int idx)
0039 {
0040     setTabData(idx, QVariant());
0041 }
0042 
0043 void DetachableTabBar::middleMouseButtonClickAt(const QPoint &pos)
0044 {
0045     tabId = tabAt(pos);
0046 
0047     if (tabId != -1) {
0048         Q_EMIT closeTab(tabId);
0049     }
0050 }
0051 
0052 void DetachableTabBar::mousePressEvent(QMouseEvent *event)
0053 {
0054     QTabBar::mousePressEvent(event);
0055     _containers = window()->findChildren<Konsole::TabbedViewContainer *>();
0056 }
0057 
0058 void DetachableTabBar::mouseMoveEvent(QMouseEvent *event)
0059 {
0060     QTabBar::mouseMoveEvent(event);
0061     auto widgetAtPos = qApp->topLevelAt(event->globalPosition().toPoint());
0062     if (widgetAtPos != nullptr) {
0063         if (window() == widgetAtPos->window()) {
0064             if (dragType != DragType::NONE) {
0065                 dragType = DragType::NONE;
0066                 setCursor(_originalCursor);
0067             }
0068         } else {
0069             if (dragType != DragType::WINDOW) {
0070                 dragType = DragType::WINDOW;
0071                 setCursor(QCursor(Qt::DragMoveCursor));
0072             }
0073         }
0074     } else if (!contentsRect().adjusted(-30, -30, 30, 30).contains(event->pos())) {
0075         // Don't let it detach the last tab.
0076         if (count() == 1) {
0077             return;
0078         }
0079         if (dragType != DragType::OUTSIDE) {
0080             dragType = DragType::OUTSIDE;
0081             setCursor(QCursor(Qt::DragCopyCursor));
0082         }
0083     }
0084 }
0085 
0086 void DetachableTabBar::mouseReleaseEvent(QMouseEvent *event)
0087 {
0088     QTabBar::mouseReleaseEvent(event);
0089 
0090     switch (event->button()) {
0091     case Qt::MiddleButton:
0092         if (KonsoleSettings::closeTabOnMiddleMouseButton()) {
0093             middleMouseButtonClickAt(event->pos());
0094         }
0095 
0096         tabId = tabAt(event->pos());
0097         if (tabId == -1) {
0098             Q_EMIT newTabRequest();
0099         }
0100         break;
0101     case Qt::LeftButton:
0102         _containers = window()->findChildren<Konsole::TabbedViewContainer *>();
0103         break;
0104     default:
0105         break;
0106     }
0107 
0108     setCursor(_originalCursor);
0109 
0110     if (contentsRect().adjusted(-30, -30, 30, 30).contains(event->pos())) {
0111         return;
0112     }
0113 
0114     auto widgetAtPos = qApp->topLevelAt(event->globalPosition().toPoint());
0115     if (widgetAtPos == nullptr) {
0116         if (count() != 1) {
0117             Q_EMIT detachTab(currentIndex());
0118         }
0119     } else if (window() != widgetAtPos->window()) {
0120         if (_containers.size() == 1 || count() > 1) {
0121             Q_EMIT moveTabToWindow(currentIndex(), widgetAtPos);
0122         }
0123     }
0124 }
0125 
0126 void DetachableTabBar::dragEnterEvent(QDragEnterEvent *event)
0127 {
0128     const auto dragId = QStringLiteral("konsole/terminal_display");
0129     if (!event->mimeData()->hasFormat(dragId)) {
0130         return;
0131     }
0132     auto other_pid = event->mimeData()->data(dragId).toInt();
0133     // don't accept the drop if it's another instance of konsole
0134     if (qApp->applicationPid() != other_pid) {
0135         return;
0136     }
0137     event->accept();
0138 }
0139 
0140 void DetachableTabBar::dragMoveEvent(QDragMoveEvent *event)
0141 {
0142     int tabIdx = tabAt(event->position().toPoint());
0143     if (tabIdx != -1) {
0144         setCurrentIndex(tabIdx);
0145     }
0146 }
0147 
0148 void DetachableTabBar::paintEvent(QPaintEvent *event)
0149 {
0150     QTabBar::paintEvent(event);
0151     if (!event->isAccepted()) {
0152         return; // Reduces repainting
0153     }
0154 
0155     QPainter painter(this);
0156     painter.setPen(Qt::NoPen);
0157 
0158     for (int tabIndex = 0; tabIndex < count(); tabIndex++) {
0159         const QVariant data = tabData(tabIndex);
0160         if (!data.isValid() || data.isNull()) {
0161             continue;
0162         }
0163 
0164         QColor varColor = data.value<QColor>();
0165         if (!varColor.isValid() || varColor.alpha() == 0) {
0166             continue;
0167         }
0168 
0169         painter.setBrush(varColor);
0170         QRect tRect = tabRect(tabIndex);
0171         tRect.setTop(painter.fontMetrics().height() + 6); // Color bar top position consider a height the font and fixed spacing of 6px
0172         tRect.setHeight(4);
0173         tRect.setLeft(tRect.left() + 6);
0174         tRect.setWidth(tRect.width() - 6);
0175         painter.drawRect(tRect);
0176     }
0177 }
0178 
0179 }
0180 
0181 #include "moc_DetachableTabBar.cpp"