MailJD nbsp;·nbsp; Test Dashboard nbsp;·nbsp; Coverage
LCOV - code coverage report
Current view: top level - ui - AccountFormWidget.cpp (source / functions) Coverage Total Hit
Test: MailJD Coverage (Unit + E2E) Lines: 92.3 % 297 274
Test Date: 2026-07-27 17:53:44 Functions: 96.0 % 25 24
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 44.4 % 738 328

             Branch data     Line data    Source code
       1                 :             : #include "AccountFormWidget.h"
       2                 :             : 
       3                 :             : #include <QAction>
       4                 :             : #include <QComboBox>
       5                 :             : #include <QEvent>
       6                 :             : #include <QFormLayout>
       7                 :             : #include <QGroupBox>
       8                 :             : #include <QHBoxLayout>
       9                 :             : #include <QLabel>
      10                 :             : #include <QLineEdit>
      11                 :             : #include <QLoggingCategory>
      12                 :             : #include <QPushButton>
      13                 :             : #include <QSpinBox>
      14                 :             : #include <QTimer>
      15                 :             : #include <QVBoxLayout>
      16                 :             : #include <QEvent>
      17                 :             : 
      18                 :             : #include "data/AccountConfig.h"
      19                 :             : #include "service/ImapService.h"
      20                 :             : #include "ui/ThemeManager.h"
      21                 :             : 
      22   [ #  #  #  #  :           0 : Q_LOGGING_CATEGORY(lcAccountForm, "mailjd.accountform")
             #  #  #  # ]
      23                 :             : 
      24         [ +  - ]:          99 : AccountFormWidget::AccountFormWidget(QWidget *parent) : QWidget(parent) {
      25         [ +  - ]:          99 :   setupUi();
      26         [ +  - ]:          99 :   setupTabOrder();
      27         [ +  - ]:          99 :   connectFieldSignals();
      28                 :          99 : }
      29                 :             : 
      30                 :         190 : AccountFormWidget::~AccountFormWidget() {
      31                 :             :   // Clean up test service if running
      32         [ -  + ]:          99 :   if (m_testService) {
      33                 :           0 :     m_testService->disconnect();
      34                 :           0 :     m_testService->deleteLater();
      35                 :           0 :     m_testService = nullptr;
      36                 :             :   }
      37                 :         190 : }
      38                 :             : 
      39                 :          99 : void AccountFormWidget::setupUi() {
      40   [ +  -  -  +  :          99 :   auto *mainLayout = new QVBoxLayout(this);
                   -  - ]
      41                 :          99 :   mainLayout->setContentsMargins(0, 0, 0, 0);
      42                 :             : 
      43                 :             :   // --- Account basics ---
      44   [ +  -  -  +  :          99 :   auto *basicsLayout = new QFormLayout();
                   -  - ]
      45   [ +  -  -  +  :          99 :   m_nameEdit = new QLineEdit(this);
                   -  - ]
      46   [ +  -  +  - ]:          99 :   m_nameEdit->setPlaceholderText(tr("e.g. Personal, Work"));
      47   [ +  -  -  +  :          99 :   m_emailEdit = new QLineEdit(this);
                   -  - ]
      48   [ +  -  +  - ]:          99 :   m_emailEdit->setPlaceholderText("user@example.com");
      49   [ +  -  +  -  :          99 :   m_nameLabel = new QLabel(tr("&Name:"), this);
             -  +  -  - ]
      50                 :          99 :   m_nameLabel->setBuddy(m_nameEdit);
      51                 :          99 :   basicsLayout->addRow(m_nameLabel, m_nameEdit);
      52   [ +  -  +  -  :          99 :   m_emailLabel = new QLabel(tr("&Email:"), this);
             -  +  -  - ]
      53                 :          99 :   m_emailLabel->setBuddy(m_emailEdit);
      54                 :          99 :   basicsLayout->addRow(m_emailLabel, m_emailEdit);
      55                 :          99 :   mainLayout->addLayout(basicsLayout);
      56                 :             : 
      57                 :             :   // --- IMAP group ---
      58   [ +  -  +  -  :          99 :   m_imapGroup = new QGroupBox(tr("IMAP Server (Incoming)"), this);
             -  +  -  - ]
      59   [ +  -  -  +  :          99 :   auto *imapLayout = new QFormLayout(m_imapGroup);
                   -  - ]
      60                 :             : 
      61   [ +  -  -  +  :          99 :   m_imapHost = new QLineEdit(this);
                   -  - ]
      62   [ +  -  +  - ]:          99 :   m_imapHost->setPlaceholderText("imap.example.com");
      63   [ +  -  -  +  :          99 :   m_imapPort = new QSpinBox(this);
                   -  - ]
      64                 :          99 :   m_imapPort->setRange(1, 65535);
      65                 :          99 :   m_imapPort->setValue(993);
      66   [ +  -  -  +  :          99 :   m_imapSecurity = new QComboBox(this);
                   -  - ]
      67   [ +  -  +  -  :          99 :   m_imapSecurity->addItem("SSL/TLS", "ssl");
                   +  - ]
      68   [ +  -  +  -  :          99 :   m_imapSecurity->addItem("STARTTLS", "starttls");
                   +  - ]
      69   [ +  -  -  +  :          99 :   m_imapUsername = new QLineEdit(this);
                   -  - ]
      70   [ +  -  +  - ]:          99 :   m_imapUsername->setPlaceholderText("user@example.com");
      71   [ +  -  -  +  :          99 :   m_imapPassword = new QLineEdit(this);
                   -  - ]
      72                 :          99 :   m_imapPassword->setEchoMode(QLineEdit::Password);
      73   [ +  -  +  - ]:          99 :   m_imapPassword->setPlaceholderText(tr("Password"));
      74                 :             :   // Password visibility toggle via action
      75         [ +  - ]:          99 :   m_imapToggleAction = m_imapPassword->addAction(
      76   [ +  -  +  - ]:         198 :       style()->standardIcon(QStyle::SP_FileDialogDetailedView),
      77                 :             :       QLineEdit::TrailingPosition);
      78   [ +  -  +  - ]:          99 :   m_imapToggleAction->setToolTip(tr("Show/hide password (Alt+P)"));
      79   [ +  -  +  -  :          99 :   m_imapToggleAction->setShortcut(QKeySequence("Alt+P"));
                   +  - ]
      80         [ +  - ]:          99 :   connect(m_imapToggleAction, &QAction::triggered, this, [this]() {
      81         [ #  # ]:           0 :     m_imapPassword->setEchoMode(m_imapPassword->echoMode() ==
      82                 :             :                                         QLineEdit::Password
      83                 :             :                                     ? QLineEdit::Normal
      84                 :             :                                     : QLineEdit::Password);
      85                 :           0 :   });
      86                 :             : 
      87   [ +  -  +  -  :          99 :   m_imapHostLabel = new QLabel(tr("&Host:"), m_imapGroup);
             -  +  -  - ]
      88                 :          99 :   m_imapHostLabel->setBuddy(m_imapHost);
      89                 :          99 :   imapLayout->addRow(m_imapHostLabel, m_imapHost);
      90   [ +  -  +  -  :          99 :   m_imapPortLabel = new QLabel(tr("P&ort:"), m_imapGroup);
             -  +  -  - ]
      91                 :          99 :   m_imapPortLabel->setBuddy(m_imapPort);
      92                 :          99 :   imapLayout->addRow(m_imapPortLabel, m_imapPort);
      93   [ +  -  +  -  :          99 :   m_imapSecurityLabel = new QLabel(tr("S&ecurity:"), m_imapGroup);
             -  +  -  - ]
      94                 :          99 :   m_imapSecurityLabel->setBuddy(m_imapSecurity);
      95                 :          99 :   imapLayout->addRow(m_imapSecurityLabel, m_imapSecurity);
      96   [ +  -  +  -  :          99 :   m_imapUsernameLabel = new QLabel(tr("&Username:"), m_imapGroup);
             -  +  -  - ]
      97                 :          99 :   m_imapUsernameLabel->setBuddy(m_imapUsername);
      98                 :          99 :   imapLayout->addRow(m_imapUsernameLabel, m_imapUsername);
      99   [ +  -  +  -  :          99 :   m_imapPasswordLabel = new QLabel(tr("&Password:"), m_imapGroup);
             -  +  -  - ]
     100                 :          99 :   m_imapPasswordLabel->setBuddy(m_imapPassword);
     101                 :          99 :   imapLayout->addRow(m_imapPasswordLabel, m_imapPassword);
     102                 :             : 
     103         [ +  - ]:          99 :   mainLayout->addWidget(m_imapGroup);
     104                 :             : 
     105                 :             :   // Auto-update port when security changes
     106         [ +  - ]:          99 :   connect(m_imapSecurity, &QComboBox::currentIndexChanged, this, [this](int) {
     107   [ +  -  +  - ]:           2 :     auto sec = m_imapSecurity->currentData().toString();
     108   [ +  +  +  -  :           2 :     if (sec == "ssl" && m_imapPort->value() == 143) {
             -  +  -  + ]
     109         [ #  # ]:           0 :       m_imapPort->setValue(993);
     110   [ +  +  +  -  :           2 :     } else if (sec == "starttls" && m_imapPort->value() == 993) {
             -  +  -  + ]
     111         [ #  # ]:           0 :       m_imapPort->setValue(143);
     112                 :             :     }
     113                 :           2 :   });
     114                 :             : 
     115                 :             :   // --- SMTP group ---
     116   [ +  -  +  -  :          99 :   m_smtpGroup = new QGroupBox(tr("SMTP Server (Outgoing)"), this);
             -  +  -  - ]
     117   [ +  -  -  +  :          99 :   auto *smtpLayout = new QFormLayout(m_smtpGroup);
                   -  - ]
     118                 :             : 
     119   [ +  -  -  +  :          99 :   m_smtpHost = new QLineEdit(this);
                   -  - ]
     120   [ +  -  +  - ]:          99 :   m_smtpHost->setPlaceholderText("smtp.example.com");
     121   [ +  -  -  +  :          99 :   m_smtpPort = new QSpinBox(this);
                   -  - ]
     122                 :          99 :   m_smtpPort->setRange(1, 65535);
     123                 :          99 :   m_smtpPort->setValue(587);
     124   [ +  -  -  +  :          99 :   m_smtpSecurity = new QComboBox(this);
                   -  - ]
     125   [ +  -  +  -  :          99 :   m_smtpSecurity->addItem("STARTTLS", "starttls");
                   +  - ]
     126   [ +  -  +  -  :          99 :   m_smtpSecurity->addItem("SSL/TLS", "ssl");
                   +  - ]
     127   [ +  -  -  +  :          99 :   m_smtpUsername = new QLineEdit(this);
                   -  - ]
     128   [ +  -  +  - ]:          99 :   m_smtpUsername->setPlaceholderText("user@example.com");
     129   [ +  -  -  +  :          99 :   m_smtpPassword = new QLineEdit(this);
                   -  - ]
     130                 :          99 :   m_smtpPassword->setEchoMode(QLineEdit::Password);
     131   [ +  -  +  - ]:          99 :   m_smtpPassword->setPlaceholderText(tr("Password"));
     132                 :             :   // SMTP password visibility toggle
     133         [ +  - ]:          99 :   m_smtpToggleAction = m_smtpPassword->addAction(
     134   [ +  -  +  - ]:         198 :       style()->standardIcon(QStyle::SP_FileDialogDetailedView),
     135                 :             :       QLineEdit::TrailingPosition);
     136   [ +  -  +  - ]:          99 :   m_smtpToggleAction->setToolTip(tr("Show/hide password"));
     137         [ +  - ]:          99 :   connect(m_smtpToggleAction, &QAction::triggered, this, [this]() {
     138         [ #  # ]:           0 :     m_smtpPassword->setEchoMode(m_smtpPassword->echoMode() ==
     139                 :             :                                         QLineEdit::Password
     140                 :             :                                     ? QLineEdit::Normal
     141                 :             :                                     : QLineEdit::Password);
     142                 :           0 :   });
     143                 :             : 
     144   [ +  -  +  -  :          99 :   m_smtpHostLabel = new QLabel(tr("H&ost:"), m_smtpGroup);
             -  +  -  - ]
     145                 :          99 :   m_smtpHostLabel->setBuddy(m_smtpHost);
     146                 :          99 :   smtpLayout->addRow(m_smtpHostLabel, m_smtpHost);
     147   [ +  -  +  -  :          99 :   m_smtpPortLabel = new QLabel(tr("Po&rt:"), m_smtpGroup);
             -  +  -  - ]
     148                 :          99 :   m_smtpPortLabel->setBuddy(m_smtpPort);
     149                 :          99 :   smtpLayout->addRow(m_smtpPortLabel, m_smtpPort);
     150   [ +  -  +  -  :          99 :   m_smtpSecurityLabel = new QLabel(tr("Se&curity:"), m_smtpGroup);
             -  +  -  - ]
     151                 :          99 :   m_smtpSecurityLabel->setBuddy(m_smtpSecurity);
     152                 :          99 :   smtpLayout->addRow(m_smtpSecurityLabel, m_smtpSecurity);
     153   [ +  -  +  -  :          99 :   m_smtpUsernameLabel = new QLabel(tr("User&name:"), m_smtpGroup);
             -  +  -  - ]
     154                 :          99 :   m_smtpUsernameLabel->setBuddy(m_smtpUsername);
     155                 :          99 :   smtpLayout->addRow(m_smtpUsernameLabel, m_smtpUsername);
     156   [ +  -  +  -  :          99 :   m_smtpPasswordLabel = new QLabel(tr("Pass&word:"), m_smtpGroup);
             -  +  -  - ]
     157                 :          99 :   m_smtpPasswordLabel->setBuddy(m_smtpPassword);
     158                 :          99 :   smtpLayout->addRow(m_smtpPasswordLabel, m_smtpPassword);
     159                 :             : 
     160                 :             :   // Auto-update SMTP port on security change
     161         [ +  - ]:          99 :   connect(m_smtpSecurity, &QComboBox::currentIndexChanged, this, [this](int) {
     162   [ +  -  +  - ]:          10 :     auto sec = m_smtpSecurity->currentData().toString();
     163   [ +  +  +  -  :          10 :     if (sec == "ssl" && m_smtpPort->value() == 587) {
             -  +  -  + ]
     164         [ #  # ]:           0 :       m_smtpPort->setValue(465);
     165   [ +  +  +  -  :          10 :     } else if (sec == "starttls" && m_smtpPort->value() == 465) {
             -  +  -  + ]
     166         [ #  # ]:           0 :       m_smtpPort->setValue(587);
     167                 :             :     }
     168                 :          10 :   });
     169                 :             : 
     170         [ +  - ]:          99 :   mainLayout->addWidget(m_smtpGroup);
     171                 :             : 
     172                 :             :   // --- Connection test ---
     173   [ +  -  -  +  :          99 :   auto *testLayout = new QHBoxLayout();
                   -  - ]
     174   [ +  -  +  -  :          99 :   m_testButton = new QPushButton(tr("Test Connection"), this);
             -  +  -  - ]
     175   [ +  -  -  +  :          99 :   m_testResultLabel = new QLabel(this);
                   -  - ]
     176         [ +  - ]:         198 :   m_testResultLabel->setObjectName(QStringLiteral("accountTestResult"));
     177                 :          99 :   m_testResultLabel->setTextFormat(Qt::PlainText);
     178                 :          99 :   m_testResultLabel->setWordWrap(true);
     179         [ +  - ]:          99 :   testLayout->addWidget(m_testButton);
     180         [ +  - ]:          99 :   testLayout->addWidget(m_testResultLabel, 1);
     181                 :          99 :   mainLayout->addLayout(testLayout);
     182                 :             : 
     183                 :          99 :   connect(m_testButton, &QPushButton::clicked, this,
     184         [ +  - ]:          99 :           &AccountFormWidget::testConnection);
     185                 :          99 : }
     186                 :             : 
     187                 :          99 : void AccountFormWidget::setupTabOrder() {
     188                 :          99 :   setTabOrder(m_nameEdit, m_emailEdit);
     189                 :          99 :   setTabOrder(m_emailEdit, m_imapHost);
     190                 :          99 :   setTabOrder(m_imapHost, m_imapPort);
     191                 :          99 :   setTabOrder(m_imapPort, m_imapSecurity);
     192                 :          99 :   setTabOrder(m_imapSecurity, m_imapUsername);
     193                 :          99 :   setTabOrder(m_imapUsername, m_imapPassword);
     194                 :          99 :   setTabOrder(m_imapPassword, m_smtpHost);
     195                 :          99 :   setTabOrder(m_smtpHost, m_smtpPort);
     196                 :          99 :   setTabOrder(m_smtpPort, m_smtpSecurity);
     197                 :          99 :   setTabOrder(m_smtpSecurity, m_smtpUsername);
     198                 :          99 :   setTabOrder(m_smtpUsername, m_smtpPassword);
     199                 :          99 :   setTabOrder(m_smtpPassword, m_testButton);
     200                 :          99 : }
     201                 :             : 
     202                 :          99 : void AccountFormWidget::connectFieldSignals() {
     203                 :             :   // Track modifications
     204                 :         529 :   auto markModified = [this]() {
     205                 :         529 :     m_modified = true;
     206                 :         529 :     emit formChanged();
     207                 :         628 :   };
     208                 :             : 
     209         [ +  - ]:          99 :   connect(m_nameEdit, &QLineEdit::textChanged, this, markModified);
     210         [ +  - ]:          99 :   connect(m_emailEdit, &QLineEdit::textChanged, this, markModified);
     211         [ +  - ]:          99 :   connect(m_imapHost, &QLineEdit::textChanged, this, markModified);
     212         [ +  - ]:          99 :   connect(m_imapPort, &QSpinBox::valueChanged, this, markModified);
     213         [ +  - ]:          99 :   connect(m_imapSecurity, &QComboBox::currentIndexChanged, this, markModified);
     214         [ +  - ]:          99 :   connect(m_imapUsername, &QLineEdit::textChanged, this, markModified);
     215         [ +  - ]:          99 :   connect(m_imapPassword, &QLineEdit::textChanged, this, markModified);
     216         [ +  - ]:          99 :   connect(m_smtpHost, &QLineEdit::textChanged, this, markModified);
     217         [ +  - ]:          99 :   connect(m_smtpPort, &QSpinBox::valueChanged, this, markModified);
     218         [ +  - ]:          99 :   connect(m_smtpSecurity, &QComboBox::currentIndexChanged, this, markModified);
     219         [ +  - ]:          99 :   connect(m_smtpUsername, &QLineEdit::textChanged, this, markModified);
     220         [ +  - ]:          99 :   connect(m_smtpPassword, &QLineEdit::textChanged, this, markModified);
     221                 :          99 : }
     222                 :             : 
     223                 :          57 : void AccountFormWidget::setConfig(const AccountConfig &config) {
     224                 :             :   // Block signals to avoid marking as modified during population
     225                 :          57 :   const QSignalBlocker blocker(this);
     226                 :             : 
     227         [ +  - ]:          57 :   m_nameEdit->setText(config.name);
     228         [ +  - ]:          57 :   m_emailEdit->setText(config.email);
     229                 :             : 
     230         [ +  - ]:          57 :   m_imapHost->setText(config.imap.host);
     231         [ +  - ]:          57 :   m_imapPort->setValue(config.imap.port);
     232   [ +  -  +  - ]:          57 :   m_imapSecurity->setCurrentIndex(
     233                 :         114 :       m_imapSecurity->findData(config.imap.security));
     234         [ +  - ]:          57 :   m_imapUsername->setText(config.imap.username);
     235   [ +  -  +  - ]:          57 :   m_imapPassword->setText(QString::fromUtf8(config.imap.password));
     236                 :             : 
     237         [ +  - ]:          57 :   m_smtpHost->setText(config.smtp.host);
     238         [ +  - ]:          57 :   m_smtpPort->setValue(config.smtp.port);
     239   [ +  -  +  - ]:          57 :   m_smtpSecurity->setCurrentIndex(
     240                 :         114 :       m_smtpSecurity->findData(config.smtp.security));
     241         [ +  - ]:          57 :   m_smtpUsername->setText(config.smtp.username);
     242   [ +  -  +  - ]:          57 :   m_smtpPassword->setText(QString::fromUtf8(config.smtp.password));
     243                 :             : 
     244                 :          57 :   m_modified = false;
     245         [ +  - ]:          57 :   m_testResultLabel->clear();
     246                 :          57 : }
     247                 :             : 
     248                 :          31 : AccountConfig AccountFormWidget::config() const {
     249                 :          31 :   AccountConfig cfg;
     250   [ +  -  +  - ]:          31 :   cfg.name = m_nameEdit->text().trimmed();
     251   [ +  -  +  - ]:          31 :   cfg.email = m_emailEdit->text().trimmed();
     252                 :             : 
     253   [ +  -  +  - ]:          31 :   cfg.imap.host = m_imapHost->text().trimmed();
     254         [ +  - ]:          31 :   cfg.imap.port = static_cast<quint16>(m_imapPort->value());
     255   [ +  -  +  - ]:          31 :   cfg.imap.security = m_imapSecurity->currentData().toString();
     256   [ +  -  +  - ]:          31 :   cfg.imap.username = m_imapUsername->text().trimmed();
     257   [ +  -  +  - ]:          31 :   cfg.imap.password = m_imapPassword->text().toUtf8();
     258                 :             : 
     259   [ +  -  +  - ]:          31 :   cfg.smtp.host = m_smtpHost->text().trimmed();
     260         [ +  - ]:          31 :   cfg.smtp.port = static_cast<quint16>(m_smtpPort->value());
     261   [ +  -  +  - ]:          31 :   cfg.smtp.security = m_smtpSecurity->currentData().toString();
     262   [ +  -  +  - ]:          31 :   cfg.smtp.username = m_smtpUsername->text().trimmed();
     263   [ +  -  +  - ]:          31 :   cfg.smtp.password = m_smtpPassword->text().toUtf8();
     264                 :             : 
     265                 :          31 :   return cfg;
     266                 :           0 : }
     267                 :             : 
     268                 :          11 : QStringList AccountFormWidget::validate() const {
     269   [ +  -  +  - ]:          11 :   return AccountConfigLoader::validate(config());
     270                 :             : }
     271                 :             : 
     272                 :           6 : bool AccountFormWidget::isModified() const { return m_modified; }
     273                 :             : 
     274                 :           6 : void AccountFormWidget::resetModified() { m_modified = false; }
     275                 :             : 
     276                 :          73 : void AccountFormWidget::clear() {
     277                 :          73 :   const QSignalBlocker blocker(this);
     278                 :             : 
     279         [ +  - ]:          73 :   m_nameEdit->clear();
     280         [ +  - ]:          73 :   m_emailEdit->clear();
     281         [ +  - ]:          73 :   m_imapHost->clear();
     282         [ +  - ]:          73 :   m_imapPort->setValue(993);
     283         [ +  - ]:          73 :   m_imapSecurity->setCurrentIndex(0); // SSL
     284         [ +  - ]:          73 :   m_imapUsername->clear();
     285         [ +  - ]:          73 :   m_imapPassword->clear();
     286         [ +  - ]:          73 :   m_smtpHost->clear();
     287         [ +  - ]:          73 :   m_smtpPort->setValue(587);
     288         [ +  - ]:          73 :   m_smtpSecurity->setCurrentIndex(0); // STARTTLS
     289         [ +  - ]:          73 :   m_smtpUsername->clear();
     290         [ +  - ]:          73 :   m_smtpPassword->clear();
     291         [ +  - ]:          73 :   m_testResultLabel->clear();
     292                 :             : 
     293                 :          73 :   m_modified = false;
     294                 :          73 : }
     295                 :             : 
     296                 :           4 : void AccountFormWidget::testConnection() {
     297                 :             :   // Validate first
     298         [ +  - ]:           4 :   auto errors = validate();
     299         [ +  + ]:           4 :   if (!errors.isEmpty()) {
     300   [ +  -  +  -  :           1 :     setTestResult("Formular unvollständig: " + errors.first(), false);
                   +  - ]
     301                 :           1 :     return;
     302                 :             :   }
     303                 :             : 
     304                 :             :   // Disable button and show "testing" state
     305         [ +  - ]:           3 :   m_testButton->setEnabled(false);
     306   [ +  -  +  - ]:           3 :   m_testButton->setText(tr("Testing..."));
     307   [ +  -  +  - ]:           3 :   m_testResultLabel->setText(tr("Testing connection..."));
     308   [ +  -  +  - ]:           3 :   m_testResultLabel->setStyleSheet("");
     309                 :             : 
     310                 :             :   // Clean up previous test service
     311         [ +  + ]:           3 :   if (m_testService) {
     312         [ +  - ]:           1 :     m_testService->disconnect();
     313         [ +  - ]:           1 :     m_testService->deleteLater();
     314                 :             :   }
     315                 :             : 
     316                 :             :   // Create a temporary ImapService for this test
     317   [ +  -  +  -  :           3 :   m_testService = new ImapService(this);
             -  +  -  - ]
     318                 :             : 
     319         [ +  - ]:           3 :   auto cfg = config();
     320                 :             : 
     321                 :             :   // On state change: look for Authenticated (success) or Error
     322                 :           3 :   connect(m_testService, &ImapService::stateChanged, this,
     323         [ +  - ]:           3 :           [this](ImapService::State state) {
     324         [ +  + ]:           6 :             if (state == ImapService::State::Authenticated) {
     325   [ +  -  +  - ]:           1 :               setTestResult("✅ Verbindung erfolgreich!", true);
     326                 :           1 :               m_testService->disconnect();
     327                 :           1 :               m_testService->deleteLater();
     328                 :           1 :               m_testService = nullptr;
     329                 :             :             }
     330                 :           6 :           });
     331                 :             : 
     332                 :           3 :   connect(m_testService, &ImapService::errorOccurred, this,
     333         [ +  - ]:           3 :           [this](const QString &error) {
     334   [ +  -  +  - ]:           1 :             setTestResult("❌ " + error, false);
     335                 :           1 :             m_testService->deleteLater();
     336                 :           1 :             m_testService = nullptr;
     337                 :           1 :           });
     338                 :             : 
     339                 :             :   // Timeout: 10s
     340         [ +  - ]:           3 :   QTimer::singleShot(10000, this, [this]() {
     341         [ #  # ]:           0 :     if (m_testService) {
     342   [ #  #  #  # ]:           0 :       setTestResult("❌ Zeitüberschreitung (10s)", false);
     343                 :           0 :       m_testService->disconnect();
     344                 :           0 :       m_testService->deleteLater();
     345                 :           0 :       m_testService = nullptr;
     346                 :             :     }
     347                 :           0 :   });
     348                 :             : 
     349         [ +  - ]:           3 :   m_testService->connectToServer(cfg.imap);
     350         [ +  + ]:           4 : }
     351                 :             : 
     352                 :           3 : void AccountFormWidget::setTestResult(const QString &message, bool success) {
     353         [ +  - ]:           3 :   m_testResultLabel->setText(message);
     354                 :             :   // Sprint 69: @success/@danger tokens instead of CSS named colors
     355                 :             :   // (so dark theme and the no_inline_colors gate work).
     356   [ +  -  +  +  :           6 :   const QString color = ThemeManager::instance().color(
                   +  - ]
     357         [ +  - ]:           3 :       success ? QLatin1String("@success") : QLatin1String("@danger"));
     358         [ +  - ]:           3 :   m_testResultLabel->setStyleSheet(
     359   [ +  +  +  -  :          12 :       success ? QStringLiteral("color: %1; font-weight: bold;").arg(color)
          +  -  +  +  -  
                -  -  - ]
     360   [ +  +  +  +  :           5 :               : QStringLiteral("color: %1;").arg(color));
          +  +  -  -  -  
                      - ]
     361                 :             : 
     362         [ +  - ]:           3 :   m_testButton->setEnabled(true);
     363   [ +  -  +  - ]:           3 :   m_testButton->setText(tr("Test Connection"));
     364                 :             : 
     365                 :             :   // Auto-clear success after 3 seconds
     366         [ +  + ]:           3 :   if (success) {
     367         [ +  - ]:           1 :     QTimer::singleShot(3000, this, [this]() {
     368   [ #  #  #  #  :           0 :       if (m_testResultLabel->text().startsWith("✅")) {
             #  #  #  # ]
     369                 :           0 :         m_testResultLabel->clear();
     370   [ #  #  #  # ]:           0 :         m_testResultLabel->setStyleSheet("");
     371                 :             :       }
     372                 :           0 :     });
     373                 :             :   }
     374                 :           3 : }
     375                 :             : 
     376                 :             : // T-76.B3: Runtime language switching
     377                 :         487 : void AccountFormWidget::changeEvent(QEvent *event) {
     378         [ +  + ]:         487 :   if (event->type() == QEvent::LanguageChange)
     379                 :           6 :     retranslateUi();
     380                 :         487 :   QWidget::changeEvent(event);
     381                 :         487 : }
     382                 :             : 
     383                 :           6 : void AccountFormWidget::retranslateUi() {
     384   [ +  -  +  - ]:           6 :   m_nameLabel->setText(tr("&Name:"));
     385   [ +  -  +  - ]:           6 :   m_emailLabel->setText(tr("&Email:"));
     386   [ +  -  +  - ]:           6 :   m_imapGroup->setTitle(tr("IMAP Server (Incoming)"));
     387   [ +  -  +  - ]:           6 :   m_imapHostLabel->setText(tr("&Host:"));
     388   [ +  -  +  - ]:           6 :   m_imapPortLabel->setText(tr("P&ort:"));
     389   [ +  -  +  - ]:           6 :   m_imapSecurityLabel->setText(tr("S&ecurity:"));
     390   [ +  -  +  - ]:           6 :   m_imapUsernameLabel->setText(tr("&Username:"));
     391   [ +  -  +  - ]:           6 :   m_imapPasswordLabel->setText(tr("&Password:"));
     392   [ +  -  +  - ]:           6 :   m_smtpGroup->setTitle(tr("SMTP Server (Outgoing)"));
     393   [ +  -  +  - ]:           6 :   m_smtpHostLabel->setText(tr("H&ost:"));
     394   [ +  -  +  - ]:           6 :   m_smtpPortLabel->setText(tr("Po&rt:"));
     395   [ +  -  +  - ]:           6 :   m_smtpSecurityLabel->setText(tr("Se&curity:"));
     396   [ +  -  +  - ]:           6 :   m_smtpUsernameLabel->setText(tr("User&name:"));
     397   [ +  -  +  - ]:           6 :   m_smtpPasswordLabel->setText(tr("Pass&word:"));
     398                 :             : 
     399   [ +  -  +  - ]:           6 :   m_nameEdit->setPlaceholderText(tr("e.g. Personal, Work"));
     400   [ +  -  +  - ]:           6 :   m_imapPassword->setPlaceholderText(tr("Password"));
     401   [ +  -  +  - ]:           6 :   m_smtpPassword->setPlaceholderText(tr("Password"));
     402   [ +  -  +  - ]:           6 :   m_imapToggleAction->setToolTip(tr("Show/hide password (Alt+P)"));
     403   [ +  -  +  - ]:           6 :   m_smtpToggleAction->setToolTip(tr("Show/hide password"));
     404                 :             : 
     405                 :             :   // Don't clobber the "Testing..." state of an in-flight connection test.
     406         [ +  - ]:           6 :   if (!m_testService)
     407   [ +  -  +  - ]:           6 :     m_testButton->setText(tr("Test Connection"));
     408                 :           6 : }
        

Generated by: LCOV version 2.0-1