File indexing completed on 2024-05-05 05:57:01
0001 /* 0002 SPDX-FileCopyrightText: 2008-2014 Eike Hein <hein@kde.org> 0003 SPDX-FileCopyrightText: 2009 Juan Carlos Torres <carlosdgtorres@gmail.com> 0004 0005 SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0006 */ 0007 0008 #include "tabbar.h" 0009 #include "mainwindow.h" 0010 #include "session.h" 0011 #include "sessionstack.h" 0012 #include "settings.h" 0013 #include "skin.h" 0014 0015 #include <KActionCollection> 0016 #include <KLocalizedString> 0017 0018 #include <QApplication> 0019 #include <QDBusConnection> 0020 #include <QFontDatabase> 0021 #include <QLineEdit> 0022 #include <QMenu> 0023 #include <QPainter> 0024 #include <QPushButton> 0025 #include <QToolButton> 0026 #include <QWhatsThis> 0027 #include <QWheelEvent> 0028 0029 #include <QDrag> 0030 #include <QLabel> 0031 #include <QMimeData> 0032 0033 TabBar::TabBar(MainWindow *mainWindow) 0034 : QWidget(mainWindow) 0035 { 0036 QDBusConnection::sessionBus().registerObject(QStringLiteral("/yakuake/tabs"), this, QDBusConnection::ExportScriptableSlots); 0037 0038 setWhatsThis(xi18nc("@info:whatsthis", 0039 "<title>Tab Bar</title>" 0040 "<para>The tab bar allows you to switch between sessions. You can double-click a tab to edit its label.</para>")); 0041 0042 m_selectedSessionId = -1; 0043 m_renamingSessionId = -1; 0044 0045 m_mousePressed = false; 0046 m_mousePressedIndex = -1; 0047 0048 m_dropIndicator = nullptr; 0049 0050 m_mainWindow = mainWindow; 0051 0052 m_skin = mainWindow->skin(); 0053 connect(m_skin, SIGNAL(iconChanged()), this, SLOT(repaint())); 0054 0055 m_tabContextMenu = new QMenu(this); 0056 connect(m_tabContextMenu, SIGNAL(hovered(QAction *)), this, SLOT(contextMenuActionHovered(QAction *))); 0057 0058 m_toggleKeyboardInputMenu = new QMenu(xi18nc("@title:menu", "Disable Keyboard Input"), this); 0059 m_toggleMonitorActivityMenu = new QMenu(xi18nc("@title:menu", "Monitor for Activity"), this); 0060 m_toggleMonitorSilenceMenu = new QMenu(xi18nc("@title:menu", "Monitor for Silence"), this); 0061 0062 m_sessionMenu = new QMenu(this); 0063 connect(m_sessionMenu, SIGNAL(aboutToShow()), this, SLOT(readySessionMenu())); 0064 0065 m_newTabButton = new QToolButton(this); 0066 m_newTabButton->setFocusPolicy(Qt::NoFocus); 0067 m_newTabButton->setMenu(m_sessionMenu); 0068 m_newTabButton->setPopupMode(QToolButton::DelayedPopup); 0069 m_newTabButton->setToolTip(xi18nc("@info:tooltip", "New Session")); 0070 m_newTabButton->setWhatsThis(xi18nc("@info:whatsthis", "Adds a new session. Press and hold to select session type from menu.")); 0071 connect(m_newTabButton, SIGNAL(clicked()), this, SIGNAL(newTabRequested())); 0072 0073 m_closeTabButton = new QPushButton(this); 0074 m_closeTabButton->setFocusPolicy(Qt::NoFocus); 0075 m_closeTabButton->setToolTip(xi18nc("@info:tooltip", "Close Session")); 0076 m_closeTabButton->setWhatsThis(xi18nc("@info:whatsthis", "Closes the active session.")); 0077 connect(m_closeTabButton, SIGNAL(clicked()), this, SLOT(closeTabButtonClicked())); 0078 0079 m_lineEdit = new QLineEdit(this); 0080 m_lineEdit->setFrame(false); 0081 m_lineEdit->setClearButtonEnabled(false); 0082 m_lineEdit->setAlignment(Qt::AlignHCenter); 0083 m_lineEdit->hide(); 0084 0085 connect(m_lineEdit, SIGNAL(editingFinished()), m_lineEdit, SLOT(hide())); 0086 connect(m_lineEdit, SIGNAL(returnPressed()), this, SLOT(interactiveRenameDone())); 0087 0088 setAcceptDrops(true); 0089 } 0090 0091 TabBar::~TabBar() 0092 { 0093 } 0094 0095 void TabBar::applySkin() 0096 { 0097 resize(width(), m_skin->tabBarBackgroundImage().height()); 0098 0099 m_newTabButton->setStyleSheet(m_skin->tabBarNewTabButtonStyleSheet()); 0100 m_closeTabButton->setStyleSheet(m_skin->tabBarCloseTabButtonStyleSheet()); 0101 0102 moveNewTabButton(); 0103 m_closeTabButton->move(width() - m_skin->tabBarCloseTabButtonPosition().x(), m_skin->tabBarCloseTabButtonPosition().y()); 0104 repaint(); 0105 } 0106 0107 void TabBar::readyTabContextMenu() 0108 { 0109 if (m_tabContextMenu->isEmpty()) { 0110 m_tabContextMenu->addAction(m_mainWindow->actionCollection()->action(QStringLiteral("split-left-right"))); 0111 m_tabContextMenu->addAction(m_mainWindow->actionCollection()->action(QStringLiteral("split-top-bottom"))); 0112 m_tabContextMenu->addSeparator(); 0113 m_tabContextMenu->addAction(m_mainWindow->actionCollection()->action(QStringLiteral("edit-profile"))); 0114 m_tabContextMenu->addAction(m_mainWindow->actionCollection()->action(QStringLiteral("rename-session"))); 0115 m_tabContextMenu->addAction(m_mainWindow->actionCollection()->action(QStringLiteral("toggle-session-prevent-closing"))); 0116 m_tabContextMenu->addMenu(m_toggleKeyboardInputMenu); 0117 m_tabContextMenu->addMenu(m_toggleMonitorActivityMenu); 0118 m_tabContextMenu->addMenu(m_toggleMonitorSilenceMenu); 0119 m_tabContextMenu->addSeparator(); 0120 m_tabContextMenu->addAction(m_mainWindow->actionCollection()->action(QStringLiteral("move-session-left"))); 0121 m_tabContextMenu->addAction(m_mainWindow->actionCollection()->action(QStringLiteral("move-session-right"))); 0122 m_tabContextMenu->addSeparator(); 0123 m_tabContextMenu->addAction(m_mainWindow->actionCollection()->action(QStringLiteral("close-active-terminal"))); 0124 m_tabContextMenu->addAction(m_mainWindow->actionCollection()->action(QStringLiteral("close-session"))); 0125 } 0126 } 0127 0128 void TabBar::readySessionMenu() 0129 { 0130 if (m_sessionMenu->isEmpty()) { 0131 m_sessionMenu->addAction(m_mainWindow->actionCollection()->action(QStringLiteral("new-session"))); 0132 m_sessionMenu->addSeparator(); 0133 m_sessionMenu->addAction(m_mainWindow->actionCollection()->action(QStringLiteral("new-session-two-horizontal"))); 0134 m_sessionMenu->addAction(m_mainWindow->actionCollection()->action(QStringLiteral("new-session-two-vertical"))); 0135 m_sessionMenu->addAction(m_mainWindow->actionCollection()->action(QStringLiteral("new-session-quad"))); 0136 } 0137 } 0138 0139 void TabBar::updateMoveActions(int index) 0140 { 0141 if (index == -1) 0142 return; 0143 0144 m_mainWindow->actionCollection()->action(QStringLiteral("move-session-left"))->setEnabled(false); 0145 m_mainWindow->actionCollection()->action(QStringLiteral("move-session-right"))->setEnabled(false); 0146 0147 if (index != m_tabs.indexOf(m_tabs.first())) 0148 m_mainWindow->actionCollection()->action(QStringLiteral("move-session-left"))->setEnabled(true); 0149 0150 if (index != m_tabs.indexOf(m_tabs.last())) 0151 m_mainWindow->actionCollection()->action(QStringLiteral("move-session-right"))->setEnabled(true); 0152 } 0153 0154 void TabBar::updateToggleActions(int sessionId) 0155 { 0156 if (sessionId == -1) 0157 return; 0158 0159 KActionCollection *actionCollection = m_mainWindow->actionCollection(); 0160 SessionStack *sessionStack = m_mainWindow->sessionStack(); 0161 0162 QAction *toggleAction = actionCollection->action(QStringLiteral("toggle-session-prevent-closing")); 0163 toggleAction->setChecked(!sessionStack->isSessionClosable(sessionId)); 0164 0165 toggleAction = actionCollection->action(QStringLiteral("toggle-session-keyboard-input")); 0166 toggleAction->setChecked(!sessionStack->hasTerminalsWithKeyboardInputEnabled(sessionId)); 0167 0168 toggleAction = actionCollection->action(QStringLiteral("toggle-session-monitor-activity")); 0169 toggleAction->setChecked(!sessionStack->hasTerminalsWithMonitorActivityDisabled(sessionId)); 0170 0171 toggleAction = actionCollection->action(QStringLiteral("toggle-session-monitor-silence")); 0172 toggleAction->setChecked(!sessionStack->hasTerminalsWithMonitorSilenceDisabled(sessionId)); 0173 } 0174 0175 void TabBar::updateToggleKeyboardInputMenu(int sessionId) 0176 { 0177 if (!m_tabs.contains(sessionId)) 0178 return; 0179 0180 QAction *toggleKeyboardInputAction = m_mainWindow->actionCollection()->action(QStringLiteral("toggle-session-keyboard-input")); 0181 QAction *anchor = m_toggleKeyboardInputMenu->menuAction(); 0182 0183 SessionStack *sessionStack = m_mainWindow->sessionStack(); 0184 0185 QStringList terminalIds = sessionStack->terminalIdsForSessionId(sessionId).split(QLatin1Char(','), Qt::SkipEmptyParts); 0186 0187 m_toggleKeyboardInputMenu->clear(); 0188 0189 if (terminalIds.count() <= 1) { 0190 toggleKeyboardInputAction->setText(xi18nc("@action", "Disable Keyboard Input")); 0191 m_tabContextMenu->insertAction(anchor, toggleKeyboardInputAction); 0192 m_toggleKeyboardInputMenu->menuAction()->setVisible(false); 0193 } else { 0194 toggleKeyboardInputAction->setText(xi18nc("@action", "For This Session")); 0195 m_toggleKeyboardInputMenu->menuAction()->setVisible(true); 0196 0197 m_tabContextMenu->removeAction(toggleKeyboardInputAction); 0198 m_toggleKeyboardInputMenu->addAction(toggleKeyboardInputAction); 0199 0200 m_toggleKeyboardInputMenu->addSeparator(); 0201 0202 int count = 0; 0203 0204 QStringListIterator i(terminalIds); 0205 0206 while (i.hasNext()) { 0207 int terminalId = i.next().toInt(); 0208 0209 ++count; 0210 0211 QAction *action = m_toggleKeyboardInputMenu->addAction(xi18nc("@action", "For Terminal %1", count)); 0212 action->setCheckable(true); 0213 action->setChecked(!sessionStack->isTerminalKeyboardInputEnabled(terminalId)); 0214 action->setData(terminalId); 0215 connect(action, SIGNAL(triggered(bool)), m_mainWindow, SLOT(handleToggleTerminalKeyboardInput(bool))); 0216 } 0217 } 0218 } 0219 0220 void TabBar::updateToggleMonitorActivityMenu(int sessionId) 0221 { 0222 if (!m_tabs.contains(sessionId)) 0223 return; 0224 0225 QAction *toggleMonitorActivityAction = m_mainWindow->actionCollection()->action(QStringLiteral("toggle-session-monitor-activity")); 0226 QAction *anchor = m_toggleMonitorActivityMenu->menuAction(); 0227 0228 SessionStack *sessionStack = m_mainWindow->sessionStack(); 0229 0230 QStringList terminalIds = sessionStack->terminalIdsForSessionId(sessionId).split(QLatin1Char(','), Qt::SkipEmptyParts); 0231 0232 m_toggleMonitorActivityMenu->clear(); 0233 0234 if (terminalIds.count() <= 1) { 0235 toggleMonitorActivityAction->setText(xi18nc("@action", "Monitor for Activity")); 0236 m_tabContextMenu->insertAction(anchor, toggleMonitorActivityAction); 0237 m_toggleMonitorActivityMenu->menuAction()->setVisible(false); 0238 } else { 0239 toggleMonitorActivityAction->setText(xi18nc("@action", "In This Session")); 0240 m_toggleMonitorActivityMenu->menuAction()->setVisible(true); 0241 0242 m_tabContextMenu->removeAction(toggleMonitorActivityAction); 0243 m_toggleMonitorActivityMenu->addAction(toggleMonitorActivityAction); 0244 0245 m_toggleMonitorActivityMenu->addSeparator(); 0246 0247 int count = 0; 0248 0249 QStringListIterator i(terminalIds); 0250 0251 while (i.hasNext()) { 0252 int terminalId = i.next().toInt(); 0253 0254 ++count; 0255 0256 QAction *action = m_toggleMonitorActivityMenu->addAction(xi18nc("@action", "In Terminal %1", count)); 0257 action->setCheckable(true); 0258 action->setChecked(sessionStack->isTerminalMonitorActivityEnabled(terminalId)); 0259 action->setData(terminalId); 0260 connect(action, SIGNAL(triggered(bool)), m_mainWindow, SLOT(handleToggleTerminalMonitorActivity(bool))); 0261 } 0262 } 0263 } 0264 0265 void TabBar::updateToggleMonitorSilenceMenu(int sessionId) 0266 { 0267 if (!m_tabs.contains(sessionId)) 0268 return; 0269 0270 QAction *toggleMonitorSilenceAction = m_mainWindow->actionCollection()->action(QStringLiteral("toggle-session-monitor-silence")); 0271 QAction *anchor = m_toggleMonitorSilenceMenu->menuAction(); 0272 0273 SessionStack *sessionStack = m_mainWindow->sessionStack(); 0274 0275 QStringList terminalIds = sessionStack->terminalIdsForSessionId(sessionId).split(QLatin1Char(','), Qt::SkipEmptyParts); 0276 0277 m_toggleMonitorSilenceMenu->clear(); 0278 0279 if (terminalIds.count() <= 1) { 0280 toggleMonitorSilenceAction->setText(xi18nc("@action", "Monitor for Silence")); 0281 m_tabContextMenu->insertAction(anchor, toggleMonitorSilenceAction); 0282 m_toggleMonitorSilenceMenu->menuAction()->setVisible(false); 0283 } else { 0284 toggleMonitorSilenceAction->setText(xi18nc("@action", "In This Session")); 0285 m_toggleMonitorSilenceMenu->menuAction()->setVisible(true); 0286 0287 m_tabContextMenu->removeAction(toggleMonitorSilenceAction); 0288 m_toggleMonitorSilenceMenu->addAction(toggleMonitorSilenceAction); 0289 0290 m_toggleMonitorSilenceMenu->addSeparator(); 0291 0292 int count = 0; 0293 0294 QStringListIterator i(terminalIds); 0295 0296 while (i.hasNext()) { 0297 int terminalId = i.next().toInt(); 0298 0299 ++count; 0300 0301 QAction *action = m_toggleMonitorSilenceMenu->addAction(xi18nc("@action", "In Terminal %1", count)); 0302 action->setCheckable(true); 0303 action->setChecked(sessionStack->isTerminalMonitorSilenceEnabled(terminalId)); 0304 action->setData(terminalId); 0305 connect(action, SIGNAL(triggered(bool)), m_mainWindow, SLOT(handleToggleTerminalMonitorSilence(bool))); 0306 } 0307 } 0308 } 0309 0310 void TabBar::contextMenuActionHovered(QAction *action) 0311 { 0312 bool ok = false; 0313 0314 if (!action->data().isNull()) { 0315 int terminalId = action->data().toInt(&ok); 0316 0317 if (ok) 0318 Q_EMIT requestTerminalHighlight(terminalId); 0319 } else if (!ok) 0320 Q_EMIT requestRemoveTerminalHighlight(); 0321 } 0322 0323 void TabBar::contextMenuEvent(QContextMenuEvent *event) 0324 { 0325 if (event->x() < 0) 0326 return; 0327 0328 int index = tabAt(event->x()); 0329 0330 if (index == -1) 0331 m_sessionMenu->exec(QCursor::pos()); 0332 else { 0333 readyTabContextMenu(); 0334 0335 updateMoveActions(index); 0336 0337 int sessionId = sessionAtTab(index); 0338 updateToggleActions(sessionId); 0339 updateToggleKeyboardInputMenu(sessionId); 0340 updateToggleMonitorActivityMenu(sessionId); 0341 updateToggleMonitorSilenceMenu(sessionId); 0342 0343 m_mainWindow->setContextDependentActionsQuiet(true); 0344 0345 QAction *action = m_tabContextMenu->exec(QCursor::pos()); 0346 0347 Q_EMIT tabContextMenuClosed(); 0348 0349 if (action) { 0350 if (action->isCheckable()) 0351 m_mainWindow->handleContextDependentToggleAction(action->isChecked(), action, sessionId); 0352 else 0353 m_mainWindow->handleContextDependentAction(action, sessionId); 0354 } 0355 0356 m_mainWindow->setContextDependentActionsQuiet(false); 0357 0358 updateMoveActions(m_tabs.indexOf(m_selectedSessionId)); 0359 updateToggleActions(m_selectedSessionId); 0360 updateToggleKeyboardInputMenu(m_selectedSessionId); 0361 updateToggleMonitorActivityMenu(m_selectedSessionId); 0362 updateToggleMonitorSilenceMenu(m_selectedSessionId); 0363 } 0364 0365 QWidget::contextMenuEvent(event); 0366 } 0367 0368 void TabBar::resizeEvent(QResizeEvent *event) 0369 { 0370 moveNewTabButton(); 0371 m_closeTabButton->move(width() - m_skin->tabBarCloseTabButtonPosition().x(), m_skin->tabBarCloseTabButtonPosition().y()); 0372 QWidget::resizeEvent(event); 0373 } 0374 0375 void TabBar::moveNewTabButton() 0376 { 0377 int newTabButtonX = m_skin->tabBarNewTabButtonPosition().x(); 0378 if (m_skin->tabBarNewTabButtonIsAtEndOfTabs()) { 0379 newTabButtonX += m_tabWidths.last(); 0380 } 0381 m_newTabButton->move(newTabButtonX, m_skin->tabBarNewTabButtonPosition().y()); 0382 } 0383 0384 void TabBar::paintEvent(QPaintEvent *) 0385 { 0386 QPainter painter(this); 0387 painter.setPen(m_skin->tabBarTextColor()); 0388 0389 int x = m_skin->tabBarPosition().x(); 0390 int y = m_skin->tabBarPosition().y(); 0391 m_tabWidths.clear(); 0392 0393 QRect tabsClipRect(x, y, m_closeTabButton->x() - x, height() - y); 0394 painter.setClipRect(tabsClipRect); 0395 0396 for (int index = 0; index < m_tabs.count(); ++index) { 0397 x = drawTab(x, y, index, painter); 0398 m_tabWidths << x; 0399 } 0400 0401 const QPixmap &backgroundImage = m_skin->tabBarBackgroundImage(); 0402 const QPixmap &leftCornerImage = m_skin->tabBarLeftCornerImage(); 0403 const QPixmap &rightCornerImage = m_skin->tabBarRightCornerImage(); 0404 0405 x = x > tabsClipRect.right() ? tabsClipRect.right() + 1 : x; 0406 0407 QRegion backgroundClipRegion(rect()); 0408 backgroundClipRegion = backgroundClipRegion.subtracted(m_newTabButton->geometry()); 0409 backgroundClipRegion = backgroundClipRegion.subtracted(m_closeTabButton->geometry()); 0410 QRect tabsRect(m_skin->tabBarPosition().x(), y, x - m_skin->tabBarPosition().x(), height() - m_skin->tabBarPosition().y()); 0411 backgroundClipRegion = backgroundClipRegion.subtracted(tabsRect); 0412 painter.setClipRegion(backgroundClipRegion); 0413 0414 painter.drawImage(0, 0, leftCornerImage.toImage()); 0415 QRect leftCornerImageRect(0, 0, leftCornerImage.width(), height()); 0416 backgroundClipRegion = backgroundClipRegion.subtracted(leftCornerImageRect); 0417 0418 painter.drawImage(width() - rightCornerImage.width(), 0, rightCornerImage.toImage()); 0419 QRect rightCornerImageRect(width() - rightCornerImage.width(), 0, rightCornerImage.width(), height()); 0420 backgroundClipRegion = backgroundClipRegion.subtracted(rightCornerImageRect); 0421 0422 painter.setClipRegion(backgroundClipRegion); 0423 0424 painter.drawTiledPixmap(0, 0, width(), height(), backgroundImage); 0425 0426 painter.end(); 0427 0428 if (m_skin->tabBarNewTabButtonIsAtEndOfTabs()) { 0429 moveNewTabButton(); 0430 } 0431 } 0432 0433 int TabBar::drawTab(int x, int y, int index, QPainter &painter) 0434 { 0435 QString title; 0436 int sessionId; 0437 bool selected; 0438 QFont font = QFontDatabase::systemFont(QFontDatabase::GeneralFont); 0439 int textWidth = 0; 0440 0441 sessionId = m_tabs.at(index); 0442 selected = (sessionId == m_selectedSessionId); 0443 title = m_tabTitles[sessionId]; 0444 0445 if (selected) { 0446 painter.drawPixmap(x, y, m_skin->tabBarSelectedLeftCornerImage()); 0447 x += m_skin->tabBarSelectedLeftCornerImage().width(); 0448 } else if (!m_skin->tabBarUnselectedLeftCornerImage().isNull()) { 0449 painter.drawPixmap(x, y, m_skin->tabBarUnselectedLeftCornerImage()); 0450 x += m_skin->tabBarUnselectedLeftCornerImage().width(); 0451 } else if (index != m_tabs.indexOf(m_selectedSessionId) + 1) { 0452 painter.drawPixmap(x, y, m_skin->tabBarSeparatorImage()); 0453 x += m_skin->tabBarSeparatorImage().width(); 0454 } 0455 0456 if (selected) 0457 font.setBold(m_skin->tabBarSelectedTextBold()); 0458 else 0459 font.setBold(false); 0460 0461 painter.setFont(font); 0462 0463 QFontMetrics fontMetrics(font); 0464 textWidth = fontMetrics.horizontalAdvance(title) + 10; 0465 0466 // Draw the Prevent Closing image in the tab button. 0467 if (m_mainWindow->sessionStack()->isSessionClosable(sessionId) == false) { 0468 if (selected) 0469 painter.drawTiledPixmap(x, 0470 y, 0471 m_skin->tabBarPreventClosingImagePosition().x() + m_skin->tabBarPreventClosingImage().width(), 0472 height(), 0473 m_skin->tabBarSelectedBackgroundImage()); 0474 else 0475 painter.drawTiledPixmap(x, 0476 y, 0477 m_skin->tabBarPreventClosingImagePosition().x() + m_skin->tabBarPreventClosingImage().width(), 0478 height(), 0479 m_skin->tabBarUnselectedBackgroundImage()); 0480 0481 painter.drawPixmap(x + m_skin->tabBarPreventClosingImagePosition().x(), 0482 m_skin->tabBarPreventClosingImagePosition().y(), 0483 m_skin->tabBarPreventClosingImage()); 0484 0485 x += m_skin->tabBarPreventClosingImagePosition().x(); 0486 x += m_skin->tabBarPreventClosingImage().width(); 0487 } 0488 0489 if (selected) 0490 painter.drawTiledPixmap(x, y, textWidth, height(), m_skin->tabBarSelectedBackgroundImage()); 0491 else 0492 painter.drawTiledPixmap(x, y, textWidth, height(), m_skin->tabBarUnselectedBackgroundImage()); 0493 0494 painter.drawText(x, y, textWidth + 1, height() + 2, Qt::AlignHCenter | Qt::AlignVCenter, title); 0495 0496 x += textWidth; 0497 0498 if (selected) { 0499 painter.drawPixmap(x, m_skin->tabBarPosition().y(), m_skin->tabBarSelectedRightCornerImage()); 0500 x += m_skin->tabBarSelectedRightCornerImage().width(); 0501 } else if (!m_skin->tabBarUnselectedRightCornerImage().isNull()) { 0502 painter.drawPixmap(x, m_skin->tabBarPosition().y(), m_skin->tabBarUnselectedRightCornerImage()); 0503 x += m_skin->tabBarUnselectedRightCornerImage().width(); 0504 } else if (index != m_tabs.indexOf(m_selectedSessionId) - 1) { 0505 painter.drawPixmap(x, m_skin->tabBarPosition().y(), m_skin->tabBarSeparatorImage()); 0506 x += m_skin->tabBarSeparatorImage().width(); 0507 } 0508 0509 return x; 0510 } 0511 0512 int TabBar::tabAt(int x) 0513 { 0514 for (int index = 0; index < m_tabWidths.count(); ++index) { 0515 if (x > m_skin->tabBarPosition().x() && x < m_tabWidths.at(index)) 0516 return index; 0517 } 0518 0519 return -1; 0520 } 0521 0522 void TabBar::wheelEvent(QWheelEvent *event) 0523 { 0524 if (event->angleDelta().y() < 0) 0525 selectNextTab(); 0526 else 0527 selectPreviousTab(); 0528 } 0529 0530 void TabBar::keyPressEvent(QKeyEvent *event) 0531 { 0532 if (event->key() == Qt::Key_Escape && m_lineEdit->isVisible()) 0533 m_lineEdit->hide(); 0534 0535 QWidget::keyPressEvent(event); 0536 } 0537 0538 void TabBar::mousePressEvent(QMouseEvent *event) 0539 { 0540 if (QWhatsThis::inWhatsThisMode()) 0541 return; 0542 0543 if (event->x() < m_skin->tabBarPosition().x()) 0544 return; 0545 0546 int index = tabAt(event->x()); 0547 0548 if (index == -1) 0549 return; 0550 0551 if (event->button() == Qt::LeftButton || event->button() == Qt::MiddleButton) { 0552 m_startPos = event->pos(); 0553 if (index != m_tabs.indexOf(m_selectedSessionId) || event->button() == Qt::MiddleButton) { 0554 m_mousePressed = true; 0555 m_mousePressedIndex = index; 0556 } 0557 return; 0558 } 0559 0560 QWidget::mousePressEvent(event); 0561 } 0562 0563 void TabBar::mouseReleaseEvent(QMouseEvent *event) 0564 { 0565 if (QWhatsThis::inWhatsThisMode()) 0566 return; 0567 0568 if (event->x() < m_skin->tabBarPosition().x()) 0569 return; 0570 0571 int index = tabAt(event->x()); 0572 0573 if (m_mousePressed && m_mousePressedIndex == index) { 0574 if (event->button() == Qt::LeftButton && index != m_tabs.indexOf(m_selectedSessionId)) 0575 Q_EMIT tabSelected(m_tabs.at(index)); 0576 0577 if (event->button() == Qt::MiddleButton) 0578 Q_EMIT tabClosed(m_tabs.at(index)); 0579 } 0580 0581 m_mousePressed = false; 0582 0583 m_startPos.setX(0); 0584 m_startPos.setY(0); 0585 0586 QWidget::mouseReleaseEvent(event); 0587 } 0588 0589 void TabBar::mouseMoveEvent(QMouseEvent *event) 0590 { 0591 if (!m_startPos.isNull() && ((event->buttons() & Qt::LeftButton) || (event->buttons() & Qt::MiddleButton))) { 0592 int distance = (event->pos() - m_startPos).manhattanLength(); 0593 0594 if (distance >= QApplication::startDragDistance()) { 0595 int index = tabAt(m_startPos.x()); 0596 0597 if (index >= 0 && !m_lineEdit->isVisible()) 0598 startDrag(index); 0599 } 0600 } 0601 0602 QWidget::mouseMoveEvent(event); 0603 } 0604 0605 void TabBar::dragEnterEvent(QDragEnterEvent *event) 0606 { 0607 TabBar *eventSource = qobject_cast<TabBar *>(event->source()); 0608 0609 if (eventSource) { 0610 event->setDropAction(Qt::MoveAction); 0611 event->acceptProposedAction(); 0612 } else { 0613 drawDropIndicator(-1); 0614 event->ignore(); 0615 } 0616 0617 return; 0618 } 0619 0620 void TabBar::dragMoveEvent(QDragMoveEvent *event) 0621 { 0622 TabBar *eventSource = qobject_cast<TabBar *>(event->source()); 0623 0624 if (eventSource && event->pos().x() > m_skin->tabBarPosition().x() && event->pos().x() < m_closeTabButton->x()) { 0625 int index = dropIndex(event->pos()); 0626 0627 if (index == -1) 0628 index = m_tabs.count(); 0629 0630 drawDropIndicator(index, isSameTab(event)); 0631 0632 event->setDropAction(Qt::MoveAction); 0633 event->accept(); 0634 } else { 0635 drawDropIndicator(-1); 0636 event->ignore(); 0637 } 0638 0639 return; 0640 } 0641 0642 void TabBar::dragLeaveEvent(QDragLeaveEvent *event) 0643 { 0644 drawDropIndicator(-1); 0645 event->ignore(); 0646 0647 return; 0648 } 0649 0650 void TabBar::dropEvent(QDropEvent *event) 0651 { 0652 drawDropIndicator(-1); 0653 0654 int x = event->pos().x(); 0655 0656 if (isSameTab(event) || x < m_skin->tabBarPosition().x() || x > m_closeTabButton->x()) 0657 event->ignore(); 0658 else { 0659 int targetIndex = dropIndex(event->pos()); 0660 int sourceSessionId = event->mimeData()->text().toInt(); 0661 int sourceIndex = m_tabs.indexOf(sourceSessionId); 0662 0663 if (targetIndex == -1) 0664 targetIndex = m_tabs.count() - 1; 0665 else if (targetIndex < 0) 0666 targetIndex = 0; 0667 else if (sourceIndex < targetIndex) 0668 --targetIndex; 0669 0670 m_tabs.move(sourceIndex, targetIndex); 0671 Q_EMIT tabSelected(m_tabs.at(targetIndex)); 0672 0673 event->accept(); 0674 } 0675 0676 return; 0677 } 0678 0679 void TabBar::mouseDoubleClickEvent(QMouseEvent *event) 0680 { 0681 if (QWhatsThis::inWhatsThisMode()) 0682 return; 0683 0684 m_lineEdit->hide(); 0685 0686 if (event->x() < 0) 0687 return; 0688 0689 int index = tabAt(event->x()); 0690 0691 if (event->button() == Qt::LeftButton) { 0692 if (event->x() <= m_tabWidths.last()) 0693 interactiveRename(m_tabs.at(index)); 0694 else if (event->x() > m_tabWidths.last()) 0695 Q_EMIT newTabRequested(); 0696 } 0697 0698 QWidget::mouseDoubleClickEvent(event); 0699 } 0700 0701 void TabBar::leaveEvent(QEvent *event) 0702 { 0703 m_mousePressed = false; 0704 drawDropIndicator(-1); 0705 event->ignore(); 0706 0707 QWidget::leaveEvent(event); 0708 } 0709 0710 void TabBar::addTab(int sessionId, const QString &title) 0711 { 0712 m_tabs.append(sessionId); 0713 0714 if (title.isEmpty()) 0715 m_tabTitles.insert(sessionId, standardTabTitle()); 0716 else 0717 m_tabTitles.insert(sessionId, title); 0718 0719 Q_EMIT tabSelected(sessionId); 0720 } 0721 0722 void TabBar::removeTab(int sessionId) 0723 { 0724 if (sessionId == -1) 0725 sessionId = m_selectedSessionId; 0726 if (sessionId == -1) 0727 return; 0728 if (!m_tabs.contains(sessionId)) 0729 return; 0730 0731 int index = m_tabs.indexOf(sessionId); 0732 0733 if (m_lineEdit->isVisible() && sessionId == m_renamingSessionId) 0734 m_lineEdit->hide(); 0735 0736 m_tabs.removeAt(index); 0737 m_tabTitles.remove(sessionId); 0738 0739 if (m_tabs.isEmpty()) 0740 Q_EMIT lastTabClosed(); 0741 else if (sessionId == m_selectedSessionId) 0742 Q_EMIT tabSelected(m_tabs.last()); 0743 else 0744 Q_EMIT tabSelected(m_selectedSessionId); 0745 } 0746 0747 void TabBar::interactiveRename(int sessionId) 0748 { 0749 if (sessionId == -1) 0750 return; 0751 if (!m_tabs.contains(sessionId)) 0752 return; 0753 0754 m_renamingSessionId = sessionId; 0755 0756 int index = m_tabs.indexOf(sessionId); 0757 int x = index ? m_tabWidths.at(index - 1) : m_skin->tabBarPosition().x(); 0758 int y = m_skin->tabBarPosition().y(); 0759 int width = m_tabWidths.at(index) - x; 0760 0761 m_lineEdit->setText(m_tabTitles[sessionId]); 0762 m_lineEdit->setGeometry(x - 1, y - 1, width + 3, height() + 2); 0763 m_lineEdit->selectAll(); 0764 m_lineEdit->setFocus(); 0765 m_lineEdit->show(); 0766 } 0767 0768 void TabBar::interactiveRenameDone() 0769 { 0770 int sessionId = m_renamingSessionId; 0771 0772 m_renamingSessionId = -1; 0773 0774 setTabTitle(sessionId, m_lineEdit->text().trimmed()); 0775 } 0776 0777 void TabBar::selectTab(int sessionId) 0778 { 0779 if (!m_tabs.contains(sessionId)) 0780 return; 0781 0782 m_selectedSessionId = sessionId; 0783 0784 updateMoveActions(m_tabs.indexOf(sessionId)); 0785 updateToggleActions(sessionId); 0786 0787 repaint(); 0788 } 0789 0790 void TabBar::selectNextTab() 0791 { 0792 int index = m_tabs.indexOf(m_selectedSessionId); 0793 int newSelectedSessionId = m_selectedSessionId; 0794 0795 if (index == -1) 0796 return; 0797 else if (index == m_tabs.count() - 1) 0798 newSelectedSessionId = m_tabs.at(0); 0799 else 0800 newSelectedSessionId = m_tabs.at(index + 1); 0801 0802 Q_EMIT tabSelected(newSelectedSessionId); 0803 } 0804 0805 void TabBar::selectPreviousTab() 0806 { 0807 int index = m_tabs.indexOf(m_selectedSessionId); 0808 int newSelectedSessionId = m_selectedSessionId; 0809 0810 if (index == -1) 0811 return; 0812 else if (index == 0) 0813 newSelectedSessionId = m_tabs.at(m_tabs.count() - 1); 0814 else 0815 newSelectedSessionId = m_tabs.at(index - 1); 0816 0817 Q_EMIT tabSelected(newSelectedSessionId); 0818 } 0819 0820 void TabBar::moveTabLeft(int sessionId) 0821 { 0822 if (sessionId == -1) 0823 sessionId = m_selectedSessionId; 0824 0825 int index = m_tabs.indexOf(sessionId); 0826 0827 if (index < 1) 0828 return; 0829 0830 m_tabs.swapItemsAt(index, index - 1); 0831 0832 repaint(); 0833 0834 updateMoveActions(index - 1); 0835 } 0836 0837 void TabBar::moveTabRight(int sessionId) 0838 { 0839 if (sessionId == -1) 0840 sessionId = m_selectedSessionId; 0841 0842 int index = m_tabs.indexOf(sessionId); 0843 0844 if (index == -1 || index == m_tabs.count() - 1) 0845 return; 0846 0847 m_tabs.swapItemsAt(index, index + 1); 0848 0849 repaint(); 0850 0851 updateMoveActions(index + 1); 0852 } 0853 0854 void TabBar::closeTabButtonClicked() 0855 { 0856 Q_EMIT tabClosed(m_selectedSessionId); 0857 } 0858 0859 QString TabBar::tabTitle(int sessionId) 0860 { 0861 if (m_tabTitles.contains(sessionId)) 0862 return m_tabTitles[sessionId]; 0863 else 0864 return QString(); 0865 } 0866 0867 void TabBar::setTabTitle(int sessionId, const QString &newTitle, InteractiveType interactive) 0868 { 0869 if (sessionId == -1) 0870 return; 0871 if (!m_tabTitles.contains(sessionId)) 0872 return; 0873 if (!interactive && m_tabTitlesSetInteractive.value(sessionId, false)) 0874 return; 0875 if (interactive) 0876 m_tabTitlesSetInteractive[sessionId] = interactive; 0877 0878 if (!newTitle.isEmpty()) { 0879 m_tabTitles[sessionId] = newTitle; 0880 } else 0881 m_tabTitlesSetInteractive.remove(sessionId); 0882 0883 Q_EMIT tabTitleEdited(sessionId, newTitle); 0884 update(); 0885 } 0886 0887 void TabBar::setTabTitleAutomated(int sessionId, const QString &newTitle) 0888 { 0889 setTabTitle(sessionId, newTitle, NonInteractive); 0890 } 0891 0892 int TabBar::sessionAtTab(int index) 0893 { 0894 if (index < 0 || index > m_tabs.count() - 1) 0895 return -1; 0896 else 0897 return m_tabs.at(index); 0898 } 0899 0900 QString TabBar::standardTabTitle() 0901 { 0902 QString newTitle = makeTabTitle(0); 0903 0904 bool nameOk; 0905 int count = 0; 0906 0907 do { 0908 nameOk = true; 0909 0910 QHashIterator<int, QString> it(m_tabTitles); 0911 0912 while (it.hasNext()) { 0913 it.next(); 0914 0915 if (newTitle == it.value()) { 0916 nameOk = false; 0917 break; 0918 } 0919 } 0920 0921 if (!nameOk) { 0922 count++; 0923 newTitle = makeTabTitle(count); 0924 } 0925 } while (!nameOk); 0926 0927 return newTitle; 0928 } 0929 0930 QString TabBar::makeTabTitle(int id) 0931 { 0932 if (id == 0) { 0933 return xi18nc("@title:tab", "Shell"); 0934 } else { 0935 return xi18nc("@title:tab", "Shell No. %1", id + 1); 0936 } 0937 } 0938 0939 void TabBar::startDrag(int index) 0940 { 0941 int sessionId = sessionAtTab(index); 0942 0943 m_startPos.setX(0); 0944 m_startPos.setY(0); 0945 0946 int x = index ? m_tabWidths.at(index - 1) : m_skin->tabBarPosition().x(); 0947 int tabWidth = m_tabWidths.at(index) - x; 0948 0949 QPixmap tab(tabWidth, height()); 0950 QColor fillColor(Settings::backgroundColor()); 0951 0952 if (m_mainWindow->useTranslucency()) 0953 fillColor.setAlphaF(qreal(Settings::backgroundColorOpacity()) / 100); 0954 0955 tab.fill(fillColor); 0956 0957 QPainter painter(&tab); 0958 painter.begin(this); 0959 painter.setPen(m_skin->tabBarTextColor()); 0960 0961 drawTab(0, 0, index, painter); 0962 painter.end(); 0963 0964 QMimeData *mimeData = new QMimeData; 0965 mimeData->setText(QVariant(sessionId).toString()); 0966 0967 QDrag *drag = new QDrag(this); 0968 drag->setMimeData(mimeData); 0969 drag->setPixmap(tab); 0970 drag->exec(Qt::MoveAction); 0971 0972 return; 0973 } 0974 0975 void TabBar::drawDropIndicator(int index, bool disabled) 0976 { 0977 const int arrowSize = 16; 0978 0979 if (!m_dropIndicator) { 0980 m_dropIndicator = new QLabel(parentWidget()); 0981 m_dropIndicator->resize(arrowSize, arrowSize); 0982 } 0983 0984 QIcon::Mode drawMode = disabled ? QIcon::Disabled : QIcon::Normal; 0985 m_dropIndicator->setPixmap(QIcon::fromTheme(QStringLiteral("arrow-down")).pixmap(arrowSize, arrowSize, drawMode)); 0986 0987 if (index < 0) { 0988 m_dropIndicator->hide(); 0989 return; 0990 } 0991 0992 int temp_index; 0993 if (index == m_tabs.count()) 0994 temp_index = index - 1; 0995 else 0996 temp_index = index; 0997 0998 int x = temp_index ? m_tabWidths.at(temp_index - 1) : m_skin->tabBarPosition().x(); 0999 int tabWidth = m_tabWidths.at(temp_index) - x; 1000 int y = m_skin->tabBarPosition().y(); 1001 1002 m_dropRect = QRect(x, y - height(), tabWidth, height() - y); 1003 QPoint pos; 1004 1005 if (index < m_tabs.count()) 1006 pos = m_dropRect.topLeft(); 1007 else 1008 pos = m_dropRect.topRight(); 1009 1010 pos.rx() -= arrowSize / 2; 1011 1012 m_dropIndicator->move(mapTo(parentWidget(), pos)); 1013 m_dropIndicator->show(); 1014 1015 return; 1016 } 1017 1018 int TabBar::dropIndex(const QPoint pos) 1019 { 1020 int index = tabAt(pos.x()); 1021 if (index < 0) 1022 return index; 1023 1024 int x = index ? m_tabWidths.at(index - 1) : m_skin->tabBarPosition().x(); 1025 int tabWidth = m_tabWidths.at(index) - x; 1026 int y = m_skin->tabBarPosition().y(); 1027 m_dropRect = QRect(x, y - height(), tabWidth, height() - y); 1028 1029 if ((pos.x() - m_dropRect.left()) > (m_dropRect.width() / 2)) 1030 ++index; 1031 1032 if (index == m_tabs.count()) 1033 return -1; 1034 1035 return index; 1036 } 1037 1038 bool TabBar::isSameTab(const QDropEvent *event) 1039 { 1040 int index = dropIndex(event->pos()); 1041 int sourceSessionId = event->mimeData()->text().toInt(); 1042 int sourceIndex = m_tabs.indexOf(sourceSessionId); 1043 1044 bool isLastTab = (sourceIndex == m_tabs.count() - 1) && (index == -1); 1045 1046 if ((sourceIndex == index) || (sourceIndex == index - 1) || isLastTab) 1047 return true; 1048 else 1049 return false; 1050 } 1051 1052 #include "moc_tabbar.cpp"