MailJD nbsp;·nbsp; Test Dashboard nbsp;·nbsp; Coverage
LCOV - code coverage report
Current view: top level - ui - SettingsDialog.h (source / functions) Coverage Total Hit
Test: MailJD Coverage (Unit + E2E) Lines: 100.0 % 2 2
Test Date: 2026-06-21 21:10:19 Functions: 100.0 % 2 2
Legend: Lines:     hit not hit

            Line data    Source code
       1              : #pragma once
       2              : 
       3              : #include <QDialog>
       4              : #include <QMap>
       5              : #include <functional>
       6              : #include <vector>
       7              : 
       8              : class QNetworkAccessManager;
       9              : 
      10              : class QCheckBox;
      11              : class QComboBox;
      12              : class QLabel;
      13              : class QTabWidget;
      14              : class QListWidget;
      15              : class QTableWidget;
      16              : class QPushButton;
      17              : class QLineEdit;
      18              : class AccountFormWidget;
      19              : class ContactStore;
      20              : class CalendarStore;
      21              : class MailCache;
      22              : class NextcloudAuth;
      23              : struct AccountConfig;
      24              : 
      25              : // Settings dialog with tabbed interface.
      26              : // Tab "Accounts": Account list + shared AccountFormWidget for editing.
      27              : // Tab "General": Default view mode and external content policy.
      28              : class SettingsDialog : public QDialog {
      29         6344 :   Q_OBJECT
      30              :   friend class TestSprint55Dialogs;
      31              : #ifdef MAILJD_UNIT_TEST
      32              :   friend class TestSettingsDialogDeep;
      33              : #endif
      34              : 
      35              : public:
      36              :   explicit SettingsDialog(QWidget *parent = nullptr);
      37              : 
      38              :   // Pass the config directory for testing (default:
      39              :   // AccountConfigLoader::defaultConfigDir())
      40              :   void setConfigDir(const QString &dir);
      41              : 
      42              :   // True if account configs were modified (added/deleted/changed).
      43              :   // Only valid after accept(). If false, only view settings changed.
      44            4 :   bool accountsChanged() const { return m_accountsChanged; }
      45              : 
      46              :   void setCache(MailCache *cache);
      47              : 
      48              :   // Fix C: Inject ContactStore for Kontakte tab
      49              :   void setContactStore(ContactStore *store);
      50              :   void setCalendarStore(CalendarStore *store);
      51              : 
      52              : signals:
      53              :   void languageChangeRequested(const QString &locale);
      54              : 
      55              : private slots:
      56              :   void onAccountSelected(int row);
      57              :   void addAccount();
      58              :   void deleteAccount();
      59              :   void saveAll();
      60              : 
      61              : private:
      62              :   // T-304: Runtime language switching
      63              :   void retranslateUi();
      64              : 
      65              : protected:
      66              :   void changeEvent(QEvent *event) override;
      67              : 
      68              :   void setupUi();
      69              :   void setupShortcuts();
      70              :   void loadAccountList();
      71              :   bool hasUnsavedChanges() const;
      72              :   void reject() override; // Override to check unsaved changes
      73              : 
      74              :   QTabWidget *m_tabs = nullptr;
      75              : 
      76              :   // Accounts tab
      77              :   QListWidget *m_accountList = nullptr;
      78              :   AccountFormWidget *m_accountForm = nullptr;
      79              :   QPushButton *m_addButton = nullptr;
      80              :   QPushButton *m_deleteButton = nullptr;
      81              :   QPushButton *m_saveButton = nullptr;
      82              :   QPushButton *m_cancelButton = nullptr;
      83              : 
      84              :   // General tab
      85              :   QComboBox *m_themeCombo = nullptr; // 67.B2: Light/Dark/System
      86              :   QComboBox *m_defaultViewCombo = nullptr;
      87              :   QComboBox *m_externalContentCombo = nullptr;
      88              :   QComboBox *m_languageCombo = nullptr;
      89              : 
      90              :   // Account data
      91              :   std::vector<AccountConfig> m_accounts;
      92              :   int m_currentIndex = -1;
      93              :   bool m_dirty = false;
      94              :   bool m_accountsChanged = false;
      95              : 
      96              :   // Snapshot of accounts at dialog open, used to detect real changes
      97              :   std::vector<AccountConfig> m_originalAccounts;
      98              : 
      99              :   QString m_configDir;
     100              : 
     101              :   // Modal test seams (same pattern as MainWindow/FolderOperationsController):
     102              :   // default to the real Qt dialogs, overridden in unit tests so the CardDAV/
     103              :   // CalDAV account flows run headless.
     104              :   std::function<QString(const QString &title, const QString &label,
     105              :                         const QString &initial, bool *ok)>
     106              :       m_promptText;
     107              :   std::function<bool(const QString &title, const QString &text)> m_confirm;
     108              :   std::function<void(const QString &title, const QString &text)> m_warn;
     109              :   // Test seam: injected into CardDavClient/CalDavClient instances created by
     110              :   // the discover/sync flows so tests can serve canned PROPFIND/REPORT
     111              :   // responses (tests/fake_network.h).
     112              :   QNetworkAccessManager *m_testNam = nullptr;
     113              : 
     114              :   // T-122: Whitelist tab
     115              :   MailCache *m_cache = nullptr;
     116              :   QTableWidget *m_whitelistTable = nullptr;
     117              :   QComboBox *m_whitelistTypeCombo = nullptr;
     118              :   QLineEdit *m_whitelistValueEdit = nullptr;
     119              :   void loadWhitelistTable();
     120              : 
     121              :   // Kontakte tab – multi-server CardDAV
     122              :   struct CdAccount {
     123              :     QString id;          // UUID
     124              :     QString serverUrl;
     125              :     QString username;
     126              :     QString password;
     127              :     QStringList selectedBooks;              // paths to sync
     128              :     QMap<QString, QString> discoveredBooks; // path → displayName
     129              :   };
     130              : 
     131              :   ContactStore *m_contactStore = nullptr;
     132              :   CalendarStore *m_calendarStore = nullptr;
     133              :   NextcloudAuth *m_ncAuth = nullptr;
     134              : 
     135              :   QTableWidget *m_cdAccountTable = nullptr;
     136              :   QPushButton *m_cdAddBtn = nullptr;
     137              :   QPushButton *m_cdRemoveBtn = nullptr;
     138              :   QPushButton *m_cdAuthorizeBtn = nullptr;
     139              :   QListWidget *m_cdBookList = nullptr;
     140              :   QPushButton *m_cdDiscoverBtn = nullptr;
     141              :   QPushButton *m_cdSyncBtn = nullptr;
     142              :   QLabel *m_cdStatusLabel = nullptr;
     143              :   QComboBox *m_cdIntervalCombo = nullptr;
     144              : 
     145              :   std::vector<CdAccount> m_cdAccounts;
     146              :   int m_cdCurrentIdx = -1;
     147              : 
     148              :   // Sprint 73: stable identifier for the account awaiting an async Nextcloud
     149              :   // login flow. Resolved by account ID on loginSuccess so a selection change
     150              :   // during browser login can never write credentials to the wrong account.
     151              :   QString m_pendingDavAuthAccountId;
     152              : 
     153              :   void loadCdAccounts();
     154              :   void saveCdAccounts();
     155              :   QString cdPasswordForAccount(const CdAccount &account) const;
     156              :   // Sprint 73: a DAV account is "locally authorized" only when metadata
     157              :   // (serverUrl + username) and a non-empty keyring secret are all present.
     158              :   // Synced accounts restore metadata but not secrets, so they appear
     159              :   // complete until discovery/sync fails. The UI derives this state on demand
     160              :   // rather than persisting a boolean that could go stale.
     161              :   bool cdAccountHasLocalCredentials(const CdAccount &account) const;
     162              :   int findCdAccountIndexById(const QString &accountId) const;
     163              :   void updateCdAccountTable();
     164              :   void onCdAccountSelected(int row);
     165              :   void addCdAccount();
     166              :   void removeCdAccount();
     167              :   void authorizeCdAccount();
     168              :   void discoverBooks();
     169              :   void syncAllAccounts();
     170              : 
     171              :   // T-315: Sync tab
     172              :   QCheckBox *m_syncEnabledCheck = nullptr;
     173              :   QLineEdit *m_syncFolderEdit = nullptr;
     174              :   QCheckBox *m_syncCatIcons = nullptr;
     175              :   QCheckBox *m_syncCatColors = nullptr;
     176              :   QCheckBox *m_syncCatCalColors = nullptr;
     177              :   QCheckBox *m_syncCatHidden = nullptr;
     178              :   QCheckBox *m_syncCatWhitelist = nullptr;
     179              :   QCheckBox *m_syncCatDav = nullptr;
     180              :   QCheckBox *m_syncCatGeneral = nullptr;
     181              :   QPushButton *m_syncNowBtn = nullptr;
     182              :   QPushButton *m_syncResetBtn = nullptr;
     183              :   QLabel *m_syncStatusLabel = nullptr;
     184              : 
     185              :    // T-335: Kalender tab (Sprint 32)
     186              :   QComboBox *m_calAccountCombo = nullptr;
     187              :   QListWidget *m_calCalendarList = nullptr;
     188              :   QPushButton *m_calDiscoverBtn = nullptr;
     189              :   QPushButton *m_calSyncBtn = nullptr;
     190              :   QLabel *m_calStatusLabel = nullptr;
     191              :   QComboBox *m_calIntervalCombo = nullptr;
     192              :   QLabel *m_calInfoLabel = nullptr;
     193              : 
     194              :   // Sprint 75: opt-in exec-seam for the calendar list context menu.
     195              :   // When m_interceptCalMenuExec is true, the context-menu handler
     196              :   // stores the received global position in m_lastCalMenuExecGlobalPos
     197              :   // and returns WITHOUT calling QMenu::exec() — so unit tests can
     198              :   // deterministically assert the exec coordinate (viewport-mapped via
     199              :   // QListWidget::viewport()->mapToGlobal) without blocking in the
     200              :   // popup event loop and without relying on QMenu's post-adjustment
     201              :   // screen geometry. Production and the default test path keep the
     202              :   // real exec().
     203              :   bool m_interceptCalMenuExec = false;
     204              :   QPoint m_lastCalMenuExecGlobalPos;
     205              : 
     206              :   struct CalConfig {
     207              :     QString carddavAccountId;
     208              :     QStringList selectedCalendars;
     209              :     QStringList readOnlyCalendars;
     210              :     QMap<QString, QString> discoveredCalendars; // path → displayName
     211              :     int syncIntervalMinutes = 15;
     212              :   };
     213              :   std::vector<CalConfig> m_calConfigs;
     214              : 
     215              :   void loadCalConfigs();
     216              :   void saveCalConfigs();
     217              :   void onCalAccountSelected(int index);
     218              :   void discoverCalendars();
     219              :   void syncCalendars();
     220              :   int findCalConfigForAccount(const QString &accountId) const;
     221              : 
     222              : signals:
     223              :   void calendarSyncRequested();
     224              :   void syncRequested();
     225              :   void syncResetRequested();
     226              :   void syncSettingsChanged();
     227              : };
        

Generated by: LCOV version 2.0-1