summaryrefslogtreecommitdiff
path: root/src/bookmarks/bookmarkstreemodel.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/bookmarks/bookmarkstreemodel.cpp')
-rw-r--r--src/bookmarks/bookmarkstreemodel.cpp518
1 files changed, 184 insertions, 334 deletions
diff --git a/src/bookmarks/bookmarkstreemodel.cpp b/src/bookmarks/bookmarkstreemodel.cpp
index 45b50253..444d2e7b 100644
--- a/src/bookmarks/bookmarkstreemodel.cpp
+++ b/src/bookmarks/bookmarkstreemodel.cpp
@@ -1,406 +1,256 @@
/* ============================================================
-*
-* This file is a part of the rekonq project
-*
-* Copyright (C) 2009 by Nils Weigel <nehlsen at gmail dot com>
-* Copyright (C) 2010-2013 by Andrea Diamantini <adjam7 at gmail dot 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 2 of
-* the License or (at your option) version 3 or any later version
-* accepted by the membership of KDE e.V. (or its successor approved
-* by the membership of KDE e.V.), which shall act as a proxy
-* defined in Section 14 of version 3 of the license.
-*
-* 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/>.
-*
-* ============================================================ */
-
-
-// Self Includes
-#include "bookmarkstreemodel.h"
-#include "bookmarkstreemodel.moc"
-
-// Local Includes
-#include "bookmarkmanager.h"
-#include "iconmanager.h"
-
-// KDE Includes
-#include <KBookmarkManager>
-#include <KLocalizedString>
-#include <KIcon>
-
-// Qt Includes
-#include <QtCore/QMimeData>
-
-
-BtmItem::BtmItem(const KBookmark &bm)
- : m_parent(0)
- , m_kbm(bm)
+ * rekonq
+ * ============================================================
+ * SPDX-License-Identifier: GPL-3.0-only
+ * Copyright (C) 2022 aqua <aqua@iserlohn-fortress.net>
+ * ============================================================
+ * Description: rekonq bookmarks model
+ * ============================================================ */
+
+#include "bookmarkstreemodel.hpp"
+#include "bookmarkstreeformats.hpp"
+#include <QBuffer>
+#include <QDateTime>
+#include <QFile>
+#include <QMimeData>
+
+BookmarkModel::BookmarkModel(const QString &path, QObject *parent)
+ : QAbstractItemModel(parent), bookmarksFile(new QFile(path))
{
-}
-
-
-BtmItem::~BtmItem()
-{
- qDeleteAll(m_children);
-}
-
+ rootItem = new BookmarksTreeItem(BookmarksTreeItem::Root, {.title = tr("Title"), .href = tr("Address")}, nullptr);
-QVariant BtmItem::data(int role) const
-{
- if (m_kbm.isNull())
- return QVariant(); // should only happen for root item
-
- if (role == Qt::DisplayRole)
- return m_kbm.text();
-
- if (role == Qt::DecorationRole)
- {
- // NOTE
- // this should be:
- // return KIcon(m_kbm.icon());
- // but I cannot let it work :(
- // I really cannot understand how let this work properly...
- if (m_kbm.isGroup() || m_kbm.isSeparator())
- return KIcon(m_kbm.icon());
- else
- return IconManager::self()->iconForUrl(KUrl(m_kbm.url()));
- }
-
- if (role == Qt::UserRole)
- return m_kbm.url();
-
- if (role == Qt::ToolTipRole)
- {
- QString tooltip = m_kbm.fullText();
- if (m_kbm.isGroup())
- tooltip += i18ncp("%1=Number of items in bookmark folder", " (1 item)", " (%1 items)", childCount());
-
- QString url = m_kbm.url().url();
- if (!url.isEmpty())
- {
- if (!tooltip.isEmpty())
- tooltip += '\n';
- tooltip += url;
- }
-
- if (!m_kbm.description().isEmpty())
- {
- if (!tooltip.isEmpty())
- tooltip += '\n';
- tooltip += m_kbm.description();
- }
-
- return tooltip;
- }
-
- return QVariant();
-}
-
-
-int BtmItem::row() const
-{
- if (m_parent)
- return m_parent->m_children.indexOf(const_cast< BtmItem* >(this));
- return 0;
-}
-
-
-int BtmItem::childCount() const
-{
- return m_children.count();
+ if (bookmarksFile->open(QIODevice::ReadOnly | QIODevice::Text)) {
+ if (path.endsWith(".xbel")) { readFns[Formats::FormatXbel](bookmarksFile, rootItem); }
+ bookmarksFile->close();
+ }
}
-
-BtmItem* BtmItem::child(int n)
+BookmarkModel::~BookmarkModel()
{
- Q_ASSERT(n >= 0);
- Q_ASSERT(n < childCount());
+ save(); // save on exit
+ bookmarksFile->flush();
- return m_children.at(n);
+ delete rootItem;
+ delete bookmarksFile;
}
-
-BtmItem* BtmItem::parent() const
+void BookmarkModel::load(const QIODevice *buffer)
{
- return m_parent;
+ if (buffer->isOpen() && buffer->isReadable()) { readFns[Formats::FormatXbel](buffer, rootItem); }
}
-
-void BtmItem::appendChild(BtmItem *child)
+QVariant BookmarkModel::headerData(int section, Qt::Orientation, int role) const
{
- if (!child)
- return;
-
- child->m_parent = this;
- m_children << child;
+ if (role != Qt::DisplayRole) return {};
+ return rootItem->data(static_cast<BookmarksTreeItem::Attributes>(section));
}
-
-void BtmItem::clear()
+QVariant BookmarkModel::data(const QModelIndex &index, int role) const
{
- qDeleteAll(m_children);
- m_children.clear();
+ if (!index.isValid()) return {};
+
+ auto *it = item(index);
+
+ // find item Alias points to
+ if (it->type() == BookmarksTreeItem::Alias) {
+ // find the item this is an alias of
+ auto *child = rootItem->findChild(it->data(BookmarksTreeItem::Href).toString());
+ if (child == nullptr) return {};
+ it = child;
+ }
+
+ switch (role) {
+ case Qt::DecorationRole:
+ if (index.column() == 0) return it->icon();
+ break;
+ case Qt::ToolTipRole:
+ return it->tooltip();
+ case Qt::DisplayRole:
+ case Qt::EditRole:
+ if (index.column() == 0) return it->data(BookmarksTreeItem::Title);
+ if (index.column() == 1) return it->data(BookmarksTreeItem::Href);
+ break;
+ case CompletionMatchingRole:
+ if (it->type() == BookmarksTreeItem::Bookmark) return it->data(BookmarksTreeItem::Href);
+ return it->data(BookmarksTreeItem::Title);
+ default:
+ break;
+ }
+
+ return {};
}
-KBookmark BtmItem::getBkm() const
+bool BookmarkModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
- return m_kbm;
-}
+ if (!index.isValid()) return false;
+ bool success = false;
-// -------------------------------------------------------------------------------------
+ if (role == Qt::DisplayRole || role == Qt::EditRole) {
+ auto *item = static_cast<BookmarksTreeItem *>(index.internalPointer());
+ success = item->setData(static_cast<BookmarksTreeItem::Attributes>(index.column()), value);
+ }
+ if (success) {
+ emit dataChanged(index, index, {role});
+ m_isModified = true;
+ }
-BookmarksTreeModel::BookmarksTreeModel(QObject *parent)
- : QAbstractItemModel(parent)
- , m_root(0)
-{
- resetModel();
- connect(BookmarkManager::self()->manager(), SIGNAL(changed(QString,QString)),
- this, SLOT(bookmarksChanged(QString)));
+ return success;
}
-
-BookmarksTreeModel::~BookmarksTreeModel()
+Qt::ItemFlags BookmarkModel::flags(const QModelIndex &index) const
{
- delete m_root;
+ switch (item(index)->type()) {
+ case BookmarksTreeItem::Root:
+ return QAbstractItemModel::flags(index) /*| Qt::ItemIsDragEnabled*/ | Qt::ItemIsDropEnabled;
+ case BookmarksTreeItem::Folder:
+ return QAbstractItemModel::flags(index) | (index.column() == 0 ? Qt::ItemIsEditable : Qt::NoItemFlags) |
+ Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled;
+ case BookmarksTreeItem::Bookmark:
+ return QAbstractItemModel::flags(index) | Qt::ItemIsEditable | Qt::ItemIsDragEnabled | Qt::ItemNeverHasChildren;
+ case BookmarksTreeItem::Separator:
+ return QAbstractItemModel::flags(index) | Qt::ItemIsDragEnabled | Qt::ItemNeverHasChildren;
+ case BookmarksTreeItem::Alias:
+ // TODO find aliased item and return its flags
+ return QAbstractItemModel::flags(index);
+ }
+
+ __builtin_unreachable();
}
-
-int BookmarksTreeModel::rowCount(const QModelIndex &parent) const
+int BookmarkModel::rowCount(const QModelIndex &index) const
{
- BtmItem *parentItem = 0;
- if (!parent.isValid())
- {
- parentItem = m_root;
- }
- else
- {
- parentItem = static_cast<BtmItem*>(parent.internalPointer());
- }
-
- return parentItem->childCount();
+ if (index.column() > 0) return 0;
+ return static_cast<int>(item(index)->childCount());
}
-
-int BookmarksTreeModel::columnCount(const QModelIndex& /*parent*/) const
+QModelIndex BookmarkModel::appendItem(BookmarksTreeItem::Types type, BookmarksTreeItem::Attributes_t data,
+ const QModelIndex &parent)
{
- return 1;
+ auto *parentItem = item(parent);
+ const auto row = rowCount(parent);
+
+ beginInsertRows(parent, row, row);
+ auto *child = new BookmarksTreeItem(type, std::move(data), parentItem);
+ child->setData(BookmarksTreeItem::Added, QDateTime::currentDateTime());
+ bool success = parentItem->appendChild(child);
+ endInsertRows();
+
+ if (success) {
+ m_isModified = true;
+ return createIndex(row, 0, child);
+ }
+ else
+ return {};
}
-
-Qt::ItemFlags BookmarksTreeModel::flags(const QModelIndex &index) const
+bool BookmarkModel::removeRows(int position, int rows, const QModelIndex &parent)
{
- Qt::ItemFlags flags = QAbstractItemModel::flags(index);
-
- if (!index.isValid())
- return flags | Qt::ItemIsDropEnabled;
+ auto *parentItem = item(parent);
- flags = Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled;
+ beginRemoveRows(parent, position, position + rows - 1);
+ bool success = parentItem->removeChildAt(position, rows);
+ endRemoveRows();
- if (bookmarkForIndex(index).isGroup())
- flags |= Qt::ItemIsDropEnabled;
-
- return flags;
+ if (success) m_isModified = true;
+ return success;
}
-
-QModelIndex BookmarksTreeModel::index(int row, int column, const QModelIndex &parent) const
+QModelIndex BookmarkModel::index(int row, int column, const QModelIndex &parent) const
{
- if (!hasIndex(row, column, parent))
- return QModelIndex();
-
- BtmItem *parentItem;
+ if (!this->hasIndex(row, column, parent)) return {};
- if (!parent.isValid())
- parentItem = m_root;
- else
- parentItem = static_cast<BtmItem*>(parent.internalPointer());
-
- BtmItem *childItem = parentItem->child(row);
- if (childItem)
- return createIndex(row, column, childItem);
-
- return QModelIndex();
+ BookmarksTreeItem *parentItem = item(parent);
+ BookmarksTreeItem *childItem = parentItem->child(row);
+ if (childItem) return createIndex(row, column, childItem);
+ return {};
}
-
-QModelIndex BookmarksTreeModel::parent(const QModelIndex &index) const
+QModelIndex BookmarkModel::parent(const QModelIndex &index) const
{
- if (!index.isValid())
- return QModelIndex();
-
- BtmItem *childItem = static_cast<BtmItem*>(index.internalPointer());
- BtmItem *parentItem = childItem->parent();
+ if (!index.isValid()) return {};
- if (parentItem == m_root)
- return QModelIndex();
-
- return createIndex(parentItem->row(), 0, parentItem);
-}
+ auto *childItem = static_cast<BookmarksTreeItem *>(index.internalPointer());
+ auto *parentItem = childItem->parent();
+ if (parentItem == rootItem) return {};
-QVariant BookmarksTreeModel::data(const QModelIndex &index, int role) const
-{
- if (!index.isValid())
- return QVariant();
-
- BtmItem *node = static_cast<BtmItem*>(index.internalPointer());
- if (node && node == m_root)
- {
- if (role == Qt::DisplayRole)
- return i18n("Bookmarks");
- if (role == Qt::DecorationRole)
- return KIcon("bookmarks");
- }
- else
- {
- if (node)
- return node->data(role);
- }
-
- return QVariant();
+ return createIndex(parentItem->row(), 0, parentItem);
}
-
-QStringList BookmarksTreeModel::mimeTypes() const
+QModelIndex BookmarkModel::parentFolder(const QModelIndex &index) const
{
- return QStringList(BookmarkManager::bookmark_mime_type());
-}
-
-
-bool BookmarksTreeModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent)
-{
- if (action != Qt::MoveAction || !data->hasFormat(BookmarkManager::bookmark_mime_type()))
- return false;
-
- QByteArray addresses = data->data(BookmarkManager::bookmark_mime_type());
- KBookmark bookmark = BookmarkManager::self()->findByAddress(QString::fromLatin1(addresses.data()));
-
- KBookmarkGroup root;
- if (parent.isValid())
- root = bookmarkForIndex(parent).toGroup();
- else
- root = BookmarkManager::self()->rootGroup();
-
- QModelIndex destIndex = index(row, column, parent);
+ // invalid index is the root index -> return it back
+ if (!index.isValid()) return {};
- if (destIndex.isValid() && row != -1)
- {
- root.moveBookmark(bookmark, root.previous(bookmarkForIndex(destIndex)));
- }
- else
- {
- root.deleteBookmark(bookmark);
- root.addBookmark(bookmark);
- }
+ if (item(index)->type() == BookmarksTreeItem::Bookmark) { return index.parent(); }
- BookmarkManager::self()->emitChanged();
-
- return true;
+ return index;
}
-
-Qt::DropActions BookmarksTreeModel::supportedDropActions() const
+BookmarksTreeItem *BookmarkModel::item(const QModelIndex &index) const
{
- return Qt::MoveAction;
+ if (!index.isValid()) return rootItem;
+ return static_cast<BookmarksTreeItem *>(index.internalPointer());
}
+/*
+ * Drag'n'Drop implementation
+ * How drag and drop actually works: the view encodes the data of the original item (using BookmarkModel::mimeData), and
+ * then uses BookmarkModel::dropMimeData to create the new item. If successful, the old item is removed (through
+ * BookmarkModel::removeRows).
+ */
-QMimeData* BookmarksTreeModel::mimeData(const QModelIndexList &indexes) const
+QMimeData *BookmarkModel::mimeData(const QModelIndexList &indexes) const
{
- QMimeData *mimeData = new QMimeData;
-
- QByteArray address = bookmarkForIndex(indexes.first()).address().toLatin1();
- mimeData->setData(BookmarkManager::bookmark_mime_type(), address);
- bookmarkForIndex(indexes.first()).populateMimeData(mimeData);
-
- return mimeData;
+ QByteArray data;
+ QBuffer buffer(&data);
+ buffer.open(QIODevice::WriteOnly | QIODevice::Text);
+
+ QVector<const BookmarksTreeItem *> items;
+ for (const QModelIndex &index : indexes) {
+ if (index.isValid() && index.column() == 0) items.append(item(index));
+ }
+ xbel::write(&buffer, items);
+
+ auto *mimeData = new QMimeData;
+ mimeData->setData(mimeType, data);
+ return mimeData;
}
-
-void BookmarksTreeModel::bookmarksChanged(const QString &groupAddress)
+bool BookmarkModel::dropMimeData(const QMimeData *mimeData, Qt::DropAction action, int row, int column,
+ const QModelIndex &parent)
{
- if (groupAddress.isEmpty())
- {
- resetModel();
- }
- else
- {
- beginResetModel();
- BtmItem *node = m_root;
- QModelIndex nodeIndex;
-
- QStringList indexChain(groupAddress.split('/', QString::SkipEmptyParts));
- bool ok;
- int i;
- Q_FOREACH(const QString & sIndex, indexChain)
- {
- i = sIndex.toInt(&ok);
- if (!ok)
- break;
-
- if (i < 0 || i >= node->childCount())
- break;
-
- node = node->child(i);
- nodeIndex = index(i, 0, nodeIndex);
- }
- populate(node, BookmarkManager::self()->findByAddress(groupAddress).toGroup());
- endResetModel();
- }
-
- emit bookmarksUpdated();
-}
+ if (action == Qt::IgnoreAction) return true;
+ if (action != Qt::MoveAction) return false; // we only implement MoveAction's
+ if (!mimeData->hasFormat(mimeType) || column > 0) return false;
+ auto data = mimeData->data(mimeType);
+ QBuffer buffer(&data);
+ buffer.open(QIODevice::ReadOnly | QIODevice::Text);
-void BookmarksTreeModel::resetModel()
-{
- setRoot(BookmarkManager::self()->rootGroup());
-}
+ auto *fake_root = new BookmarksTreeItem(BookmarksTreeItem::Root, {}, nullptr);
+ xbel::read(&buffer, fake_root);
+ const auto childCount = static_cast<int>(fake_root->childCount());
+ auto *parentItem = item(parent);
-void BookmarksTreeModel::setRoot(KBookmarkGroup bmg)
-{
- beginResetModel();
- delete m_root;
- m_root = new BtmItem(KBookmark());
- populate(m_root, bmg);
- endResetModel();
-}
+ beginInsertRows(parent, row, row + childCount - 1);
+ for (int i = 0; i < childCount; ++i) parentItem->insertChild(row + i, fake_root->takeChild(i));
+ endInsertRows();
+ delete fake_root;
-void BookmarksTreeModel::populate(BtmItem *node, KBookmarkGroup bmg)
-{
- node->clear();
-
- if (bmg.isNull())
- return;
-
- KBookmark bm = bmg.first();
- while (!bm.isNull())
- {
- BtmItem *newChild = new BtmItem(bm);
- if (bm.isGroup())
- populate(newChild, bm.toGroup());
-
- node->appendChild(newChild);
- bm = bmg.next(bm);
- }
+ m_isModified = true;
+ return true;
}
-
-KBookmark BookmarksTreeModel::bookmarkForIndex(const QModelIndex &index) const
+void BookmarkModel::save()
{
- return static_cast<BtmItem*>(index.internalPointer())->getBkm();
+ if (m_isModified) {
+ bookmarksFile->open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate);
+ m_isModified = !writeFns[Formats::FormatXbel](bookmarksFile, {rootItem});
+ bookmarksFile->close();
+ }
}