From 03186060aa41b38bc425bd1f3092f7ec33b9774d Mon Sep 17 00:00:00 2001 From: nowrep Date: Thu, 6 Feb 2014 17:07:19 +0100 Subject: [PATCH] [Bookmarks] New bookmarks backend using JSON format New format is compatible with Chromium's Bookmarks file. It will support everything as the current backend + * multi-level bookmarks * bookmark description * bookmark keyword * remember expanded state (for folders) NOTE: It is NOT yet complete. There is a LOT of work still needed. Only bookmarks loading + saving and internal tree representation is done. --- .travis.yml | 2 +- src/lib/app/qz_namespace.h | 3 + src/lib/bookmarks/bookmarkitem.cpp | 159 +++++++++++++++++++++++++++++ src/lib/bookmarks/bookmarkitem.h | 80 +++++++++++++++ src/lib/bookmarks/bookmarks.cpp | 152 ++++++++++++++++++++++++++- src/lib/bookmarks/bookmarks.h | 13 +++ src/lib/lib.pro | 16 +-- src/lib/tools/json.cpp | 33 ++++++ src/lib/tools/json.h | 33 ++++++ 9 files changed, 483 insertions(+), 8 deletions(-) create mode 100644 src/lib/bookmarks/bookmarkitem.cpp create mode 100644 src/lib/bookmarks/bookmarkitem.h create mode 100644 src/lib/tools/json.cpp create mode 100644 src/lib/tools/json.h diff --git a/.travis.yml b/.travis.yml index 9177ed452..d11917904 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,7 +11,7 @@ before_install: install: - sudo apt-get -qq update - - sudo apt-get -qq install libssl-dev pkg-config libhunspell-dev + - sudo apt-get -qq install libssl-dev pkg-config libhunspell-dev libqjson-dev - if [[ "$QT" == "qt4" ]]; then sudo apt-get -qq install libqt4-dev libqt4-webkit libqt4-sql-sqlite; fi - if [[ "$QT" == "qt5" ]]; then sudo apt-add-repository -y ppa:beineri/opt-qt511; sudo apt-get update -qq; sudo apt-get install -qq qt51base qt51webkit qt51tools qt51script libgstreamer0.10-dev libgstreamer-plugins-base0.10-dev; fi diff --git a/src/lib/app/qz_namespace.h b/src/lib/app/qz_namespace.h index 76e98f94d..d8cf1551f 100644 --- a/src/lib/app/qz_namespace.h +++ b/src/lib/app/qz_namespace.h @@ -43,6 +43,9 @@ static const int sessionVersion = 0x0003 | 0x050000; static const int sessionVersion = 0x0003; #endif +// Version of bookmarks.json file +static const int bookmarksVersion = 1; + enum AppMessageType { AM_SetAdBlockIconEnabled, AM_CheckPrivateBrowsing, diff --git a/src/lib/bookmarks/bookmarkitem.cpp b/src/lib/bookmarks/bookmarkitem.cpp new file mode 100644 index 000000000..34fc8da89 --- /dev/null +++ b/src/lib/bookmarks/bookmarkitem.cpp @@ -0,0 +1,159 @@ +/* ============================================================ +* QupZilla - WebKit based browser +* Copyright (C) 2014 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 "bookmarkitem.h" + +BookmarkItem::BookmarkItem(BookmarkItem::Type type, BookmarkItem *parent) + : m_type(type) + , m_parent(parent) + , m_expanded(false) +{ + if (m_parent) { + parent->addChild(this); + } +} + +BookmarkItem::~BookmarkItem() +{ + qDeleteAll(m_children); +} + +BookmarkItem::Type BookmarkItem::type() const +{ + return m_type; +} + +void BookmarkItem::setType(BookmarkItem::Type type) +{ + m_type = type; +} + +BookmarkItem *BookmarkItem::parent() const +{ + return m_parent; +} + +QList BookmarkItem::children() const +{ + return m_children; +} + +QUrl BookmarkItem::url() const +{ + return m_url; +} + +void BookmarkItem::setUrl(const QUrl &url) +{ + m_url = url; +} + +QString BookmarkItem::title() const +{ + return m_title; +} + +void BookmarkItem::setTitle(const QString &title) +{ + m_title = title; +} + +QString BookmarkItem::description() const +{ + return m_description; +} + +void BookmarkItem::setDescription(const QString &description) +{ + m_description = description; +} + +QString BookmarkItem::keyword() const +{ + return m_keyword; +} + +void BookmarkItem::setKeyword(const QString &keyword) +{ + m_keyword = keyword; +} + +bool BookmarkItem::isExpanded() const +{ + return m_type == Root ? true : m_expanded; +} + +void BookmarkItem::setExpanded(bool expanded) +{ + m_expanded = expanded; +} + +void BookmarkItem::addChild(BookmarkItem *child, int index) +{ + if (child->m_parent) { + child->m_parent->removeChild(child); + } + + child->m_parent = this; + + if (index == -1) { + m_children.append(child); + } + else { + m_children.insert(index, child); + } +} + +void BookmarkItem::removeChild(BookmarkItem *child) +{ + child->m_parent = 0; + m_children.removeOne(child); +} + +BookmarkItem::Type BookmarkItem::typeFromString(const QString &string) +{ + if (string == QLatin1String("url")) { + return Url; + } + + if (string == QLatin1String("folder")) { + return Folder; + } + + if (string == QLatin1String("separator")) { + return Separator; + } + + return Invalid; +} + +QString BookmarkItem::typeToString(BookmarkItem::Type type) +{ + switch (type) { + case Url: + return QString("url"); + + case Folder: + return QString("folder"); + + case Separator: + return QString("separator"); + + default: + return QString("invalid"); + } +} diff --git a/src/lib/bookmarks/bookmarkitem.h b/src/lib/bookmarks/bookmarkitem.h new file mode 100644 index 000000000..26fd61f5a --- /dev/null +++ b/src/lib/bookmarks/bookmarkitem.h @@ -0,0 +1,80 @@ +/* ============================================================ +* QupZilla - WebKit based browser +* Copyright (C) 2014 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 . +* ============================================================ */ +#ifndef BOOKMARKITEM_H +#define BOOKMARKITEM_H + +#include +#include +#include + +#include "qz_namespace.h" + +class QT_QUPZILLA_EXPORT BookmarkItem +{ +public: + enum Type { + Root, + Url, + Folder, + Separator, + Invalid + }; + + explicit BookmarkItem(Type type, BookmarkItem* parent = 0); + ~BookmarkItem(); + + Type type() const; + void setType(Type type); + + BookmarkItem *parent() const; + QList children() const; + + QUrl url() const; + void setUrl(const QUrl &url); + + QString title() const; + void setTitle(const QString &title); + + QString description() const; + void setDescription(const QString &description); + + QString keyword() const; + void setKeyword(const QString &keyword); + + bool isExpanded() const; + void setExpanded(bool expanded); + + void addChild(BookmarkItem *child, int index = -1); + void removeChild(BookmarkItem *child); + + static Type typeFromString(const QString &string); + static QString typeToString(Type type); + +private: + Type m_type; + BookmarkItem* m_parent; + QList m_children; + + QUrl m_url; + QString m_title; + QString m_description; + QString m_keyword; + bool m_expanded; +}; + +#endif // BOOKMARKITEM_H diff --git a/src/lib/bookmarks/bookmarks.cpp b/src/lib/bookmarks/bookmarks.cpp index 2dd1815e5..9d11f948c 100644 --- a/src/lib/bookmarks/bookmarks.cpp +++ b/src/lib/bookmarks/bookmarks.cpp @@ -16,12 +16,14 @@ * along with this program. If not, see . * ============================================================ */ #include "bookmarks.h" +#include "bookmarkitem.h" #include "tabbedwebview.h" #include "iconprovider.h" -#include "databasewriter.h" #include "mainapplication.h" #include "settings.h" +#include "json.h" +#include #include #include #include @@ -35,9 +37,157 @@ Bookmarks::Bookmarks(QObject* parent) : QObject(parent) { + loadBookmarks(); loadSettings(); } +void Bookmarks::loadBookmarks() +{ + m_root = new BookmarkItem(BookmarkItem::Root); + + m_folderToolbar = new BookmarkItem(BookmarkItem::Folder, m_root); + m_folderToolbar->setTitle(tr("Bookmarks ToolBar")); + m_folderToolbar->setDescription(tr("Bookmarks located in Bookmarks Toolbar")); + + m_folderMenu = new BookmarkItem(BookmarkItem::Folder, m_root); + m_folderMenu->setTitle(tr("Bookmarks In Menu")); + m_folderMenu->setDescription(tr("Bookmarks located in Bookmarks Menu")); + + m_folderUnsorted = new BookmarkItem(BookmarkItem::Folder, m_root); + m_folderUnsorted->setTitle(tr("Unsorted Bookmarks")); + m_folderUnsorted->setDescription(tr("All other bookmarks")); + + // TODO: Make sure bookmarks are loaded correctly even on error + + QFile bFile(mApp->currentProfilePath() + QLatin1String("/bookmarks.json")); + bFile.open(QFile::ReadOnly); + QByteArray data = bFile.readAll(); + bFile.close(); + + bool ok; + const QVariant res = Json::parse(data, &ok); + + if (!ok || res.type() != QVariant::Map) { + qWarning() << "Bookmarks::loadBookmarks() Error parsing bookmarks!"; + return; + } + + const QVariantMap map = res.toMap(); + const QVariantMap bookmarksMap = map.value("roots").toMap(); + + readBookmarks(bookmarksMap.value("bookmark_bar").toMap().value("children").toList(), m_folderToolbar); + readBookmarks(bookmarksMap.value("bookmark_menu").toMap().value("children").toList(), m_folderMenu); + readBookmarks(bookmarksMap.value("other").toMap().value("children").toList(), m_folderUnsorted); +} + +void Bookmarks::saveBookmarks() +{ + QVariantMap toolbarMap; + toolbarMap.insert("children", writeBookmarks(m_folderToolbar)); + + QVariantMap menuMap; + menuMap.insert("children", writeBookmarks(m_folderMenu)); + + QVariantMap unsortedMap; + unsortedMap.insert("children", writeBookmarks(m_folderUnsorted)); + + QVariantMap bookmarksMap; + bookmarksMap.insert("bookmark_bar", toolbarMap); + bookmarksMap.insert("bookmark_menu", menuMap); + bookmarksMap.insert("other", unsortedMap); + + QVariantMap map; + map.insert("version", Qz::bookmarksVersion); + map.insert("roots", bookmarksMap); + + bool ok; + const QByteArray data = Json::serialize(map, &ok); + + if (!ok || data.isEmpty()) { + qWarning() << "Bookmarks::saveBookmarks() Error serializing bookmarks!"; + return; + } + + QFile bFile(mApp->currentProfilePath() + QLatin1String("/bookmarks.json")); + + if (!bFile.open(QFile::WriteOnly)) { + qWarning() << "Bookmarks::saveBookmarks() Error opening bookmarks file for writing!"; + } + + bFile.write(data); + bFile.close(); +} + +void Bookmarks::readBookmarks(const QVariantList &list, BookmarkItem *parent) +{ + if (!parent) { + return; + } + + foreach (const QVariant &entry, list) { + const QVariantMap map = entry.toMap(); + BookmarkItem::Type type = BookmarkItem::typeFromString(map.value("type").toString()); + + if (type == BookmarkItem::Invalid) { + continue; + } + + BookmarkItem* item = new BookmarkItem(type, parent); + item->setUrl(map.value("url").toUrl()); + item->setTitle(map.value("name").toString()); + item->setDescription(map.value("description").toString()); + item->setKeyword(map.value("keyword").toString()); + item->setExpanded(map.value("expanded").toBool()); + + if (map.contains("children")) { + readBookmarks(map.value("children").toList(), item); + } + } +} + +QVariantList Bookmarks::writeBookmarks(BookmarkItem *parent) +{ + QVariantList list; + + if (!parent) { + return list; + } + + foreach (BookmarkItem* child, parent->children()) { + QVariantMap map; + map.insert("type", BookmarkItem::typeToString(child->type())); + map.insert("url", child->url()); + map.insert("name", child->title()); + map.insert("description", child->description()); + map.insert("keyword", child->keyword()); + map.insert("expanded", child->isExpanded()); + + if (!child->children().isEmpty()) { + map.insert("children", writeBookmarks(child)); + } + + list.append(map); + } + + return list; +} + +void Bookmarks::writeChildren(BookmarkItem *parent) +{ + if (!parent) { + return; + } + + foreach (BookmarkItem* child, parent->children()) { + if (child->type() == BookmarkItem::Url) { + qDebug() << child->title() << child->url(); + } + else { + qDebug() << "folder" << child->title(); + } + } +} + void Bookmarks::loadSettings() { Settings settings; diff --git a/src/lib/bookmarks/bookmarks.h b/src/lib/bookmarks/bookmarks.h index 277eddd39..e2f5e4cfa 100644 --- a/src/lib/bookmarks/bookmarks.h +++ b/src/lib/bookmarks/bookmarks.h @@ -32,6 +32,7 @@ class QIcon; class WebView; +class BookmarkItem; class QT_QUPZILLA_EXPORT Bookmarks : public QObject { @@ -120,9 +121,21 @@ public slots: void changeFolderParent(const QString &name, bool isSubfolder, bool* ok = 0); private: + void loadBookmarks(); + void saveBookmarks(); + + void readBookmarks(const QVariantList &list, BookmarkItem* parent); + QVariantList writeBookmarks(BookmarkItem* parent); + void writeChildren(BookmarkItem* parent); + bool m_showMostVisited; bool m_showOnlyIconsInToolbar; QString m_lastFolder; + + BookmarkItem* m_root; + BookmarkItem* m_folderToolbar; + BookmarkItem* m_folderMenu; + BookmarkItem* m_folderUnsorted; }; typedef Bookmarks::Bookmark Bookmark; diff --git a/src/lib/lib.pro b/src/lib/lib.pro index d674e9048..f1499f657 100644 --- a/src/lib/lib.pro +++ b/src/lib/lib.pro @@ -251,7 +251,9 @@ SOURCES += \ tools/tabstackedwidget.cpp \ tools/combotabbar.cpp \ webview/javascript/externaljsobject.cpp \ - bookmarks/bookmarks.cpp + bookmarks/bookmarks.cpp \ + bookmarks/bookmarkitem.cpp \ + tools/json.cpp HEADERS += \ @@ -439,7 +441,9 @@ HEADERS += \ tools/tabstackedwidget.h \ tools/combotabbar.h \ webview/javascript/externaljsobject.h \ - bookmarks/bookmarks.h + bookmarks/bookmarks.h \ + bookmarks/bookmarkitem.h \ + tools/json.h FORMS += \ preferences/autofillmanager.ui \ @@ -510,7 +514,7 @@ isEqual(QT_MAJOR_VERSION, 5) { INSTALLS += target !contains(DEFINES, NO_X11):LIBS += -lX11 - LIBS += -lcrypto + LIBS += -lcrypto -lqjson RESOURCES -= data/certs.qrc } @@ -519,11 +523,11 @@ win32 { HEADERS += other/registerqappassociation.h SOURCES += other/registerqappassociation.cpp - LIBS += -llibeay32 + LIBS += -llibeay32 -lqjson } os2 { - LIBS += -lcrypto + LIBS += -lcrypto -lqjson } mac { @@ -533,7 +537,7 @@ mac { webview/macwebviewscroller.cpp RESOURCES -= data/certs.qrc - LIBS += -lcrypto -framework CoreServices + LIBS += -lcrypto -lqjson -framework CoreServices } message(===========================================) diff --git a/src/lib/tools/json.cpp b/src/lib/tools/json.cpp new file mode 100644 index 000000000..c1c82198c --- /dev/null +++ b/src/lib/tools/json.cpp @@ -0,0 +1,33 @@ +/* =========================================================== +* QupZilla - WebKit based browser +* Copyright (C) 2014 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 "json.h" +#include +#include + +QVariant Json::parse(const QByteArray &data, bool *ok) +{ + QJson::Parser parser; + return parser.parse(data, ok); +} + +QByteArray Json::serialize(const QVariant &variant, bool *ok) +{ + QJson::Serializer serializer; + serializer.setIndentMode(QJson::IndentFull); + return serializer.serialize(variant, ok); +} diff --git a/src/lib/tools/json.h b/src/lib/tools/json.h new file mode 100644 index 000000000..3ec8a6062 --- /dev/null +++ b/src/lib/tools/json.h @@ -0,0 +1,33 @@ +/* ============================================================ +* QupZilla - WebKit based browser +* Copyright (C) 2014 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 . +* ============================================================ */ +#ifndef JSON_H +#define JSON_H + +#include +#include + +#include "qz_namespace.h" + +class QT_QUPZILLA_EXPORT Json +{ +public: + static QVariant parse(const QByteArray &data, bool* ok); + static QByteArray serialize(const QVariant &variant, bool* ok); +}; + +#endif // JSON_H