File indexing completed on 2024-05-19 04:59:22

0001 /* ============================================================
0002 * VerticalTabs plugin for Falkon
0003 * Copyright (C) 2018 David Rosca <nowrep@gmail.com>
0004 *
0005 * This program is free software: you can redistribute it and/or modify
0006 * it under the terms of the GNU General Public License as published by
0007 * the Free Software Foundation, either version 3 of the License, or
0008 * (at your option) any later version.
0009 *
0010 * This program is distributed in the hope that it will be useful,
0011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
0012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0013 * GNU General Public License for more details.
0014 *
0015 * You should have received a copy of the GNU General Public License
0016 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
0017 * ============================================================ */
0018 #include "verticaltabswidget.h"
0019 #include "tabtreeview.h"
0020 #include "tablistview.h"
0021 #include "tabfiltermodel.h"
0022 
0023 #include "webtab.h"
0024 #include "tabmodel.h"
0025 #include "tabwidget.h"
0026 #include "toolbutton.h"
0027 #include "tabtreemodel.h"
0028 #include "browserwindow.h"
0029 
0030 #include <QListView>
0031 #include <QScrollBar>
0032 #include <QVBoxLayout>
0033 #include <QWheelEvent>
0034 
0035 VerticalTabsWidget::VerticalTabsWidget(BrowserWindow *window)
0036     : QWidget()
0037     , m_window(window)
0038 {
0039     auto *layout = new QVBoxLayout(this);
0040     layout->setSpacing(0);
0041     layout->setContentsMargins(0, 0, 0, 0);
0042 
0043     m_pinnedView = new TabListView(m_window, this);
0044     auto *model = new TabFilterModel(m_pinnedView);
0045     model->setFilterPinnedTabs(false);
0046     model->setRejectDropOnLastIndex(true);
0047     model->setSourceModel(m_window->tabModel());
0048     m_pinnedView->setModel(model);
0049     m_pinnedView->setHideWhenEmpty(true);
0050 
0051     m_normalView = new TabTreeView(m_window, this);
0052     m_pinnedView->setFocusProxy(m_normalView);
0053 
0054     auto *buttonAddTab = new ToolButton(this);
0055     buttonAddTab->setObjectName(QSL("verticaltabs-button-addtab"));
0056     buttonAddTab->setAutoRaise(true);
0057     buttonAddTab->setFocusPolicy(Qt::NoFocus);
0058     buttonAddTab->setToolTip(tr("New Tab"));
0059     buttonAddTab->setIcon(QIcon::fromTheme(QSL("list-add")));
0060     buttonAddTab->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
0061     connect(buttonAddTab, &QAbstractButton::clicked, m_window, &BrowserWindow::addTab);
0062     connect(buttonAddTab, &ToolButton::middleMouseClicked, this, &VerticalTabsWidget::addChildTab);
0063 
0064     m_groupMenu = new QMenu(this);
0065     buttonAddTab->setMenu(m_groupMenu);
0066     connect(m_groupMenu, &QMenu::aboutToShow, this, &VerticalTabsWidget::updateGroupMenu);
0067 
0068     layout->addWidget(m_pinnedView);
0069     layout->addWidget(m_normalView);
0070     layout->addWidget(buttonAddTab);
0071 }
0072 
0073 void VerticalTabsWidget::setViewType(VerticalTabsPlugin::ViewType type)
0074 {
0075     auto *model = new TabFilterModel(m_normalView);
0076     model->setFilterPinnedTabs(true);
0077 
0078     delete m_normalView->model();
0079 
0080     switch (type) {
0081     case VerticalTabsPlugin::TabListView:
0082         model->setSourceModel(m_window->tabModel());
0083         m_normalView->setModel(model);
0084         m_normalView->setTabsInOrder(true);
0085         m_normalView->setHaveTreeModel(false);
0086         break;
0087 
0088     case VerticalTabsPlugin::TabTreeView:
0089         m_treeModel = new TabTreeModel(m_window, model);
0090         m_treeModel->setSourceModel(m_window->tabModel());
0091         model->setSourceModel(m_treeModel);
0092         m_normalView->setModel(model);
0093         m_normalView->setTabsInOrder(false);
0094         m_normalView->setHaveTreeModel(true);
0095         break;
0096 
0097     default:
0098         break;
0099     };
0100 }
0101 
0102 void VerticalTabsWidget::switchToNextTab()
0103 {
0104     WebTab *tab = nextTab();
0105     if (tab) {
0106         tab->makeCurrentTab();
0107     }
0108 }
0109 
0110 void VerticalTabsWidget::switchToPreviousTab()
0111 {
0112     WebTab *tab = previousTab();
0113     if (tab) {
0114         tab->makeCurrentTab();
0115     }
0116 }
0117 
0118 WebTab *VerticalTabsWidget::nextTab() const
0119 {
0120     QModelIndex next;
0121     if (m_window->tabWidget()->webTab()->isPinned()) {
0122         next = m_pinnedView->indexAfter(m_pinnedView->currentIndex());
0123         if (!next.isValid()) {
0124             next = m_normalView->model()->index(0, 0);
0125         }
0126     } else {
0127         next = m_normalView->indexBelow(m_normalView->currentIndex());
0128         if (!next.isValid()) {
0129             next = m_pinnedView->model()->index(0, 0);
0130         }
0131     }
0132     return next.data(TabModel::WebTabRole).value<WebTab*>();
0133 }
0134 
0135 WebTab *VerticalTabsWidget::previousTab() const
0136 {
0137     QModelIndex previous;
0138     if (m_window->tabWidget()->webTab()->isPinned()) {
0139         previous = m_pinnedView->indexBefore(m_pinnedView->currentIndex());
0140         if (!previous.isValid()) {
0141             previous = m_normalView->model()->index(m_normalView->model()->rowCount() - 1, 0);
0142             while (previous.isValid()) {
0143                 const QModelIndex below = m_normalView->indexBelow(previous);
0144                 if (below.isValid()) {
0145                     previous = below;
0146                 } else {
0147                     break;
0148                 }
0149             }
0150         }
0151     } else {
0152         previous = m_normalView->indexAbove(m_normalView->currentIndex());
0153         if (!previous.isValid()) {
0154             previous = m_pinnedView->model()->index(m_pinnedView->model()->rowCount() - 1, 0);
0155         }
0156     }
0157     return previous.data(TabModel::WebTabRole).value<WebTab*>();
0158 }
0159 
0160 void VerticalTabsWidget::wheelEvent(QWheelEvent *event)
0161 {
0162     if (m_normalView->verticalScrollBar()->isVisible()) {
0163         return;
0164     }
0165 
0166     m_wheelHelper.processEvent(event);
0167     while (WheelHelper::Direction direction = m_wheelHelper.takeDirection()) {
0168         switch (direction) {
0169         case WheelHelper::WheelUp:
0170         case WheelHelper::WheelLeft:
0171             switchToPreviousTab();
0172             break;
0173 
0174         case WheelHelper::WheelDown:
0175         case WheelHelper::WheelRight:
0176             switchToNextTab();
0177             break;
0178 
0179         default:
0180             break;
0181         }
0182     }
0183     event->accept();
0184 }
0185 
0186 void VerticalTabsWidget::updateGroupMenu()
0187 {
0188     m_groupMenu->clear();
0189 
0190     for (int i = 0; i < m_window->tabWidget()->count(); ++i) {
0191         WebTab *tab = m_window->tabWidget()->webTab(i);
0192         if (tab->url().toString(QUrl::RemoveFragment) == QL1S("extension://verticaltabs/group")) {
0193             m_groupMenu->addAction(tab->url().fragment(), this, [=]() {
0194                 QMetaObject::invokeMethod(m_window, "addTab");
0195                 m_window->tabWidget()->webTab()->setParentTab(tab);
0196             });
0197         }
0198     }
0199 
0200     m_groupMenu->addSeparator();
0201     m_groupMenu->addAction(tr("Add New Group..."), this, [this]() {
0202         m_window->tabWidget()->addView(QUrl(QSL("extension://verticaltabs/group")), Qz::NT_SelectedTab);
0203     });
0204 }
0205 
0206 void VerticalTabsWidget::addChildTab()
0207 {
0208     WebTab *tab = m_window->tabWidget()->webTab();
0209     m_window->addTab();
0210     m_window->tabWidget()->webTab()->setParentTab(tab);
0211 }