diff --git a/src/lib/downloads/downloadmanager.cpp b/src/lib/downloads/downloadmanager.cpp index 5e285900..3dd46dac 100644 --- a/src/lib/downloads/downloadmanager.cpp +++ b/src/lib/downloads/downloadmanager.cpp @@ -1,486 +1,483 @@ /* ============================================================ * Falkon - Qt web browser * Copyright (C) 2010-2018 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 "downloadmanager.h" #include "ui_downloadmanager.h" #include "browserwindow.h" #include "mainapplication.h" #include "downloadoptionsdialog.h" #include "downloaditem.h" #include "networkmanager.h" #include "desktopnotificationsfactory.h" #include "qztools.h" #include "webpage.h" #include "webview.h" #include "settings.h" #include "datapaths.h" #include "tabwidget.h" #include "tabbedwebview.h" #include "tabbar.h" #include "locationbar.h" #include #include #include #include #include #include #include #ifdef Q_OS_WIN #include #include #include #include #endif DownloadManager::DownloadManager(QWidget* parent) : QWidget(parent) , ui(new Ui::DownloadManager) , m_isClosing(false) , m_lastDownloadOption(NoOption) { setWindowFlags(windowFlags() ^ Qt::WindowMaximizeButtonHint); ui->setupUi(this); #ifdef Q_OS_WIN if (QtWin::isCompositionEnabled()) { QtWin::extendFrameIntoClientArea(this, -1, -1, -1, -1); } #endif ui->clearButton->setIcon(QIcon::fromTheme("edit-clear")); QzTools::centerWidgetOnScreen(this); connect(ui->clearButton, SIGNAL(clicked()), this, SLOT(clearList())); QShortcut* clearShortcut = new QShortcut(QKeySequence("CTRL+L"), this); connect(clearShortcut, SIGNAL(activated()), this, SLOT(clearList())); loadSettings(); QzTools::setWmClass("Download Manager", this); } void DownloadManager::loadSettings() { Settings settings; settings.beginGroup("DownloadManager"); m_downloadPath = settings.value("defaultDownloadPath", QString()).toString(); m_lastDownloadPath = settings.value("lastDownloadPath", QStandardPaths::writableLocation(QStandardPaths::DownloadLocation)).toString(); m_closeOnFinish = settings.value("CloseManagerOnFinish", false).toBool(); m_useNativeDialog = settings.value("useNativeDialog", DEFAULT_DOWNLOAD_USE_NATIVE_DIALOG).toBool(); m_useExternalManager = settings.value("UseExternalManager", false).toBool(); m_externalExecutable = settings.value("ExternalManagerExecutable", QString()).toString(); m_externalArguments = settings.value("ExternalManagerArguments", QString()).toString(); settings.endGroup(); if (!m_externalArguments.contains(QLatin1String("%d"))) { m_externalArguments.append(QLatin1String(" %d")); } } void DownloadManager::show() { m_timer.start(500, this); QWidget::show(); raise(); activateWindow(); } void DownloadManager::resizeEvent(QResizeEvent* e) { QWidget::resizeEvent(e); emit resized(size()); } void DownloadManager::keyPressEvent(QKeyEvent* e) { if (e->key() == Qt::Key_Escape || (e->key() == Qt::Key_W && e->modifiers() == Qt::ControlModifier)) { close(); } QWidget::keyPressEvent(e); } void DownloadManager::closeDownloadTab(const QUrl &url) const { // Attempt to close empty tab that was opened only for loading the download url auto testWebView = [](TabbedWebView *view, const QUrl &url) { if (!view->webTab()->isRestored()) { return false; } if (view->browserWindow()->tabWidget()->tabBar()->normalTabsCount() < 2) { return false; } WebPage *page = view->page(); if (page->history()->count() != 0) { return false; } if (page->url() != QUrl()) { return false; } QUrl tabUrl = page->requestedUrl(); if (tabUrl.isEmpty()) { tabUrl = QUrl(view->webTab()->locationBar()->text()); } return tabUrl.host() == url.host(); }; if (testWebView(mApp->getWindow()->weView(), url)) { mApp->getWindow()->weView()->closeView(); return; } const auto windows = mApp->windows(); for (auto *window : windows) { const auto tabs = window->tabWidget()->allTabs(); for (auto *tab : tabs) { auto *view = tab->webView(); if (testWebView(view, url)) { view->closeView(); return; } } } } QWinTaskbarButton *DownloadManager::taskbarButton() { #ifdef Q_OS_WIN if (!m_taskbarButton) { BrowserWindow *window = mApp->getWindow(); m_taskbarButton = new QWinTaskbarButton(window ? window->windowHandle() : windowHandle()); m_taskbarButton->progress()->setRange(0, 100); } return m_taskbarButton; #else return nullptr; #endif } void DownloadManager::startExternalManager(const QUrl &url) { QString arguments = m_externalArguments; arguments.replace(QLatin1String("%d"), url.toEncoded()); QzTools::startExternalProcess(m_externalExecutable, arguments); m_lastDownloadOption = ExternalManager; } void DownloadManager::timerEvent(QTimerEvent* e) { QVector remTimes; QVector progresses; QVector speeds; if (e->timerId() == m_timer.timerId()) { if (!ui->list->count()) { ui->speedLabel->clear(); setWindowTitle(tr("Download Manager")); #ifdef Q_OS_WIN taskbarButton()->progress()->hide(); #endif return; } for (int i = 0; i < ui->list->count(); i++) { DownloadItem* downItem = qobject_cast(ui->list->itemWidget(ui->list->item(i))); if (!downItem || downItem->isCancelled() || !downItem->isDownloading()) { continue; } progresses.append(downItem->progress()); remTimes.append(downItem->remainingTime()); speeds.append(downItem->currentSpeed()); } if (remTimes.isEmpty()) { return; } QTime remaining; foreach (const QTime &time, remTimes) { if (time > remaining) { remaining = time; } } int progress = 0; foreach (int prog, progresses) { progress += prog; } progress = progress / progresses.count(); double speed = 0.00; foreach (double spee, speeds) { speed += spee; } #ifndef Q_OS_WIN ui->speedLabel->setText(tr("%1% of %2 files (%3) %4 remaining").arg(QString::number(progress), QString::number(progresses.count()), DownloadItem::currentSpeedToString(speed), DownloadItem::remaingTimeToString(remaining))); #endif setWindowTitle(tr("%1% - Download Manager").arg(progress)); #ifdef Q_OS_WIN taskbarButton()->progress()->show(); taskbarButton()->progress()->setValue(progress); #endif } QWidget::timerEvent(e); } void DownloadManager::clearList() { QList items; for (int i = 0; i < ui->list->count(); i++) { DownloadItem* downItem = qobject_cast(ui->list->itemWidget(ui->list->item(i))); if (!downItem) { continue; } if (downItem->isDownloading()) { continue; } items.append(downItem); } qDeleteAll(items); emit downloadsCountChanged(); } void DownloadManager::download(QWebEngineDownloadItem *downloadItem) { closeDownloadTab(downloadItem->url()); QString downloadPath; bool openFile = false; - QString fileName = QFileInfo(downloadItem->path()).fileName(); - fileName = QUrl::fromPercentEncoding(fileName.toUtf8()); - // Filename may have been percent encoded and actually containing path - fileName = QFileInfo(fileName).fileName(); + const QString fileName = QFileInfo(downloadItem->path()).fileName(); const bool forceAsk = downloadItem->savePageFormat() != QWebEngineDownloadItem::UnknownSaveFormat || downloadItem->type() == QWebEngineDownloadItem::UserRequested; if (m_useExternalManager) { startExternalManager(downloadItem->url()); } else if (forceAsk || m_downloadPath.isEmpty()) { enum Result { Open = 1, Save = 2, ExternalManager = 3, SavePage = 4, Unknown = 0 }; Result result = Unknown; if (downloadItem->savePageFormat() != QWebEngineDownloadItem::UnknownSaveFormat) { // Save Page requested result = SavePage; } else if (downloadItem->type() == QWebEngineDownloadItem::UserRequested) { // Save x as... requested result = Save; } else { // Ask what to do DownloadOptionsDialog optionsDialog(fileName, downloadItem, mApp->activeWindow()); optionsDialog.showExternalManagerOption(m_useExternalManager); optionsDialog.setLastDownloadOption(m_lastDownloadOption); result = Result(optionsDialog.exec()); } switch (result) { case Open: openFile = true; downloadPath = QzTools::ensureUniqueFilename(DataPaths::path(DataPaths::Temp) + QLatin1Char('/') + fileName); m_lastDownloadOption = OpenFile; break; case Save: downloadPath = QFileDialog::getSaveFileName(mApp->activeWindow(), tr("Save file as..."), m_lastDownloadPath + QLatin1Char('/') + fileName); if (!downloadPath.isEmpty()) { m_lastDownloadPath = QFileInfo(downloadPath).absolutePath(); Settings().setValue(QSL("DownloadManager/lastDownloadPath"), m_lastDownloadPath); m_lastDownloadOption = SaveFile; } break; case SavePage: { const QString mhtml = tr("MIME HTML Archive (*.mhtml)"); const QString htmlSingle = tr("HTML Page, single (*.html)"); const QString htmlComplete = tr("HTML Page, complete (*.html)"); const QString filter = QStringLiteral("%1;;%2;;%3").arg(mhtml, htmlSingle, htmlComplete); QString selectedFilter; downloadPath = QFileDialog::getSaveFileName(mApp->activeWindow(), tr("Save page as..."), m_lastDownloadPath + QLatin1Char('/') + fileName, filter, &selectedFilter); if (!downloadPath.isEmpty()) { m_lastDownloadPath = QFileInfo(downloadPath).absolutePath(); Settings().setValue(QSL("DownloadManager/lastDownloadPath"), m_lastDownloadPath); m_lastDownloadOption = SaveFile; QWebEngineDownloadItem::SavePageFormat format = QWebEngineDownloadItem::UnknownSaveFormat; if (selectedFilter == mhtml) { format = QWebEngineDownloadItem::MimeHtmlSaveFormat; } else if (selectedFilter == htmlSingle) { format = QWebEngineDownloadItem::SingleHtmlSaveFormat; } else if (selectedFilter == htmlComplete) { format = QWebEngineDownloadItem::CompleteHtmlSaveFormat; } if (format != QWebEngineDownloadItem::UnknownSaveFormat) { downloadItem->setSavePageFormat(format); } } break; } case ExternalManager: startExternalManager(downloadItem->url()); // fallthrough default: downloadItem->cancel(); return; } } else { downloadPath = QzTools::ensureUniqueFilename(m_downloadPath + QL1C('/') + fileName); } if (downloadPath.isEmpty()) { downloadItem->cancel(); return; } // Set download path and accept downloadItem->setPath(downloadPath); downloadItem->accept(); // Create download item QListWidgetItem* listItem = new QListWidgetItem(ui->list); DownloadItem* downItem = new DownloadItem(listItem, downloadItem, QFileInfo(downloadPath).absolutePath(), QFileInfo(downloadPath).fileName(), openFile, this); connect(downItem, SIGNAL(deleteItem(DownloadItem*)), this, SLOT(deleteItem(DownloadItem*))); connect(downItem, SIGNAL(downloadFinished(bool)), this, SLOT(downloadFinished(bool))); ui->list->setItemWidget(listItem, downItem); listItem->setSizeHint(downItem->sizeHint()); downItem->show(); m_activeDownloadsCount++; emit downloadsCountChanged(); } int DownloadManager::downloadsCount() const { return ui->list->count(); } int DownloadManager::activeDownloadsCount() const { return m_activeDownloadsCount; } void DownloadManager::downloadFinished(bool success) { m_activeDownloadsCount = 0; bool downloadingAllFilesFinished = true; for (int i = 0; i < ui->list->count(); i++) { DownloadItem* downItem = qobject_cast(ui->list->itemWidget(ui->list->item(i))); if (!downItem) { continue; } if (downItem->isDownloading()) { m_activeDownloadsCount++; } if (downItem->isCancelled() || !downItem->isDownloading()) { continue; } downloadingAllFilesFinished = false; } emit downloadsCountChanged(); if (downloadingAllFilesFinished) { if (success && qApp->activeWindow() != this) { mApp->desktopNotifications()->showNotification(QIcon::fromTheme(QSL("download"), QIcon(QSL(":icons/other/download.svg"))).pixmap(48), tr("Falkon: Download Finished"), tr("All files have been successfully downloaded.")); if (!m_closeOnFinish) { raise(); activateWindow(); } } ui->speedLabel->clear(); setWindowTitle(tr("Download Manager")); #ifdef Q_OS_WIN taskbarButton()->progress()->hide(); #endif if (m_closeOnFinish) { close(); } } } void DownloadManager::deleteItem(DownloadItem* item) { if (item && !item->isDownloading()) { delete item; } } bool DownloadManager::canClose() { if (m_isClosing) { return true; } bool isDownloading = false; for (int i = 0; i < ui->list->count(); i++) { DownloadItem* downItem = qobject_cast(ui->list->itemWidget(ui->list->item(i))); if (!downItem) { continue; } if (downItem->isDownloading()) { isDownloading = true; break; } } return !isDownloading; } bool DownloadManager::useExternalManager() const { return m_useExternalManager; } void DownloadManager::closeEvent(QCloseEvent* e) { if (mApp->windowCount() == 0) { // No main windows -> we are going to quit if (!canClose()) { QMessageBox::StandardButton button = QMessageBox::warning(this, tr("Warning"), tr("Are you sure you want to quit? All uncompleted downloads will be cancelled!"), QMessageBox::Yes | QMessageBox::No); if (button != QMessageBox::Yes) { e->ignore(); return; } m_isClosing = true; } mApp->quitApplication(); } e->accept(); } DownloadManager::~DownloadManager() { delete ui; } diff --git a/src/lib/navigation/navigationbar.cpp b/src/lib/navigation/navigationbar.cpp index 8ffccac8..88294b29 100644 --- a/src/lib/navigation/navigationbar.cpp +++ b/src/lib/navigation/navigationbar.cpp @@ -1,682 +1,687 @@ /* ============================================================ * Falkon - Qt web browser * Copyright (C) 2010-2018 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 "navigationbar.h" #include "toolbutton.h" #include "browserwindow.h" #include "mainapplication.h" #include "iconprovider.h" #include "websearchbar.h" #include "reloadstopbutton.h" #include "enhancedmenu.h" #include "tabwidget.h" #include "tabbedwebview.h" #include "webpage.h" #include "qzsettings.h" #include "qztools.h" #include "abstractbuttoninterface.h" #include "navigationbartoolbutton.h" #include "navigationbarconfigdialog.h" #include #include #include #include #include #include #include static QString titleForUrl(QString title, const QUrl &url) { if (title.isEmpty()) { title = url.toString(QUrl::RemoveFragment); } if (title.isEmpty()) { return NavigationBar::tr("Empty Page"); } return QzTools::truncatedText(title, 40); } static QIcon iconForPage(const QUrl &url, const QIcon &sIcon) { QIcon icon; icon.addPixmap(IconProvider::iconForUrl(url).pixmap(16)); icon.addPixmap(sIcon.pixmap(16), QIcon::Active); return icon; } NavigationBar::NavigationBar(BrowserWindow* window) : QWidget(window) , m_window(window) { setObjectName(QSL("navigationbar")); m_layout = new QHBoxLayout(this); m_layout->setMargin(style()->pixelMetric(QStyle::PM_ToolBarItemMargin, 0, this) + style()->pixelMetric(QStyle::PM_ToolBarFrameWidth, 0, this)); m_layout->setSpacing(style()->pixelMetric(QStyle::PM_ToolBarItemSpacing, 0, this)); setLayout(m_layout); m_buttonBack = new ToolButton(this); m_buttonBack->setObjectName("navigation-button-back"); m_buttonBack->setToolTip(tr("Back")); m_buttonBack->setToolButtonStyle(Qt::ToolButtonIconOnly); m_buttonBack->setToolbarButtonLook(true); m_buttonBack->setShowMenuOnRightClick(true); m_buttonBack->setAutoRaise(true); m_buttonBack->setEnabled(false); m_buttonBack->setFocusPolicy(Qt::NoFocus); m_buttonForward = new ToolButton(this); m_buttonForward->setObjectName("navigation-button-next"); m_buttonForward->setToolTip(tr("Forward")); m_buttonForward->setToolButtonStyle(Qt::ToolButtonIconOnly); m_buttonForward->setToolbarButtonLook(true); m_buttonForward->setShowMenuOnRightClick(true); m_buttonForward->setAutoRaise(true); m_buttonForward->setEnabled(false); m_buttonForward->setFocusPolicy(Qt::NoFocus); QHBoxLayout* backNextLayout = new QHBoxLayout(); backNextLayout->setContentsMargins(0, 0, 0, 0); backNextLayout->setSpacing(0); backNextLayout->addWidget(m_buttonBack); backNextLayout->addWidget(m_buttonForward); QWidget *backNextWidget = new QWidget(this); backNextWidget->setLayout(backNextLayout); m_reloadStop = new ReloadStopButton(this); ToolButton *buttonHome = new ToolButton(this); buttonHome->setObjectName("navigation-button-home"); buttonHome->setToolTip(tr("Home")); buttonHome->setToolButtonStyle(Qt::ToolButtonIconOnly); buttonHome->setToolbarButtonLook(true); buttonHome->setAutoRaise(true); buttonHome->setFocusPolicy(Qt::NoFocus); ToolButton *buttonAddTab = new ToolButton(this); buttonAddTab->setObjectName("navigation-button-addtab"); buttonAddTab->setToolTip(tr("New Tab")); buttonAddTab->setToolButtonStyle(Qt::ToolButtonIconOnly); buttonAddTab->setToolbarButtonLook(true); buttonAddTab->setAutoRaise(true); buttonAddTab->setFocusPolicy(Qt::NoFocus); m_menuBack = new Menu(this); m_menuBack->setCloseOnMiddleClick(true); m_buttonBack->setMenu(m_menuBack); connect(m_buttonBack, SIGNAL(aboutToShowMenu()), this, SLOT(aboutToShowHistoryBackMenu())); m_menuForward = new Menu(this); m_menuForward->setCloseOnMiddleClick(true); m_buttonForward->setMenu(m_menuForward); connect(m_buttonForward, SIGNAL(aboutToShowMenu()), this, SLOT(aboutToShowHistoryNextMenu())); ToolButton *buttonTools = new ToolButton(this); buttonTools->setObjectName("navigation-button-tools"); buttonTools->setPopupMode(QToolButton::InstantPopup); buttonTools->setToolbarButtonLook(true); buttonTools->setToolTip(tr("Tools")); buttonTools->setAutoRaise(true); buttonTools->setFocusPolicy(Qt::NoFocus); buttonTools->setShowMenuInside(true); m_menuTools = new Menu(this); buttonTools->setMenu(m_menuTools); connect(buttonTools, &ToolButton::aboutToShowMenu, this, &NavigationBar::aboutToShowToolsMenu); m_supMenu = new ToolButton(this); m_supMenu->setObjectName("navigation-button-supermenu"); m_supMenu->setPopupMode(QToolButton::InstantPopup); m_supMenu->setToolbarButtonLook(true); m_supMenu->setToolTip(tr("Main Menu")); m_supMenu->setAutoRaise(true); m_supMenu->setFocusPolicy(Qt::NoFocus); m_supMenu->setMenu(m_window->superMenu()); m_supMenu->setShowMenuInside(true); m_searchLine = new WebSearchBar(m_window); m_navigationSplitter = new QSplitter(this); m_navigationSplitter->addWidget(m_window->tabWidget()->locationBars()); m_navigationSplitter->addWidget(m_searchLine); m_navigationSplitter->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum); m_navigationSplitter->setCollapsible(0, false); m_exitFullscreen = new ToolButton(this); m_exitFullscreen->setObjectName("navigation-button-exitfullscreen"); m_exitFullscreen->setToolTip(tr("Exit Fullscreen")); m_exitFullscreen->setToolButtonStyle(Qt::ToolButtonIconOnly); m_exitFullscreen->setToolbarButtonLook(true); m_exitFullscreen->setFocusPolicy(Qt::NoFocus); m_exitFullscreen->setAutoRaise(true); m_exitFullscreen->setVisible(false); setContextMenuPolicy(Qt::CustomContextMenu); connect(this, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(contextMenuRequested(QPoint))); connect(m_buttonBack, SIGNAL(clicked()), this, SLOT(goBack())); connect(m_buttonBack, SIGNAL(middleMouseClicked()), this, SLOT(goBackInNewTab())); connect(m_buttonBack, SIGNAL(controlClicked()), this, SLOT(goBackInNewTab())); connect(m_buttonForward, SIGNAL(clicked()), this, SLOT(goForward())); connect(m_buttonForward, SIGNAL(middleMouseClicked()), this, SLOT(goForwardInNewTab())); connect(m_buttonForward, SIGNAL(controlClicked()), this, SLOT(goForwardInNewTab())); connect(m_reloadStop, SIGNAL(stopClicked()), this, SLOT(stop())); connect(m_reloadStop, SIGNAL(reloadClicked()), this, SLOT(reload())); connect(buttonHome, SIGNAL(clicked()), m_window, SLOT(goHome())); connect(buttonHome, SIGNAL(middleMouseClicked()), m_window, SLOT(goHomeInNewTab())); connect(buttonHome, SIGNAL(controlClicked()), m_window, SLOT(goHomeInNewTab())); connect(buttonAddTab, SIGNAL(clicked()), m_window, SLOT(addTab())); connect(buttonAddTab, SIGNAL(middleMouseClicked()), m_window->tabWidget(), SLOT(addTabFromClipboard())); connect(m_exitFullscreen, SIGNAL(clicked(bool)), m_window, SLOT(toggleFullScreen())); addWidget(backNextWidget, QSL("button-backforward"), tr("Back and Forward buttons")); addWidget(m_reloadStop, QSL("button-reloadstop"), tr("Reload button")); addWidget(buttonHome, QSL("button-home"), tr("Home button")); addWidget(buttonAddTab, QSL("button-addtab"), tr("Add tab button")); addWidget(m_navigationSplitter, QSL("locationbar"), tr("Address and Search bar")); addWidget(buttonTools, QSL("button-tools"), tr("Tools button")); addWidget(m_exitFullscreen, QSL("button-exitfullscreen"), tr("Exit Fullscreen button")); loadSettings(); } NavigationBar::~NavigationBar() { setCurrentView(nullptr); } void NavigationBar::setSplitterSizes(int locationBar, int websearchBar) { QList sizes; if (locationBar == 0) { int splitterWidth = m_navigationSplitter->width(); sizes << (int)((double)splitterWidth * .80) << (int)((double)splitterWidth * .20); } else { sizes << locationBar << websearchBar; } m_navigationSplitter->setSizes(sizes); } void NavigationBar::setCurrentView(TabbedWebView *view) { for (const WidgetData &data : qAsConst(m_widgets)) { if (data.button) { data.button->setWebView(view); } } if (!view) { return; } - auto updateButton = [](ToolButton *button, QAction *action) { - button->setEnabled(action->isEnabled()); + auto connectPageActions = [this](QWebEnginePage *page) { + auto updateButton = [](ToolButton *button, QAction *action) { + button->setEnabled(action->isEnabled()); + }; + auto updateBackButton = std::bind(updateButton, m_buttonBack, page->action(QWebEnginePage::Back)); + auto updateForwardButton = std::bind(updateButton, m_buttonForward, page->action(QWebEnginePage::Forward)); + + updateBackButton(); + updateForwardButton(); + + disconnect(m_backConnection); + disconnect(m_forwardConnection); + m_backConnection = connect(page->action(QWebEnginePage::Back), &QAction::changed, this, updateBackButton); + m_forwardConnection = connect(page->action(QWebEnginePage::Forward), &QAction::changed, this, updateForwardButton); }; - auto updateBackButton = std::bind(updateButton, m_buttonBack, view->pageAction(QWebEnginePage::Back)); - auto updateForwardButton = std::bind(updateButton, m_buttonForward, view->pageAction(QWebEnginePage::Forward)); - updateBackButton(); - updateForwardButton(); - - disconnect(m_backConnection); - disconnect(m_forwardConnection); - m_backConnection = connect(view->pageAction(QWebEnginePage::Back), &QAction::changed, this, updateBackButton); - m_forwardConnection = connect(view->pageAction(QWebEnginePage::Forward), &QAction::changed, this, updateForwardButton); + connectPageActions(view->page()); + connect(view, &TabbedWebView::pageChanged, this, connectPageActions); } void NavigationBar::showReloadButton() { m_reloadStop->showReloadButton(); } void NavigationBar::showStopButton() { m_reloadStop->showStopButton(); } void NavigationBar::enterFullScreen() { if (m_layout->indexOf(m_exitFullscreen) != -1) { m_exitFullscreen->show(); } } void NavigationBar::leaveFullScreen() { if (m_layout->indexOf(m_exitFullscreen) != -1) { m_exitFullscreen->hide(); } } void NavigationBar::setSuperMenuVisible(bool visible) { m_supMenu->setVisible(visible); } int NavigationBar::layoutMargin() const { return m_layout->margin(); } void NavigationBar::setLayoutMargin(int margin) { m_layout->setMargin(margin); } int NavigationBar::layoutSpacing() const { return m_layout->spacing(); } void NavigationBar::setLayoutSpacing(int spacing) { m_layout->setSpacing(spacing); } void NavigationBar::addWidget(QWidget *widget, const QString &id, const QString &name) { if (!widget || id.isEmpty() || name.isEmpty()) { return; } WidgetData data; data.id = id; data.name = name; data.widget = widget; m_widgets[id] = data; reloadLayout(); } void NavigationBar::removeWidget(const QString &id) { if (!m_widgets.contains(id)) { return; } m_widgets.remove(id); reloadLayout(); } void NavigationBar::addToolButton(AbstractButtonInterface *button) { if (!button || !button->isValid()) { return; } NavigationBarToolButton *toolButton = new NavigationBarToolButton(button, this); toolButton->setProperty("button-id", button->id()); connect(toolButton, &NavigationBarToolButton::visibilityChangeRequested, this, [=]() { if (m_layout->indexOf(toolButton) != -1) { toolButton->updateVisibility(); } }); WidgetData data; data.id = button->id(); data.name = button->name(); data.widget = toolButton; data.button = button; m_widgets[data.id] = data; data.button->setWebView(m_window->weView()); reloadLayout(); } void NavigationBar::removeToolButton(AbstractButtonInterface *button) { if (!button || !m_widgets.contains(button->id())) { return; } delete m_widgets.take(button->id()).widget; } void NavigationBar::aboutToShowHistoryBackMenu() { if (!m_menuBack || !m_window->weView()) { return; } m_menuBack->clear(); QWebEngineHistory* history = m_window->weView()->history(); int curindex = history->currentItemIndex(); int count = 0; for (int i = curindex - 1; i >= 0; i--) { QWebEngineHistoryItem item = history->itemAt(i); if (item.isValid()) { QString title = titleForUrl(item.title(), item.url()); const QIcon icon = iconForPage(item.url(), IconProvider::standardIcon(QStyle::SP_ArrowBack)); Action* act = new Action(icon, title); act->setData(i); connect(act, SIGNAL(triggered()), this, SLOT(loadHistoryIndex())); connect(act, SIGNAL(ctrlTriggered()), this, SLOT(loadHistoryIndexInNewTab())); m_menuBack->addAction(act); } count++; if (count == 20) { break; } } m_menuBack->addSeparator(); m_menuBack->addAction(QIcon::fromTheme(QSL("edit-clear")), tr("Clear history"), this, SLOT(clearHistory())); } void NavigationBar::aboutToShowHistoryNextMenu() { if (!m_menuForward || !m_window->weView()) { return; } m_menuForward->clear(); QWebEngineHistory* history = m_window->weView()->history(); int curindex = history->currentItemIndex(); int count = 0; for (int i = curindex + 1; i < history->count(); i++) { QWebEngineHistoryItem item = history->itemAt(i); if (item.isValid()) { QString title = titleForUrl(item.title(), item.url()); const QIcon icon = iconForPage(item.url(), IconProvider::standardIcon(QStyle::SP_ArrowForward)); Action* act = new Action(icon, title); act->setData(i); connect(act, SIGNAL(triggered()), this, SLOT(loadHistoryIndex())); connect(act, SIGNAL(ctrlTriggered()), this, SLOT(loadHistoryIndexInNewTab())); m_menuForward->addAction(act); } count++; if (count == 20) { break; } } m_menuForward->addSeparator(); m_menuForward->addAction(QIcon::fromTheme(QSL("edit-clear")), tr("Clear history"), this, SLOT(clearHistory())); } void NavigationBar::aboutToShowToolsMenu() { m_menuTools->clear(); m_window->createToolbarsMenu(m_menuTools->addMenu(tr("Toolbars"))); m_window->createSidebarsMenu(m_menuTools->addMenu(tr("Sidebar"))); m_menuTools->addSeparator(); for (const WidgetData &data : qAsConst(m_widgets)) { AbstractButtonInterface *button = data.button; if (button && (!button->isVisible() || !m_layoutIds.contains(data.id))) { QString title = button->title(); if (!button->badgeText().isEmpty()) { title.append(QSL(" (%1)").arg(button->badgeText())); } m_menuTools->addAction(button->icon(), title, this, &NavigationBar::toolActionActivated)->setData(data.id); } } m_menuTools->addSeparator(); m_menuTools->addAction(IconProvider::settingsIcon(), tr("Configure Toolbar"), this, SLOT(openConfigurationDialog())); } void NavigationBar::clearHistory() { QWebEngineHistory* history = m_window->weView()->page()->history(); history->clear(); } void NavigationBar::contextMenuRequested(const QPoint &pos) { QMenu menu; m_window->createToolbarsMenu(&menu); menu.addSeparator(); menu.addAction(IconProvider::settingsIcon(), tr("Configure Toolbar"), this, SLOT(openConfigurationDialog())); menu.exec(mapToGlobal(pos)); } void NavigationBar::openConfigurationDialog() { NavigationBarConfigDialog *dialog = new NavigationBarConfigDialog(this); dialog->show(); } void NavigationBar::toolActionActivated() { QAction *act = qobject_cast(sender()); if (!act) { return; } const QString id = act->data().toString(); if (!m_widgets.contains(id)) { return; } WidgetData data = m_widgets.value(id); if (!data.button) { return; } ToolButton *buttonTools = qobject_cast(m_widgets.value(QSL("button-tools")).widget); if (!buttonTools) { return; } AbstractButtonInterface::ClickController *c = new AbstractButtonInterface::ClickController; c->visualParent = buttonTools; c->popupPosition = [=](const QSize &size) { QPoint pos = buttonTools->mapToGlobal(buttonTools->rect().bottomRight()); if (QApplication::isRightToLeft()) { pos.setX(pos.x() - buttonTools->rect().width()); } else { pos.setX(pos.x() - size.width()); } c->popupOpened = true; return pos; }; c->popupClosed = [=]() { buttonTools->setDown(false); delete c; }; emit data.button->clicked(c); if (c->popupOpened) { buttonTools->setDown(true); } else { c->popupClosed(); } } void NavigationBar::loadSettings() { const QStringList defaultIds = { QSL("button-backforward"), QSL("button-reloadstop"), QSL("button-home"), QSL("locationbar"), QSL("button-downloads"), QSL("adblock-icon"), QSL("button-tools") }; Settings settings; settings.beginGroup(QSL("NavigationBar")); m_layoutIds = settings.value(QSL("Layout"), defaultIds).toStringList(); m_searchLine->setVisible(settings.value(QSL("ShowSearchBar"), true).toBool()); settings.endGroup(); m_layoutIds.removeDuplicates(); m_layoutIds.removeAll(QString()); if (!m_layoutIds.contains(QSL("locationbar"))) { m_layoutIds.append(QSL("locationbar")); } reloadLayout(); } void NavigationBar::reloadLayout() { if (m_widgets.isEmpty()) { return; } setUpdatesEnabled(false); // Clear layout while (m_layout->count() != 0) { QLayoutItem *item = m_layout->takeAt(0); if (!item) { continue; } QWidget *widget = item->widget(); if (!widget) { continue; } widget->setParent(nullptr); } // Hide all widgets for (const WidgetData &data : m_widgets) { data.widget->hide(); } // Add widgets to layout for (const QString &id : qAsConst(m_layoutIds)) { const WidgetData data = m_widgets.value(id); if (data.widget) { m_layout->addWidget(data.widget); NavigationBarToolButton *button = qobject_cast(data.widget); if (button) { button->updateVisibility(); } else { data.widget->show(); } } } m_layout->addWidget(m_supMenu); // Make sure search bar is visible if (m_searchLine->isVisible() && m_navigationSplitter->sizes().at(1) == 0) { const int locationBarSize = m_navigationSplitter->sizes().at(0); setSplitterSizes(locationBarSize - 50, 50); } if (m_window->isFullScreen()) { enterFullScreen(); } else { leaveFullScreen(); } setUpdatesEnabled(true); } void NavigationBar::loadHistoryIndex() { QWebEngineHistory* history = m_window->weView()->page()->history(); if (QAction* action = qobject_cast(sender())) { loadHistoryItem(history->itemAt(action->data().toInt())); } } void NavigationBar::loadHistoryIndexInNewTab(int index) { if (QAction* action = qobject_cast(sender())) { index = action->data().toInt(); } if (index == -1) { return; } QWebEngineHistory* history = m_window->weView()->page()->history(); loadHistoryItemInNewTab(history->itemAt(index)); } void NavigationBar::stop() { m_window->action(QSL("View/Stop"))->trigger(); } void NavigationBar::reload() { m_window->action(QSL("View/Reload"))->trigger(); } void NavigationBar::goBack() { auto view = m_window->weView(); view->setFocus(); view->back(); } void NavigationBar::goBackInNewTab() { QWebEngineHistory* history = m_window->weView()->page()->history(); if (!history->canGoBack()) { return; } loadHistoryItemInNewTab(history->backItem()); } void NavigationBar::goForward() { auto view = m_window->weView(); view->setFocus(); view->forward(); } void NavigationBar::goForwardInNewTab() { QWebEngineHistory* history = m_window->weView()->page()->history(); if (!history->canGoForward()) { return; } loadHistoryItemInNewTab(history->forwardItem()); } void NavigationBar::loadHistoryItem(const QWebEngineHistoryItem &item) { m_window->weView()->page()->history()->goToItem(item); } void NavigationBar::loadHistoryItemInNewTab(const QWebEngineHistoryItem &item) { TabWidget* tabWidget = m_window->tabWidget(); int tabIndex = tabWidget->duplicateTab(tabWidget->currentIndex()); QWebEngineHistory* history = m_window->weView(tabIndex)->page()->history(); history->goToItem(item); if (qzSettings->newTabPosition == Qz::NT_SelectedTab) { tabWidget->setCurrentIndex(tabIndex); } }