diff --git a/src/core/feedsmodel.cpp b/src/core/feedsmodel.cpp index 502e5fb17..4e478513f 100755 --- a/src/core/feedsmodel.cpp +++ b/src/core/feedsmodel.cpp @@ -204,6 +204,122 @@ DatabaseCleaner *FeedsModel::databaseCleaner() { return m_dbCleaner; } +QMimeData *FeedsModel::mimeData(const QModelIndexList &indexes) const { + QMimeData *mime_data = new QMimeData(); + QByteArray encoded_data; + QDataStream stream(&encoded_data, QIODevice::WriteOnly); + + foreach (const QModelIndex &index, indexes) { + if (index.column() != 0) { + continue; + } + + RootItem *item_for_index = itemForIndex(index); + + if (item_for_index->kind() != RootItemKind::Root) { + stream << (quintptr) item_for_index; + } + } + + mime_data->setData(MIME_TYPE_ITEM_POINTER, encoded_data); + return mime_data; +} + +QStringList FeedsModel::mimeTypes() const { + return QStringList() << MIME_TYPE_ITEM_POINTER; +} + +bool FeedsModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) { + Q_UNUSED(row) + Q_UNUSED(column) + + if (action == Qt::IgnoreAction) { + return true; + } + else if (action != Qt::MoveAction) { + return false; + } + + QByteArray dragged_items_data = data->data(MIME_TYPE_ITEM_POINTER); + + if (dragged_items_data.isEmpty()) { + return false; + } + else { + QDataStream stream(&dragged_items_data, QIODevice::ReadOnly); + + while (!stream.atEnd()) { + quintptr pointer_to_item; + stream >> pointer_to_item; + + // We have item we want to drag, we also determine the target item. + RootItem *dragged_item = (RootItem*) pointer_to_item; + RootItem *target_item = itemForIndex(parent); + ServiceRoot *dragged_item_root = dragged_item->getParentServiceRoot(); + ServiceRoot *target_item_root = target_item->getParentServiceRoot(); + + if (dragged_item == target_item || dragged_item->parent() == target_item) { + qDebug("Dragged item is equal to target item or its parent is equal to target item. Cancelling drag-drop action."); + return false; + } + + if (dragged_item_root != target_item_root) { + // Transferring of items between different accounts is not possible. + qApp->showGuiMessage(tr("Cannot perform drag \& drop operation."), + tr("You can't transfer dragged item into different account, this is not supported."), + QSystemTrayIcon::Warning, + qApp->mainForm(), + true); + + qDebug("Dragged item cannot be dragged into different account. Cancelling drag-drop action."); + return false; + } + + /* + if (dragged_item->kind() == RootItem::Feeed) { + qDebug("Drag-drop action for feed '%s' detected, editing the feed.", qPrintable(dragged_item->title())); + + Feed *actual_feed = dragged_item->toFeed(); + Feed *feed_new = new Feed(*actual_feed); + + feed_new->setParent(target_item); + editFeed(actual_feed, feed_new); + + emit requireItemValidationAfterDragDrop(indexForItem(actual_feed)); + } + else if (dragged_item->kind() == RootItem::Cattegory) { + qDebug("Drag-drop action for category '%s' detected, editing the feed.", qPrintable(dragged_item->title())); + + Category *actual_category = dragged_item->toCategory(); + Category *category_new = new Category(*actual_category); + + category_new->clearChildren(); + category_new->setParent(target_item); + editCategory(actual_category, category_new); + + emit requireItemValidationAfterDragDrop(indexForItem(actual_category)); + } + */ + } + + return true; + } + + return false; +} + +Qt::DropActions FeedsModel::supportedDropActions() const { + return Qt::MoveAction; +} + +Qt::ItemFlags FeedsModel::flags(const QModelIndex &index) const { + Qt::ItemFlags base_flags = QAbstractItemModel::flags(index); + RootItem *item_for_index = itemForIndex(index); + Qt::ItemFlags additional_flags = item_for_index->additionalFlags(); + + return base_flags | additional_flags; +} + void FeedsModel::executeNextAutoUpdate() { if (!qApp->feedUpdateLock()->tryLock()) { qDebug("Delaying scheduled feed auto-updates for one minute due to another running update."); diff --git a/src/core/feedsmodel.h b/src/core/feedsmodel.h index 08b205d96..9a1ffb40c 100755 --- a/src/core/feedsmodel.h +++ b/src/core/feedsmodel.h @@ -47,6 +47,13 @@ class FeedsModel : public QAbstractItemModel { return itemForIndex(index)->data(index.column(), role); } + // Drag & drop. + QMimeData *mimeData(const QModelIndexList &indexes) const; + QStringList mimeTypes() const; + bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent); + Qt::DropActions supportedDropActions() const; + Qt::ItemFlags flags(const QModelIndex &index) const; + QVariant headerData(int section, Qt::Orientation orientation, int role) const; QModelIndex index(int row, int column, const QModelIndex &parent) const; QModelIndex parent(const QModelIndex &child) const; @@ -181,8 +188,11 @@ class FeedsModel : public QAbstractItemModel { void onFeedUpdatesFinished(FeedDownloadResults results); signals: + // Update of feeds is finished. void feedsUpdateFinished(); + // Counts of unread messages are changed in some feeds, + // notify view about this shit. void readFeedsFilterInvalidationRequested(); // Emitted when model requests update of some feeds. @@ -194,6 +204,10 @@ class FeedsModel : public QAbstractItemModel { // Emitted when there is a need of reloading of displayed messages. void reloadMessageListRequested(bool mark_selected_messages_read); + // There was some drag/drop operation, notify view about this. + // NOTE: View will probably expand dropped index. + void requireItemValidationAfterDragDrop(const QModelIndex &source_index); + private: // Returns converted ids of given feeds // which are suitable as IN clause for SQL queries. diff --git a/src/core/feedsproxymodel.cpp b/src/core/feedsproxymodel.cpp index a2dd06225..ba83fb4f6 100755 --- a/src/core/feedsproxymodel.cpp +++ b/src/core/feedsproxymodel.cpp @@ -206,7 +206,9 @@ bool FeedsProxyModel::filterAcceptsRow(int source_row, const QModelIndex &source return true; } else { - return item->countOfUnreadMessages() > 0; + // NOTE: If item has < 0 of unread message it may mean, that the count + // of unread messages is not (yet) known, display that item too. + return item->countOfUnreadMessages() != 0; } } diff --git a/src/core/rootitem.cpp b/src/core/rootitem.cpp index 4b4ef2493..42738133f 100755 --- a/src/core/rootitem.cpp +++ b/src/core/rootitem.cpp @@ -166,6 +166,10 @@ QVariant RootItem::data(int column, int role) const { } } +Qt::ItemFlags RootItem::additionalFlags() const { + return Qt::NoItemFlags; +} + int RootItem::countOfAllMessages() const { int total_count = 0; diff --git a/src/core/rootitem.h b/src/core/rootitem.h index ef47662f5..1b0b6646e 100755 --- a/src/core/rootitem.h +++ b/src/core/rootitem.h @@ -74,8 +74,7 @@ class RootItem : public QObject { ///////////////////////////////////////// // Returns list of specific actions which can be done with the item. - // Do not include general actions here like actions: - // Mark as read, Update, ... + // Do not include general actions here like actions: Mark as read, Update, ... // NOTE: Ownership of returned actions is not switched to caller, free them when needed. virtual QList contextMenuActions(); @@ -113,6 +112,7 @@ class RootItem : public QObject { virtual int row() const; virtual QVariant data(int column, int role) const; + virtual Qt::ItemFlags additionalFlags() const; // Each item offers "counts" of messages. // Returns counts of messages of all child items summed up. diff --git a/src/gui/feedsview.cpp b/src/gui/feedsview.cpp index e2fc28122..f750ff432 100755 --- a/src/gui/feedsview.cpp +++ b/src/gui/feedsview.cpp @@ -54,6 +54,7 @@ FeedsView::FeedsView(QWidget *parent) m_sourceModel = m_proxyModel->sourceModel(); // Connections. + connect(m_sourceModel, SIGNAL(requireItemValidationAfterDragDrop(QModelIndex)), this, SLOT(validateItemAfterDragDrop(QModelIndex))); connect(header(), SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)), this, SLOT(saveSortState(int,Qt::SortOrder))); setModel(m_proxyModel); diff --git a/src/services/standard/standardcategory.cpp b/src/services/standard/standardcategory.cpp index 2ef830d2a..578016dd5 100755 --- a/src/services/standard/standardcategory.cpp +++ b/src/services/standard/standardcategory.cpp @@ -90,6 +90,10 @@ QVariant StandardCategory::data(int column, int role) const { } } +Qt::ItemFlags StandardCategory::additionalFlags() const { + return Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled; +} + bool StandardCategory::editViaGui() { QPointer form_pointer = new FormStandardCategoryDetails(serviceRoot(), qApp->mainForm()); diff --git a/src/services/standard/standardcategory.h b/src/services/standard/standardcategory.h index d318ec99f..38a8d513f 100755 --- a/src/services/standard/standardcategory.h +++ b/src/services/standard/standardcategory.h @@ -44,6 +44,7 @@ class StandardCategory : public Category { // Returns the actual data representation of standard category. QVariant data(int column, int role) const; + Qt::ItemFlags additionalFlags() const; bool canBeEdited() { return true; diff --git a/src/services/standard/standardfeed.cpp b/src/services/standard/standardfeed.cpp index 066562f3d..8902b6fe6 100755 --- a/src/services/standard/standardfeed.cpp +++ b/src/services/standard/standardfeed.cpp @@ -436,6 +436,10 @@ QVariant StandardFeed::data(int column, int role) const { } } +Qt::ItemFlags StandardFeed::additionalFlags() const { + return Qt::ItemIsDragEnabled; +} + int StandardFeed::update() { QByteArray feed_contents; int download_timeout = qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::UpdateTimeout)).toInt(); diff --git a/src/services/standard/standardfeed.h b/src/services/standard/standardfeed.h index 24577662b..f97714ba8 100755 --- a/src/services/standard/standardfeed.h +++ b/src/services/standard/standardfeed.h @@ -81,6 +81,7 @@ class StandardFeed : public Feed { // Obtains data related to this feed. QVariant data(int column, int role) const; + Qt::ItemFlags additionalFlags() const; // Perform fetching of new messages. Returns number of newly updated messages. int update(); diff --git a/src/services/standard/standardserviceroot.cpp b/src/services/standard/standardserviceroot.cpp index 236a4b0ab..94a6e6ba0 100755 --- a/src/services/standard/standardserviceroot.cpp +++ b/src/services/standard/standardserviceroot.cpp @@ -128,6 +128,10 @@ QVariant StandardServiceRoot::data(int column, int role) const { } } +Qt::ItemFlags StandardServiceRoot::additionalFlags() const { + return Qt::ItemIsDropEnabled; +} + RecycleBin *StandardServiceRoot::recycleBin() { return m_recycleBin; } diff --git a/src/services/standard/standardserviceroot.h b/src/services/standard/standardserviceroot.h index aa65fc15c..dd1572ff6 100755 --- a/src/services/standard/standardserviceroot.h +++ b/src/services/standard/standardserviceroot.h @@ -50,6 +50,7 @@ class StandardServiceRoot : public ServiceRoot { bool canBeEdited(); bool canBeDeleted(); QVariant data(int column, int role) const; + Qt::ItemFlags additionalFlags() const; RecycleBin *recycleBin();