From 186976e2095f3cc13f1a4fe09fcae69facb43974 Mon Sep 17 00:00:00 2001 From: thunder2 Date: Thu, 13 Apr 2023 15:53:14 +0200 Subject: [PATCH] FeedReader: The feed can be moved with drag and drop to a folder --- plugins/FeedReader/FeedReader.pro | 2 + plugins/FeedReader/gui/FeedReaderDialog.cpp | 37 ++++++ plugins/FeedReader/gui/FeedReaderDialog.h | 1 + plugins/FeedReader/gui/FeedReaderDialog.ui | 6 +- plugins/FeedReader/gui/FeedTreeWidget.cpp | 119 ++++++++++++++++++++ plugins/FeedReader/gui/FeedTreeWidget.h | 50 ++++++++ plugins/FeedReader/interface/rsFeedReader.h | 1 + plugins/FeedReader/lang/FeedReader_en.ts | 20 +++- plugins/FeedReader/services/p3FeedReader.cc | 56 +++++++++ plugins/FeedReader/services/p3FeedReader.h | 1 + 10 files changed, 285 insertions(+), 8 deletions(-) create mode 100644 plugins/FeedReader/gui/FeedTreeWidget.cpp create mode 100644 plugins/FeedReader/gui/FeedTreeWidget.h diff --git a/plugins/FeedReader/FeedReader.pro b/plugins/FeedReader/FeedReader.pro index b5dbbf43a..5c696b5c3 100644 --- a/plugins/FeedReader/FeedReader.pro +++ b/plugins/FeedReader/FeedReader.pro @@ -44,6 +44,7 @@ SOURCES = FeedReaderPlugin.cpp \ gui/FeedReaderFeedNotify.cpp \ gui/FeedReaderUserNotify.cpp \ gui/FeedReaderFeedItem.cpp \ + gui/FeedTreeWidget.cpp \ util/CURLWrapper.cpp \ util/XMLWrapper.cpp \ util/HTMLWrapper.cpp \ @@ -64,6 +65,7 @@ HEADERS = FeedReaderPlugin.h \ gui/FeedReaderFeedNotify.h \ gui/FeedReaderUserNotify.h \ gui/FeedReaderFeedItem.h \ + gui/FeedTreeWidget.h \ util/CURLWrapper.h \ util/XMLWrapper.h \ util/HTMLWrapper.h \ diff --git a/plugins/FeedReader/gui/FeedReaderDialog.cpp b/plugins/FeedReader/gui/FeedReaderDialog.cpp index abc2f1aa5..4c409a38c 100644 --- a/plugins/FeedReader/gui/FeedReaderDialog.cpp +++ b/plugins/FeedReader/gui/FeedReaderDialog.cpp @@ -84,9 +84,16 @@ FeedReaderDialog::FeedReaderDialog(RsFeedReader *feedReader, FeedReaderNotify *n connect(ui->feedAddButton, SIGNAL(clicked()), this, SLOT(newFeed())); connect(ui->feedProcessButton, SIGNAL(clicked()), this, SLOT(processFeed())); + connect(ui->feedTreeWidget, SIGNAL(feedReparent(QTreeWidgetItem*,QTreeWidgetItem*)), this, SLOT(feedTreeReparent(QTreeWidgetItem*,QTreeWidgetItem*))); + mFeedCompareRole = new RSTreeWidgetItemCompareRole; mFeedCompareRole->setRole(COLUMN_FEED_NAME, ROLE_FEED_SORT); + /* enable drag and drop */ + ui->feedTreeWidget->setAcceptDrops(true); + ui->feedTreeWidget->setDragEnabled(true); + ui->feedTreeWidget->setDragDropMode(QAbstractItemView::InternalMove); + /* initialize root item */ mRootItem = new QTreeWidgetItem(ui->feedTreeWidget); QString name = tr("Message Folders"); @@ -395,6 +402,9 @@ void FeedReaderDialog::updateFeeds(uint32_t parentId, QTreeWidgetItem *parentIte mOpenFeedIds->removeAt(index); } } + } else { + /* disable drop */ + item->setFlags(item->flags() & ~Qt::ItemIsDropEnabled); } } @@ -832,3 +842,30 @@ void FeedReaderDialog::processFeed() mFeedReader->processFeed(feedId); } + +void FeedReaderDialog::feedTreeReparent(QTreeWidgetItem *item, QTreeWidgetItem *newParent) +{ + if (!item || ! newParent) { + return; + } + + uint32_t feedId = item->data(COLUMN_FEED_DATA, ROLE_FEED_ID).toUInt(); + uint32_t parentId = newParent->data(COLUMN_FEED_DATA, ROLE_FEED_ID).toUInt(); + + if (feedId == 0) { + return; + } + + RsFeedAddResult result = mFeedReader->setParent(feedId, parentId); + if (FeedReaderStringDefs::showError(this, result, tr("Move feed"), tr("Cannot move feed."))) { + return; + } + + bool expanded = item->isExpanded(); + item->parent()->removeChild(item); + newParent->addChild(item); + item->setExpanded(expanded); + newParent->setExpanded(true); + + calculateFeedItems(); +} diff --git a/plugins/FeedReader/gui/FeedReaderDialog.h b/plugins/FeedReader/gui/FeedReaderDialog.h index a221cfe64..d684f1f4b 100644 --- a/plugins/FeedReader/gui/FeedReaderDialog.h +++ b/plugins/FeedReader/gui/FeedReaderDialog.h @@ -61,6 +61,7 @@ private slots: void editFeed(); void activateFeed(); void processFeed(); + void feedTreeReparent(QTreeWidgetItem *item, QTreeWidgetItem *newParent); void messageTabCloseRequested(int index); void messageTabChanged(int index); diff --git a/plugins/FeedReader/gui/FeedReaderDialog.ui b/plugins/FeedReader/gui/FeedReaderDialog.ui index 5eed95bc7..b6b004d69 100644 --- a/plugins/FeedReader/gui/FeedReaderDialog.ui +++ b/plugins/FeedReader/gui/FeedReaderDialog.ui @@ -150,7 +150,7 @@ - + Qt::CustomContextMenu @@ -186,9 +186,9 @@ - RSTreeWidget + FeedTreeWidget QTreeWidget -
gui/common/RSTreeWidget.h
+
gui/FeedTreeWidget.h
RSTabWidget diff --git a/plugins/FeedReader/gui/FeedTreeWidget.cpp b/plugins/FeedReader/gui/FeedTreeWidget.cpp new file mode 100644 index 000000000..37baaf235 --- /dev/null +++ b/plugins/FeedReader/gui/FeedTreeWidget.cpp @@ -0,0 +1,119 @@ +/******************************************************************************* + * plugins/FeedReader/gui/FeedTreeWidget.cpp * + * * + * Copyright (C) 2012 RetroShare Team * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU Affero 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 Affero General Public License for more details. * + * * + * You should have received a copy of the GNU Affero General Public License * + * along with this program. If not, see . * + * * + *******************************************************************************/ + +#include +#include "FeedTreeWidget.h" + +FeedTreeWidget::FeedTreeWidget(QWidget *parent) : RSTreeWidget(parent) +{ + mDraggedItem = NULL; +} + +void FeedTreeWidget::dragEnterEvent(QDragEnterEvent *event) +{ + mDraggedItem = currentItem(); + RSTreeWidget::dragEnterEvent(event); +} + +void FeedTreeWidget::dragLeaveEvent(QDragLeaveEvent *event) +{ + RSTreeWidget::dragLeaveEvent(event); + mDraggedItem = NULL; +} + +bool FeedTreeWidget::canDrop(QDropEvent *event, QTreeWidgetItem **dropItem) +{ + if (dropItem) { + *dropItem = NULL; + } + + if (!mDraggedItem) { + /* no drag item */ + return false; + } + + QModelIndex droppedIndex = indexAt(event->pos()); + if (!droppedIndex.isValid()) { + /* no drop target */ + return false; + } + + QTreeWidgetItem *dropItemIntern = itemFromIndex(droppedIndex); + if (!dropItemIntern) { + /* no drop item */ + return false; + } + + if ((dropItemIntern->flags() & Qt::ItemIsDropEnabled) == 0) { + /* drop is disabled */ + return false; + } + + if (dropItemIntern == mDraggedItem->parent()) { + /* drag item parent */ + return false; + } + + if (dropItem) { + *dropItem = dropItemIntern; + } + + return true; +} + +void FeedTreeWidget::dragMoveEvent(QDragMoveEvent *event) +{ + if (!canDrop(event)) { + event->ignore(); + return; + } + + RSTreeWidget::dragMoveEvent(event); +} + +void FeedTreeWidget::dropEvent(QDropEvent *event) +{ + QTreeWidgetItem *dropItem; + if (!canDrop(event, &dropItem)) { + event->ignore(); + return; + } + + if (!mDraggedItem) { + /* no drag item */ + event->ignore(); + return; + } + + QTreeWidgetItem *draggedParent = mDraggedItem->parent(); + if (!draggedParent) { + /* no drag item parent */ + event->ignore(); + return; + } + + if (!dropItem) { + /* no drop item */ + event->ignore(); + return; + } + + emit feedReparent(mDraggedItem, dropItem); +} diff --git a/plugins/FeedReader/gui/FeedTreeWidget.h b/plugins/FeedReader/gui/FeedTreeWidget.h new file mode 100644 index 000000000..e9eb197a9 --- /dev/null +++ b/plugins/FeedReader/gui/FeedTreeWidget.h @@ -0,0 +1,50 @@ +/******************************************************************************* + * plugins/FeedReader/gui/FeedTreeWidget.h * + * * + * Copyright (C) 2012 by Retroshare Team * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU Affero 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 Affero General Public License for more details. * + * * + * You should have received a copy of the GNU Affero General Public License * + * along with this program. If not, see . * + * * + *******************************************************************************/ + +#ifndef _FEEDTREEWIDGET_H +#define _FEEDTREEWIDGET_H + +#include "gui/common/RSTreeWidget.h" + +/* Subclassing RSTreeWidget */ +class FeedTreeWidget : public RSTreeWidget +{ + Q_OBJECT + +public: + FeedTreeWidget(QWidget *parent = 0); + +Q_SIGNALS: + void feedReparent(QTreeWidgetItem *item, QTreeWidgetItem *newParent); + +protected: + void dragEnterEvent(QDragEnterEvent *event); + void dragLeaveEvent(QDragLeaveEvent *event); + void dragMoveEvent(QDragMoveEvent *event); + void dropEvent(QDropEvent *event); + +private: + bool canDrop(QDropEvent *event, QTreeWidgetItem **dropItem = NULL); + +private: + QTreeWidgetItem *mDraggedItem; +}; + +#endif diff --git a/plugins/FeedReader/interface/rsFeedReader.h b/plugins/FeedReader/interface/rsFeedReader.h index 7158d29ee..6ff39cdc9 100644 --- a/plugins/FeedReader/interface/rsFeedReader.h +++ b/plugins/FeedReader/interface/rsFeedReader.h @@ -216,6 +216,7 @@ public: virtual RsFeedAddResult setFolder(uint32_t feedId, const std::string &name) = 0; virtual RsFeedAddResult addFeed(const FeedInfo &feedInfo, uint32_t &feedId) = 0; virtual RsFeedAddResult setFeed(uint32_t feedId, const FeedInfo &feedInfo) = 0; + virtual RsFeedAddResult setParent(uint32_t feedId, uint32_t parentId) = 0; virtual bool removeFeed(uint32_t feedId) = 0; virtual bool addPreviewFeed(const FeedInfo &feedInfo, uint32_t &feedId) = 0; virtual void getFeedList(uint32_t parentId, std::list &feedInfos) = 0; diff --git a/plugins/FeedReader/lang/FeedReader_en.ts b/plugins/FeedReader/lang/FeedReader_en.ts index f366ccc9c..500c46810 100644 --- a/plugins/FeedReader/lang/FeedReader_en.ts +++ b/plugins/FeedReader/lang/FeedReader_en.ts @@ -194,7 +194,7 @@ - + Edit feed @@ -312,7 +312,7 @@ - + Message Folders @@ -362,7 +362,7 @@ - + No name @@ -418,6 +418,16 @@ Please enter a new name for the folder + + + Move feed + + + + + Cannot move feed. + + FeedReaderFeedItem @@ -520,7 +530,7 @@ - + Title @@ -612,7 +622,7 @@ - + Hide diff --git a/plugins/FeedReader/services/p3FeedReader.cc b/plugins/FeedReader/services/p3FeedReader.cc index 4c2eacaaf..5d861710b 100644 --- a/plugins/FeedReader/services/p3FeedReader.cc +++ b/plugins/FeedReader/services/p3FeedReader.cc @@ -598,6 +598,62 @@ RsFeedAddResult p3FeedReader::setFeed(uint32_t feedId, const FeedInfo &feedInfo) return RS_FEED_ADD_RESULT_SUCCESS; } +RsFeedAddResult p3FeedReader::setParent(uint32_t feedId, uint32_t parentId) +{ + bool changed = false; + + { + RsStackMutex stack(mFeedReaderMtx); /******* LOCK STACK MUTEX *********/ + +#ifdef FEEDREADER_DEBUG + std::cerr << "p3FeedReader::setParent - set parent " << parentId << std::endl; +#endif + + std::map::iterator feedIt = mFeeds.find(feedId); + if (feedIt == mFeeds.end()) { +#ifdef FEEDREADER_DEBUG + std::cerr << "p3FeedReader::setParent - feed id " << feedId << " not found" << std::endl; +#endif + return RS_FEED_ADD_RESULT_FEED_NOT_FOUND; + } + + if (parentId) { + /* check parent id */ + std::map::iterator parentIt = mFeeds.find(parentId); + if (parentIt == mFeeds.end()) { +#ifdef FEEDREADER_DEBUG + std::cerr << "p3FeedReader::setParent - parent id " << parentId << " not found" << std::endl; +#endif + return RS_FEED_ADD_RESULT_PARENT_NOT_FOUND; + } + + if ((parentIt->second->flag & RS_FEED_FLAG_FOLDER) == 0) { +#ifdef FEEDREADER_DEBUG + std::cerr << "p3FeedReader::setParent - parent " << parentIt->second->name << " is no folder" << std::endl; +#endif + return RS_FEED_ADD_RESULT_PARENT_IS_NO_FOLDER; + } + } + + RsFeedReaderFeed *fi = feedIt->second; + + if (fi->parentId != parentId) { + fi->parentId = parentId; + changed = true; + } + } + + if (changed) { + IndicateConfigChanged(); + + if (mNotify) { + mNotify->notifyFeedChanged(feedId, NOTIFY_TYPE_MOD); + } + } + + return RS_FEED_ADD_RESULT_SUCCESS; +} + void p3FeedReader::deleteAllMsgs_locked(RsFeedReaderFeed *fi) { if (!fi) { diff --git a/plugins/FeedReader/services/p3FeedReader.h b/plugins/FeedReader/services/p3FeedReader.h index d60b63ca2..d98259a3b 100644 --- a/plugins/FeedReader/services/p3FeedReader.h +++ b/plugins/FeedReader/services/p3FeedReader.h @@ -59,6 +59,7 @@ public: virtual RsFeedAddResult setFolder(uint32_t feedId, const std::string &name); virtual RsFeedAddResult addFeed(const FeedInfo &feedInfo, uint32_t &feedId); virtual RsFeedAddResult setFeed(uint32_t feedId, const FeedInfo &feedInfo); + virtual RsFeedAddResult setParent(uint32_t feedId, uint32_t parentId); virtual bool removeFeed(uint32_t feedId); virtual bool addPreviewFeed(const FeedInfo &feedInfo, uint32_t &feedId); virtual void getFeedList(uint32_t parentId, std::list &feedInfos);