diff --git a/krusader/KViewer/CMakeLists.txt b/krusader/KViewer/CMakeLists.txt --- a/krusader/KViewer/CMakeLists.txt +++ b/krusader/KViewer/CMakeLists.txt @@ -2,7 +2,8 @@ krviewer.cpp panelviewer.cpp diskusageviewer.cpp - lister.cpp) + lister.cpp + viewertabbar.cpp) add_library(KViewer STATIC ${KViewer_SRCS}) diff --git a/krusader/KViewer/krviewer.h b/krusader/KViewer/krviewer.h --- a/krusader/KViewer/krviewer.h +++ b/krusader/KViewer/krviewer.h @@ -40,6 +40,7 @@ #include #include "../krglobal.h" +#include "viewertabbar.h" class PanelViewerBase; @@ -113,7 +114,8 @@ KParts::PartManager manager; QMenu* viewerMenu; - QTabWidget tabBar; + ViewerTabWidget tabWidget; + ViewerTabBar *tabBar; QPointer returnFocusTo; QAction *detachAction; diff --git a/krusader/KViewer/krviewer.cpp b/krusader/KViewer/krviewer.cpp --- a/krusader/KViewer/krviewer.cpp +++ b/krusader/KViewer/krviewer.cpp @@ -49,6 +49,7 @@ #include "../defaults.h" #include "../icon.h" #include "panelviewer.h" +#include "viewertabbar.h" #define VIEW_ICON "document-preview" #define EDIT_ICON "document-edit" @@ -65,19 +66,21 @@ KrViewer::KrViewer(QWidget *parent) : KParts::MainWindow(parent, (Qt::WindowFlags)KDE_DEFAULT_WINDOWFLAGS), manager(this, this), - tabBar(this), sizeX(-1), sizeY(-1) + tabWidget(this), sizeX(-1), sizeY(-1) { //setWFlags(Qt::WType_TopLevel | WDestructiveClose); setXMLFile("krviewer.rc"); // kpart-related xml file setHelpMenuEnabled(false); connect(&manager, &KParts::PartManager::activePartChanged, this, &KrViewer::createGUI); - connect(&tabBar, &QTabWidget::currentChanged, this, &KrViewer::tabChanged); - connect(&tabBar, &QTabWidget::tabCloseRequested, this, [=](int index) { tabCloseRequest(index, false); }); + connect(&tabWidget, &QTabWidget::currentChanged, this, &KrViewer::tabChanged); + connect(&tabWidget, &QTabWidget::tabCloseRequested, this, [=](int index) { tabCloseRequest(index, false); }); - tabBar.setDocumentMode(true); - tabBar.setMovable(true); - setCentralWidget(&tabBar); + tabWidget.setDocumentMode(true); + tabWidget.setMovable(true); + tabBar = qobject_cast(tabWidget.tabBar()); + connect(tabBar, &ViewerTabBar::closeTabSignal, this, [=](int index) { tabCloseRequest(index, false); }); + setCentralWidget(&tabWidget); printAction = KStandardAction::print(this, SLOT(print()), nullptr); copyAction = KStandardAction::copy(this, SLOT(copy()), nullptr); @@ -152,7 +155,7 @@ ac->setDefaultShortcuts(tabPrevAction, shortcuts); - tabBar.setTabsClosable(true); + tabWidget.setTabsClosable(true); checkModified(); @@ -182,8 +185,8 @@ // close tabs before deleting tab bar - this avoids Qt bug 26115 // https://bugreports.qt-project.org/browse/QTBUG-26115 - while(tabBar.count()) - tabCloseRequest(tabBar.currentIndex(), true); + while(tabWidget.count()) + tabCloseRequest(tabWidget.currentIndex(), true); delete printAction; delete copyAction; @@ -341,18 +344,18 @@ void KrViewer::addTab(PanelViewerBase *pvb) { - int tabIndex = tabBar.addTab(pvb, makeTabIcon(pvb), makeTabText(pvb)); - tabBar.setCurrentIndex(tabIndex); - tabBar.setTabToolTip(tabIndex, makeTabToolTip(pvb)); + int tabIndex = tabWidget.addTab(pvb, makeTabIcon(pvb), makeTabText(pvb)); + tabWidget.setCurrentIndex(tabIndex); + tabWidget.setTabToolTip(tabIndex, makeTabToolTip(pvb)); updateActions(); // now we can offer the option to detach tabs (we have more than one) - if (tabBar.count() > 1) { + if (tabWidget.count() > 1) { detachAction->setEnabled(true); } - tabBar.show(); + tabWidget.show(); connect(pvb, &PanelViewerBase::openUrlFinished, this, &KrViewer::openUrlFinished); @@ -372,20 +375,20 @@ if (part) { if (!isPartAdded(part)) addPart(part); - if (tabBar.currentWidget() == pvb) { + if (tabWidget.currentWidget() == pvb) { manager.setActivePart(part); if (part->widget()) part->widget()->setFocus(); } } } else { - tabCloseRequest(tabBar.currentIndex(), false); + tabCloseRequest(tabWidget.currentIndex(), false); } } void KrViewer::tabChanged(int index) { - QWidget *w = tabBar.widget(index); + QWidget *w = tabWidget.widget(index); if(!w) return; KParts::ReadOnlyPart *part = dynamic_cast(w)->part(); if (part && isPartAdded(part)) { @@ -405,7 +408,7 @@ // important to save as returnFocusTo will be cleared at removePart QWidget *returnFocusToThisWidget = returnFocusTo; - auto *pvb = dynamic_cast(tabBar.widget(index)); + auto *pvb = dynamic_cast(tabWidget.widget(index)); if (!pvb) return; @@ -419,12 +422,12 @@ pvb->closeUrl(); - tabBar.removeTab(index); + tabWidget.removeTab(index); delete pvb; pvb = nullptr; - if (tabBar.count() <= 0) { + if (tabWidget.count() <= 0) { if (returnFocusToThisWidget) { returnFocusToThisWidget->raise(); returnFocusToThisWidget->activateWindow(); @@ -434,7 +437,7 @@ } QTimer::singleShot(0, this, &KrViewer::close); - } else if (tabBar.count() == 1) { + } else if (tabWidget.count() == 1) { // no point in detaching only one tab.. detachAction->setEnabled(false); } @@ -442,7 +445,7 @@ void KrViewer::tabCloseRequest() { - tabCloseRequest(tabBar.currentIndex()); + tabCloseRequest(tabWidget.currentIndex()); } bool KrViewer::queryClose() @@ -453,12 +456,12 @@ group.writeEntry("Window Height", sizeY); group.writeEntry("Window Maximized", isMaximized()); - for (int i = 0; i != tabBar.count(); i++) { - auto* pvb = dynamic_cast(tabBar.widget(i)); + for (int i = 0; i != tabWidget.count(); i++) { + auto* pvb = dynamic_cast(tabWidget.widget(i)); if (!pvb) continue; - tabBar.setCurrentIndex(i); + tabWidget.setCurrentIndex(i); if (!pvb->queryClose()) return false; @@ -468,35 +471,35 @@ void KrViewer::viewGeneric() { - auto* pvb = dynamic_cast(tabBar.currentWidget()); + auto* pvb = dynamic_cast(tabWidget.currentWidget()); if (pvb) viewInternal(pvb->url(), Generic); } void KrViewer::viewText() { - auto* pvb = dynamic_cast(tabBar.currentWidget()); + auto* pvb = dynamic_cast(tabWidget.currentWidget()); if (pvb) viewInternal(pvb->url(), Text); } void KrViewer::viewLister() { - auto* pvb = dynamic_cast(tabBar.currentWidget()); + auto* pvb = dynamic_cast(tabWidget.currentWidget()); if (pvb) viewInternal(pvb->url(), Lister); } void KrViewer::viewHex() { - auto* pvb = dynamic_cast(tabBar.currentWidget()); + auto* pvb = dynamic_cast(tabWidget.currentWidget()); if (pvb) viewInternal(pvb->url(), Hex); } void KrViewer::editText() { - auto* pvb = dynamic_cast(tabBar.currentWidget()); + auto* pvb = dynamic_cast(tabWidget.currentWidget()); if (pvb) editInternal(pvb->url(), Text); } @@ -505,35 +508,35 @@ { QTimer::singleShot(CHECK_MODFIED_INTERVAL, this, &KrViewer::checkModified); - auto* pvb = dynamic_cast(tabBar.currentWidget()); + auto* pvb = dynamic_cast(tabWidget.currentWidget()); if (pvb) refreshTab(pvb); } void KrViewer::refreshTab(PanelViewerBase* pvb) { - int ndx = tabBar.indexOf(pvb); - tabBar.setTabText(ndx, makeTabText(pvb)); - tabBar.setTabIcon(ndx, makeTabIcon(pvb)); - tabBar.setTabToolTip(ndx, makeTabToolTip(pvb)); + int ndx = tabWidget.indexOf(pvb); + tabWidget.setTabText(ndx, makeTabText(pvb)); + tabWidget.setTabIcon(ndx, makeTabIcon(pvb)); + tabWidget.setTabToolTip(ndx, makeTabToolTip(pvb)); } void KrViewer::nextTab() { - int index = (tabBar.currentIndex() + 1) % tabBar.count(); - tabBar.setCurrentIndex(index); + int index = (tabWidget.currentIndex() + 1) % tabWidget.count(); + tabWidget.setCurrentIndex(index); } void KrViewer::prevTab() { - int index = (tabBar.currentIndex() - 1) % tabBar.count(); - while (index < 0) index += tabBar.count(); - tabBar.setCurrentIndex(index); + int index = (tabWidget.currentIndex() - 1) % tabWidget.count(); + while (index < 0) index += tabWidget.count(); + tabWidget.setCurrentIndex(index); } void KrViewer::detachTab() { - auto* pvb = dynamic_cast(tabBar.currentWidget()); + auto* pvb = dynamic_cast(tabWidget.currentWidget()); if (!pvb) return; KrViewer* viewer = getViewer(true); @@ -548,14 +551,14 @@ disconnect(pvb, nullptr, this, nullptr); - tabBar.removeTab(tabBar.indexOf(pvb)); + tabWidget.removeTab(tabWidget.indexOf(pvb)); - if (tabBar.count() == 1) { + if (tabWidget.count() == 1) { //no point in detaching only one tab.. detachAction->setEnabled(false); } - pvb->setParent(&viewer->tabBar); + pvb->setParent(&viewer->tabWidget); pvb->move(QPoint(0, 0)); viewer->addTab(pvb); @@ -577,7 +580,7 @@ void KrViewer::print() { - auto* pvb = dynamic_cast(tabBar.currentWidget()); + auto* pvb = dynamic_cast(tabWidget.currentWidget()); if (!pvb || !pvb->part() || !isPartAdded(pvb->part())) return; @@ -588,7 +591,7 @@ void KrViewer::copy() { - auto* pvb = dynamic_cast(tabBar.currentWidget()); + auto* pvb = dynamic_cast(tabWidget.currentWidget()); if (!pvb || !pvb->part() || !isPartAdded(pvb->part())) return; @@ -695,7 +698,7 @@ { returnFocusTo = parent; - PanelViewerBase* viewWidget = new PanelViewer(&tabBar, mode); + PanelViewerBase* viewWidget = new PanelViewer(&tabWidget, mode); addTab(viewWidget); viewWidget->openUrl(std::move(url)); @@ -705,7 +708,7 @@ { returnFocusTo = parent; - PanelViewerBase* editWidget = new PanelEditor(&tabBar, mode); + PanelViewerBase* editWidget = new PanelEditor(&tabWidget, mode); addTab(editWidget); editWidget->openUrl(std::move(url)); diff --git a/krusader/KViewer/viewertabbar.h b/krusader/KViewer/viewertabbar.h new file mode 100644 --- /dev/null +++ b/krusader/KViewer/viewertabbar.h @@ -0,0 +1,61 @@ +/***************************************************************************** + * Copyright (C) 2020 Krusader Krew [https://krusader.org] * + * * + * This file is part of Krusader [https://krusader.org]. * + * * + * Krusader is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 2 of the License, or * + * (at your option) any later version. * + * * + * Krusader is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with Krusader. If not, see [http://www.gnu.org/licenses/]. * + *****************************************************************************/ + +#ifndef VIEWERTABBAR_H +#define VIEWERTABBAR_H + +// QtWidgets +#include +#include +#include + +/** + * This class extends QTabWidget such that we can use a custom QTabBar on it + */ +class ViewerTabWidget : public QTabWidget +{ + Q_OBJECT +public: + explicit ViewerTabWidget(QWidget *parent); + +}; + +/** + * This class extends QTabBar such that right-clicking on a tab pops-up a menu + * containing relevant actions for the tab. It also emits signals to close the + * current tab. + */ +class ViewerTabBar : public QTabBar +{ + Q_OBJECT +public: + explicit ViewerTabBar(QWidget *parent) : QTabBar(parent) {}; + +protected: + void mousePressEvent(QMouseEvent *) override; + +signals: + /** + * emitted when the user mid-clicks on the tab + */ + void closeTabSignal(int index); + +}; + +#endif diff --git a/krusader/KViewer/viewertabbar.cpp b/krusader/KViewer/viewertabbar.cpp new file mode 100644 --- /dev/null +++ b/krusader/KViewer/viewertabbar.cpp @@ -0,0 +1,52 @@ +/***************************************************************************** + * Copyright (C) 2020 Krusader Krew [https://krusader.org] * + * * + * This file is part of Krusader [https://krusader.org]. * + * * + * Krusader is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 2 of the License, or * + * (at your option) any later version. * + * * + * Krusader is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with Krusader. If not, see [http://www.gnu.org/licenses/]. * + *****************************************************************************/ + +#include "viewertabbar.h" + +#include +// QtGui +#include + +ViewerTabWidget::ViewerTabWidget(QWidget *parent) : QTabWidget(parent) +{ + setTabBar(new ViewerTabBar(this)); +} + +void ViewerTabBar::mousePressEvent(QMouseEvent* e) +{ + int clickedTab = tabAt(e->pos()); + + if (-1 == clickedTab) { // clicked on nothing ... + QTabBar::mousePressEvent(e); + return; + } + + setCurrentIndex(clickedTab); + + if (e->button() == Qt::RightButton) { + // show the popup menu + // TODO + //_panelActionMenu->menu()->popup(e->globalPos()); + } else if (e->button() == Qt::MidButton) { + // close the current tab + emit closeTabSignal(clickedTab); + } + + QTabBar::mousePressEvent(e); +}