presentation/QuickFolderActions.h
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #pragma once | ||
| 2 | |||
| 3 | #include "FolderIconCatalog.h" | ||
| 4 | #include "data/Models.h" | ||
| 5 | #include <QAbstractItemModel> | ||
| 6 | #include <QObject> | ||
| 7 | #include <QSet> | ||
| 8 | |||
| 9 | #include <initializer_list> | ||
| 10 | #include <QThreadPool> | ||
| 11 | #include <QVariantMap> | ||
| 12 | #include <functional> | ||
| 13 | #include <memory> | ||
| 14 | |||
| 15 | class FolderPresentationModel; | ||
| 16 | class MailSessionCore; | ||
| 17 | struct FolderInfo; | ||
| 18 | |||
| 19 | // Folder operations, folder properties/appearance and cache maintenance of | ||
| 20 | // the Quick frontend (Sprint 91 S91.2.1, extracted from QuickMailBackend). | ||
| 21 | // QML reaches it as `backend.folderActions` (`backend.folders` is the | ||
| 22 | // folder tree model). | ||
| 23 | // | ||
| 24 | // Owner: QuickMailBackend (value member). GUI thread only; folder | ||
| 25 | // statistics run on the unit's own single-thread pool with a read-only | ||
| 26 | // cache connection. The folder list itself (FolderInfo list, selectable | ||
| 27 | // paths, current path, presentation model) stays owned by the backend and | ||
| 28 | // is read through references; the backend also keeps the IMAP | ||
| 29 | // folder-operation result handlers (wireFolderOperations), because they | ||
| 30 | // rewrite that list. Deps call back into the backend for status feedback, | ||
| 31 | // re-applying the folder list and dropping a folder's thread snapshot. | ||
| 32 | class QuickFolderActions final : public QObject { | ||
| 33 | 43 | Q_OBJECT | |
| 34 | Q_PROPERTY(QAbstractItemModel *folderIcons READ folderIcons CONSTANT) | ||
| 35 | public: | ||
| 36 | struct Deps { | ||
| 37 | std::function<bool()> configured; | ||
| 38 | std::function<QString()> accountName; | ||
| 39 | std::function<void(const QString &)> setStatus; | ||
| 40 | std::function<void(const QString &)> reportError; | ||
| 41 | // applyFolderList(folderInfos, false) on the backend. | ||
| 42 | std::function<void()> reapplyFolderList; | ||
| 43 | // Invalidate the backend's retained thread snapshot of this folder. | ||
| 44 | std::function<void(const QString &)> forgetFolderProjection; | ||
| 45 | }; | ||
| 46 | QuickFolderActions(MailSessionCore &session, FolderPresentationModel &folders, | ||
| 47 | const QList<FolderInfo> &folderInfos, | ||
| 48 | const QSet<QString> &availableFolders, const QString &folderPath, | ||
| 49 | const QString &profileDirectory, Deps deps, QObject *parent = nullptr); | ||
| 50 | |||
| 51 | QAbstractItemModel *folderIcons(); | ||
| 52 | // Folder properties popup (Widgets FolderPropertiesDialog parity). | ||
| 53 | // Appearance lives in QSettings folder/icon/<path> and folder/color/<path> | ||
| 54 | // (settings-sync categories folderIcons/folderColors). | ||
| 55 | Q_INVOKABLE QVariantMap folderProperties(const QString &path); | ||
| 56 | Q_INVOKABLE bool saveFolderProperties(const QString &path, const QString &icon, const QString &color, | ||
| 57 | bool subscribed, bool hidden); | ||
| 58 | // Cache statistics run on a worker connection; folderStatisticsReady follows. | ||
| 59 | Q_INVOKABLE void requestFolderStatistics(const QString &path); | ||
| 60 | Q_INVOKABLE bool clearFolderBodyCache(const QString &path); | ||
| 61 | Q_INVOKABLE bool clearFolderCache(const QString &path); | ||
| 62 | Q_INVOKABLE int iconGlyph(const QString &name); | ||
| 63 | // Sprint 95: "Rules for this folder…" while the account has server rules. | ||
| 64 | 892 | void setRulesMenuEnabled(bool enabled) { m_rulesMenu = enabled; } | |
| 65 | Q_PROPERTY(bool rulesMenuEnabled READ rulesMenuEnabled CONSTANT) | ||
| 66 | ✗ | bool rulesMenuEnabled() const { return m_rulesMenu; } | |
| 67 | // Folder context menu as a platform (QMenu) popup at the pointer: native | ||
| 68 | // style and exact position. False without widget menus (QGuiApplication | ||
| 69 | // hosts); QML then opens its own menu. The choice is reported through | ||
| 70 | // folderContextActionRequested(action, path). | ||
| 71 | Q_INVOKABLE bool showFolderContextMenu(const QString &path, QObject *window, qreal sceneX, qreal sceneY); | ||
| 72 | // Folder operations (D1): CREATE/DENAME/DELETE through the session IMAP | ||
| 73 | // transport with the Widgets protection rules (INBOX and special-use | ||
| 74 | // folders cannot be deleted; deletion cascades to subfolders bottom-up). | ||
| 75 | Q_INVOKABLE bool createFolder(const QString &name); | ||
| 76 | Q_INVOKABLE bool deleteFolder(const QString &folderPath); | ||
| 77 | // RENAME through the session transport; protected folders (INBOX, | ||
| 78 | // special-use) are rejected and the new name is validated as exactly one | ||
| 79 | // hierarchy level. | ||
| 80 | Q_INVOKABLE bool renameFolder(const QString &folderPath, const QString &newName); | ||
| 81 | // Moves a folder under a new parent (empty parent = top level) via RENAME. | ||
| 82 | // Rejects protected folders, unknown parents and self/descendant targets. | ||
| 83 | Q_INVOKABLE bool moveFolder(const QString &folderPath, const QString &newParentPath); | ||
| 84 | // The decoded last path component (rename prefill, notifications). | ||
| 85 | Q_INVOKABLE QString folderLeafName(const QString &folderPath) const; | ||
| 86 | Q_INVOKABLE bool folderIsProtected(const QString &folderPath) const; | ||
| 87 | Q_INVOKABLE QStringList childFolders(const QString &folderPath) const; | ||
| 88 | // Hierarchy delimiter of the account's folder list ("/" by default). | ||
| 89 | QString folderDelimiter() const; | ||
| 90 | // F-49 (SPRINT-104): special-folder name matching on the whole path or | ||
| 91 | // its last component, and the three-step role resolution (assignment → | ||
| 92 | // flag → common names) over a folder list. | ||
| 93 | static bool matchesSpecialName(const QString &path, const QString &delimiter, | ||
| 94 | std::initializer_list<const char *> names); | ||
| 95 | static QString resolveSpecialFolder(const QList<FolderInfo> &folders, const QString &delimiter, | ||
| 96 | const QString &account, const QString &settingKey, | ||
| 97 | bool (FolderInfo::*flag)() const, | ||
| 98 | std::initializer_list<const char *> names); | ||
| 99 | // Publish icon glyphs and colors of the current folder list. | ||
| 100 | void refreshFolderAppearance(); | ||
| 101 | |||
| 102 | signals: | ||
| 103 | void folderContextActionRequested(const QString &action, const QString &path); | ||
| 104 | void folderStatisticsReady(const QString &path, const QVariantMap &statistics); | ||
| 105 | |||
| 106 | private: | ||
| 107 | QString wireLeaf(const QString &folderPath) const; | ||
| 108 | MailSessionCore &m_session; | ||
| 109 | FolderPresentationModel &m_folders; // owned by QuickMailBackend | ||
| 110 | const QList<FolderInfo> &m_folderInfos; // owned by QuickMailBackend | ||
| 111 | const QSet<QString> &m_availableFolders; // owned by QuickMailBackend | ||
| 112 | const QString &m_folderPath; // owned by QuickMailBackend | ||
| 113 | const QString &m_profileDirectory; // owned by QuickMailBackend | ||
| 114 | Deps m_deps; | ||
| 115 | FolderIconCatalog m_iconCatalog; | ||
| 116 | std::unique_ptr<FolderIconListModel> m_iconList; | ||
| 117 | QThreadPool m_folderStatsPool; | ||
| 118 | quint64 m_folderStatsSequence = 0; | ||
| 119 | bool m_rulesMenu = false; | ||
| 120 | }; | ||
| 121 |