mirror of
https://invent.kde.org/network/falkon.git
synced 2024-09-22 18:22:10 +02:00
19800b174b
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).
464 lines
12 KiB
C++
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;
|
|
}
|
|
}
|