This commit is contained in:
Martin Rotter 2022-10-14 13:59:06 +02:00
parent 49785b348a
commit edb8ec5866
3 changed files with 62 additions and 35 deletions

View file

@ -19,25 +19,19 @@ class QAction;
// NOTE: This class is derived to add functionality for // NOTE: This class is derived to add functionality for
// all other non-root items of FeedsModel. // all other non-root items of FeedsModel.
class RSSGUARD_DLLSPEC RootItem : public QObject { class RSSGUARD_DLLSPEC RootItem : public QObject {
Q_OBJECT Q_OBJECT
// Added for message filtering with labels. // Added for message filtering with labels.
Q_PROPERTY(QString title READ title) Q_PROPERTY(QString title READ title)
Q_PROPERTY(int id READ id) Q_PROPERTY(int id READ id)
Q_PROPERTY(QString customId READ customId) Q_PROPERTY(QString customId READ customId)
public: public:
enum class ReadStatus { enum class ReadStatus { Unread = 0, Read = 1 };
Unread = 0,
Read = 1
};
// Holds statuses for messages // Holds statuses for messages
// to be switched importance (starred). // to be switched importance (starred).
enum class Importance { enum class Importance { NotImportant = 0, Important = 1 };
NotImportant = 0,
Important = 1
};
// Describes the kind of the item. // Describes the kind of the item.
enum class Kind { enum class Kind {
@ -119,6 +113,8 @@ class RSSGUARD_DLLSPEC RootItem : public QObject {
int childCount() const; int childCount() const;
void appendChild(RootItem* child); void appendChild(RootItem* child);
QList<RootItem*> childItems() const; QList<RootItem*> childItems() const;
QList<RootItem*>& childItems();
void clearChildren(); void clearChildren();
void setChildItems(const QList<RootItem*>& child_items); void setChildItems(const QList<RootItem*>& child_items);
@ -254,6 +250,10 @@ inline QList<RootItem*> RootItem::childItems() const {
return m_childItems; return m_childItems;
} }
inline QList<RootItem*>& RootItem::childItems() {
return m_childItems;
}
inline void RootItem::clearChildren() { inline void RootItem::clearChildren() {
m_childItems.clear(); m_childItems.clear();
} }

View file

@ -260,17 +260,6 @@ bool ServiceRoot::cleanFeeds(const QList<Feed*>& items, bool clean_read_only) {
} }
} }
void ServiceRoot::storeNewFeedTree(RootItem* root) {
try {
DatabaseQueries::storeAccountTree(qApp->database()->driver()->connection(metaObject()->className()),
root,
accountId());
}
catch (const ApplicationException& ex) {
qFatal("Cannot store account tree: '%s'.", qPrintable(ex.message()));
}
}
void ServiceRoot::removeLeftOverMessages() { void ServiceRoot::removeLeftOverMessages() {
QSqlDatabase database = qApp->database()->driver()->connection(metaObject()->className()); QSqlDatabase database = qApp->database()->driver()->connection(metaObject()->className());
@ -379,13 +368,21 @@ QMap<QString, QVariantMap> ServiceRoot::storeCustomFeedsData() {
QVariantMap feed_custom_data; QVariantMap feed_custom_data;
// TODO: This could potentially call Feed::customDatabaseData() and append it // TODO: This could potentially call Feed::customDatabaseData() and append it
// to this map and also subsequently restore. // to this map and also subsequently restore, but the method is at this point
// not really used by any syncable plugin.
feed_custom_data.insert(QSL("auto_update_interval"), feed->autoUpdateInterval()); feed_custom_data.insert(QSL("auto_update_interval"), feed->autoUpdateInterval());
feed_custom_data.insert(QSL("auto_update_type"), int(feed->autoUpdateType())); feed_custom_data.insert(QSL("auto_update_type"), int(feed->autoUpdateType()));
feed_custom_data.insert(QSL("msg_filters"), QVariant::fromValue(feed->messageFilters())); feed_custom_data.insert(QSL("msg_filters"), QVariant::fromValue(feed->messageFilters()));
feed_custom_data.insert(QSL("is_off"), feed->isSwitchedOff()); feed_custom_data.insert(QSL("is_off"), feed->isSwitchedOff());
feed_custom_data.insert(QSL("open_articles_directly"), feed->openArticlesDirectly()); feed_custom_data.insert(QSL("open_articles_directly"), feed->openArticlesDirectly());
// NOTE: These are here specifically to be able to restore custom sort order.
// Otherwise the information is lost when list of feeds/folders is refreshed from remote
// service.
feed_custom_data.insert(QSL("sort_order"), feed->sortOrder());
feed_custom_data.insert(QSL("custom_id"), feed->customId());
feed_custom_data.insert(QSL("category"), feed->parent()->id());
custom_data.insert(feed->customId(), feed_custom_data); custom_data.insert(feed->customId(), feed_custom_data);
} }
@ -459,12 +456,17 @@ void ServiceRoot::syncIn() {
cleanAllItemsFromModel(uses_remote_labels); cleanAllItemsFromModel(uses_remote_labels);
removeOldAccountFromDatabase(false, uses_remote_labels); removeOldAccountFromDatabase(false, uses_remote_labels);
// Re-sort items to accomodate current sort order.
resortAccountTree(new_tree, feed_custom_data);
// Restore some local settings to feeds etc. // Restore some local settings to feeds etc.
restoreCustomFeedsData(feed_custom_data, new_tree->getHashedSubTreeFeeds()); restoreCustomFeedsData(feed_custom_data, new_tree->getHashedSubTreeFeeds());
// Model is clean, now store new tree into DB and // Model is clean, now store new tree into DB and
// set primary IDs of the items. // set primary IDs of the items.
storeNewFeedTree(new_tree); DatabaseQueries::storeAccountTree(qApp->database()->driver()->connection(metaObject()->className()),
new_tree,
accountId());
// We have new feed, some feeds were maybe removed, // We have new feed, some feeds were maybe removed,
// so remove left over messages and filter assignments. // so remove left over messages and filter assignments.
@ -880,6 +882,34 @@ void ServiceRoot::assembleFeeds(const Assignment& feeds) {
} }
} }
void ServiceRoot::resortAccountTree(RootItem* tree, const QMap<QString, QVariantMap>& custom_data) const {
// Iterate tree and rearrange children.
QList<RootItem*> traversable_items;
traversable_items.append(tree);
while (!traversable_items.isEmpty()) {
auto* root = traversable_items.takeFirst();
auto& chldr = root->childItems();
// Sort children so that we are sure that feeds are sorted with sort order
// other item types do not matter.
std::sort(chldr.begin(), chldr.end(), [&](const RootItem* lhs, const RootItem* rhs) {
if (lhs->kind() == RootItem::Kind::Feed && rhs->kind() == RootItem::Kind::Feed) {
auto lhs_order = custom_data[lhs->customId()].value(QSL("sort_order")).toInt();
auto rhs_order = custom_data[rhs->customId()].value(QSL("sort_order")).toInt();
return lhs_order < rhs_order;
}
else {
return lhs->kind() < rhs->kind();
}
});
traversable_items.append(root->childItems());
}
}
void ServiceRoot::assembleCategories(const Assignment& categories) { void ServiceRoot::assembleCategories(const Assignment& categories) {
Assignment editable_categories = categories; Assignment editable_categories = categories;
QHash<int, RootItem*> assignments; QHash<int, RootItem*> assignments;

View file

@ -28,7 +28,7 @@ class CacheForServiceRoot;
// NOTE: The root usually contains some core functionality of the // NOTE: The root usually contains some core functionality of the
// service like service account username/password etc. // service like service account username/password etc.
class ServiceRoot : public RootItem { class ServiceRoot : public RootItem {
Q_OBJECT Q_OBJECT
public: public:
enum class LabelOperation { enum class LabelOperation {
@ -41,11 +41,7 @@ class ServiceRoot : public RootItem {
Synchronised = 8 Synchronised = 8
}; };
enum class BagOfMessages { enum class BagOfMessages { Read, Unread, Starred };
Read,
Unread,
Starred
};
public: public:
explicit ServiceRoot(RootItem* parent = nullptr); explicit ServiceRoot(RootItem* parent = nullptr);
@ -70,7 +66,8 @@ class ServiceRoot : public RootItem {
virtual void setCustomDatabaseData(const QVariantHash& data); virtual void setCustomDatabaseData(const QVariantHash& data);
virtual bool wantsBaggedIdsOfExistingMessages() const; virtual bool wantsBaggedIdsOfExistingMessages() const;
virtual void aboutToBeginFeedFetching(const QList<Feed*>& feeds, virtual void aboutToBeginFeedFetching(const QList<Feed*>& feeds,
const QHash<QString, QHash<ServiceRoot::BagOfMessages, QStringList>>& stated_messages, const QHash<QString, QHash<ServiceRoot::BagOfMessages, QStringList>>&
stated_messages,
const QHash<QString, QStringList>& tagged_messages); const QHash<QString, QStringList>& tagged_messages);
// Returns list of specific actions for "Add new item" main window menu. // Returns list of specific actions for "Add new item" main window menu.
@ -233,14 +230,12 @@ class ServiceRoot : public RootItem {
virtual void syncIn(); virtual void syncIn();
protected: protected:
// This method should obtain new tree of feed/categories/whatever to perform sync in. // This method should obtain new tree of feed/categories/whatever to perform sync in.
virtual RootItem* obtainNewTreeForSyncIn() const; virtual RootItem* obtainNewTreeForSyncIn() const;
// Removes all messages/categories/feeds which are // Removes all messages/categories/feeds which are
// associated with this account. // associated with this account.
void removeOldAccountFromDatabase(bool delete_messages_too, bool delete_labels_too); void removeOldAccountFromDatabase(bool delete_messages_too, bool delete_labels_too);
void storeNewFeedTree(RootItem* root);
void cleanAllItemsFromModel(bool clean_labels_too); void cleanAllItemsFromModel(bool clean_labels_too);
void appendCommonNodes(); void appendCommonNodes();
@ -278,6 +273,8 @@ class ServiceRoot : public RootItem {
void itemRemovalRequested(RootItem* item); void itemRemovalRequested(RootItem* item);
private: private:
void resortAccountTree(RootItem* tree, const QMap<QString, QVariantMap>& custom_data) const;
virtual QMap<QString, QVariantMap> storeCustomFeedsData(); virtual QMap<QString, QVariantMap> storeCustomFeedsData();
virtual void restoreCustomFeedsData(const QMap<QString, QVariantMap>& data, const QHash<QString, Feed*>& feeds); virtual void restoreCustomFeedsData(const QMap<QString, QVariantMap>& data, const QHash<QString, Feed*>& feeds);