/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:BSD$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "tabwidget.h" #include "webpage.h" #include "webview.h" #include #include #include #include TabWidget::TabWidget(QWebEngineProfile *profile, QWidget *parent) : QTabWidget(parent) , m_profile(profile) { QTabBar *tabBar = this->tabBar(); tabBar->setTabsClosable(true); tabBar->setSelectionBehaviorOnRemove(QTabBar::SelectPreviousTab); tabBar->setMovable(true); tabBar->setContextMenuPolicy(Qt::CustomContextMenu); connect(tabBar, &QTabBar::customContextMenuRequested, this, &TabWidget::handleContextMenuRequested); connect(tabBar, &QTabBar::tabCloseRequested, this, &TabWidget::closeTab); connect(tabBar, &QTabBar::tabBarDoubleClicked, [this](int index) { if (index == -1) createTab(); }); setDocumentMode(true); setElideMode(Qt::ElideRight); connect(this, &QTabWidget::currentChanged, this, &TabWidget::handleCurrentChanged); if (profile->isOffTheRecord()) { QLabel *icon = new QLabel(this); QPixmap pixmap(QStringLiteral(":ninja.png")); icon->setPixmap(pixmap.scaledToHeight(tabBar->height())); setStyleSheet(QStringLiteral("QTabWidget::tab-bar { left: %1px; }"). arg(icon->pixmap()->width())); } } void TabWidget::handleCurrentChanged(int index) { if (index != -1) { WebView *view = webView(index); if (!view->url().isEmpty()) view->setFocus(); emit titleChanged(view->title()); emit loadProgress(view->loadProgress()); emit urlChanged(view->url()); emit favIconChanged(view->favIcon()); emit webActionEnabledChanged(QWebEnginePage::Back, view->isWebActionEnabled(QWebEnginePage::Back)); emit webActionEnabledChanged(QWebEnginePage::Forward, view->isWebActionEnabled(QWebEnginePage::Forward)); emit webActionEnabledChanged(QWebEnginePage::Stop, view->isWebActionEnabled(QWebEnginePage::Stop)); emit webActionEnabledChanged(QWebEnginePage::Reload,view->isWebActionEnabled(QWebEnginePage::Reload)); } else { emit titleChanged(QString()); emit loadProgress(0); emit urlChanged(QUrl()); emit favIconChanged(QIcon()); emit webActionEnabledChanged(QWebEnginePage::Back, false); emit webActionEnabledChanged(QWebEnginePage::Forward, false); emit webActionEnabledChanged(QWebEnginePage::Stop, false); emit webActionEnabledChanged(QWebEnginePage::Reload, true); } } void TabWidget::handleContextMenuRequested(const QPoint &pos) { QMenu menu; menu.addAction(tr("New &Tab"), this, &TabWidget::createTab, QKeySequence::AddTab); int index = tabBar()->tabAt(pos); if (index != -1) { QAction *action = menu.addAction(tr("Clone Tab")); connect(action, &QAction::triggered, this, [this,index]() { cloneTab(index); }); menu.addSeparator(); action = menu.addAction(tr("&Close Tab")); action->setShortcut(QKeySequence::Close); connect(action, &QAction::triggered, this, [this,index]() { closeTab(index); }); action = menu.addAction(tr("Close &Other Tabs")); connect(action, &QAction::triggered, this, [this,index]() { closeOtherTabs(index); }); menu.addSeparator(); action = menu.addAction(tr("Reload Tab")); action->setShortcut(QKeySequence::Refresh); connect(action, &QAction::triggered, this, [this,index]() { reloadTab(index); }); } else { menu.addSeparator(); } menu.addAction(tr("Reload All Tabs"), this, &TabWidget::reloadAllTabs); menu.exec(QCursor::pos()); } WebView *TabWidget::currentWebView() const { return webView(currentIndex()); } WebView *TabWidget::webView(int index) const { return qobject_cast(widget(index)); } void TabWidget::setupView(WebView *webView) { QWebEnginePage *webPage = webView->page(); connect(webView, &QWebEngineView::titleChanged, [this, webView](const QString &title) { int index = indexOf(webView); if (index != -1) { setTabText(index, title); setTabToolTip(index, title); } if (currentIndex() == index) emit titleChanged(title); }); connect(webView, &QWebEngineView::urlChanged, [this, webView](const QUrl &url) { int index = indexOf(webView); if (index != -1) tabBar()->setTabData(index, url); if (currentIndex() == index) emit urlChanged(url); }); connect(webView, &QWebEngineView::loadProgress, [this, webView](int progress) { if (currentIndex() == indexOf(webView)) emit loadProgress(progress); }); connect(webPage, &QWebEnginePage::linkHovered, [this, webView](const QString &url) { if (currentIndex() == indexOf(webView)) emit linkHovered(url); }); connect(webView, &WebView::favIconChanged, [this, webView](const QIcon &icon) { int index = indexOf(webView); if (index != -1) setTabIcon(index, icon); if (currentIndex() == index) emit favIconChanged(icon); }); connect(webView, &WebView::webActionEnabledChanged, [this, webView](QWebEnginePage::WebAction action, bool enabled) { if (currentIndex() == indexOf(webView)) emit webActionEnabledChanged(action,enabled); }); connect(webPage, &QWebEnginePage::windowCloseRequested, [this, webView]() { int index = indexOf(webView); if (index >= 0) closeTab(index); }); connect(webView, &WebView::devToolsRequested, this, &TabWidget::devToolsRequested); #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) connect(webPage, &QWebEnginePage::findTextFinished, [this, webView](const QWebEngineFindTextResult &result) { if (currentIndex() == indexOf(webView)) emit findTextFinished(result); }); #endif } WebView *TabWidget::createTab() { WebView *webView = createBackgroundTab(); setCurrentWidget(webView); return webView; } WebView *TabWidget::createBackgroundTab() { WebView *webView = new WebView; WebPage *webPage = new WebPage(m_profile, webView); webView->setPage(webPage); setupView(webView); int index = addTab(webView, tr("(Untitled)")); setTabIcon(index, webView->favIcon()); // Workaround for QTBUG-61770 webView->resize(currentWidget()->size()); webView->show(); return webView; } void TabWidget::reloadAllTabs() { for (int i = 0; i < count(); ++i) webView(i)->reload(); } void TabWidget::closeOtherTabs(int index) { for (int i = count() - 1; i > index; --i) closeTab(i); for (int i = index - 1; i >= 0; --i) closeTab(i); } void TabWidget::closeTab(int index) { if (WebView *view = webView(index)) { bool hasFocus = view->hasFocus(); removeTab(index); if (hasFocus && count() > 0) currentWebView()->setFocus(); if (count() == 0) createTab(); view->deleteLater(); } } void TabWidget::cloneTab(int index) { if (WebView *view = webView(index)) { WebView *tab = createTab(); tab->setUrl(view->url()); } } void TabWidget::setUrl(const QUrl &url) { if (WebView *view = currentWebView()) { view->setUrl(url); view->setFocus(); } } void TabWidget::triggerWebPageAction(QWebEnginePage::WebAction action) { if (WebView *webView = currentWebView()) { webView->triggerPageAction(action); webView->setFocus(); } } void TabWidget::nextTab() { int next = currentIndex() + 1; if (next == count()) next = 0; setCurrentIndex(next); } void TabWidget::previousTab() { int next = currentIndex() - 1; if (next < 0) next = count() - 1; setCurrentIndex(next); } void TabWidget::reloadTab(int index) { if (WebView *view = webView(index)) view->reload(); }