| /**************************************************************************** |
| ** |
| ** 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 <QLabel> |
| #include <QMenu> |
| #include <QTabBar> |
| #include <QWebEngineProfile> |
| |
| 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<WebView*>(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(); |
| } |