diff --git a/src/browsermanager.cpp b/src/browsermanager.cpp index fc4b8db..2ed3e52 100644 --- a/src/browsermanager.cpp +++ b/src/browsermanager.cpp @@ -1,190 +1,181 @@ /*************************************************************************** * Copyright 2014 Sebastian Kügler * * * * 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 2 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, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * ***************************************************************************/ #include "browsermanager.h" #include #include #include #include #include #include using namespace AngelFish; BrowserManager::BrowserManager(QObject *parent) : QObject(parent), m_settings(new QSettings(this)) { loadTabs(); } BrowserManager::~BrowserManager() { history()->save(); bookmarks()->save(); } void BrowserManager::reload() { qDebug() << "BookmarksManager::reload()"; } UrlModel *BrowserManager::bookmarks() { // qDebug() << "BookmarksManager::bookmarks()"; if (!m_bookmarks) { m_bookmarks = new UrlModel(QStringLiteral("bookmarks.json"), this); m_bookmarks->load(); } return m_bookmarks; } UrlModel *BrowserManager::history() { // qDebug() << "BrowserManager::history()"; if (!m_history) { m_history = new UrlModel(QStringLiteral("history.json"), this); m_history->load(); } return m_history; } void BrowserManager::addBookmark(const QVariantMap &bookmarkdata) { qDebug() << "Add bookmark"; qDebug() << " data: " << bookmarkdata; bookmarks()->add(QJsonObject::fromVariantMap(bookmarkdata)); } void BrowserManager::removeBookmark(const QString &url) { bookmarks()->remove(url); } void BrowserManager::addToHistory(const QVariantMap &pagedata) { // qDebug() << "Add History"; // qDebug() << " data: " << pagedata; history()->add(QJsonObject::fromVariantMap(pagedata)); emit historyChanged(); } void BrowserManager::removeFromHistory(const QString &url) { history()->remove(url); emit historyChanged(); } void BrowserManager::setHomepage(const QString &homepage) { m_settings->setValue("browser/homepage", homepage); emit homepageChanged(); } QString BrowserManager::homepage() { return m_settings->value("browser/homepage", "https://start.duckduckgo.com").toString(); } void BrowserManager::setSearchBaseUrl(const QString &searchBaseUrl) { m_settings->setValue("browser/searchBaseUrl", searchBaseUrl); emit searchBaseUrlChanged(); } QString BrowserManager::searchBaseUrl() { return m_settings->value("browser/searchBaseUrl", "https://start.duckduckgo.com/?q=") .toString(); } int BrowserManager::currentTab() const { return m_current_tab; } -QString BrowserManager::tabs() const -{ - QJsonArray arr; - for (auto i=m_tabs.constBegin(); i != m_tabs.constEnd(); ++i) { - QJsonObject o; - o["url"] = i->url; - o["isMobile"] = i->isMobile; - arr.append(o); - } - return QJsonDocument(arr).toJson(); +QList BrowserManager::tabs() const +{ + return m_tabs; } void BrowserManager::loadTabs() { - QJsonArray arr = QJsonDocument::fromJson(m_settings->value("browser/tabs").toByteArray()).array(); - m_tabs.clear(); - for (auto i = arr.constBegin(); i != arr.constEnd(); ++i) { - QJsonObject o = i->toObject(); - TabState ts(o.value("url").toString(), o.value("isMobile").toBool()); - m_tabs.push_back(ts); - } + m_tabs = m_settings->value("browser/tabs").toStringList(); m_current_tab = m_settings->value("browser/current_tab", 0).toInt(); } void BrowserManager::saveTabs() { - m_settings->setValue("browser/tabs", tabs()); + qDebug() << "saveTabs called" << m_tabs; + m_settings->setValue("browser/tabs", QVariant(m_tabs)); } void BrowserManager::setCurrentTab(int index) { - if (m_tabs_readonly) return; + if (m_tabsReadonly) return; m_current_tab = index; m_settings->setValue("browser/current_tab", m_current_tab); } void BrowserManager::setTab(int index, QString url, bool isMobile) { - if (m_tabs_readonly) return; + if (m_tabsReadonly) + return; + while (m_tabs.length() <= index) { - m_tabs.append(TabState()); + m_tabs.append(QString()); } - m_tabs[index] = TabState(url, isMobile); + m_tabs[index] = url; saveTabs(); -} -void BrowserManager::setTabIsMobile(int index, bool isMobile) -{ - TabState ts = m_tabs.value(index); - setTab(index, ts.url, isMobile); + tabsChanged(); } void BrowserManager::setTabUrl(int index, QString url) { - TabState ts = m_tabs.value(index); - setTab(index, url, ts.isMobile); + while (m_tabs.length() <= index) { + m_tabs.append(QString()); + } + m_tabs[index] = url; + + saveTabs(); + tabsChanged(); } void BrowserManager::setTabsWritable() { - m_tabs_readonly = false; + m_tabsReadonly = false; } void BrowserManager::rmTab(int index) { if (index >= 0 && index < m_tabs.size()) { m_tabs.removeAt(index); saveTabs(); } } diff --git a/src/browsermanager.h b/src/browsermanager.h index 177764b..cab6010 100644 --- a/src/browsermanager.h +++ b/src/browsermanager.h @@ -1,113 +1,112 @@ /*************************************************************************** * * * Copyright 2014 Sebastian Kügler * * * * 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 2 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, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * * * ***************************************************************************/ #ifndef BOOKMARKSMANAGER_H #define BOOKMARKSMANAGER_H #include #include #include "urlmodel.h" class QSettings; namespace AngelFish { /** * @class BookmarksManager * @short Access to Bookmarks and History. This is a singleton for * administration and access to the various models and browser-internal * data. */ class BrowserManager : public QObject { Q_OBJECT Q_PROPERTY(QAbstractListModel *bookmarks READ bookmarks NOTIFY bookmarksChanged) Q_PROPERTY(QAbstractListModel *history READ history NOTIFY historyChanged) Q_PROPERTY(QString homepage READ homepage WRITE setHomepage NOTIFY homepageChanged) Q_PROPERTY(QString searchBaseUrl READ searchBaseUrl WRITE setSearchBaseUrl NOTIFY searchBaseUrlChanged) + Q_PROPERTY(int currentTab READ currentTab NOTIFY currentTabChanged) + Q_PROPERTY(QList tabs READ tabs NOTIFY tabsChanged) + public: BrowserManager(QObject *parent = nullptr); ~BrowserManager() override; UrlModel *bookmarks(); UrlModel *history(); QString homepage(); QString searchBaseUrl(); Q_INVOKABLE int currentTab() const; - Q_INVOKABLE QString tabs() const; + Q_INVOKABLE QList tabs() const; Q_INVOKABLE void setCurrentTab(int index); Q_INVOKABLE void setTab(int index, QString url, bool isMobile); - Q_INVOKABLE void setTabIsMobile(int index, bool isMobile); Q_INVOKABLE void setTabUrl(int index, QString url); Q_INVOKABLE void setTabsWritable(); Q_INVOKABLE void rmTab(int index); signals: void updated(); void bookmarksChanged(); void historyChanged(); void homepageChanged(); void searchBaseUrlChanged(); void loadUrlRequested(const QString &url); + void currentTabChanged(); + void tabsChanged(); + public slots: void reload(); void addBookmark(const QVariantMap &bookmarkdata); void removeBookmark(const QString &url); void addToHistory(const QVariantMap &pagedata); void removeFromHistory(const QString &url); void setHomepage(const QString &homepage); void setSearchBaseUrl(const QString &searchBaseUrl); protected: void loadTabs(); void saveTabs(); private: UrlModel *m_bookmarks = nullptr; UrlModel *m_history = nullptr; QSettings *m_settings; - struct TabState { - TabState(QString u=QString(), bool im=false): url(u), isMobile(im) {} - QString url; - bool isMobile = false; - }; - int m_current_tab = 0; - QList m_tabs; - bool m_tabs_readonly = true; + QList m_tabs; + bool m_tabsReadonly = true; }; } // namespace #endif // BOOKMARKSMANAGER_H diff --git a/src/contents/ui/webbrowser.qml b/src/contents/ui/webbrowser.qml index e6dd48d..f7df182 100644 --- a/src/contents/ui/webbrowser.qml +++ b/src/contents/ui/webbrowser.qml @@ -1,404 +1,403 @@ /*************************************************************************** * * * Copyright 2014-2015 Sebastian Kügler * * * * 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 2 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, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * * * ***************************************************************************/ import QtQuick 2.1 import QtWebEngine 1.6 import QtQuick.Window 2.3 import QtGraphicalEffects 1.0 import org.kde.kirigami 2.7 as Kirigami import org.kde.mobile.angelfish 1.0 import QtQuick.Layouts 1.2 Kirigami.ApplicationWindow { id: webBrowser title: i18n("Angelfish Web Browser") /** Pointer to the currently active view. * * Browser-level functionality should use this to refer to the current * view, rather than looking up views in the mode, as far as possible. */ property Item currentWebView: tabs.currentItem // Pointer to the currently active list of tabs. // // As there are private and normal tabs, switch between // them according to the current mode. property Item tabs: rootPage.privateMode ? privateTabs : regularTabs onCurrentWebViewChanged: { print("Current WebView is now : " + tabs.currentIndex); } property int borderWidth: Math.round(Kirigami.Units.gridUnit / 18); property color borderColor: Kirigami.Theme.highlightColor; /** * Load a url in the current tab */ function load(url) { print("Loading url: " + url); currentWebView.url = url; currentWebView.forceActiveFocus() } BrowserManager { id: browserManager } /** * Make loading available to c++ */ Connections { target: browserManager onLoadUrlRequested: { load(url) } } width: Kirigami.Units.gridUnit * 20 height: Kirigami.Units.gridUnit * 30 /** * Add page of currently active webview to history */ function addHistoryEntry() { //print("Adding history"); var request = new Object;// FIXME request.url = currentWebView.url; request.title = currentWebView.title; request.icon = currentWebView.icon; request.lastVisited = new Date(); browserManager.addToHistory(request); } pageStack.globalToolBar.showNavigationButtons: { if (pageStack.depth <= 1) return Kirigami.ApplicationHeaderStyle.None; if (pageStack.currentIndex === pageStack.depth - 1) return Kirigami.ApplicationHeaderStyle.ShowBackButton; // not used so far, but maybe in future return (Kirigami.ApplicationHeaderStyle.ShowBackButton | Kirigami.ApplicationHeaderStyle.ShowForwardButton); } globalDrawer: Kirigami.GlobalDrawer { id: globalDrawer handleVisible: false actions: [ Kirigami.Action { icon.name: "tab-duplicate" onTriggered: { pageStack.push(Qt.resolvedUrl("Tabs.qml")) } text: i18n("Tabs") }, Kirigami.Action { icon.name: "view-private" onTriggered: { rootPage.privateMode ? rootPage.privateMode = false : rootPage.privateMode = true } text: rootPage.privateMode ? i18n("Leave private mode") : i18n("Private mode") }, Kirigami.Action { icon.name: "bookmarks" onTriggered: { pageStack.push(Qt.resolvedUrl("Bookmarks.qml")) } text: i18n("Bookmarks") }, Kirigami.Action { icon.name: "view-history" onTriggered: { pageStack.push(Qt.resolvedUrl("History.qml")) } text: i18n("History") }, Kirigami.Action { icon.name: "configure" text: i18n("Settings") onTriggered: { pageStack.push(Qt.resolvedUrl("Settings.qml")) } } ] } contextDrawer: Kirigami.ContextDrawer { id: contextDrawer handleVisible: false } // Main Page pageStack.initialPage: Kirigami.Page { id: rootPage leftPadding: 0 rightPadding: 0 topPadding: 0 bottomPadding: 0 globalToolBarStyle: Kirigami.ApplicationHeaderStyle.None Kirigami.ColumnView.fillWidth: true Kirigami.ColumnView.pinned: true Kirigami.ColumnView.preventStealing: true property bool privateMode: false ListWebView { id: regularTabs anchors { top: parent.top left: parent.left right: parent.right bottom: navigation.top } activeTabs: !rootPage.privateMode } ListWebView { id: privateTabs anchors { top: parent.top left: parent.left right: parent.right bottom: navigation.top } activeTabs: rootPage.privateMode privateTabsMode: true } ErrorHandler { id: errorHandler errorString: currentWebView.errorString errorCode: currentWebView.errorCode anchors { top: parent.top left: parent.left right: parent.right bottom: navigation.top } visible: currentWebView.errorCode !== "" } Loader { id: questionLoader anchors.bottom: navigation.top anchors.left: parent.left anchors.right: parent.right } // Container for the progress bar Item { id: progressItem height: Math.round(Kirigami.Units.gridUnit / 6) z: navigation.z + 1 anchors { top: tabs.bottom topMargin: -Math.round(height / 2) left: tabs.left right: tabs.right } opacity: currentWebView.loading ? 1 : 0 Behavior on opacity { NumberAnimation { duration: Kirigami.Units.longDuration; easing.type: Easing.InOutQuad; } } Rectangle { color: Kirigami.Theme.highlightColor width: Math.round((currentWebView.loadProgress / 100) * parent.width) anchors { top: parent.top left: parent.left bottom: parent.bottom } } } Loader { id: sheetLoader } // The menu at the bottom right contextualActions: [ Kirigami.Action { icon.name: "edit-find" shortcut: "Ctrl+F" onTriggered: { if (!sheetLoader.item || !sheetLoader.item.sheetOpen) { sheetLoader.setSource("FindInPageSheet.qml") sheetLoader.item.open() } } text: i18n("Find in page") }, Kirigami.Action { icon.name: "document-share" text: i18n("Share page") onTriggered: { sheetLoader.setSource("ShareSheet.qml") sheetLoader.item.url = currentWebView.url sheetLoader.item.title = currentWebView.title sheetLoader.item.open() } }, Kirigami.Action { enabled: currentWebView.canGoBack icon.name: "go-previous" text: i18n("Go previous") onTriggered: { currentWebView.goBack() } }, Kirigami.Action { enabled: currentWebView.canGoForward icon.name: "go-next" text: i18n("Go forward") onTriggered: { currentWebView.goForward() } }, Kirigami.Action { icon.name: currentWebView.loading ? "process-stop" : "view-refresh" text: currentWebView.loading ? i18n("Stop loading") : i18n("Refresh") onTriggered: { currentWebView.loading ? currentWebView.stop() : currentWebView.reload() } }, Kirigami.Action { icon.name: "bookmarks" text: i18n("Add bookmark") onTriggered: { print("Adding bookmark"); var request = new Object;// FIXME request.url = currentWebView.url; request.title = currentWebView.title; request.icon = currentWebView.icon; request.bookmarked = true; browserManager.addBookmark(request); } }, Kirigami.Action { icon.name: "computer" text: i18n("Show desktop site") checkable: true checked: !currentWebView.userAgent.isMobile onTriggered: { if (currentWebView.userAgent.isMobile) { currentWebView.userAgent.isMobile = false } else { currentWebView.userAgent.isMobile = true } if (!rootPage.privateMode) { browserManager.setTabIsMobile(tabs.currentIndex, currentWebView.userAgent.isMobile); } currentWebView.reload() } } ] // Bottom navigation bar Navigation { id: navigation navigationShown: !webappcontainer && webBrowser.visibility !== Window.FullScreen Kirigami.Theme.colorSet: rootPage.privateMode ? Kirigami.Theme.Complementary : Kirigami.Theme.Window layer.enabled: navigation.visible layer.effect: DropShadow { verticalOffset: - 1 color: Kirigami.Theme.disabledTextColor samples: 10 spread: 0.1 cached: true // element is static } anchors { bottom: parent.bottom left: parent.left right: parent.right } onActivateUrlEntry: urlEntry.open() } NavigationEntrySheet { id: urlEntry } // Thin line above navigation Rectangle { height: webBrowser.borderWidth color: webBrowser.borderColor anchors { left: parent.left bottom: navigation.top right: parent.right } } } Connections { target: webBrowser.pageStack onCurrentIndexChanged: { // drop all sub pages as soon as the browser window is the // focussed one if (webBrowser.pageStack.currentIndex === 0) webBrowser.pageStack.pop(); } } Component.onCompleted: { if (!webappcontainer) { // initialize tabs - var t = JSON.parse(browserManager.tabs()); - var ct = browserManager.currentTab(); - for (var i = 0; i < t.length; i++) { + for (var i = 0; i < browserManager.tabs.length; i++) { if (i < regularTabs.count) - regularTabs.itemAt(i).url = t[i].url; + regularTabs.itemAt(i).url = browserManager.tabs[i]; else - regularTabs.newTab(t[i].url); - regularTabs.itemAt(i).userAgent.isMobile = t[i].isMobile; + regularTabs.newTab(browserManager.tabs[i]); regularTabs.itemAt(i).reloadOnVisible = true; } - if (ct >= 0 && ct < regularTabs.count) regularTabs.currentIndex = ct; + if (browserManager.currentTab >= 0 && browserManager.currentTab < regularTabs.count) + regularTabs.currentIndex = browserManager.currentTab; + browserManager.setTabsWritable(); if (initialUrl) { regularTabs.newTab(initialUrl); } } else { if (initialUrl) { load(initialUrl); } } } }