diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt index 75f89e6bc..5c4e7c5bd 100644 --- a/src/lib/CMakeLists.txt +++ b/src/lib/CMakeLists.txt @@ -121,6 +121,7 @@ set(SRCS ${SRCS} navigation/locationbar.cpp navigation/locationbarpopup.cpp navigation/navigationbar.cpp + navigation/navigationbartoolbutton.cpp navigation/navigationcontainer.cpp navigation/reloadstopbutton.cpp navigation/siteicon.cpp @@ -178,6 +179,7 @@ set(SRCS ${SRCS} tabwidget/tabstackedwidget.cpp tabwidget/tabwidget.cpp tabwidget/tabcontextmenu.cpp + tools/abstractbuttoninterface.cpp tools/aesinterface.cpp tools/animatedwidget.cpp tools/buttonbox.cpp diff --git a/src/lib/app/browserwindow.cpp b/src/lib/app/browserwindow.cpp index ff2b65b44..e3679810d 100644 --- a/src/lib/app/browserwindow.cpp +++ b/src/lib/app/browserwindow.cpp @@ -983,6 +983,7 @@ void BrowserWindow::currentTabChanged() m_ipLabel->setText(view->getIp()); view->setFocus(); + m_navigationToolbar->setCurrentView(view); updateLoadingActions(); // Setting correct tab order (LocationBar -> WebSearchBar -> WebView) diff --git a/src/lib/navigation/navigationbar.cpp b/src/lib/navigation/navigationbar.cpp index e0ff3a982..c4f5fb715 100644 --- a/src/lib/navigation/navigationbar.cpp +++ b/src/lib/navigation/navigationbar.cpp @@ -28,6 +28,8 @@ #include "webpage.h" #include "qzsettings.h" #include "qztools.h" +#include "abstractbuttoninterface.h" +#include "navigationbartoolbutton.h" #include #include @@ -153,13 +155,6 @@ NavigationBar::NavigationBar(BrowserWindow* window) m_navigationSplitter->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum); m_navigationSplitter->setCollapsible(0, false); - addWidget(backNextWidget, QSL("button-backforward")); - addWidget(m_reloadStop, QSL("button-reloadstop")); - addWidget(buttonHome, QSL("button-home")); - addWidget(buttonAddTab, QSL("button-addtab")); - addWidget(m_navigationSplitter, QSL("locationbar")); - addWidget(buttonTools, QSL("button-tools")); - setContextMenuPolicy(Qt::CustomContextMenu); connect(this, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(contextMenuRequested(QPoint))); @@ -177,6 +172,16 @@ NavigationBar::NavigationBar(BrowserWindow* window) 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())); + + loadSettings(); + connect(mApp, &MainApplication::settingsReloaded, this, &NavigationBar::loadSettings); + + 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")); } void NavigationBar::setSplitterSizes(int locationBar, int websearchBar) @@ -194,6 +199,15 @@ void NavigationBar::setSplitterSizes(int locationBar, int websearchBar) m_navigationSplitter->setSizes(sizes); } +void NavigationBar::setCurrentView(TabbedWebView *view) +{ + for (const WidgetData &data : qAsConst(m_widgets)) { + if (data.button) { + data.button->setWebPage(view->page()); + } + } +} + void NavigationBar::showReloadButton() { m_reloadStop->showReloadButton(); @@ -229,18 +243,56 @@ void NavigationBar::setLayoutSpacing(int spacing) m_layout->setSpacing(spacing); } -void NavigationBar::addWidget(QWidget *widget, const QString &id) +void NavigationBar::addWidget(QWidget *widget, const QString &id, const QString &name) { - m_widgets[id] = widget; + 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; + } + + WidgetData data; + data.id = button->id(); + data.name = button->name(); + data.widget = new NavigationBarToolButton(button, this); + data.button = button; + m_widgets[data.id] = data; + + 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()) { @@ -317,6 +369,14 @@ void NavigationBar::aboutToShowToolsMenu() m_window->createSidebarsMenu(m_menuTools->addMenu(tr("Sidebars"))); m_menuTools->addSeparator(); + for (const WidgetData &data : qAsConst(m_widgets)) { + AbstractButtonInterface *button = data.button; + if (button && !m_layoutIds.contains(data.id)) { + m_menuTools->addAction(button->icon(), button->title(), this, &NavigationBar::toolActionActivated)->setData(data.id); + } + } + + m_menuTools->addSeparator(); m_menuTools->addAction(IconProvider::settingsIcon(), tr("Configure Toolbar"), this, SLOT(openConfigurationDialog())); } @@ -338,7 +398,42 @@ void NavigationBar::openConfigurationDialog() { } -void NavigationBar::reloadLayout() +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; + 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()); + } + return pos; + }; + buttonTools->setDown(true); + emit data.button->clicked(&c); + buttonTools->setDown(false); +} + +void NavigationBar::loadSettings() { const QStringList defaultIds = { QSL("button-backforward"), @@ -348,12 +443,20 @@ void NavigationBar::reloadLayout() QSL("button-tools") }; - QStringList ids = Settings().value(QSL("NavigationBar/Layout"), defaultIds).toStringList(); - ids.removeDuplicates(); - if (!ids.contains(QSL("locationbar"))) { - ids.append(QSL("locationbar")); - } + Settings settings; + settings.beginGroup(QSL("NavigationBar")); + m_layoutIds = settings.value(QSL("Layout"), defaultIds).toStringList(); + settings.endGroup(); + m_layoutIds.removeDuplicates(); + if (!m_layoutIds.contains(QSL("locationbar"))) { + m_layoutIds.append(QSL("locationbar")); + } +} + +void NavigationBar::reloadLayout() +{ + // Clear layout while (m_layout->count() != 0) { QLayoutItem *item = m_layout->takeAt(0); if (!item) { @@ -366,15 +469,17 @@ void NavigationBar::reloadLayout() widget->setParent(nullptr); } - for (QWidget *widget : m_widgets) { - widget->hide(); + // Hide all widgets + for (const WidgetData &data : m_widgets) { + data.widget->hide(); } - for (const QString &id : qAsConst(ids)) { - QWidget *widget = m_widgets.value(id); - if (widget) { - m_layout->addWidget(widget); - widget->show(); + // 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); + data.widget->show(); } } diff --git a/src/lib/navigation/navigationbar.h b/src/lib/navigation/navigationbar.h index 920dfbe46..85a2e35e2 100644 --- a/src/lib/navigation/navigationbar.h +++ b/src/lib/navigation/navigationbar.h @@ -22,6 +22,7 @@ #include "qzcommon.h" +class QUrl; class QHBoxLayout; class QSplitter; class QWebEngineHistoryItem; @@ -31,19 +32,21 @@ class WebSearchBar; class BrowserWindow; class ReloadStopButton; class Menu; -class QUrl; +class AbstractButtonInterface; +class TabbedWebView; class FALKON_EXPORT NavigationBar : public QWidget { Q_OBJECT -public: - explicit NavigationBar(BrowserWindow* window); - Q_PROPERTY(int layoutMargin READ layoutMargin WRITE setLayoutMargin) Q_PROPERTY(int layoutSpacing READ layoutSpacing WRITE setLayoutSpacing) +public: + explicit NavigationBar(BrowserWindow* window); + void setSplitterSizes(int locationBar, int websearchBar); + void setCurrentView(TabbedWebView *view); void showReloadButton(); void showStopButton(); @@ -58,9 +61,12 @@ public: int layoutSpacing() const; void setLayoutSpacing(int spacing); - void addWidget(QWidget *widget, const QString &id); + void addWidget(QWidget *widget, const QString &id, const QString &name); void removeWidget(const QString &id); + void addToolButton(AbstractButtonInterface *button); + void removeToolButton(AbstractButtonInterface *button); + public slots: void refreshHistory(); @@ -82,8 +88,10 @@ private slots: void clearHistory(); void contextMenuRequested(const QPoint &pos); void openConfigurationDialog(); + void toolActionActivated(); private: + void loadSettings(); void reloadLayout(); void loadHistoryItem(const QWebEngineHistoryItem &item); void loadHistoryItemInNewTab(const QWebEngineHistoryItem &item); @@ -101,7 +109,15 @@ private: Menu *m_menuTools; ToolButton* m_supMenu; - QHash m_widgets; + struct WidgetData { + QString id; + QString name; + QWidget *widget = nullptr; + AbstractButtonInterface *button = nullptr; + }; + + QStringList m_layoutIds; + QHash m_widgets; }; #endif // NAVIGATIONBAR_H diff --git a/src/lib/navigation/navigationbartoolbutton.cpp b/src/lib/navigation/navigationbartoolbutton.cpp new file mode 100644 index 000000000..635cd93a2 --- /dev/null +++ b/src/lib/navigation/navigationbartoolbutton.cpp @@ -0,0 +1,55 @@ +/* ============================================================ +* QupZilla - Qt web browser +* Copyright (C) 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 "navigationbartoolbutton.h" +#include "abstractbuttoninterface.h" + +#include + +NavigationBarToolButton::NavigationBarToolButton(AbstractButtonInterface *button, QWidget *parent) + : ToolButton(parent) + , m_button(button) +{ + setAutoRaise(true); + setToolbarButtonLook(true); + setFocusPolicy(Qt::NoFocus); + + setToolTip(button->toolTip()); + setIcon(button->icon()); + + connect(button, &AbstractButtonInterface::iconChanged, this, &ToolButton::setIcon); + connect(button, &AbstractButtonInterface::toolTipChanged, this, &ToolButton::setToolTip); + connect(this, &ToolButton::clicked, this, &NavigationBarToolButton::clicked); +} + +void NavigationBarToolButton::clicked() +{ + AbstractButtonInterface::ClickController c; + c.visualParent = this; + c.popupPosition = [this](const QSize &size) { + QPoint pos = mapToGlobal(rect().bottomRight()); + if (QApplication::isRightToLeft()) { + pos.setX(pos.x() - rect().width()); + } else { + pos.setX(pos.x() - size.width()); + } + return pos; + }; + setDown(true); + emit m_button->clicked(&c); + setDown(false); +} diff --git a/src/lib/navigation/navigationbartoolbutton.h b/src/lib/navigation/navigationbartoolbutton.h new file mode 100644 index 000000000..b3628ad30 --- /dev/null +++ b/src/lib/navigation/navigationbartoolbutton.h @@ -0,0 +1,34 @@ +/* ============================================================ +* QupZilla - Qt web browser +* Copyright (C) 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 . +* ============================================================ */ +#pragma once + +#include "qzcommon.h" +#include "toolbutton.h" + +class AbstractButtonInterface; + +class QUPZILLA_EXPORT NavigationBarToolButton : public ToolButton +{ +public: + explicit NavigationBarToolButton(AbstractButtonInterface *button, QWidget *parent = nullptr); + +private: + void clicked(); + + AbstractButtonInterface *m_button; +}; diff --git a/src/lib/tools/abstractbuttoninterface.cpp b/src/lib/tools/abstractbuttoninterface.cpp new file mode 100644 index 000000000..f8e59a198 --- /dev/null +++ b/src/lib/tools/abstractbuttoninterface.cpp @@ -0,0 +1,114 @@ +/* ============================================================ +* QupZilla - Qt web browser +* Copyright (C) 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 "abstractbuttoninterface.h" + +AbstractButtonInterface::AbstractButtonInterface(QObject *parent) + : QObject(parent) +{ +} + +bool AbstractButtonInterface::isValid() const +{ + return !id().isEmpty() && !name().isEmpty(); +} + +bool AbstractButtonInterface::isActive() const +{ + return m_active; +} + +void AbstractButtonInterface::setActive(bool active) +{ + if (m_active == active) { + return; + } + + m_active = active; + emit activeChanged(m_active); +} + +QString AbstractButtonInterface::title() const +{ + return m_title; +} + +void AbstractButtonInterface::setTitle(const QString &title) +{ + if (m_title == title) { + return; + } + + m_title = title; + emit titleChanged(m_title); +} + +QString AbstractButtonInterface::toolTip() const +{ + return m_toolTip; +} + +void AbstractButtonInterface::setToolTip(const QString &toolTip) +{ + if (m_toolTip == toolTip) { + return; + } + + m_toolTip = toolTip; + emit toolTipChanged(m_toolTip); +} + +QIcon AbstractButtonInterface::icon() const +{ + return m_icon; +} + +void AbstractButtonInterface::setIcon(const QIcon &icon) +{ + m_icon = icon; + emit iconChanged(icon); +} + +QString AbstractButtonInterface::badgeLabelText() const +{ + return m_badgeLabelText; +} + +void AbstractButtonInterface::setBadgeLabelText(const QString &badgeLabelText) +{ + if (m_badgeLabelText == badgeLabelText) { + return; + } + + m_badgeLabelText = badgeLabelText; + emit badgeLabelTextChanged(m_badgeLabelText); +} + +WebPage *AbstractButtonInterface::webPage() const +{ + return m_page; +} + +void AbstractButtonInterface::setWebPage(WebPage *page) +{ + if (m_page == page) { + return; + } + + m_page = page; + emit webPageChanged(m_page); +} diff --git a/src/lib/tools/abstractbuttoninterface.h b/src/lib/tools/abstractbuttoninterface.h new file mode 100644 index 000000000..1bcb444e2 --- /dev/null +++ b/src/lib/tools/abstractbuttoninterface.h @@ -0,0 +1,80 @@ +/* ============================================================ +* QupZilla - Qt web browser +* Copyright (C) 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 . +* ============================================================ */ +#pragma once + +#include +#include + +#include + +#include "qzcommon.h" + +class WebPage; + +class QUPZILLA_EXPORT AbstractButtonInterface : public QObject +{ + Q_OBJECT + +public: + struct ClickController { + QWidget *visualParent; + std::function popupPosition; + }; + + explicit AbstractButtonInterface(QObject *parent = nullptr); + + virtual QString id() const = 0; + virtual QString name() const = 0; + + bool isValid() const; + + bool isActive() const; + void setActive(bool active); + + QString title() const; + void setTitle(const QString &text); + + QString toolTip() const; + void setToolTip(const QString &toolTip); + + QIcon icon() const; + void setIcon(const QIcon &icon); + + QString badgeLabelText() const; + void setBadgeLabelText(const QString &badgeLabelText); + + WebPage *webPage() const; + void setWebPage(WebPage *page); + +signals: + void activeChanged(bool active); + void titleChanged(const QString &title); + void toolTipChanged(const QString &toolTip); + void iconChanged(const QIcon &icon); + void badgeLabelTextChanged(const QString &badgeLabelText); + void webPageChanged(WebPage *page); + void clicked(ClickController *controller); + +private: + bool m_active = true; + QString m_title; + QString m_toolTip; + QIcon m_icon; + QString m_badgeLabelText; + WebPage *m_page = nullptr; +};