// For license of this file, see /LICENSE.md. #ifndef SERVICEROOT_H #define SERVICEROOT_H #include "services/abstract/rootitem.h" #include "core/message.h" #include "core/messagefilter.h" #include "definitions/typedefs.h" #include #include #include class QAction; class QMutex; class FeedsModel; class RecycleBin; class ImportantNode; class UnreadNode; class SearchsNode; class LabelsNode; class Label; class MessagesModel; class CustomMessagePreviewer; class CacheForServiceRoot; // THIS IS the root node of the service. // NOTE: The root usually contains some core functionality of the // service like service account username/password etc. class ServiceRoot : public RootItem { Q_OBJECT public: enum class LabelOperation { Adding = 1, Editing = 2, Deleting = 4, // NOTE: Service fetches list of labels from remote source // and does not use local offline labels. Synchronised = 8 }; enum class BagOfMessages { Read, Unread, Starred }; public: explicit ServiceRoot(RootItem* parent = nullptr); virtual ~ServiceRoot(); // These methods bellow are part of "interface". RecycleBin* recycleBin() const; ImportantNode* importantNode() const; LabelsNode* labelsNode() const; SearchsNode* probesNode() const; UnreadNode* unreadNode() const; virtual void updateCounts(bool including_total_count); virtual bool canBeDeleted() const; virtual bool deleteViaGui(); virtual bool markAsReadUnread(ReadStatus status); virtual QList undeletedMessages() const; virtual bool supportsFeedAdding() const; virtual bool supportsCategoryAdding() const; virtual LabelOperation supportedLabelOperations() const; virtual QString additionalTooltip() const; virtual void saveAccountDataToDatabase(); virtual QVariantHash customDatabaseData() const; virtual void setCustomDatabaseData(const QVariantHash& data); virtual bool wantsBaggedIdsOfExistingMessages() const; virtual bool displaysEnclosures() const; virtual void aboutToBeginFeedFetching(const QList& feeds, const QHash>& stated_messages, const QHash& tagged_messages); // Returns list of specific actions for "Add new item" main window menu. // So typical list of returned actions could look like: // a) Add new feed // b) Add new category // c) ... // NOTE: Caller does NOT take ownership of created menu/actions! virtual QList addItemMenu(); // NOTE: Caller does NOT take ownership of created menu/actions! virtual QList contextMenuFeedsList(); // NOTE: Caller does NOT take ownership of created menu/actions! virtual QList contextMenuMessagesList(const QList& messages); // Returns list of specific actions to be shown in main window menu // bar in sections "Services -> 'this service'". // NOTE: Caller does NOT take ownership of created menu! virtual QList serviceMenu(); // If plugin uses online synchronization of feeds/labels/etc, then returns true. virtual bool isSyncable() const; // Start/stop services. // Start method is called when feed model gets initialized OR after user adds new service. // Account should synchronously initialize its children (load them from DB is recommended // here). // // Stop method is called just before application exits OR when // user explicitly deletes existing service instance. virtual void start(bool freshly_activated); virtual void stop(); // Obtains list of messages. // Throws exception subclassed from ApplicationException, preferably FeedFetchException // if any problems arise. virtual QList obtainNewMessages(Feed* feed, const QHash& stated_messages, const QHash& tagged_messages) = 0; // Returns special widget to display articles of this account type. // Caller does NOT free returned previewer after usage from memory, // it only may hide it. // Thus, account is responsible to free any custom previewers. virtual CustomMessagePreviewer* customMessagePreviewer(); // This method should load messages for given "item" into model. virtual bool loadMessagesForItem(RootItem* item, MessagesModel* model); // Called BEFORE this read status update (triggered by user in message list) is stored in DB, // when false is returned, change is aborted. // This is the place to make some other changes like updating // some ONLINE service or something. // // "read" is status which is ABOUT TO BE SET. virtual bool onBeforeSetMessagesRead(RootItem* selected_item, const QList& messages, ReadStatus read); // Called AFTER this read status update (triggered by user in message list) is stored in DB, // when false is returned, change is aborted. // Here service root should inform (via signals) // which items are actually changed. // // "read" is status which is ABOUT TO BE SET. virtual bool onAfterSetMessagesRead(RootItem* selected_item, const QList& messages, ReadStatus read); // Called BEFORE this importance switch update is stored in DB, // when false is returned, change is aborted. // This is the place to make some other changes like updating // some ONLINE service or something. // // "changes" - list of pairs - virtual bool onBeforeSwitchMessageImportance(RootItem* selected_item, const QList& changes); // Called AFTER this importance switch update is stored in DB, // when false is returned, change is aborted. // Here service root should inform (via signals) // which items are actually changed. // // "changes" - list of pairs - virtual bool onAfterSwitchMessageImportance(RootItem* selected_item, const QList& changes); // Called BEFORE the list of messages is about to be deleted // by the user from message list. virtual bool onBeforeMessagesDelete(RootItem* selected_item, const QList& messages); // Called AFTER the list of messages was deleted // by the user from message list. virtual bool onAfterMessagesDelete(RootItem* selected_item, const QList& messages); // Called BEFORE some labels are assigned/deassigned from/to messages. virtual bool onBeforeLabelMessageAssignmentChanged(const QList& labels, const QList& messages, bool assign); // Called AFTER some labels are assigned/deassigned from/to messages. virtual bool onAfterLabelMessageAssignmentChanged(const QList& labels, const QList& messages, bool assign); // Called BEFORE the list of messages is about to be restored from recycle bin // by the user from message list. // Selected item is naturally recycle bin. virtual bool onBeforeMessagesRestoredFromBin(RootItem* selected_item, const QList& messages); // Called AFTER the list of messages was restored from recycle bin // by the user from message list. // Selected item is naturally recycle bin. virtual bool onAfterMessagesRestoredFromBin(RootItem* selected_item, const QList& messages); // Returns the UNIQUE code of the given service. // NOTE: Keep in sync with ServiceEntryRoot::code(). virtual QString code() const = 0; public: CacheForServiceRoot* toCache() const; // Account ID corresponds with DB attribute Accounts (id). int accountId() const; void setAccountId(int account_id); QNetworkProxy networkProxy() const; void setNetworkProxy(const QNetworkProxy& network_proxy); // Removes all data associated with this account from DB // and from model. void completelyRemoveAllData(); // Returns counts of updated messages . QPair updateMessages(QList& messages, Feed* feed, bool force_update, QMutex* db_mutex); QIcon feedIconForMessage(const QString& feed_custom_id) const; // Removes all/read only messages from given underlying feeds. bool cleanFeeds(const QList& items, bool clean_read_only); // Marks all messages from feeds read/unread. bool markFeedsReadUnread(const QList& items, ReadStatus read); // Obvious methods to wrap signals. void itemChanged(const QList& items); void requestReloadMessageList(bool mark_selected_messages_read); void requestItemExpand(const QList& items, bool expand); void requestItemExpandStateSave(RootItem* subtree_root); void requestItemReassignment(RootItem* item, RootItem* new_parent); void requestItemRemoval(RootItem* item); // Some message/feed attribute selectors. QStringList textualFeedUrls(const QList& feeds) const; QStringList textualFeedIds(const QList& feeds) const; QStringList customIDsOfMessages(const QList& changes); QStringList customIDsOfMessages(const QList& messages); // Returns list of article IDs depending on what target operation is. // NOTE: So if we want to mark some articles as read, // then we only return UNREAD IDs here to really return // only IDs when the change makes sense. // NOTE: Importance is not dealt here because it was not needed // yet. QStringList customIDSOfMessagesForItem(RootItem* item, RootItem::ReadStatus target_read = RootItem::ReadStatus::Unknown); void performInitialAssembly(const Assignment& categories, const Assignment& feeds, const QList& labels, const QList& probes); public slots: virtual void addNewFeed(RootItem* selected_item, const QString& url = QString()); virtual void addNewCategory(RootItem* selected_item); virtual void syncIn(); protected: // This method should obtain new tree of feed/categories/whatever to perform sync in. virtual RootItem* obtainNewTreeForSyncIn() const; // Removes all messages/categories/feeds which are // associated with this account. void removeOldAccountFromDatabase(bool delete_messages_too, bool delete_labels_too); void cleanAllItemsFromModel(bool clean_labels_too); void appendCommonNodes(); // Removes messages which do not belong to any // existing feed. // // NOTE: This situation may happen if user deletes some feed // from another machine and then performs sync-in on this machine. void removeLeftOverMessages(); // Removes all msg. filter assignments which are (within this account) // assigned to feed (via custom ID) which does not exist anymore. // // NOTE: This situation may happen if user deletes some feed // from another machine and then performs sync-in on this machine. void removeLeftOverMessageFilterAssignments(); // Takes lists of feeds/categories and assembles them into the tree structure. void assembleCategories(const Assignment& categories); void assembleFeeds(const Assignment& feeds); signals: void proxyChanged(QNetworkProxy proxy); void dataChanged(QList items); void reloadMessageListRequested(bool mark_selected_messages_read); void itemExpandRequested(QList items, bool expand); void itemExpandStateSaveRequested(RootItem* subtree_root); void itemReassignmentRequested(RootItem* item, RootItem* new_parent); void itemRemovalRequested(RootItem* item); private: void resortAccountTree(RootItem* tree, const QMap& custom_category_data, const QMap& custom_feed_data) const; // Key is feed's custom ID. virtual QMap storeCustomFeedsData(); // Key is category's custom ID. virtual QMap storeCustomCategoriesData(); virtual void restoreCustomFeedsData(const QMap& data, const QHash& feeds); virtual void restoreCustomCategoriesData(const QMap& data, const QHash& cats); protected: RecycleBin* m_recycleBin; ImportantNode* m_importantNode; LabelsNode* m_labelsNode; SearchsNode* m_probesNode; UnreadNode* m_unreadNode; int m_accountId; QList m_serviceMenu; QNetworkProxy m_networkProxy; }; #if QT_VERSION_MAJOR == 6 inline size_t qHash(ServiceRoot::BagOfMessages key, size_t seed) { return ::qHash(static_cast(key), seed); } #else inline uint qHash(ServiceRoot::BagOfMessages key, uint seed) { return ::qHash(static_cast(key), seed); } #endif ServiceRoot::LabelOperation operator|(ServiceRoot::LabelOperation lhs, ServiceRoot::LabelOperation rhs); ServiceRoot::LabelOperation operator&(ServiceRoot::LabelOperation lhs, ServiceRoot::LabelOperation rhs); #endif // SERVICEROOT_H