File indexing completed on 2024-05-12 04:58:25
0001 /* ============================================================ 0002 * Falkon - Qt web browser 0003 * Copyright (C) 2010-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 "tabwidget.h" 0019 #include "tabbar.h" 0020 #include "tabbedwebview.h" 0021 #include "webpage.h" 0022 #include "browserwindow.h" 0023 #include "mainapplication.h" 0024 #include "clickablelabel.h" 0025 #include "closedtabsmanager.h" 0026 #include "locationbar.h" 0027 #include "settings.h" 0028 #include "datapaths.h" 0029 #include "qzsettings.h" 0030 #include "qztools.h" 0031 #include "tabicon.h" 0032 #include "pluginproxy.h" 0033 0034 #include <QFile> 0035 #include <QTimer> 0036 #include <QMimeData> 0037 #include <QStackedWidget> 0038 #include <QMouseEvent> 0039 #include <QWebEngineHistory> 0040 #include <QClipboard> 0041 0042 AddTabButton::AddTabButton(TabWidget* tabWidget, TabBar* tabBar) 0043 : ToolButton(tabBar) 0044 , m_tabBar(tabBar) 0045 , m_tabWidget(tabWidget) 0046 { 0047 setObjectName("tabwidget-button-addtab"); 0048 setAutoRaise(true); 0049 setFocusPolicy(Qt::NoFocus); 0050 setAcceptDrops(true); 0051 setToolTip(TabWidget::tr("New Tab")); 0052 } 0053 0054 void AddTabButton::wheelEvent(QWheelEvent* event) 0055 { 0056 m_tabBar->wheelEvent(event); 0057 } 0058 0059 void AddTabButton::mouseReleaseEvent(QMouseEvent* event) 0060 { 0061 if (event->button() == Qt::MiddleButton && rect().contains(event->position().toPoint())) { 0062 m_tabWidget->addTabFromClipboard(); 0063 } 0064 0065 ToolButton::mouseReleaseEvent(event); 0066 } 0067 0068 void MenuTabs::mouseReleaseEvent(QMouseEvent* event) 0069 { 0070 if (event->button() == Qt::MiddleButton) { 0071 QAction* action = actionAt(event->position().toPoint()); 0072 if (action && action->isEnabled()) { 0073 auto* tab = qobject_cast<WebTab*>(qvariant_cast<QWidget*>(action->data())); 0074 if (tab) { 0075 Q_EMIT closeTab(tab->tabIndex()); 0076 action->setEnabled(false); 0077 event->accept(); 0078 } 0079 } 0080 } 0081 QMenu::mouseReleaseEvent(event); 0082 } 0083 0084 TabWidget::TabWidget(BrowserWindow *window, QWidget *parent) 0085 : TabStackedWidget(parent) 0086 , m_window(window) 0087 , m_locationBars(new QStackedWidget) 0088 , m_closedTabsManager(new ClosedTabsManager) 0089 { 0090 setObjectName(QSL("tabwidget")); 0091 0092 m_tabBar = new TabBar(m_window, this); 0093 setTabBar(m_tabBar); 0094 0095 connect(this, &TabWidget::changed, mApp, &MainApplication::changeOccurred); 0096 connect(this, &TabStackedWidget::pinStateChanged, this, &TabWidget::changed); 0097 0098 connect(m_tabBar, &ComboTabBar::tabCloseRequested, this, &TabWidget::requestCloseTab); 0099 connect(m_tabBar, &TabBar::tabMoved, this, &TabWidget::tabWasMoved); 0100 0101 connect(m_tabBar, &TabBar::moveAddTabButton, this, &TabWidget::moveAddTabButton); 0102 0103 connect(mApp, &MainApplication::settingsReloaded, this, &TabWidget::loadSettings); 0104 0105 m_menuTabs = new MenuTabs(this); 0106 connect(m_menuTabs, &MenuTabs::closeTab, this, &TabWidget::requestCloseTab); 0107 0108 m_menuClosedTabs = new QMenu(this); 0109 0110 // AddTab button displayed next to last tab 0111 m_buttonAddTab = new AddTabButton(this, m_tabBar); 0112 m_buttonAddTab->setProperty("outside-tabbar", false); 0113 connect(m_buttonAddTab, &QAbstractButton::clicked, m_window, &BrowserWindow::addTab); 0114 0115 // AddTab button displayed outside tabbar (as corner widget) 0116 m_buttonAddTab2 = new AddTabButton(this, m_tabBar); 0117 m_buttonAddTab2->setProperty("outside-tabbar", true); 0118 m_buttonAddTab2->hide(); 0119 connect(m_buttonAddTab2, &QAbstractButton::clicked, m_window, &BrowserWindow::addTab); 0120 0121 // ClosedTabs button displayed as a permanent corner widget 0122 m_buttonClosedTabs = new ToolButton(m_tabBar); 0123 m_buttonClosedTabs->setObjectName("tabwidget-button-closedtabs"); 0124 m_buttonClosedTabs->setMenu(m_menuClosedTabs); 0125 m_buttonClosedTabs->setPopupMode(QToolButton::InstantPopup); 0126 m_buttonClosedTabs->setToolTip(tr("Closed tabs")); 0127 m_buttonClosedTabs->setAutoRaise(true); 0128 m_buttonClosedTabs->setFocusPolicy(Qt::NoFocus); 0129 m_buttonClosedTabs->setShowMenuInside(true); 0130 connect(m_buttonClosedTabs, &ToolButton::aboutToShowMenu, this, &TabWidget::aboutToShowClosedTabsMenu); 0131 0132 // ListTabs button is showed only when tabbar overflows 0133 m_buttonListTabs = new ToolButton(m_tabBar); 0134 m_buttonListTabs->setObjectName("tabwidget-button-opentabs"); 0135 m_buttonListTabs->setMenu(m_menuTabs); 0136 m_buttonListTabs->setPopupMode(QToolButton::InstantPopup); 0137 m_buttonListTabs->setToolTip(tr("List of tabs")); 0138 m_buttonListTabs->setAutoRaise(true); 0139 m_buttonListTabs->setFocusPolicy(Qt::NoFocus); 0140 m_buttonListTabs->setShowMenuInside(true); 0141 m_buttonListTabs->hide(); 0142 connect(m_buttonListTabs, &ToolButton::aboutToShowMenu, this, &TabWidget::aboutToShowTabsMenu); 0143 0144 m_tabBar->addCornerWidget(m_buttonAddTab2, Qt::TopRightCorner); 0145 m_tabBar->addCornerWidget(m_buttonClosedTabs, Qt::TopRightCorner); 0146 m_tabBar->addCornerWidget(m_buttonListTabs, Qt::TopRightCorner); 0147 connect(m_tabBar, &ComboTabBar::overFlowChanged, this, &TabWidget::tabBarOverFlowChanged); 0148 0149 loadSettings(); 0150 } 0151 0152 BrowserWindow *TabWidget::browserWindow() const 0153 { 0154 return m_window; 0155 } 0156 0157 void TabWidget::loadSettings() 0158 { 0159 Settings settings; 0160 settings.beginGroup(QSL("Browser-Tabs-Settings")); 0161 m_dontCloseWithOneTab = settings.value(QSL("dontCloseWithOneTab"), false).toBool(); 0162 m_showClosedTabsButton = settings.value(QSL("showClosedTabsButton"), false).toBool(); 0163 m_newTabAfterActive = settings.value(QSL("newTabAfterActive"), true).toBool(); 0164 m_newEmptyTabAfterActive = settings.value(QSL("newEmptyTabAfterActive"), false).toBool(); 0165 settings.endGroup(); 0166 0167 settings.beginGroup(QSL("Web-URL-Settings")); 0168 m_urlOnNewTab = settings.value(QSL("newTabUrl"), QSL("falkon:speeddial")).toUrl(); 0169 settings.endGroup(); 0170 0171 m_tabBar->loadSettings(); 0172 0173 updateClosedTabsButton(); 0174 } 0175 0176 WebTab* TabWidget::weTab() const 0177 { 0178 return weTab(currentIndex()); 0179 } 0180 0181 WebTab* TabWidget::weTab(int index) const 0182 { 0183 return qobject_cast<WebTab*>(widget(index)); 0184 } 0185 0186 TabIcon* TabWidget::tabIcon(int index) const 0187 { 0188 return weTab(index)->tabIcon(); 0189 } 0190 0191 bool TabWidget::validIndex(int index) const 0192 { 0193 return index >= 0 && index < count(); 0194 } 0195 0196 void TabWidget::updateClosedTabsButton() 0197 { 0198 m_buttonClosedTabs->setVisible(m_showClosedTabsButton && canRestoreTab()); 0199 } 0200 0201 void TabWidget::keyPressEvent(QKeyEvent *event) 0202 { 0203 if (mApp->plugins()->processKeyPress(Qz::ON_TabWidget, this, event)) { 0204 return; 0205 } 0206 0207 TabStackedWidget::keyPressEvent(event); 0208 } 0209 0210 void TabWidget::keyReleaseEvent(QKeyEvent *event) 0211 { 0212 if (mApp->plugins()->processKeyRelease(Qz::ON_TabWidget, this, event)) { 0213 return; 0214 } 0215 0216 TabStackedWidget::keyReleaseEvent(event); 0217 } 0218 0219 bool TabWidget::isCurrentTabFresh() const 0220 { 0221 return m_currentTabFresh; 0222 } 0223 0224 void TabWidget::setCurrentTabFresh(bool currentTabFresh) 0225 { 0226 m_currentTabFresh = currentTabFresh; 0227 } 0228 0229 void TabWidget::tabBarOverFlowChanged(bool overflowed) 0230 { 0231 // Show buttons inside tabbar 0232 m_buttonAddTab->setVisible(!overflowed); 0233 0234 // Show buttons displayed outside tabbar (corner widgets) 0235 m_buttonAddTab2->setVisible(overflowed); 0236 m_buttonListTabs->setVisible(overflowed); 0237 } 0238 0239 void TabWidget::moveAddTabButton(int posX) 0240 { 0241 int posY = (m_tabBar->height() - m_buttonAddTab->height()) / 2; 0242 0243 if (QApplication::layoutDirection() == Qt::RightToLeft) { 0244 posX = qMax(posX - m_buttonAddTab->width(), 0); 0245 } 0246 else { 0247 posX = qMin(posX, m_tabBar->width() - m_buttonAddTab->width()); 0248 } 0249 0250 m_buttonAddTab->move(posX, posY); 0251 } 0252 0253 void TabWidget::aboutToShowTabsMenu() 0254 { 0255 m_menuTabs->clear(); 0256 0257 for (int i = 0; i < count(); i++) { 0258 WebTab* tab = weTab(i); 0259 if (!tab || tab->isPinned()) { 0260 continue; 0261 } 0262 0263 auto* action = new QAction(this); 0264 action->setIcon(tab->icon()); 0265 0266 if (i == currentIndex()) { 0267 QFont f = action->font(); 0268 f.setBold(true); 0269 action->setFont(f); 0270 } 0271 0272 QString title = tab->title(); 0273 title.replace(QLatin1Char('&'), QLatin1String("&&")); 0274 action->setText(QzTools::truncatedText(title, 40)); 0275 0276 action->setData(QVariant::fromValue(qobject_cast<QWidget*>(tab))); 0277 connect(action, &QAction::triggered, this, &TabWidget::actionChangeIndex); 0278 m_menuTabs->addAction(action); 0279 } 0280 } 0281 0282 void TabWidget::aboutToShowClosedTabsMenu() 0283 { 0284 m_menuClosedTabs->clear(); 0285 0286 const auto closedTabs = closedTabsManager()->closedTabs(); 0287 for (int i = 0; i < closedTabs.count(); ++i) { 0288 const ClosedTabsManager::Tab tab = closedTabs.at(i); 0289 const QString title = QzTools::truncatedText(tab.tabState.title, 40); 0290 m_menuClosedTabs->addAction(tab.tabState.icon, title, this, SLOT(restoreClosedTab()))->setData(i); 0291 } 0292 0293 if (m_menuClosedTabs->isEmpty()) { 0294 m_menuClosedTabs->addAction(tr("Empty"))->setEnabled(false); 0295 } 0296 else { 0297 m_menuClosedTabs->addSeparator(); 0298 m_menuClosedTabs->addAction(tr("Restore All Closed Tabs"), this, &TabWidget::restoreAllClosedTabs); 0299 m_menuClosedTabs->addAction(QIcon::fromTheme(QSL("edit-clear")), tr("Clear list"), this, &TabWidget::clearClosedTabsList); 0300 } 0301 } 0302 0303 void TabWidget::actionChangeIndex() 0304 { 0305 if (auto* action = qobject_cast<QAction*>(sender())) { 0306 auto* tab = qobject_cast<WebTab*>(qvariant_cast<QWidget*>(action->data())); 0307 if (tab) { 0308 m_tabBar->ensureVisible(tab->tabIndex()); 0309 setCurrentIndex(tab->tabIndex()); 0310 } 0311 } 0312 } 0313 0314 int TabWidget::addView(const LoadRequest &req, const Qz::NewTabPositionFlags &openFlags, bool selectLine, bool pinned) 0315 { 0316 return addView(req, QString(), openFlags, selectLine, -1, pinned); 0317 } 0318 0319 int TabWidget::addView(const LoadRequest &req, const QString &title, const Qz::NewTabPositionFlags &openFlags, bool selectLine, int position, bool pinned) 0320 { 0321 QUrl url = req.url(); 0322 m_currentTabFresh = false; 0323 0324 if (url.isEmpty() && !(openFlags & Qz::NT_CleanTab)) { 0325 url = m_urlOnNewTab; 0326 } 0327 0328 bool openAfterActive = m_newTabAfterActive && !(openFlags & Qz::NT_TabAtTheEnd); 0329 0330 if (openFlags == Qz::NT_SelectedNewEmptyTab && m_newEmptyTabAfterActive) { 0331 openAfterActive = true; 0332 } 0333 0334 if (openAfterActive && position == -1) { 0335 // If we are opening newBgTab from pinned tab, make sure it won't be 0336 // opened between other pinned tabs 0337 if (openFlags & Qz::NT_NotSelectedTab && m_lastBackgroundTab) { 0338 position = m_lastBackgroundTab->tabIndex() + 1; 0339 } 0340 else { 0341 position = qMax(currentIndex() + 1, m_tabBar->pinnedTabsCount()); 0342 } 0343 } 0344 0345 auto* webTab = new WebTab(m_window); 0346 webTab->setPinned(pinned); 0347 webTab->locationBar()->showUrl(url); 0348 m_locationBars->addWidget(webTab->locationBar()); 0349 0350 int index = insertTab(position == -1 ? count() : position, webTab, QString(), pinned); 0351 webTab->attach(m_window); 0352 0353 if (!title.isEmpty()) { 0354 m_tabBar->setTabText(index, title); 0355 } 0356 0357 if (openFlags & Qz::NT_SelectedTab) { 0358 setCurrentIndex(index); 0359 } else { 0360 m_lastBackgroundTab = webTab; 0361 } 0362 0363 connect(webTab->webView(), &TabbedWebView::wantsCloseTab, this, &TabWidget::closeTab); 0364 connect(webTab->webView(), &QWebEngineView::urlChanged, this, &TabWidget::changed); 0365 connect(webTab->webView(), &TabbedWebView::ipChanged, m_window->ipLabel(), &QLabel::setText); 0366 connect(webTab->webView(), &WebView::urlChanged, this, [this](const QUrl &url) { 0367 if (url != m_urlOnNewTab) 0368 m_currentTabFresh = false; 0369 }); 0370 0371 if (url.isValid() && url != req.url()) { 0372 LoadRequest r(req); 0373 r.setUrl(url); 0374 webTab->webView()->load(r); 0375 } 0376 else if (req.url().isValid()) { 0377 webTab->webView()->load(req); 0378 } 0379 0380 if (selectLine && m_window->locationBar()->text().isEmpty()) { 0381 m_window->locationBar()->setFocus(); 0382 } 0383 0384 // Make sure user notice opening new background tabs 0385 if (!(openFlags & Qz::NT_SelectedTab)) { 0386 m_tabBar->ensureVisible(index); 0387 } 0388 0389 Q_EMIT changed(); 0390 Q_EMIT tabInserted(index); 0391 0392 return index; 0393 } 0394 0395 int TabWidget::addView(WebTab *tab, const Qz::NewTabPositionFlags &openFlags) 0396 { 0397 return insertView(count() + 1, tab, openFlags); 0398 } 0399 0400 int TabWidget::insertView(int index, WebTab *tab, const Qz::NewTabPositionFlags &openFlags) 0401 { 0402 m_locationBars->addWidget(tab->locationBar()); 0403 int newIndex = insertTab(index, tab, QString(), tab->isPinned()); 0404 tab->attach(m_window); 0405 0406 if (openFlags.testFlag(Qz::NT_SelectedTab)) { 0407 setCurrentIndex(newIndex); 0408 } else { 0409 m_lastBackgroundTab = tab; 0410 } 0411 0412 connect(tab->webView(), &TabbedWebView::wantsCloseTab, this, &TabWidget::closeTab); 0413 connect(tab->webView(), &QWebEngineView::urlChanged, this, &TabWidget::changed); 0414 connect(tab->webView(), &TabbedWebView::ipChanged, m_window->ipLabel(), &QLabel::setText); 0415 0416 // Make sure user notice opening new background tabs 0417 if (!(openFlags & Qz::NT_SelectedTab)) { 0418 m_tabBar->ensureVisible(index); 0419 } 0420 0421 Q_EMIT changed(); 0422 Q_EMIT tabInserted(newIndex); 0423 0424 return newIndex; 0425 } 0426 0427 void TabWidget::addTabFromClipboard() 0428 { 0429 QString selectionClipboard = QApplication::clipboard()->text(QClipboard::Selection); 0430 QUrl guessedUrl = QUrl::fromUserInput(selectionClipboard); 0431 0432 if (!guessedUrl.isEmpty()) { 0433 addView(guessedUrl, Qz::NT_SelectedNewEmptyTab); 0434 } 0435 } 0436 0437 void TabWidget::closeTab(int index) 0438 { 0439 if (index == -1) 0440 index = currentIndex(); 0441 0442 WebTab *webTab = weTab(index); 0443 if (!webTab || !validIndex(index)) 0444 return; 0445 0446 // This is already handled in requestCloseTab 0447 if (count() <= 1) { 0448 requestCloseTab(index); 0449 return; 0450 } 0451 0452 m_closedTabsManager->saveTab(webTab); 0453 0454 TabbedWebView *webView = webTab->webView(); 0455 m_locationBars->removeWidget(webView->webTab()->locationBar()); 0456 disconnect(webView, &TabbedWebView::wantsCloseTab, this, &TabWidget::closeTab); 0457 disconnect(webView, &QWebEngineView::urlChanged, this, &TabWidget::changed); 0458 disconnect(webView, &TabbedWebView::ipChanged, m_window->ipLabel(), &QLabel::setText); 0459 0460 m_lastBackgroundTab = nullptr; 0461 0462 webTab->detach(); 0463 webTab->deleteLater(); 0464 0465 updateClosedTabsButton(); 0466 0467 Q_EMIT changed(); 0468 Q_EMIT tabRemoved(index); 0469 } 0470 0471 void TabWidget::requestCloseTab(int index) 0472 { 0473 if (index == -1) 0474 index = currentIndex(); 0475 0476 WebTab *webTab = weTab(index); 0477 if (!webTab || !validIndex(index)) 0478 return; 0479 0480 TabbedWebView *webView = webTab->webView(); 0481 0482 // This would close last tab, so we close the window instead 0483 if (count() <= 1) { 0484 // If we are not closing window upon closing last tab, let's just load new-tab-url 0485 if (m_dontCloseWithOneTab) { 0486 // We don't want to accumulate more than one closed tab, if user tries 0487 // to close the last tab multiple times 0488 if (webView->url() != m_urlOnNewTab) { 0489 m_closedTabsManager->saveTab(webTab); 0490 } 0491 webView->zoomReset(); 0492 webView->load(m_urlOnNewTab); 0493 return; 0494 } 0495 m_window->close(); 0496 return; 0497 } 0498 0499 webView->triggerPageAction(QWebEnginePage::RequestClose); 0500 } 0501 0502 void TabWidget::currentTabChanged(int index) 0503 { 0504 if (!validIndex(index)) 0505 return; 0506 0507 m_lastBackgroundTab = nullptr; 0508 m_currentTabFresh = false; 0509 0510 if (!m_tabBar->isRestoring()) { 0511 WebTab* webTab = weTab(index); 0512 webTab->tabActivated(); 0513 0514 LocationBar* locBar = webTab->locationBar(); 0515 0516 if (locBar && m_locationBars->indexOf(locBar) != -1) { 0517 m_locationBars->setCurrentWidget(locBar); 0518 } 0519 0520 m_window->currentTabChanged(); 0521 } 0522 0523 Q_EMIT changed(); 0524 } 0525 0526 void TabWidget::tabWasMoved(int before, int after) 0527 { 0528 m_lastBackgroundTab = nullptr; 0529 0530 Q_EMIT changed(); 0531 if (!m_blockTabMovedSignal) { 0532 Q_EMIT tabMoved(before, after); 0533 } 0534 } 0535 0536 void TabWidget::setCurrentIndex(int index) 0537 { 0538 TabStackedWidget::setCurrentIndex(index); 0539 } 0540 0541 void TabWidget::nextTab() 0542 { 0543 setCurrentIndex((currentIndex() + 1) % count()); 0544 } 0545 0546 void TabWidget::previousTab() 0547 { 0548 setCurrentIndex(currentIndex() == 0 ? count() - 1 : currentIndex() - 1); 0549 } 0550 0551 int TabWidget::normalTabsCount() const 0552 { 0553 return m_tabBar->normalTabsCount(); 0554 } 0555 0556 int TabWidget::pinnedTabsCount() const 0557 { 0558 return m_tabBar->pinnedTabsCount(); 0559 } 0560 0561 void TabWidget::reloadTab(int index) 0562 { 0563 if (!validIndex(index)) { 0564 return; 0565 } 0566 0567 weTab(index)->reload(); 0568 } 0569 0570 WebTab *TabWidget::webTab(int index) const 0571 { 0572 return index < 0 ? weTab() : weTab(index); 0573 } 0574 0575 int TabWidget::extraReservedWidth() const 0576 { 0577 return m_buttonAddTab->width(); 0578 } 0579 0580 TabBar* TabWidget::tabBar() const 0581 { 0582 return m_tabBar; 0583 } 0584 0585 ClosedTabsManager* TabWidget::closedTabsManager() const 0586 { 0587 return m_closedTabsManager; 0588 } 0589 0590 void TabWidget::reloadAllTabs() 0591 { 0592 for (int i = 0; i < count(); i++) { 0593 reloadTab(i); 0594 } 0595 } 0596 0597 void TabWidget::stopTab(int index) 0598 { 0599 if (!validIndex(index)) { 0600 return; 0601 } 0602 0603 weTab(index)->stop(); 0604 } 0605 0606 void TabWidget::closeAllButCurrent(int index) 0607 { 0608 if (!validIndex(index)) { 0609 return; 0610 } 0611 0612 WebTab* akt = weTab(index); 0613 0614 const auto tabs = allTabs(false); 0615 for (const WebTab* tab : tabs) { 0616 int tabIndex = tab->tabIndex(); 0617 if (akt == widget(tabIndex)) { 0618 continue; 0619 } 0620 requestCloseTab(tabIndex); 0621 } 0622 } 0623 0624 void TabWidget::closeToRight(int index) 0625 { 0626 if (!validIndex(index)) { 0627 return; 0628 } 0629 0630 const auto tabs = allTabs(false); 0631 for (const WebTab* tab : tabs) { 0632 int tabIndex = tab->tabIndex(); 0633 if (index >= tabIndex) { 0634 continue; 0635 } 0636 requestCloseTab(tabIndex); 0637 } 0638 } 0639 0640 0641 void TabWidget::closeToLeft(int index) 0642 { 0643 if (!validIndex(index)) { 0644 return; 0645 } 0646 0647 const auto tabs = allTabs(false); 0648 for (const WebTab* tab : tabs) { 0649 int tabIndex = tab->tabIndex(); 0650 if (index <= tabIndex) { 0651 continue; 0652 } 0653 requestCloseTab(tabIndex); 0654 } 0655 } 0656 0657 void TabWidget::moveTab(int from, int to) 0658 { 0659 if (!validIndex(to) || from == to) { 0660 return; 0661 } 0662 WebTab *tab = webTab(from); 0663 if (!tab) { 0664 return; 0665 } 0666 m_blockTabMovedSignal = true; 0667 // (Un)pin tab when needed 0668 if ((tab->isPinned() && to >= pinnedTabsCount()) || (!tab->isPinned() && to < pinnedTabsCount())) { 0669 tab->togglePinned(); 0670 } 0671 TabStackedWidget::moveTab(tab->tabIndex(), to); 0672 m_blockTabMovedSignal = false; 0673 Q_EMIT tabMoved(from, to); 0674 } 0675 0676 int TabWidget::pinUnPinTab(int index, const QString &title) 0677 { 0678 const int newIndex = TabStackedWidget::pinUnPinTab(index, title); 0679 if (index != newIndex && !m_blockTabMovedSignal) { 0680 Q_EMIT tabMoved(index, newIndex); 0681 } 0682 return newIndex; 0683 } 0684 0685 void TabWidget::detachTab(WebTab* tab) 0686 { 0687 Q_ASSERT(tab); 0688 0689 if (count() == 1 && mApp->windowCount() == 1) { 0690 return; 0691 } 0692 0693 m_locationBars->removeWidget(tab->locationBar()); 0694 disconnect(tab->webView(), &TabbedWebView::wantsCloseTab, this, &TabWidget::closeTab); 0695 disconnect(tab->webView(), &QWebEngineView::urlChanged, this, &TabWidget::changed); 0696 disconnect(tab->webView(), &TabbedWebView::ipChanged, m_window->ipLabel(), &QLabel::setText); 0697 0698 const int index = tab->tabIndex(); 0699 0700 tab->detach(); 0701 tab->setPinned(false); 0702 0703 Q_EMIT tabRemoved(index); 0704 0705 if (count() == 0) { 0706 m_window->close(); 0707 } 0708 } 0709 0710 void TabWidget::detachTab(int index) 0711 { 0712 WebTab* tab = weTab(index); 0713 Q_ASSERT(tab); 0714 0715 if (count() == 1 && mApp->windowCount() == 1) { 0716 return; 0717 } 0718 0719 detachTab(tab); 0720 0721 BrowserWindow* window = mApp->createWindow(Qz::BW_NewWindow); 0722 window->setStartTab(tab); 0723 } 0724 0725 int TabWidget::duplicateTab(int index) 0726 { 0727 if (!validIndex(index)) { 0728 return -1; 0729 } 0730 0731 WebTab* webTab = weTab(index); 0732 0733 int id = addView(QUrl(), webTab->title(), Qz::NT_CleanSelectedTab); 0734 weTab(id)->p_restoreTab(webTab->url(), webTab->historyData(), webTab->zoomLevel()); 0735 weTab(id)->setParentTab(webTab); 0736 0737 return id; 0738 } 0739 0740 void TabWidget::loadTab(int index) 0741 { 0742 if (!validIndex(index)) { 0743 return; 0744 } 0745 0746 weTab(index)->tabActivated(); 0747 } 0748 0749 void TabWidget::unloadTab(int index) 0750 { 0751 if (!validIndex(index)) { 0752 return; 0753 } 0754 0755 weTab(index)->unload(); 0756 } 0757 0758 void TabWidget::restoreClosedTab(QObject* obj) 0759 { 0760 if (!obj) { 0761 obj = sender(); 0762 } 0763 0764 if (!m_closedTabsManager->isClosedTabAvailable()) { 0765 return; 0766 } 0767 0768 ClosedTabsManager::Tab tab; 0769 0770 auto* action = qobject_cast<QAction*>(obj); 0771 if (action && action->data().toInt() != 0) { 0772 tab = m_closedTabsManager->takeTabAt(action->data().toInt()); 0773 } 0774 else { 0775 tab = m_closedTabsManager->takeLastClosedTab(); 0776 } 0777 0778 if (tab.position < 0) { 0779 return; 0780 } 0781 0782 int index = addView(QUrl(), tab.tabState.title, Qz::NT_CleanSelectedTab, false, tab.position); 0783 WebTab* webTab = weTab(index); 0784 webTab->setParentTab(tab.parentTab); 0785 webTab->p_restoreTab(tab.tabState); 0786 0787 updateClosedTabsButton(); 0788 } 0789 0790 void TabWidget::restoreAllClosedTabs() 0791 { 0792 if (!m_closedTabsManager->isClosedTabAvailable()) { 0793 return; 0794 } 0795 0796 const auto closedTabs = m_closedTabsManager->closedTabs(); 0797 for (const ClosedTabsManager::Tab &tab : closedTabs) { 0798 int index = addView(QUrl(), tab.tabState.title, Qz::NT_CleanSelectedTab); 0799 WebTab* webTab = weTab(index); 0800 webTab->setParentTab(tab.parentTab); 0801 webTab->p_restoreTab(tab.tabState); 0802 } 0803 0804 clearClosedTabsList(); 0805 } 0806 0807 void TabWidget::clearClosedTabsList() 0808 { 0809 m_closedTabsManager->clearClosedTabs(); 0810 updateClosedTabsButton(); 0811 } 0812 0813 bool TabWidget::canRestoreTab() const 0814 { 0815 return m_closedTabsManager->isClosedTabAvailable(); 0816 } 0817 0818 QStackedWidget* TabWidget::locationBars() const 0819 { 0820 return m_locationBars; 0821 } 0822 0823 ToolButton* TabWidget::buttonClosedTabs() const 0824 { 0825 return m_buttonClosedTabs; 0826 } 0827 0828 AddTabButton* TabWidget::buttonAddTab() const 0829 { 0830 return m_buttonAddTab; 0831 } 0832 0833 QList<WebTab*> TabWidget::allTabs(bool withPinned) 0834 { 0835 QList<WebTab*> allTabs; 0836 0837 for (int i = 0; i < count(); i++) { 0838 WebTab* tab = weTab(i); 0839 if (!tab || (!withPinned && tab->isPinned())) { 0840 continue; 0841 } 0842 allTabs.append(tab); 0843 } 0844 0845 return allTabs; 0846 } 0847 0848 bool TabWidget::restoreState(const QVector<WebTab::SavedTab> &tabs, int currentTab) 0849 { 0850 if (tabs.isEmpty()) { 0851 return false; 0852 } 0853 0854 m_tabBar->setIsRestoring(true); 0855 0856 QVector<QPair<WebTab*, QVector<int>>> childTabs; 0857 0858 for (int i = 0; i < tabs.size(); ++i) { 0859 WebTab::SavedTab tab = tabs.at(i); 0860 WebTab *webTab = weTab(addView(QUrl(), Qz::NT_CleanSelectedTab, false, tab.isPinned)); 0861 webTab->restoreTab(tab); 0862 if (!tab.childTabs.isEmpty()) { 0863 childTabs.append({webTab, tab.childTabs}); 0864 } 0865 } 0866 0867 for (const auto &p : std::as_const(childTabs)) { 0868 const auto indices = p.second; 0869 for (int index : indices) { 0870 WebTab *t = weTab(index); 0871 if (t) { 0872 p.first->addChildTab(t); 0873 } 0874 } 0875 } 0876 0877 m_tabBar->setIsRestoring(false); 0878 0879 auto const l_allTabs = allTabs(); 0880 for (const WebTab* tab : l_allTabs) { 0881 m_tabBar->setTabText(tab->tabIndex(), tab->title()); 0882 } 0883 0884 setCurrentIndex(currentTab); 0885 currentTabChanged(currentTab); 0886 QTimer::singleShot(0, m_tabBar, SLOT(ensureVisible(int,int))); 0887 0888 weTab()->tabActivated(); 0889 0890 return true; 0891 } 0892 0893 TabWidget::~TabWidget() 0894 { 0895 delete m_closedTabsManager; 0896 }