You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
500 lines
11 KiB
500 lines
11 KiB
/* ============================================================ |
|
* Falkon - Qt web browser |
|
* Copyright (C) 2010-2018 David Rosca <nowrep@gmail.com> |
|
* |
|
* 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 <http://www.gnu.org/licenses/>. |
|
* ============================================================ */ |
|
#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 <QVBoxLayout> |
|
#include <QWebEngineHistory> |
|
#include <QLabel> |
|
#include <QTimer> |
|
#include <QSplitter> |
|
|
|
static const int savedTabVersion = 3; |
|
|
|
WebTab::SavedTab::SavedTab() |
|
: isPinned(false) |
|
, zoomLevel(qzSettings->defaultZoomLevel) |
|
{ |
|
} |
|
|
|
WebTab::SavedTab::SavedTab(WebTab* webTab) |
|
{ |
|
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() || !history.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<SearchToolBar*>(m_layout->itemAt(index)->widget())); |
|
toolBar = static_cast<SearchToolBar*>(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(bool allowEmpty) const |
|
{ |
|
if (isRestored()) { |
|
return m_webView->title(allowEmpty); |
|
} |
|
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_window); |
|
Q_ASSERT(m_tabBar); |
|
|
|
// Remove icon from tab |
|
m_tabBar->setTabButton(tabIndex(), m_tabBar->iconButtonPosition(), nullptr); |
|
m_tabIcon->setParent(this); |
|
|
|
// Remove the tab from tabbar |
|
m_window->tabWidget()->removeTab(tabIndex()); |
|
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(); |
|
} |
|
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->title(/*allowEmpty*/true).isEmpty()) { |
|
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); |
|
|
|
if (isRestored()) { |
|
return; |
|
} |
|
|
|
p_restoreTab(m_savedTab); |
|
m_savedTab.clear(); |
|
} |
|
|
|
void WebTab::tabActivated() |
|
{ |
|
if (isRestored()) { |
|
return; |
|
} |
|
|
|
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<WebTab*>(this)); |
|
} |
|
|
|
void WebTab::togglePinned() |
|
{ |
|
Q_ASSERT(m_tabBar); |
|
Q_ASSERT(m_window); |
|
|
|
m_isPinned = !m_isPinned; |
|
|
|
m_window->tabWidget()->pinUnPinTab(tabIndex(), title()); |
|
}
|
|
|