1
mirror of https://invent.kde.org/network/falkon.git synced 2024-09-22 18:22:10 +02:00
falkonOfficial/src/lib/bookmarks/bookmarks.cpp
David Rosca 19800b174b [Bookmarks] Use keyword as a shortcut for bookmark url in LocationBar
It is now possible to load bookmarks only with entering its keyword in
LocationBar and then pressing Enter (no need to select the bookmark
from popup completion).
2014-04-24 11:57:27 +02:00

464 lines
12 KiB
C++

/* ============================================================
* QupZilla - WebKit based browser
* Copyright (C) 2010-2014 David Rosca <nowrep@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
* ============================================================ */
#include "bookmarks.h"
#include "bookmarkitem.h"
#include "bookmarksmodel.h"
#include "bookmarkstools.h"
#include "autosaver.h"
#include "datapaths.h"
#include "settings.h"
#include "qztools.h"
#include "json.h"
#include <QFile>
Bookmarks::Bookmarks(QObject* parent)
: QObject(parent)
, m_autoSaver(0)
{
m_autoSaver = new AutoSaver(this);
connect(m_autoSaver, SIGNAL(save()), this, SLOT(saveSettings()));
init();
loadSettings();
}
Bookmarks::~Bookmarks()
{
m_autoSaver->saveIfNecessary();
delete m_root;
}
void Bookmarks::loadSettings()
{
Settings settings;
settings.beginGroup("Bookmarks");
m_showOnlyIconsInToolbar = settings.value("showOnlyIconsInToolbar", false).toBool();
settings.endGroup();
}
bool Bookmarks::showOnlyIconsInToolbar() const
{
return m_showOnlyIconsInToolbar;
}
BookmarkItem* Bookmarks::rootItem() const
{
return m_root;
}
BookmarkItem* Bookmarks::toolbarFolder() const
{
return m_folderToolbar;
}
BookmarkItem* Bookmarks::menuFolder() const
{
return m_folderMenu;
}
BookmarkItem* Bookmarks::unsortedFolder() const
{
return m_folderUnsorted;
}
BookmarkItem* Bookmarks::lastUsedFolder() const
{
return m_lastFolder;
}
BookmarksModel* Bookmarks::model() const
{
return m_model;
}
bool Bookmarks::isBookmarked(const QUrl &url)
{
return !searchBookmarks(url).isEmpty();
}
bool Bookmarks::canBeModified(BookmarkItem* item) const
{
Q_ASSERT(item);
return item != m_root &&
item != m_folderToolbar &&
item != m_folderMenu &&
item != m_folderUnsorted;
}
QList<BookmarkItem*> Bookmarks::searchBookmarks(const QUrl &url) const
{
QList<BookmarkItem*> items;
search(&items, m_root, url);
return items;
}
QList<BookmarkItem*> Bookmarks::searchBookmarks(const QString &string, int limit, Qt::CaseSensitivity sensitive) const
{
QList<BookmarkItem*> items;
search(&items, m_root, string, limit, sensitive);
return items;
}
QList<BookmarkItem*> Bookmarks::searchKeyword(const QString &keyword) const
{
QList<BookmarkItem*> items;
searchKeyword(&items, m_root, keyword);
return items;
}
void Bookmarks::addBookmark(BookmarkItem* parent, BookmarkItem* item)
{
Q_ASSERT(parent);
Q_ASSERT(parent->isFolder());
Q_ASSERT(item);
insertBookmark(parent, parent->children().count(), item);
m_autoSaver->changeOcurred();
}
void Bookmarks::insertBookmark(BookmarkItem* parent, int row, BookmarkItem* item)
{
Q_ASSERT(parent);
Q_ASSERT(parent->isFolder());
Q_ASSERT(item);
m_lastFolder = parent;
m_model->addBookmark(parent, row, item);
emit bookmarkAdded(item);
m_autoSaver->changeOcurred();
}
bool Bookmarks::removeBookmark(BookmarkItem* item)
{
if (!canBeModified(item)) {
return false;
}
m_model->removeBookmark(item);
emit bookmarkRemoved(item);
m_autoSaver->changeOcurred();
return true;
}
void Bookmarks::changeBookmark(BookmarkItem* item)
{
Q_ASSERT(item);
emit bookmarkChanged(item);
m_autoSaver->changeOcurred();
}
void Bookmarks::setShowOnlyIconsInToolbar(bool state)
{
m_showOnlyIconsInToolbar = state;
emit showOnlyIconsInToolbarChanged(state);
}
void Bookmarks::saveSettings()
{
Settings settings;
settings.beginGroup("Bookmarks");
settings.setValue("showOnlyIconsInToolbar", m_showOnlyIconsInToolbar);
settings.endGroup();
saveBookmarks();
}
void Bookmarks::init()
{
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 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"));
if (BookmarksTools::migrateBookmarksIfNecessary(this)) {
// Bookmarks migrated just now, let's save them ASAP
saveBookmarks();
}
else {
// Bookmarks don't need to be migrated, just load them as usual
loadBookmarks();
}
m_lastFolder = m_folderUnsorted;
m_model = new BookmarksModel(m_root, this, this);
}
void Bookmarks::loadBookmarks()
{
const QString bookmarksFile = DataPaths::currentProfilePath() + QLatin1String("/bookmarks.json");
const QString backupFile = bookmarksFile + QLatin1String(".old");
QFile file(bookmarksFile);
file.open(QFile::ReadOnly);
QByteArray data = file.readAll();
file.close();
Json json;
const QVariant res = json.parse(QString::fromUtf8(data));
if (!json.ok() || res.type() != QVariant::Map) {
qWarning() << "Bookmarks::init() Error parsing bookmarks! Using default bookmarks!";
qWarning() << "Bookmarks::init() Your bookmarks have been backed up in" << backupFile;
// Backup the user bookmarks
QFile::remove(backupFile);
QFile::copy(bookmarksFile, backupFile);
// Load default bookmarks
const QVariant data = json.parse(QzTools::readAllFileContents(":data/bookmarks.json"));
Q_ASSERT(json.ok());
Q_ASSERT(data.type() == QVariant::Map);
loadBookmarksFromMap(data.toMap().value("roots").toMap());
// Don't forget to save the bookmarks
m_autoSaver->changeOcurred();
}
else {
loadBookmarksFromMap(res.toMap().value("roots").toMap());
}
}
void Bookmarks::saveBookmarks()
{
QVariantMap bookmarksMap;
#define WRITE_FOLDER(name, mapName, folder) \
QVariantMap mapName; \
mapName.insert("children", writeBookmarks(folder)); \
mapName.insert("expanded", folder->isExpanded()); \
mapName.insert("expanded_sidebar", folder->isSidebarExpanded()); \
mapName.insert("name", folder->title()); \
mapName.insert("description", folder->description()); \
mapName.insert("type", "folder"); \
bookmarksMap.insert(name, mapName);
WRITE_FOLDER("bookmark_bar", toolbarMap, m_folderToolbar)
WRITE_FOLDER("bookmark_menu", menuMap, m_folderMenu)
WRITE_FOLDER("other", unsortedMap, m_folderUnsorted)
#undef WRITE_FOLDER
QVariantMap map;
map.insert("version", Qz::bookmarksVersion);
map.insert("roots", bookmarksMap);
Json json;
const QString data = json.serialize(map);
if (!json.ok() || data.isEmpty()) {
qWarning() << "Bookmarks::saveBookmarks() Error serializing bookmarks!";
return;
}
QFile file(DataPaths::currentProfilePath() + QLatin1String("/bookmarks.json"));
if (!file.open(QFile::WriteOnly)) {
qWarning() << "Bookmarks::saveBookmarks() Error opening bookmarks file for writing!";
}
file.write(data.toUtf8());
file.close();
}
void Bookmarks::loadBookmarksFromMap(const QVariantMap &map)
{
#define READ_FOLDER(name, folder) \
readBookmarks(map.value(name).toMap().value("children").toList(), folder); \
folder->setExpanded(map.value(name).toMap().value("expanded").toBool()); \
folder->setSidebarExpanded(map.value(name).toMap().value("expanded_sidebar").toBool());
READ_FOLDER("bookmark_bar", m_folderToolbar)
READ_FOLDER("bookmark_menu", m_folderMenu)
READ_FOLDER("other", m_folderUnsorted)
#undef READ_FOLDER
}
void Bookmarks::readBookmarks(const QVariantList &list, BookmarkItem* parent)
{
Q_ASSERT(parent);
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);
switch (type) {
case BookmarkItem::Url:
item->setUrl(QUrl::fromEncoded(map.value("url").toByteArray()));
item->setTitle(map.value("name").toString());
item->setDescription(map.value("description").toString());
item->setKeyword(map.value("keyword").toString());
item->setVisitCount(map.value("visit_count").toInt());
break;
case BookmarkItem::Folder:
item->setTitle(map.value("name").toString());
item->setDescription(map.value("description").toString());
item->setExpanded(map.value("expanded").toBool());
item->setSidebarExpanded(map.value("expanded_sidebar").toBool());
break;
default:
break;
}
if (map.contains("children")) {
readBookmarks(map.value("children").toList(), item);
}
}
}
QVariantList Bookmarks::writeBookmarks(BookmarkItem* parent)
{
Q_ASSERT(parent);
QVariantList list;
foreach (BookmarkItem* child, parent->children()) {
QVariantMap map;
map.insert("type", BookmarkItem::typeToString(child->type()));
switch (child->type()) {
case BookmarkItem::Url:
map.insert("url", child->urlString());
map.insert("name", child->title());
map.insert("description", child->description());
map.insert("keyword", child->keyword());
map.insert("visit_count", child->visitCount());
break;
case BookmarkItem::Folder:
map.insert("name", child->title());
map.insert("description", child->description());
map.insert("expanded", child->isExpanded());
map.insert("expanded_sidebar", child->isSidebarExpanded());
break;
default:
break;
}
if (!child->children().isEmpty()) {
map.insert("children", writeBookmarks(child));
}
list.append(map);
}
return list;
}
void Bookmarks::search(QList<BookmarkItem*>* items, BookmarkItem* parent, const QUrl &url) const
{
Q_ASSERT(items);
Q_ASSERT(parent);
switch (parent->type()) {
case BookmarkItem::Root:
case BookmarkItem::Folder:
foreach (BookmarkItem* child, parent->children()) {
search(items, child, url);
}
break;
case BookmarkItem::Url:
if (parent->url() == url) {
items->append(parent);
}
break;
default:
break;
}
}
void Bookmarks::search(QList<BookmarkItem*>* items, BookmarkItem* parent, const QString &string, int limit, Qt::CaseSensitivity sensitive) const
{
Q_ASSERT(items);
Q_ASSERT(parent);
if (limit == items->count()) {
return;
}
switch (parent->type()) {
case BookmarkItem::Root:
case BookmarkItem::Folder:
foreach (BookmarkItem* child, parent->children()) {
search(items, child, string, limit, sensitive);
}
break;
case BookmarkItem::Url:
if (parent->title().contains(string, sensitive) ||
parent->urlString().contains(string, sensitive) ||
parent->description().contains(string, sensitive) ||
parent->keyword().compare(string, sensitive) == 0
) {
items->append(parent);
}
break;
default:
break;
}
}
void Bookmarks::searchKeyword(QList<BookmarkItem*>* items, BookmarkItem* parent, const QString &keyword) const
{
Q_ASSERT(items);
Q_ASSERT(parent);
switch (parent->type()) {
case BookmarkItem::Root:
case BookmarkItem::Folder:
foreach (BookmarkItem* child, parent->children())
searchKeyword(items, child, keyword);
break;
case BookmarkItem::Url:
if (parent->keyword() == keyword)
items->append(parent);
break;
default:
break;
}
}