MailJD nbsp;·nbsp; Test Dashboard nbsp;·nbsp; Coverage
LCOV - code coverage report
Current view: top level - ui - CheckableFolderCombo.cpp (source / functions) Coverage Total Hit
Test: MailJD Coverage (Unit + E2E) Lines: 86.7 % 90 78
Test Date: 2026-06-21 21:10:19 Functions: 100.0 % 9 9
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 47.7 % 174 83

             Branch data     Line data    Source code
       1                 :             : #include "CheckableFolderCombo.h"
       2                 :             : 
       3                 :             : #include <QAbstractItemView>
       4                 :             : #include <QEvent>
       5                 :             : #include <QLineEdit>
       6                 :             : #include <QMouseEvent>
       7                 :             : #include <QStandardItem>
       8                 :             : #include <QStandardItemModel>
       9                 :             : 
      10                 :          66 : CheckableFolderCombo::CheckableFolderCombo(QWidget *parent)
      11         [ +  - ]:          66 :     : QComboBox(parent), m_emptyText(tr("All folders")) {
      12   [ +  -  +  -  :          66 :   m_model = new QStandardItemModel(this);
             -  +  -  - ]
      13         [ +  - ]:          66 :   setModel(m_model);
      14                 :             : 
      15                 :             :   // Editable + read-only line edit lets us paint a custom summary string in the
      16                 :             :   // closed combo while the popup stays a plain checkable list. The user can
      17                 :             :   // never type into it.
      18         [ +  - ]:          66 :   setEditable(true);
      19   [ +  -  +  - ]:          66 :   lineEdit()->setReadOnly(true);
      20   [ +  -  +  - ]:          66 :   lineEdit()->setFocusPolicy(Qt::NoFocus);
      21   [ +  -  +  - ]:          66 :   lineEdit()->setContextMenuPolicy(Qt::NoContextMenu);
      22         [ +  - ]:          66 :   setInsertPolicy(QComboBox::NoInsert);
      23         [ +  - ]:          66 :   setCompleter(nullptr);
      24                 :             : 
      25                 :             :   // Toggle checkboxes on click and keep the popup open for multi-selection.
      26   [ +  -  +  -  :          66 :   view()->viewport()->installEventFilter(this);
                   +  - ]
      27                 :             : 
      28                 :             :   // A check toggled in the model → refresh the summary and (unless the change
      29                 :             :   // was programmatic) notify listeners.
      30                 :          66 :   connect(m_model, &QStandardItemModel::itemChanged, this,
      31         [ +  - ]:          66 :           [this](QStandardItem *) {
      32                 :           1 :             updateSummaryText();
      33         [ -  + ]:           1 :             if (!m_suppressSignal)
      34                 :           0 :               emit selectionChanged();
      35                 :           1 :           });
      36                 :             : 
      37         [ +  - ]:          66 :   updateSummaryText();
      38                 :          66 : }
      39                 :             : 
      40                 :          36 : void CheckableFolderCombo::setFolders(const QStringList &paths) {
      41                 :          36 :   m_suppressSignal = true;
      42                 :          36 :   m_model->clear();
      43         [ +  + ]:         173 :   for (const QString &path : paths) {
      44   [ +  -  +  -  :         137 :     auto *item = new QStandardItem(path);
             -  +  -  - ]
      45         [ +  - ]:         137 :     item->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled);
      46         [ +  - ]:         137 :     item->setData(Qt::Unchecked, Qt::CheckStateRole);
      47         [ +  - ]:         137 :     m_model->appendRow(item);
      48                 :             :   }
      49                 :          36 :   m_suppressSignal = false;
      50                 :          36 :   updateSummaryText();
      51                 :          36 : }
      52                 :             : 
      53                 :         504 : QStringList CheckableFolderCombo::checkedFolders() const {
      54                 :         504 :   QStringList out;
      55   [ +  -  +  + ]:        1069 :   for (int i = 0; i < m_model->rowCount(); ++i) {
      56         [ +  - ]:         565 :     QStandardItem *item = m_model->item(i);
      57   [ +  -  +  -  :         565 :     if (item && item->checkState() == Qt::Checked)
             +  +  +  + ]
      58   [ +  -  +  - ]:          10 :       out.append(item->text());
      59                 :             :   }
      60                 :         504 :   return out;
      61                 :           0 : }
      62                 :             : 
      63                 :          96 : void CheckableFolderCombo::setCheckedFolders(const QStringList &paths) {
      64                 :          96 :   m_suppressSignal = true;
      65                 :             :   // Track which requested paths already exist so we can append the rest.
      66                 :          96 :   QStringList present;
      67   [ +  -  +  + ]:         350 :   for (int i = 0; i < m_model->rowCount(); ++i) {
      68         [ +  - ]:         254 :     QStandardItem *item = m_model->item(i);
      69         [ -  + ]:         254 :     if (!item)
      70                 :           0 :       continue;
      71         [ +  - ]:         254 :     const bool on = paths.contains(item->text());
      72   [ -  +  +  - ]:         254 :     item->setCheckState(on ? Qt::Checked : Qt::Unchecked);
      73         [ -  + ]:         254 :     if (on)
      74   [ #  #  #  # ]:           0 :       present.append(item->text());
      75                 :             :   }
      76                 :             :   // A checked path that is not (yet) in the known folder list — e.g. restored
      77                 :             :   // from a "folder:" query before the folder list loaded — is added as a
      78                 :             :   // checked item so the selection survives the round-trip and stays visible.
      79         [ +  + ]:         101 :   for (const QString &p : paths) {
      80         [ -  + ]:           5 :     if (present.contains(p))
      81                 :           0 :       continue;
      82   [ +  -  +  -  :           5 :     auto *item = new QStandardItem(p);
             -  +  -  - ]
      83         [ +  - ]:           5 :     item->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled);
      84         [ +  - ]:           5 :     item->setData(Qt::Checked, Qt::CheckStateRole);
      85         [ +  - ]:           5 :     m_model->appendRow(item);
      86                 :             :   }
      87                 :          96 :   m_suppressSignal = false;
      88         [ +  - ]:          96 :   updateSummaryText();
      89                 :          96 : }
      90                 :             : 
      91                 :         369 : void CheckableFolderCombo::updateSummaryText() {
      92         [ +  - ]:         369 :   const QStringList checked = checkedFolders();
      93                 :         369 :   QString summary;
      94         [ +  + ]:         369 :   if (checked.isEmpty())
      95                 :         365 :     summary = m_emptyText;
      96         [ +  + ]:           4 :   else if (checked.size() == 1)
      97                 :           3 :     summary = checked.first();
      98                 :             :   else
      99   [ +  -  +  - ]:           2 :     summary = tr("%1 folders").arg(checked.size());
     100   [ +  -  +  -  :         369 :   if (lineEdit() && lineEdit()->text() != summary)
          +  -  +  -  +  
          +  +  -  +  +  
                   -  - ]
     101   [ +  -  +  - ]:         189 :     lineEdit()->setText(summary);
     102                 :         369 : }
     103                 :             : 
     104                 :        1335 : bool CheckableFolderCombo::eventFilter(QObject *obj, QEvent *event) {
     105   [ +  -  -  +  :        2670 :   if (obj == view()->viewport() &&
                   -  + ]
     106                 :        1335 :       event->type() == QEvent::MouseButtonRelease) {
     107                 :           0 :     auto *me = static_cast<QMouseEvent *>(event);
     108   [ #  #  #  #  :           0 :     const QModelIndex index = view()->indexAt(me->pos());
                   #  # ]
     109         [ #  # ]:           0 :     if (index.isValid()) {
     110         [ #  # ]:           0 :       QStandardItem *item = m_model->itemFromIndex(index);
     111         [ #  # ]:           0 :       if (item) {
     112   [ #  #  #  #  :           0 :         item->setCheckState(item->checkState() == Qt::Checked ? Qt::Unchecked
                   #  # ]
     113                 :             :                                                               : Qt::Checked);
     114                 :             :       }
     115                 :             :     }
     116                 :             :     // Consume the event so the popup does NOT close — multi-select continues.
     117                 :           0 :     return true;
     118                 :             :   }
     119                 :        1335 :   return QComboBox::eventFilter(obj, event);
     120                 :             : }
     121                 :             : 
     122                 :             : // T-76.B3: Runtime language switching
     123                 :        1923 : void CheckableFolderCombo::changeEvent(QEvent *event) {
     124         [ +  + ]:        1923 :   if (event->type() == QEvent::LanguageChange)
     125                 :         170 :     retranslateUi();
     126                 :        1923 :   QComboBox::changeEvent(event);
     127                 :        1923 : }
     128                 :             : 
     129                 :         170 : void CheckableFolderCombo::retranslateUi() {
     130         [ +  - ]:         170 :   m_emptyText = tr("All folders");
     131                 :         170 :   updateSummaryText();
     132                 :         170 : }
        

Generated by: LCOV version 2.0-1