diff --git a/src/lib/tabwidget/tabwidget.cpp b/src/lib/tabwidget/tabwidget.cpp index b423c63f..eed51134 100644 --- a/src/lib/tabwidget/tabwidget.cpp +++ b/src/lib/tabwidget/tabwidget.cpp @@ -1,844 +1,846 @@ /* ============================================================ * Falkon - Qt web browser * Copyright (C) 2010-2017 David Rosca * * This program 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 3 of the License, or * (at your option) any later version. * * This program 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 this program. If not, see . * ============================================================ */ #include "tabwidget.h" #include "tabbar.h" #include "tabbedwebview.h" #include "webpage.h" #include "browserwindow.h" #include "mainapplication.h" #include "webtab.h" #include "clickablelabel.h" #include "closedtabsmanager.h" #include "locationbar.h" #include "settings.h" #include "datapaths.h" #include "qzsettings.h" #include "qztools.h" #include "tabicon.h" #include #include #include #include #include #include #include AddTabButton::AddTabButton(TabWidget* tabWidget, TabBar* tabBar) : ToolButton(tabBar) , m_tabBar(tabBar) , m_tabWidget(tabWidget) { setObjectName("tabwidget-button-addtab"); setAutoRaise(true); setFocusPolicy(Qt::NoFocus); setAcceptDrops(true); setToolTip(TabWidget::tr("New Tab")); } void AddTabButton::wheelEvent(QWheelEvent* event) { m_tabBar->wheelEvent(event); } void AddTabButton::mouseReleaseEvent(QMouseEvent* event) { if (event->button() == Qt::MiddleButton && rect().contains(event->pos())) { m_tabWidget->addTabFromClipboard(); } ToolButton::mouseReleaseEvent(event); } void AddTabButton::dragEnterEvent(QDragEnterEvent* event) { const QMimeData* mime = event->mimeData(); if (mime->hasUrls()) { event->acceptProposedAction(); return; } ToolButton::dragEnterEvent(event); } void AddTabButton::dropEvent(QDropEvent* event) { const QMimeData* mime = event->mimeData(); if (!mime->hasUrls()) { ToolButton::dropEvent(event); return; } foreach (const QUrl &url, mime->urls()) { m_tabWidget->addView(url, Qz::NT_SelectedNewEmptyTab); } } void MenuTabs::mouseReleaseEvent(QMouseEvent* event) { if (event->button() == Qt::MiddleButton) { QAction* action = actionAt(event->pos()); if (action && action->isEnabled()) { WebTab* tab = qobject_cast(qvariant_cast(action->data())); if (tab) { emit closeTab(tab->tabIndex()); action->setEnabled(false); event->accept(); } } } QMenu::mouseReleaseEvent(event); } TabWidget::TabWidget(BrowserWindow* window, QWidget* parent) : TabStackedWidget(parent) , m_window(window) , m_locationBars(new QStackedWidget) , m_closedTabsManager(new ClosedTabsManager) , m_lastTabIndex(-1) , m_lastBackgroundTabIndex(-1) { setObjectName(QSL("tabwidget")); m_tabBar = new TabBar(m_window, this); setTabBar(m_tabBar); connect(this, SIGNAL(currentChanged(int)), m_window, SLOT(refreshHistory())); connect(this, &TabWidget::changed, mApp, &MainApplication::changeOccurred); connect(this, &TabStackedWidget::pinStateChanged, this, &TabWidget::changed); connect(m_tabBar, SIGNAL(tabCloseRequested(int)), this, SLOT(requestCloseTab(int))); connect(m_tabBar, SIGNAL(tabMoved(int,int)), this, SLOT(tabMoved(int,int))); connect(m_tabBar, SIGNAL(moveAddTabButton(int)), this, SLOT(moveAddTabButton(int))); connect(mApp, SIGNAL(settingsReloaded()), this, SLOT(loadSettings())); m_menuTabs = new MenuTabs(this); connect(m_menuTabs, SIGNAL(closeTab(int)), this, SLOT(requestCloseTab(int))); m_menuClosedTabs = new QMenu(this); // AddTab button displayed next to last tab m_buttonAddTab = new AddTabButton(this, m_tabBar); connect(m_buttonAddTab, SIGNAL(clicked()), m_window, SLOT(addTab())); // AddTab button displayed outside tabbar (as corner widget) m_buttonAddTab2 = new AddTabButton(this, m_tabBar); m_buttonAddTab2->setProperty("outside-tabbar", true); m_buttonAddTab2->hide(); connect(m_buttonAddTab2, SIGNAL(clicked()), m_window, SLOT(addTab())); // ClosedTabs button displayed as a permanent corner widget m_buttonClosedTabs = new ToolButton(m_tabBar); m_buttonClosedTabs->setObjectName("tabwidget-button-closedtabs"); m_buttonClosedTabs->setMenu(m_menuClosedTabs); m_buttonClosedTabs->setPopupMode(QToolButton::InstantPopup); m_buttonClosedTabs->setToolTip(tr("Closed tabs")); m_buttonClosedTabs->setAutoRaise(true); m_buttonClosedTabs->setFocusPolicy(Qt::NoFocus); m_buttonClosedTabs->setShowMenuInside(true); connect(m_buttonClosedTabs, SIGNAL(aboutToShowMenu()), this, SLOT(aboutToShowClosedTabsMenu())); // ListTabs button is showed only when tabbar overflows m_buttonListTabs = new ToolButton(m_tabBar); m_buttonListTabs->setObjectName("tabwidget-button-opentabs"); m_buttonListTabs->setMenu(m_menuTabs); m_buttonListTabs->setPopupMode(QToolButton::InstantPopup); m_buttonListTabs->setToolTip(tr("List of tabs")); m_buttonListTabs->setAutoRaise(true); m_buttonListTabs->setFocusPolicy(Qt::NoFocus); m_buttonListTabs->setShowMenuInside(true); m_buttonListTabs->hide(); connect(m_buttonListTabs, SIGNAL(aboutToShowMenu()), this, SLOT(aboutToShowTabsMenu())); m_tabBar->addCornerWidget(m_buttonAddTab2, Qt::TopRightCorner); m_tabBar->addCornerWidget(m_buttonClosedTabs, Qt::TopRightCorner); m_tabBar->addCornerWidget(m_buttonListTabs, Qt::TopRightCorner); connect(m_tabBar, SIGNAL(overFlowChanged(bool)), this, SLOT(tabBarOverFlowChanged(bool))); loadSettings(); } void TabWidget::loadSettings() { Settings settings; settings.beginGroup("Browser-Tabs-Settings"); m_dontCloseWithOneTab = settings.value("dontCloseWithOneTab", false).toBool(); m_showClosedTabsButton = settings.value("showClosedTabsButton", false).toBool(); m_newTabAfterActive = settings.value("newTabAfterActive", true).toBool(); m_newEmptyTabAfterActive = settings.value("newEmptyTabAfterActive", false).toBool(); settings.endGroup(); settings.beginGroup("Web-URL-Settings"); m_urlOnNewTab = settings.value("newTabUrl", "falkon:speeddial").toUrl(); settings.endGroup(); m_tabBar->loadSettings(); updateClosedTabsButton(); } WebTab* TabWidget::weTab() { return weTab(currentIndex()); } WebTab* TabWidget::weTab(int index) { return qobject_cast(widget(index)); } TabIcon* TabWidget::tabIcon(int index) { return weTab(index)->tabIcon(); } bool TabWidget::validIndex(int index) const { return index >= 0 && index < count(); } void TabWidget::updateClosedTabsButton() { if (!m_showClosedTabsButton) { m_buttonClosedTabs->hide(); } m_buttonClosedTabs->setEnabled(canRestoreTab()); } bool TabWidget::isCurrentTabFresh() const { return m_currentTabFresh; } void TabWidget::setCurrentTabFresh(bool currentTabFresh) { m_currentTabFresh = currentTabFresh; } void TabWidget::tabBarOverFlowChanged(bool overflowed) { // Show buttons inside tabbar m_buttonAddTab->setVisible(!overflowed); // Show buttons displayed outside tabbar (corner widgets) m_buttonAddTab2->setVisible(overflowed); m_buttonListTabs->setVisible(overflowed); m_buttonClosedTabs->setVisible(m_showClosedTabsButton); } void TabWidget::moveAddTabButton(int posX) { int posY = (m_tabBar->height() - m_buttonAddTab->height()) / 2; if (QApplication::layoutDirection() == Qt::RightToLeft) { posX = qMax(posX - m_buttonAddTab->width(), 0); } else { posX = qMin(posX, m_tabBar->width() - m_buttonAddTab->width()); } m_buttonAddTab->move(posX, posY); } void TabWidget::aboutToShowTabsMenu() { m_menuTabs->clear(); for (int i = 0; i < count(); i++) { WebTab* tab = weTab(i); if (!tab || tab->isPinned()) { continue; } QAction* action = new QAction(this); action->setIcon(tab->icon()); if (i == currentIndex()) { QFont f = action->font(); f.setBold(true); action->setFont(f); } QString title = tab->title(); title.replace(QLatin1Char('&'), QLatin1String("&&")); action->setText(QzTools::truncatedText(title, 40)); action->setData(QVariant::fromValue(qobject_cast(tab))); connect(action, SIGNAL(triggered()), this, SLOT(actionChangeIndex())); m_menuTabs->addAction(action); } } void TabWidget::aboutToShowClosedTabsMenu() { m_menuClosedTabs->clear(); int i = 0; const QLinkedList closedTabs = closedTabsManager()->allClosedTabs(); foreach (const ClosedTabsManager::Tab &tab, closedTabs) { const QString title = QzTools::truncatedText(tab.title, 40); QAction* act = m_menuClosedTabs->addAction(tab.icon, title, this, SLOT(restoreClosedTab())); act->setData(i++); } if (m_menuClosedTabs->isEmpty()) { m_menuClosedTabs->addAction(tr("Empty"))->setEnabled(false); } else { m_menuClosedTabs->addSeparator(); m_menuClosedTabs->addAction(tr("Restore All Closed Tabs"), this, SLOT(restoreAllClosedTabs())); m_menuClosedTabs->addAction(tr("Clear list"), this, SLOT(clearClosedTabsList())); } } void TabWidget::actionChangeIndex() { if (QAction* action = qobject_cast(sender())) { WebTab* tab = qobject_cast(qvariant_cast(action->data())); if (tab) { m_tabBar->ensureVisible(tab->tabIndex()); setCurrentIndex(tab->tabIndex()); } } } int TabWidget::addView(const LoadRequest &req, const Qz::NewTabPositionFlags &openFlags, bool selectLine, bool pinned) { return addView(req, QString(), openFlags, selectLine, -1, pinned); } int TabWidget::addView(const LoadRequest &req, const QString &title, const Qz::NewTabPositionFlags &openFlags, bool selectLine, int position, bool pinned) { QUrl url = req.url(); m_lastTabIndex = currentIndex(); m_currentTabFresh = false; if (url.isEmpty() && !(openFlags & Qz::NT_CleanTab)) { url = m_urlOnNewTab; } bool openAfterActive = m_newTabAfterActive && !(openFlags & Qz::NT_TabAtTheEnd); if (openFlags == Qz::NT_SelectedNewEmptyTab && m_newEmptyTabAfterActive) { openAfterActive = true; } if (openAfterActive && position == -1) { // If we are opening newBgTab from pinned tab, make sure it won't be // opened between other pinned tabs if (openFlags & Qz::NT_NotSelectedTab && m_lastBackgroundTabIndex != -1) { position = m_lastBackgroundTabIndex + 1; } else { position = qMax(currentIndex() + 1, m_tabBar->pinnedTabsCount()); } } WebTab* webTab = new WebTab(m_window); webTab->locationBar()->showUrl(url); m_locationBars->addWidget(webTab->locationBar()); int index = insertTab(position == -1 ? count() : position, webTab, QString(), pinned); webTab->attach(m_window); if (!title.isEmpty()) { m_tabBar->setTabText(index, title); } if (openFlags & Qz::NT_SelectedTab) { setCurrentIndex(index); } else { m_lastBackgroundTabIndex = index; } connect(webTab->webView(), SIGNAL(wantsCloseTab(int)), this, SLOT(closeTab(int))); connect(webTab->webView(), SIGNAL(urlChanged(QUrl)), this, SIGNAL(changed())); connect(webTab->webView(), SIGNAL(ipChanged(QString)), m_window->ipLabel(), SLOT(setText(QString))); connect(webTab->webView(), &WebView::urlChanged, this, [this](const QUrl &url) { if (url != m_urlOnNewTab) m_currentTabFresh = false; }); if (url.isValid() && url != req.url()) { LoadRequest r(req); r.setUrl(url); webTab->webView()->load(r); } else if (req.url().isValid()) { webTab->webView()->load(req); } if (selectLine && m_window->locationBar()->text().isEmpty()) { m_window->locationBar()->setFocus(); } // Make sure user notice opening new background tabs if (!(openFlags & Qz::NT_SelectedTab)) { m_tabBar->ensureVisible(index); } emit changed(); return index; } int TabWidget::addView(WebTab* tab) { m_locationBars->addWidget(tab->locationBar()); int index = addTab(tab, QString()); tab->attach(m_window); connect(tab->webView(), SIGNAL(wantsCloseTab(int)), this, SLOT(closeTab(int))); connect(tab->webView(), SIGNAL(urlChanged(QUrl)), this, SIGNAL(changed())); connect(tab->webView(), SIGNAL(ipChanged(QString)), m_window->ipLabel(), SLOT(setText(QString))); return index; } void TabWidget::addTabFromClipboard() { QString selectionClipboard = QApplication::clipboard()->text(QClipboard::Selection); QUrl guessedUrl = QUrl::fromUserInput(selectionClipboard); if (!guessedUrl.isEmpty()) { addView(guessedUrl, Qz::NT_SelectedNewEmptyTab); } } void TabWidget::closeTab(int index) { if (index == -1) index = currentIndex(); WebTab *webTab = weTab(index); if (!webTab || !validIndex(index)) return; TabbedWebView *webView = webTab->webView(); // Save tab url and history if (webView->url().toString() != QL1S("falkon:restore")) m_closedTabsManager->saveTab(webTab, index); m_locationBars->removeWidget(webView->webTab()->locationBar()); disconnect(webView, SIGNAL(wantsCloseTab(int)), this, SLOT(closeTab(int))); disconnect(webView, SIGNAL(urlChanged(QUrl)), this, SIGNAL(changed())); disconnect(webView, SIGNAL(ipChanged(QString)), m_window->ipLabel(), SLOT(setText(QString))); m_lastBackgroundTabIndex = -1; if (m_menuTabs->isVisible()) { QAction* labelAction = m_menuTabs->actions().last(); //~ singular Currently you have %n opened tab //~ plural Currently you have %n opened tabs labelAction->setText(tr("Currently you have %n opened tab(s)", "", count() - 1)); } removeTab(index); webTab->deleteLater(); updateClosedTabsButton(); emit changed(); } void TabWidget::requestCloseTab(int index) { if (index == -1) index = currentIndex(); WebTab *webTab = weTab(index); if (!webTab || !validIndex(index)) return; TabbedWebView *webView = webTab->webView(); // Don't close restore page! if (webView->url().toString() == QL1S("falkon:restore") && mApp->restoreManager()) return; // This would close last tab, so we close the window instead if (count() == 1) { // If we are not closing window upon closing last tab, let's just load new-tab-url if (m_dontCloseWithOneTab) { if (webView->url() == m_urlOnNewTab) { // We don't want to accumulate more than one closed tab, if user tries // to close the last tab multiple times m_closedTabsManager->takeLastClosedTab(); } webView->load(m_urlOnNewTab); return; } m_window->close(); return; } webView->triggerPageAction(QWebEnginePage::RequestClose); } void TabWidget::currentTabChanged(int index) { if (!validIndex(index)) return; m_lastBackgroundTabIndex = -1; m_lastTabIndex = index; m_currentTabFresh = false; WebTab* webTab = weTab(index); + webTab->tabActivated(); + LocationBar* locBar = webTab->locationBar(); if (locBar && m_locationBars->indexOf(locBar) != -1) { m_locationBars->setCurrentWidget(locBar); } m_window->currentTabChanged(); emit changed(); } void TabWidget::tabMoved(int before, int after) { Q_UNUSED(before) Q_UNUSED(after) m_lastBackgroundTabIndex = -1; m_lastTabIndex = before; emit changed(); } void TabWidget::setCurrentIndex(int index) { m_lastTabIndex = currentIndex(); TabStackedWidget::setCurrentIndex(index); } void TabWidget::nextTab() { QKeyEvent fakeEvent(QKeyEvent::KeyPress, Qt::Key_Tab, Qt::ControlModifier); keyPressEvent(&fakeEvent); } void TabWidget::previousTab() { QKeyEvent fakeEvent(QKeyEvent::KeyPress, Qt::Key_Backtab, QFlags(Qt::ControlModifier + Qt::ShiftModifier)); keyPressEvent(&fakeEvent); } int TabWidget::normalTabsCount() const { return m_tabBar->normalTabsCount(); } int TabWidget::pinnedTabsCount() const { return m_tabBar->pinnedTabsCount(); } void TabWidget::reloadTab(int index) { if (!validIndex(index)) { return; } weTab(index)->reload(); } int TabWidget::lastTabIndex() const { return m_lastTabIndex; } int TabWidget::extraReservedWidth() const { return m_buttonAddTab->width(); } TabBar* TabWidget::tabBar() const { return m_tabBar; } ClosedTabsManager* TabWidget::closedTabsManager() const { return m_closedTabsManager; } void TabWidget::reloadAllTabs() { for (int i = 0; i < count(); i++) { reloadTab(i); } } void TabWidget::stopTab(int index) { if (!validIndex(index)) { return; } weTab(index)->stop(); } void TabWidget::closeAllButCurrent(int index) { if (!validIndex(index)) { return; } WebTab* akt = weTab(index); foreach (WebTab* tab, allTabs(false)) { int tabIndex = tab->tabIndex(); if (akt == widget(tabIndex)) { continue; } requestCloseTab(tabIndex); } } void TabWidget::closeToRight(int index) { if (!validIndex(index)) { return; } foreach (WebTab* tab, allTabs(false)) { int tabIndex = tab->tabIndex(); if (index >= tabIndex) { continue; } requestCloseTab(tabIndex); } } void TabWidget::closeToLeft(int index) { if (!validIndex(index)) { return; } foreach (WebTab* tab, allTabs(false)) { int tabIndex = tab->tabIndex(); if (index <= tabIndex) { continue; } requestCloseTab(tabIndex); } } void TabWidget::detachTab(int index) { WebTab* tab = weTab(index); if (tab->isPinned() || count() == 1) { return; } m_locationBars->removeWidget(tab->locationBar()); disconnect(tab->webView(), SIGNAL(wantsCloseTab(int)), this, SLOT(closeTab(int))); disconnect(tab->webView(), SIGNAL(urlChanged(QUrl)), this, SIGNAL(changed())); disconnect(tab->webView(), SIGNAL(ipChanged(QString)), m_window->ipLabel(), SLOT(setText(QString))); tab->detach(); BrowserWindow* window = mApp->createWindow(Qz::BW_NewWindow); window->setStartTab(tab); } int TabWidget::duplicateTab(int index) { if (!validIndex(index)) { return -1; } WebTab* webTab = weTab(index); int id = addView(QUrl(), webTab->title(), Qz::NT_CleanNotSelectedTab); weTab(id)->p_restoreTab(webTab->url(), webTab->historyData(), webTab->zoomLevel()); return id; } void TabWidget::restoreClosedTab(QObject* obj) { if (!obj) { obj = sender(); } if (!m_closedTabsManager->isClosedTabAvailable()) { return; } ClosedTabsManager::Tab tab; QAction* action = qobject_cast(obj); if (action && action->data().toInt() != 0) { tab = m_closedTabsManager->takeTabAt(action->data().toInt()); } else { tab = m_closedTabsManager->takeLastClosedTab(); } if (tab.position < 0) { return; } int index = addView(QUrl(), tab.title, Qz::NT_CleanSelectedTab, false, tab.position); WebTab* webTab = weTab(index); webTab->p_restoreTab(tab.url, tab.history, tab.zoomLevel); updateClosedTabsButton(); } void TabWidget::restoreAllClosedTabs() { if (!m_closedTabsManager->isClosedTabAvailable()) { return; } const QLinkedList &closedTabs = m_closedTabsManager->allClosedTabs(); foreach (const ClosedTabsManager::Tab &tab, closedTabs) { int index = addView(QUrl(), tab.title, Qz::NT_CleanSelectedTab); WebTab* webTab = weTab(index); webTab->p_restoreTab(tab.url, tab.history, tab.zoomLevel); } clearClosedTabsList(); } void TabWidget::clearClosedTabsList() { m_closedTabsManager->clearList(); updateClosedTabsButton(); } bool TabWidget::canRestoreTab() const { return m_closedTabsManager->isClosedTabAvailable(); } QStackedWidget* TabWidget::locationBars() const { return m_locationBars; } ToolButton* TabWidget::buttonClosedTabs() const { return m_buttonClosedTabs; } AddTabButton* TabWidget::buttonAddTab() const { return m_buttonAddTab; } QList TabWidget::allTabs(bool withPinned) { QList allTabs; for (int i = 0; i < count(); i++) { WebTab* tab = weTab(i); if (!tab || (!withPinned && tab->isPinned())) { continue; } allTabs.append(tab); } return allTabs; } QByteArray TabWidget::saveState() { int currentTabIndex = 0; QVector tabList; for (int i = 0; i < count(); ++i) { WebTab* webTab = weTab(i); if (!webTab) continue; WebTab::SavedTab tab(webTab); if (!tab.isValid()) continue; tabList.append(tab); if (webTab->isCurrentTab()) currentTabIndex = tabList.size() - 1; } QByteArray data; QDataStream stream(&data, QIODevice::WriteOnly); stream << tabList.count(); foreach (const WebTab::SavedTab &tab, tabList) { stream << tab; } stream << currentTabIndex; return data; } bool TabWidget::restoreState(const QVector &tabs, int currentTab) { for (int i = 0; i < tabs.size(); ++i) { WebTab::SavedTab tab = tabs.at(i); int index = addView(QUrl(), Qz::NT_CleanSelectedTab, false, tab.isPinned); weTab(index)->restoreTab(tab); if (tab.isPinned) m_tabBar->updatePinnedTabCloseButton(index); } setCurrentIndex(currentTab); QTimer::singleShot(0, m_tabBar, SLOT(ensureVisible(int,int))); // WebTab is restoring state on showEvent weTab()->hide(); weTab()->show(); return true; } void TabWidget::closeRecoveryTab() { foreach (WebTab* tab, allTabs(false)) { if (tab->url().toString() == QLatin1String("falkon:restore")) { closeTab(tab->tabIndex()); } } } TabWidget::~TabWidget() { delete m_closedTabsManager; } diff --git a/src/lib/webtab/webtab.cpp b/src/lib/webtab/webtab.cpp index 8cdaefd3..4a36e560 100644 --- a/src/lib/webtab/webtab.cpp +++ b/src/lib/webtab/webtab.cpp @@ -1,523 +1,517 @@ /* ============================================================ * Falkon - Qt web browser * Copyright (C) 2010-2017 David Rosca * * This program 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 3 of the License, or * (at your option) any later version. * * This program 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 this program. If not, see . * ============================================================ */ #include "webtab.h" #include "browserwindow.h" #include "tabbedwebview.h" #include "webinspector.h" #include "webpage.h" #include "tabbar.h" #include "tabicon.h" #include "tabwidget.h" #include "locationbar.h" #include "qztools.h" #include "qzsettings.h" #include "mainapplication.h" #include "iconprovider.h" #include "searchtoolbar.h" #include #include #include #include #include -bool WebTab::s_pinningTab = false; static const int savedTabVersion = 3; WebTab::SavedTab::SavedTab() : isPinned(false) , zoomLevel(qzSettings->defaultZoomLevel) { } WebTab::SavedTab::SavedTab(WebTab* webTab) { if (webTab->url().toString() == QL1S("falkon:restore")) { return; } title = webTab->title(); url = webTab->url(); icon = webTab->icon(true); history = webTab->historyData(); isPinned = webTab->isPinned(); zoomLevel = webTab->zoomLevel(); } bool WebTab::SavedTab::isValid() const { return !url.isEmpty(); } void WebTab::SavedTab::clear() { title.clear(); url.clear(); icon = QIcon(); history.clear(); isPinned = false; zoomLevel = qzSettings->defaultZoomLevel; } QDataStream &operator <<(QDataStream &stream, const WebTab::SavedTab &tab) { stream << savedTabVersion; stream << tab.title; stream << tab.url; stream << tab.icon.pixmap(16); stream << tab.history; stream << tab.isPinned; stream << tab.zoomLevel; return stream; } QDataStream &operator >>(QDataStream &stream, WebTab::SavedTab &tab) { int version; stream >> version; if (version < 1) return stream; QPixmap pixmap; stream >> tab.title; stream >> tab.url; stream >> pixmap; stream >> tab.history; if (version >= 2) stream >> tab.isPinned; if (version >= 3) stream >> tab.zoomLevel; tab.icon = QIcon(pixmap); return stream; } WebTab::WebTab(BrowserWindow* window) : QWidget() , m_window(window) , m_tabBar(0) , m_isPinned(false) { setObjectName(QSL("webtab")); m_webView = new TabbedWebView(this); m_webView->setBrowserWindow(m_window); m_webView->setWebPage(new WebPage); m_webView->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding); m_locationBar = new LocationBar(m_window); m_locationBar->setWebView(m_webView); m_tabIcon = new TabIcon(this); m_tabIcon->setWebTab(this); m_layout = new QVBoxLayout(this); m_layout->setContentsMargins(0, 0, 0, 0); m_layout->setSpacing(0); m_layout->addWidget(m_webView); QWidget *viewWidget = new QWidget(this); viewWidget->setLayout(m_layout); m_splitter = new QSplitter(Qt::Vertical, this); m_splitter->setChildrenCollapsible(false); m_splitter->addWidget(viewWidget); QVBoxLayout *layout = new QVBoxLayout(this); layout->setContentsMargins(0, 0, 0, 0); layout->setSpacing(0); layout->addWidget(m_splitter); setLayout(layout); m_notificationWidget = new QWidget(this); m_notificationWidget->setAutoFillBackground(true); QPalette pal = m_notificationWidget->palette(); pal.setColor(QPalette::Background, pal.window().color().darker(110)); m_notificationWidget->setPalette(pal); QVBoxLayout *nlayout = new QVBoxLayout(m_notificationWidget); nlayout->setSizeConstraint(QLayout::SetMinAndMaxSize); nlayout->setContentsMargins(0, 0, 0, 0); nlayout->setSpacing(1); connect(m_webView, SIGNAL(showNotification(QWidget*)), this, SLOT(showNotification(QWidget*))); connect(m_webView, SIGNAL(loadStarted()), this, SLOT(loadStarted())); connect(m_webView, SIGNAL(loadFinished(bool)), this, SLOT(loadFinished())); connect(m_webView, SIGNAL(titleChanged(QString)), this, SLOT(titleChanged(QString))); // Workaround QTabBar not immediately noticing resizing of tab buttons connect(m_tabIcon, &TabIcon::resized, this, [this]() { if (m_tabBar) { m_tabBar->setTabButton(tabIndex(), m_tabBar->iconButtonPosition(), m_tabIcon); } }); } TabbedWebView* WebTab::webView() const { return m_webView; } bool WebTab::haveInspector() const { return m_splitter->count() > 1 && m_splitter->widget(1)->inherits("WebInspector"); } void WebTab::showWebInspector(bool inspectElement) { if (!WebInspector::isEnabled() || haveInspector()) return; WebInspector *inspector = new WebInspector(this); inspector->setView(m_webView); if (inspectElement) inspector->inspectElement(); m_splitter->addWidget(inspector); } void WebTab::toggleWebInspector() { if (!haveInspector()) showWebInspector(); else delete m_splitter->widget(1); } void WebTab::showSearchToolBar() { const int index = 1; SearchToolBar *toolBar = nullptr; if (m_layout->count() == 1) { toolBar = new SearchToolBar(m_webView, this); m_layout->insertWidget(index, toolBar); } else if (m_layout->count() == 2) { Q_ASSERT(qobject_cast(m_layout->itemAt(index)->widget())); toolBar = static_cast(m_layout->itemAt(index)->widget()); } Q_ASSERT(toolBar); toolBar->focusSearchLine(); } QUrl WebTab::url() const { if (isRestored()) { return m_webView->url(); } else { return m_savedTab.url; } } QString WebTab::title() const { if (isRestored()) { return m_webView->title(); } else { return m_savedTab.title; } } QIcon WebTab::icon(bool allowNull) const { if (isRestored()) { return m_webView->icon(allowNull); } if (allowNull || !m_savedTab.icon.isNull()) { return m_savedTab.icon; } return IconProvider::emptyWebIcon(); } QWebEngineHistory* WebTab::history() const { return m_webView->history(); } int WebTab::zoomLevel() const { return m_webView->zoomLevel(); } void WebTab::setZoomLevel(int level) { m_webView->setZoomLevel(level); } void WebTab::detach() { Q_ASSERT(m_tabBar); // Remove icon from tab m_tabBar->setTabButton(tabIndex(), m_tabBar->iconButtonPosition(), 0); // Remove the tab from tabbar setParent(0); // Remove the locationbar from window m_locationBar->setParent(this); // Detach TabbedWebView m_webView->setBrowserWindow(0); // WebTab is now standalone widget m_window = 0; m_tabBar = 0; } void WebTab::attach(BrowserWindow* window) { m_window = window; m_tabBar = m_window->tabWidget()->tabBar(); m_webView->setBrowserWindow(m_window); m_tabBar->setTabText(tabIndex(), title()); m_tabBar->setTabButton(tabIndex(), m_tabBar->iconButtonPosition(), m_tabIcon); m_tabIcon->updateIcon(); } QByteArray WebTab::historyData() const { if (isRestored()) { QByteArray historyArray; QDataStream historyStream(&historyArray, QIODevice::WriteOnly); historyStream << *m_webView->history(); return historyArray; } else { return m_savedTab.history; } } void WebTab::reload() { m_webView->reload(); } void WebTab::stop() { m_webView->stop(); } bool WebTab::isLoading() const { return m_webView->isLoading(); } bool WebTab::isPinned() const { return m_isPinned; } void WebTab::setPinned(bool state) { m_isPinned = state; } bool WebTab::isMuted() const { return m_webView->page()->isAudioMuted(); } void WebTab::setMuted(bool muted) { m_webView->page()->setAudioMuted(muted); } void WebTab::toggleMuted() { bool muted = isMuted(); setMuted(!muted); } LocationBar* WebTab::locationBar() const { return m_locationBar; } TabIcon* WebTab::tabIcon() const { return m_tabIcon; } bool WebTab::isRestored() const { return !m_savedTab.isValid(); } void WebTab::restoreTab(const WebTab::SavedTab &tab) { Q_ASSERT(m_tabBar); m_isPinned = tab.isPinned; if (!m_isPinned && qzSettings->loadTabsOnActivation) { m_savedTab = tab; int index = tabIndex(); m_tabBar->setTabText(index, tab.title); m_locationBar->showUrl(tab.url); m_tabIcon->updateIcon(); if (!tab.url.isEmpty()) { QColor col = m_tabBar->palette().text().color(); QColor newCol = col.lighter(250); // It won't work for black color because (V) = 0 // It won't also work for white, as white won't get any lighter if (col == Qt::black || col == Qt::white) { newCol = Qt::gray; } m_tabBar->overrideTabTextColor(index, newCol); } } else { // This is called only on restore session and restoring tabs immediately // crashes QtWebEngine, waiting after initialization is complete fixes it QTimer::singleShot(1000, this, [=]() { p_restoreTab(tab); }); } } void WebTab::p_restoreTab(const QUrl &url, const QByteArray &history, int zoomLevel) { m_webView->load(url); // Restoring history of internal pages crashes QtWebEngine 5.8 static const QStringList blacklistedSchemes = { QSL("view-source"), QSL("chrome") }; if (!blacklistedSchemes.contains(url.scheme())) { QDataStream stream(history); stream >> *m_webView->history(); } m_webView->setZoomLevel(zoomLevel); m_webView->setFocus(); } void WebTab::p_restoreTab(const WebTab::SavedTab &tab) { p_restoreTab(tab.url, tab.history, tab.zoomLevel); } void WebTab::showNotification(QWidget* notif) { m_notificationWidget->setParent(nullptr); m_notificationWidget->setParent(this); m_notificationWidget->setFixedWidth(width()); m_notificationWidget->layout()->addWidget(notif); m_notificationWidget->show(); notif->show(); } void WebTab::loadStarted() { if (m_tabBar && m_webView->isTitleEmpty()) { m_tabBar->setTabText(tabIndex(), tr("Loading...")); } } void WebTab::loadFinished() { titleChanged(m_webView->title()); } void WebTab::titleChanged(const QString &title) { if (!m_tabBar || !m_window || title.isEmpty()) { return; } if (isCurrentTab()) { m_window->setWindowTitle(tr("%1 - Falkon").arg(title)); } m_tabBar->setTabText(tabIndex(), title); } void WebTab::slotRestore() { Q_ASSERT(m_tabBar); p_restoreTab(m_savedTab); m_savedTab.clear(); m_tabBar->restoreTabTextColor(tabIndex()); } -void WebTab::showEvent(QShowEvent* event) +void WebTab::tabActivated() { - QWidget::showEvent(event); - if (!isRestored() && !s_pinningTab) { + if (!isRestored()) { // When session is being restored, restore the tab immediately if (mApp->isRestoring()) { slotRestore(); } else { QTimer::singleShot(0, this, SLOT(slotRestore())); } } } void WebTab::resizeEvent(QResizeEvent *event) { QWidget::resizeEvent(event); m_notificationWidget->setFixedWidth(width()); } bool WebTab::isCurrentTab() const { return m_tabBar && tabIndex() == m_tabBar->currentIndex(); } int WebTab::tabIndex() const { Q_ASSERT(m_tabBar); return m_tabBar->tabWidget()->indexOf(const_cast(this)); } void WebTab::togglePinned() { Q_ASSERT(m_tabBar); Q_ASSERT(m_window); m_isPinned = !m_isPinned; - // Workaround bug in TabStackedWidget when pinning tab, other tabs may be accidentaly - // shown and restored state even when they won't be switched to by user. - s_pinningTab = true; m_window->tabWidget()->pinUnPinTab(tabIndex(), title()); - s_pinningTab = false; } diff --git a/src/lib/webtab/webtab.h b/src/lib/webtab/webtab.h index fee25eff..06d26139 100644 --- a/src/lib/webtab/webtab.h +++ b/src/lib/webtab/webtab.h @@ -1,134 +1,134 @@ /* ============================================================ * Falkon - Qt web browser * Copyright (C) 2010-2017 David Rosca * * This program 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 3 of the License, or * (at your option) any later version. * * This program 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 this program. If not, see . * ============================================================ */ #ifndef WEBTAB_H #define WEBTAB_H #include #include #include #include "qzcommon.h" class QVBoxLayout; class QWebEngineHistory; class QSplitter; class BrowserWindow; class TabbedWebView; class WebInspector; class LocationBar; class TabIcon; class TabBar; class FALKON_EXPORT WebTab : public QWidget { Q_OBJECT public: struct SavedTab { QString title; QUrl url; QIcon icon; QByteArray history; bool isPinned; int zoomLevel; SavedTab(); SavedTab(WebTab* webTab); bool isValid() const; void clear(); friend FALKON_EXPORT QDataStream &operator<<(QDataStream &stream, const SavedTab &tab); friend FALKON_EXPORT QDataStream &operator>>(QDataStream &stream, SavedTab &tab); }; explicit WebTab(BrowserWindow* window); TabbedWebView* webView() const; LocationBar* locationBar() const; TabIcon* tabIcon() const; QUrl url() const; QString title() const; QIcon icon(bool allowNull = false) const; QWebEngineHistory* history() const; int zoomLevel() const; void setZoomLevel(int level); void detach(); void attach(BrowserWindow* window); QByteArray historyData() const; void stop(); void reload(); bool isLoading() const; bool isPinned() const; void setPinned(bool state); void togglePinned(); bool isMuted() const; void setMuted(bool muted); void toggleMuted(); int tabIndex() const; bool isCurrentTab() const; bool haveInspector() const; void showWebInspector(bool inspectElement = false); void toggleWebInspector(); void showSearchToolBar(); bool isRestored() const; void restoreTab(const SavedTab &tab); void p_restoreTab(const SavedTab &tab); void p_restoreTab(const QUrl &url, const QByteArray &history, int zoomLevel); + void tabActivated(); + private slots: void showNotification(QWidget* notif); void loadStarted(); void loadFinished(); void titleChanged(const QString &title); void slotRestore(); private: - void showEvent(QShowEvent* event); void resizeEvent(QResizeEvent *event) override; BrowserWindow* m_window; QVBoxLayout* m_layout; QSplitter* m_splitter; TabbedWebView* m_webView; WebInspector* m_inspector; LocationBar* m_locationBar; TabIcon* m_tabIcon; TabBar* m_tabBar; QWidget *m_notificationWidget; SavedTab m_savedTab; bool m_isPinned; - static bool s_pinningTab; }; #endif // WEBTAB_H