From 9203de811f049c8e604a9c3065781157fa506155 Mon Sep 17 00:00:00 2001 From: Aqua-sama Date: Tue, 25 Sep 2018 14:44:01 +0200 Subject: Bookmarks: integrate model/view - fix addBookmark and search signals - fix drag'n'drop - add xbel::write --- lib/bookmarks/bookmarkmodel.cpp | 165 ++++++++++++++++++++++++++++++---------- 1 file changed, 123 insertions(+), 42 deletions(-) (limited to 'lib/bookmarks/bookmarkmodel.cpp') diff --git a/lib/bookmarks/bookmarkmodel.cpp b/lib/bookmarks/bookmarkmodel.cpp index 3b57fea..b55dcdd 100644 --- a/lib/bookmarks/bookmarkmodel.cpp +++ b/lib/bookmarks/bookmarkmodel.cpp @@ -8,6 +8,9 @@ #include "bookmarkmodel.h" #include "bookmarkitem.h" +#include "xbel.h" +#include +#include BookmarkModel::BookmarkModel(QObject *parent) : QAbstractItemModel(parent) @@ -35,12 +38,15 @@ QVariant BookmarkModel::data(const QModelIndex &index, int role) const if(role == Qt::DecorationRole && index.column() == 0) return static_cast(index.internalPointer())->icon(); + else if(role == Qt::ToolTipRole) return static_cast(index.internalPointer())->tooltip(); - else if(role != Qt::DisplayRole) - return QVariant(); - return static_cast(index.internalPointer())->data(index.column()); + else if(role == Qt::DisplayRole) + return static_cast(index.internalPointer())->data(index.column()); + + else + return QVariant(); } QVariant BookmarkModel::data(const QModelIndex &index, int column, int role) const @@ -56,10 +62,15 @@ QVariant BookmarkModel::data(const QModelIndex &index, int column, int role) con bool BookmarkModel::setData(const QModelIndex &index, const QVariant &value, int role) { - if(!index.isValid() || role != Qt::DisplayRole) + if(!index.isValid()) return false; - bool success = static_cast(index.internalPointer())->setData(static_cast(index.column()), value); + bool success = false; + + if(role == Qt::DisplayRole) { + success = static_cast(index.internalPointer())->setData(static_cast(index.column()), value); + } + if(success) emit dataChanged(index, index, { role }); return success; @@ -81,7 +92,7 @@ Qt::ItemFlags BookmarkModel::flags(const QModelIndex &index) const if(getItem(index)->type() == BookmarkItem::Folder) return QAbstractItemModel::flags(index) | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled; else - return QAbstractItemModel::flags(index) | Qt::ItemIsDragEnabled; + return QAbstractItemModel::flags(index) | Qt::ItemIsDragEnabled | Qt::ItemNeverHasChildren; } bool BookmarkModel::isItemExpanded(const QModelIndex &index) const @@ -100,24 +111,20 @@ int BookmarkModel::rowCount(const QModelIndex &index) const return getItem(index)->childCount(); } -bool BookmarkModel::insertRows(int position, int rows, const QModelIndex &parent) +bool BookmarkModel::appendBookmark(const QString &title, const QString &url, const QModelIndex &parent) { auto *parentItem = getItem(parent); - // if position is negative, or past the number of children in the item - if(position < 0 || position > parentItem->childCount()) - return false; - - beginInsertRows(parent, position, position + rows - 1); - for(int i = 0; i < rows; ++i) { - parentItem->insertChild(position + i, new BookmarkItem({}, BookmarkItem::Bookmark, parentItem)); - } + int row = parentItem->childCount(); + beginInsertRows(parent, row, row); + parentItem->appendChild(new BookmarkItem({ title, url }, BookmarkItem::Bookmark, parentItem)); endInsertRows(); return true; } bool BookmarkModel::removeRows(int position, int rows, const QModelIndex &parent) { + qDebug("removeRows: pos=%i rows=%i", position, rows); auto *parentItem = getItem(parent); beginRemoveRows(parent, position, position + rows - 1); @@ -126,36 +133,10 @@ bool BookmarkModel::removeRows(int position, int rows, const QModelIndex &parent return success; } -bool BookmarkModel::moveRows(const QModelIndex &sourceParent, int sourceRow, int count, const QModelIndex &destinationParent, int destinationChild) -{ - auto *sourceParentItem = getItem(sourceParent); - auto *destinationParentItem = getItem(destinationParent); - - bool success = true; - beginMoveRows(sourceParent, sourceRow, sourceRow + count - 1, destinationParent, destinationChild); - for(int i = 0; i < count; ++i) { - auto *child = sourceParentItem->takeChild(sourceRow, destinationParentItem); - if(!destinationParentItem->insertChild(destinationChild, child)) { - success = false; - break; - } - } - endMoveRows(); - return success; -} - int BookmarkModel::columnCount(const QModelIndex &index) const { + Q_UNUSED(index); return 2; - // if(!index.isValid()) - // return rootItem->columnCount(); - // else - // return static_cast(index.internalPointer())->columnCount(); -} - -Qt::DropActions BookmarkModel::supportedDropActions() const -{ - return Qt::MoveAction; } QModelIndex BookmarkModel::index(int row, int column, const QModelIndex &parent) const @@ -184,6 +165,26 @@ QModelIndex BookmarkModel::parent(const QModelIndex &index) const return createIndex(parentItem->row(), 0, parentItem); } + +inline QStringList searchThrough(const QString &term, BookmarkItem *item) +{ + QStringList results; + for(int i = 0; i < item->childCount(); ++i) { + auto *child = item->child(i); + if(child->type() == BookmarkItem::Bookmark && child->data(BookmarkItem::Href).toString().contains(term)) + results.append(child->data(BookmarkItem::Href).toString()); + else if(child->type() == BookmarkItem::Folder) + results.append(searchThrough(term, child)); + } + return results; +} + +QStringList BookmarkModel::search(const QString &term) const +{ + // TODO tag searching + return searchThrough(term, rootItem); +} + BookmarkItem *BookmarkModel::getItem(const QModelIndex &index) const { if(!index.isValid()) @@ -191,3 +192,83 @@ BookmarkItem *BookmarkModel::getItem(const QModelIndex &index) const else return static_cast(index.internalPointer()); } + +/* + * Drag'n'Drop implementation + * How drag and drop actually works: the view encodes the data of the original + * item (through ::mimeData), and then uses ::dropMimeData to create the new + * item. If successful, the old item is removed (through ::removeRows). + * This means that the encoding and decoding needs to be provided. In this case, + * this is done through xbel. + */ + +Qt::DropActions BookmarkModel::supportedDropActions() const +{ + return Qt::MoveAction; +} + +QStringList BookmarkModel::mimeTypes() const +{ + return { mimeType }; +} + +QMimeData *BookmarkModel::mimeData(const QModelIndexList &indexes) const +{ + auto *mimeData = new QMimeData(); + QByteArray data; + XbelWriter writer; + + QDataStream stream(&data, QIODevice::WriteOnly); + for(const QModelIndex &index : indexes) { + if(index.isValid() && index.column() == 0) { + QByteArray encodedData; + QBuffer buffer(&encodedData); + buffer.open(QIODevice::WriteOnly); + + writer.write(&buffer, getItem(index)); + + stream << encodedData; + } + } + mimeData->setData(mimeType, data); + return mimeData; +} +bool BookmarkModel::dropMimeData(const QMimeData *mimeData, Qt::DropAction action, int row, int column, const QModelIndex &parent) +{ + if(action == Qt::IgnoreAction) + return true; + + if(action != Qt::MoveAction) + return false; + + if(!mimeData->hasFormat(mimeType) || column > 0) + return false; + + QByteArray data = mimeData->data(mimeType); + QDataStream stream(&data, QIODevice::ReadOnly); + if(stream.atEnd()) + return false; + + while(!stream.atEnd()) { + QByteArray encodedData; + stream >> encodedData; + + QBuffer buffer(&encodedData); + buffer.open(QIODevice::ReadOnly); + + XbelReader reader(&buffer); + auto *fakeRoot = new BookmarkItem({}, BookmarkItem::Folder, nullptr); + auto *parentItem = getItem(parent); + reader.read(fakeRoot); + + beginInsertRows(parent, row, row + fakeRoot->childCount() - 1); + for(int i = 0; i < fakeRoot->childCount(); ++i) { + auto *child = fakeRoot->takeChild(0, parentItem); + parentItem->insertChild(row, child); + } + endInsertRows(); + + delete fakeRoot; + } + return true; +} -- cgit v1.2.1