MailJD nbsp;·nbsp; Test Dashboard nbsp;·nbsp; Coverage
LCOV - code coverage report
Current view: top level - ui - EventDetailPopup.cpp (source / functions) Coverage Total Hit
Test: MailJD Coverage (Unit + E2E) Lines: 88.9 % 144 128
Test Date: 2026-06-21 21:10:19 Functions: 87.5 % 8 7
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 43.9 % 346 152

             Branch data     Line data    Source code
       1                 :             : #include "EventDetailPopup.h"
       2                 :             : 
       3                 :             : #include "ui/ThemeManager.h"
       4                 :             : 
       5                 :             : #include <QFrame>
       6                 :             : #include <QHBoxLayout>
       7                 :             : #include <QKeyEvent>
       8                 :             : #include <QLabel>
       9                 :             : #include <QMessageBox>
      10                 :             : #include <QPushButton>
      11                 :             : #include <QVBoxLayout>
      12                 :             : 
      13                 :           7 : EventDetailPopup::EventDetailPopup(QWidget *parent)
      14                 :           7 :     : QWidget(parent, Qt::Popup | Qt::FramelessWindowHint) {
      15         [ +  - ]:          14 :   setObjectName(QStringLiteral("eventDetailPopup"));
      16         [ +  - ]:           7 :   setAttribute(Qt::WA_DeleteOnClose, false);
      17         [ +  - ]:           7 :   setAttribute(Qt::WA_StyledBackground, true);
      18         [ +  - ]:           7 :   setMinimumWidth(280);
      19         [ +  - ]:           7 :   setMaximumWidth(400);
      20                 :             : 
      21   [ +  -  +  -  :           7 :   auto *layout = new QVBoxLayout(this);
             -  +  -  - ]
      22         [ +  - ]:           7 :   layout->setContentsMargins(0, 0, 0, 0);
      23         [ +  - ]:           7 :   layout->setSpacing(0);
      24                 :             : 
      25                 :             :   // T-532: Color bar at top
      26   [ +  -  +  -  :           7 :   m_colorBar = new QFrame(this);
             -  +  -  - ]
      27         [ +  - ]:          14 :   m_colorBar->setObjectName(QStringLiteral("eventPopupColorBar"));
      28         [ +  - ]:           7 :   m_colorBar->setFixedHeight(4);
      29                 :             :   // Sprint 69: radius moved to main.qss; only dynamic bg stays inline.
      30         [ +  - ]:          14 :   m_colorBar->setStyleSheet(
      31                 :          14 :       QStringLiteral("background: %1;")
      32   [ +  -  +  - ]:          14 :           .arg(ThemeManager::calendarPalette().constFirst()));
      33         [ +  - ]:           7 :   layout->addWidget(m_colorBar);
      34                 :             : 
      35                 :             :   // Content area with padding
      36   [ +  -  +  -  :           7 :   auto *content = new QVBoxLayout();
             -  +  -  - ]
      37         [ +  - ]:           7 :   content->setContentsMargins(12, 10, 12, 10);
      38         [ +  - ]:           7 :   content->setSpacing(6);
      39                 :             : 
      40                 :             :   // Title row with action buttons
      41   [ +  -  +  -  :           7 :   auto *titleRow = new QHBoxLayout();
             -  +  -  - ]
      42   [ +  -  +  -  :           7 :   m_titleLabel = new QLabel(this);
             -  +  -  - ]
      43         [ +  - ]:          14 :   m_titleLabel->setObjectName(QStringLiteral("eventPopupTitle"));
      44         [ +  - ]:           7 :   m_titleLabel->setTextFormat(Qt::PlainText);
      45         [ +  - ]:           7 :   m_titleLabel->setWordWrap(true);
      46         [ +  - ]:           7 :   QFont titleFont = font();
      47         [ +  - ]:           7 :   titleFont.setPointSize(13);
      48         [ +  - ]:           7 :   titleFont.setBold(true);
      49         [ +  - ]:           7 :   m_titleLabel->setFont(titleFont);
      50         [ +  - ]:           7 :   titleRow->addWidget(m_titleLabel, 1);
      51                 :             : 
      52                 :             :   // Sprint 39: Compact icon-only buttons
      53         [ +  - ]:           7 :   QFont emojiFont(QStringLiteral("Noto Sans"), 14);
      54   [ +  -  +  +  :          21 :   emojiFont.setFamilies({QStringLiteral("Noto Sans"),
                   -  - ]
      55                 :           7 :                           QStringLiteral("Noto Color Emoji")});
      56                 :             : 
      57   [ +  -  +  -  :          14 :   m_editBtn = new QPushButton(QStringLiteral("\u270f\ufe0f"), this);
             -  +  -  - ]
      58         [ +  - ]:          14 :   m_editBtn->setObjectName(QStringLiteral("eventPopupEditButton"));
      59   [ +  -  +  - ]:           7 :   m_editBtn->setToolTip(tr("Edit"));
      60   [ +  -  +  - ]:           7 :   m_editBtn->setCursor(Qt::PointingHandCursor);
      61         [ +  - ]:           7 :   m_editBtn->setFixedSize(28, 28);
      62         [ +  - ]:           7 :   m_editBtn->setFont(emojiFont);
      63         [ +  - ]:           7 :   titleRow->addWidget(m_editBtn);
      64                 :             : 
      65   [ +  -  +  -  :          14 :   m_deleteBtn = new QPushButton(QStringLiteral("\U0001f5d1\ufe0f"), this);
             -  +  -  - ]
      66         [ +  - ]:          14 :   m_deleteBtn->setObjectName(QStringLiteral("eventPopupDeleteButton"));
      67   [ +  -  +  - ]:           7 :   m_deleteBtn->setToolTip(tr("Delete"));
      68   [ +  -  +  - ]:           7 :   m_deleteBtn->setCursor(Qt::PointingHandCursor);
      69         [ +  - ]:           7 :   m_deleteBtn->setFixedSize(28, 28);
      70         [ +  - ]:           7 :   m_deleteBtn->setFont(emojiFont);
      71         [ +  - ]:           7 :   titleRow->addWidget(m_deleteBtn);
      72                 :             : 
      73         [ +  - ]:           7 :   content->addLayout(titleRow);
      74                 :             : 
      75   [ +  -  +  -  :           7 :   m_timeLabel = new QLabel(this);
             -  +  -  - ]
      76         [ +  - ]:          14 :   m_timeLabel->setObjectName(QStringLiteral("eventPopupTime"));
      77         [ +  - ]:           7 :   m_timeLabel->setTextFormat(Qt::PlainText);
      78         [ +  - ]:           7 :   content->addWidget(m_timeLabel);
      79                 :             : 
      80   [ +  -  +  -  :           7 :   m_locationLabel = new QLabel(this);
             -  +  -  - ]
      81         [ +  - ]:          14 :   m_locationLabel->setObjectName(QStringLiteral("eventPopupLocation"));
      82         [ +  - ]:           7 :   m_locationLabel->setTextFormat(Qt::PlainText);
      83         [ +  - ]:           7 :   m_locationLabel->setWordWrap(true);
      84         [ +  - ]:           7 :   content->addWidget(m_locationLabel);
      85                 :             : 
      86   [ +  -  +  -  :           7 :   m_calendarLabel = new QLabel(this);
             -  +  -  - ]
      87         [ +  - ]:          14 :   m_calendarLabel->setObjectName(QStringLiteral("eventPopupCalendar"));
      88         [ +  - ]:           7 :   m_calendarLabel->setTextFormat(Qt::RichText);
      89         [ +  - ]:           7 :   content->addWidget(m_calendarLabel);
      90                 :             : 
      91   [ +  -  +  -  :           7 :   m_descLabel = new QLabel(this);
             -  +  -  - ]
      92         [ +  - ]:          14 :   m_descLabel->setObjectName(QStringLiteral("eventPopupDescription"));
      93         [ +  - ]:           7 :   m_descLabel->setTextFormat(Qt::PlainText);
      94         [ +  - ]:           7 :   m_descLabel->setWordWrap(true);
      95         [ +  - ]:           7 :   m_descLabel->setMaximumHeight(200);
      96         [ +  - ]:           7 :   content->addWidget(m_descLabel);
      97         [ +  - ]:           7 :   m_descLabel->hide();
      98                 :             : 
      99         [ +  - ]:           7 :   layout->addLayout(content);
     100                 :             : 
     101                 :             :   // Connections
     102         [ +  - ]:           7 :   connect(m_editBtn, &QPushButton::clicked, this, [this]() {
     103                 :           1 :     hide();
     104                 :           1 :     emit editRequested(m_currentEvent);
     105                 :           1 :   });
     106         [ +  - ]:           7 :   connect(m_deleteBtn, &QPushButton::clicked, this, [this]() {
     107                 :           0 :     hide();
     108                 :           0 :     emit deleteRequested(m_currentEvent);
     109                 :           0 :   });
     110                 :             : 
     111                 :             :   // Popup styling lives in main.qss (67.B3): #eventDetailPopup and the
     112                 :             :   // eventPopup* object names.
     113                 :             : 
     114         [ +  - ]:           7 :   installEventFilter(this);
     115   [ +  -  -  -  :          28 : }
                   -  - ]
     116                 :             : 
     117                 :           6 : void EventDetailPopup::showEvent(const CalendarEvent &event,
     118                 :             :                                  const QPoint &globalPos) {
     119                 :           6 :   m_currentEvent = event;
     120         [ +  - ]:           6 :   m_titleLabel->setText(event.summary);
     121                 :             : 
     122                 :             :   // T-532: Color bar
     123                 :           6 :   QColor evColor(event.color.isEmpty()
     124   [ +  -  +  +  :          10 :                      ? ThemeManager::calendarPalette().constFirst()
                   -  - ]
     125         [ +  + ]:          10 :                      : event.color);
     126                 :             :   // Sprint 69: radius moved to main.qss; only dynamic bg stays inline.
     127         [ +  - ]:          12 :   m_colorBar->setStyleSheet(
     128   [ +  -  +  - ]:          18 :       QStringLiteral("background: %1;").arg(evColor.name()));
     129                 :             : 
     130                 :             :   // Time
     131         [ +  - ]:           6 :   QLocale loc = QLocale::system();
     132                 :           6 :   QString timeStr;
     133         [ +  + ]:           6 :   if (event.allDay) {
     134   [ +  -  +  -  :           2 :     timeStr = loc.toString(event.dtStart.toLocalTime().date(),
                   +  - ]
     135                 :           1 :                            QLocale::LongFormat);
     136   [ +  -  +  - ]:           2 :     if (event.dtEnd.isValid() &&
     137   [ +  -  +  -  :           2 :         event.dtEnd.date() != event.dtStart.date())
             -  +  -  + ]
     138                 :           0 :       timeStr += QStringLiteral(" – ") +
     139   [ #  #  #  #  :           0 :                  loc.toString(event.dtEnd.toLocalTime().date(),
                   #  # ]
     140   [ #  #  #  # ]:           0 :                               QLocale::LongFormat);
     141         [ +  - ]:           1 :     timeStr += QStringLiteral("  (ganztägig)");
     142                 :             :   } else {
     143   [ +  -  +  - ]:          10 :     timeStr = loc.toString(event.dtStart.toLocalTime(),
     144                 :          15 :                            QStringLiteral("dd.MM.yyyy HH:mm"));
     145   [ +  -  +  - ]:           5 :     if (event.dtEnd.isValid())
     146                 :          10 :       timeStr += QStringLiteral(" – ") +
     147   [ +  -  +  - ]:          10 :                  loc.toString(event.dtEnd.toLocalTime(),
     148   [ +  -  +  - ]:          15 :                               QStringLiteral("HH:mm"));
     149                 :             :   }
     150         [ +  - ]:           6 :   m_timeLabel->setText(timeStr);
     151                 :             : 
     152                 :             :   // Location
     153         [ +  + ]:           6 :   if (event.location.isEmpty()) {
     154         [ +  - ]:           2 :     m_locationLabel->hide();
     155                 :             :   } else {
     156         [ +  - ]:           4 :     m_locationLabel->setText(
     157         [ +  - ]:          12 :         QStringLiteral("📍 ") + event.location);
     158         [ +  - ]:           4 :     m_locationLabel->show();
     159                 :             :   }
     160                 :             : 
     161                 :             :   // Calendar name + color
     162         [ +  - ]:          12 :   m_calendarLabel->setText(
     163                 :          12 :       QStringLiteral("<span style='color: %1;'>●</span> %2")
     164   [ +  -  +  -  :          12 :           .arg(evColor.name(), event.calendarPath.toHtmlEscaped()));
                   +  - ]
     165                 :             : 
     166                 :             :   // Description
     167         [ +  + ]:           6 :   if (event.description.isEmpty()) {
     168         [ +  - ]:           4 :     m_descLabel->hide();
     169                 :             :   } else {
     170         [ +  - ]:           2 :     m_descLabel->setText(event.description);
     171         [ +  - ]:           2 :     m_descLabel->show();
     172                 :             :   }
     173                 :             : 
     174         [ +  - ]:           6 :   adjustSize();
     175         [ +  - ]:           6 :   move(globalPos);
     176         [ +  - ]:           6 :   show();
     177         [ +  - ]:           6 :   raise();
     178         [ +  - ]:           6 :   setFocus();
     179                 :           6 : }
     180                 :             : 
     181                 :         193 : bool EventDetailPopup::eventFilter(QObject *obj, QEvent *ev) {
     182         [ -  + ]:         193 :   if (ev->type() == QEvent::MouseButtonPress) {
     183                 :           0 :     auto *me = static_cast<QMouseEvent *>(ev);
     184   [ #  #  #  #  :           0 :     if (!rect().contains(mapFromGlobal(me->globalPosition().toPoint()))) {
                   #  # ]
     185                 :           0 :       hide();
     186                 :           0 :       return true;
     187                 :             :     }
     188                 :             :   }
     189                 :         193 :   return QWidget::eventFilter(obj, ev);
     190                 :             : }
     191                 :             : 
     192                 :           2 : void EventDetailPopup::keyPressEvent(QKeyEvent *event) {
     193         [ +  - ]:           2 :   if (event->key() == Qt::Key_Escape) {
     194                 :           2 :     hide();
     195                 :           2 :     return;
     196                 :             :   }
     197                 :           0 :   QWidget::keyPressEvent(event);
     198                 :             : }
     199                 :             : 
     200                 :             : // T-76.B3: Runtime language switching
     201                 :           2 : void EventDetailPopup::changeEvent(QEvent *event) {
     202         [ -  + ]:           2 :   if (event->type() == QEvent::LanguageChange)
     203                 :           0 :     retranslateUi();
     204                 :           2 :   QWidget::changeEvent(event);
     205                 :           2 : }
     206                 :             : 
     207                 :           0 : void EventDetailPopup::retranslateUi() {
     208   [ #  #  #  # ]:           0 :   m_editBtn->setToolTip(tr("Edit"));
     209   [ #  #  #  # ]:           0 :   m_deleteBtn->setToolTip(tr("Delete"));
     210                 :           0 : }
        

Generated by: LCOV version 2.0-1