MailJD nbsp;·nbsp; Test Dashboard nbsp;·nbsp; Coverage
LCOV - code coverage report
Current view: top level - ui - PdfViewerWidget.cpp (source / functions) Coverage Total Hit
Test: MailJD Coverage (Unit + E2E) Lines: 47.4 % 114 54
Test Date: 2026-06-21 21:10:19 Functions: 53.8 % 13 7
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 26.5 % 268 71

             Branch data     Line data    Source code
       1                 :             : #include "PdfViewerWidget.h"
       2                 :             : 
       3                 :             : #include <QDir>
       4                 :             : #include <QEvent>
       5                 :             : #include <QFileDialog>
       6                 :             : #include <QHBoxLayout>
       7                 :             : #include <QLabel>
       8                 :             : #include <QLoggingCategory>
       9                 :             : #include <QMessageBox>
      10                 :             : #include <QPdfDocument>
      11                 :             : #include <QPdfView>
      12                 :             : #include <QSaveFile>
      13                 :             : #include <QScrollArea>
      14                 :             : #include <QTemporaryFile>
      15                 :             : #include <QToolButton>
      16                 :             : #include <QVBoxLayout>
      17                 :             : 
      18   [ #  #  #  #  :           0 : Q_LOGGING_CATEGORY(lcPdfViewer, "mailjd.pdfviewer")
             #  #  #  # ]
      19                 :             : 
      20         [ +  - ]:          86 : PdfViewerWidget::PdfViewerWidget(QWidget *parent) : QWidget(parent) {
      21   [ +  -  +  -  :          86 :   auto *layout = new QVBoxLayout(this);
             -  +  -  - ]
      22         [ +  - ]:          86 :   layout->setContentsMargins(0, 0, 0, 0);
      23         [ +  - ]:          86 :   layout->setSpacing(0);
      24                 :             : 
      25                 :             :   // --- Toolbar ---
      26   [ +  -  +  -  :          86 :   auto *toolbar = new QHBoxLayout();
             -  +  -  - ]
      27         [ +  - ]:          86 :   toolbar->setContentsMargins(6, 2, 6, 2);
      28         [ +  - ]:          86 :   toolbar->setSpacing(4);
      29                 :             : 
      30   [ +  -  +  -  :          86 :   auto *backBtn = m_backBtn = new QToolButton(this);
             -  +  -  - ]
      31   [ +  -  +  - ]:          86 :   backBtn->setText(tr("← Back"));
      32   [ +  -  +  - ]:          86 :   backBtn->setToolTip(tr("Back to message"));
      33         [ +  - ]:          86 :   backBtn->setAutoRaise(true);
      34         [ +  - ]:          86 :   connect(backBtn, &QToolButton::clicked, this, &PdfViewerWidget::backRequested);
      35         [ +  - ]:          86 :   toolbar->addWidget(backBtn);
      36                 :             : 
      37   [ +  -  +  -  :          86 :   auto *saveBtn = m_saveBtn = new QToolButton(this);
             -  +  -  - ]
      38   [ +  -  +  - ]:          86 :   saveBtn->setText(tr("Save…"));
      39   [ +  -  +  - ]:          86 :   saveBtn->setToolTip(tr("Save PDF to disk"));
      40         [ +  - ]:          86 :   saveBtn->setAutoRaise(true);
      41         [ +  - ]:          86 :   connect(saveBtn, &QToolButton::clicked, this, [this]() {
      42         [ #  # ]:           0 :     if (m_currentData.isEmpty()) return;
      43                 :             :     const QString suggested =
      44         [ #  # ]:           0 :         m_currentFilename.isEmpty() ? QStringLiteral("document.pdf")
      45         [ #  # ]:           0 :                                     : m_currentFilename;
      46                 :           0 :     const QString path = QFileDialog::getSaveFileName(
      47   [ #  #  #  # ]:           0 :         this, tr("Save Attachment"), suggested);
      48         [ #  # ]:           0 :     if (path.isEmpty()) return;
      49         [ #  # ]:           0 :     QSaveFile file(path);
      50   [ #  #  #  # ]:           0 :     if (!file.open(QIODevice::WriteOnly)) {
      51   [ #  #  #  # ]:           0 :       QMessageBox::warning(this, tr("Save Error"),
      52   [ #  #  #  # ]:           0 :                            tr("Could not write to %1.").arg(path));
      53                 :           0 :       return;
      54                 :             :     }
      55         [ #  # ]:           0 :     file.write(m_currentData);
      56   [ #  #  #  # ]:           0 :     if (!file.commit()) {
      57   [ #  #  #  # ]:           0 :       QMessageBox::warning(this, tr("Save Error"),
      58   [ #  #  #  # ]:           0 :                            tr("Could not save %1.").arg(path));
      59                 :             :     }
      60   [ #  #  #  #  :           0 :   });
                   #  # ]
      61         [ +  - ]:          86 :   toolbar->addWidget(saveBtn);
      62                 :             : 
      63         [ +  - ]:          86 :   toolbar->addStretch();
      64                 :             : 
      65                 :             :   // Zoom controls.
      66   [ +  -  +  -  :          86 :   auto *zoomOutBtn = m_zoomOutBtn = new QToolButton(this);
             -  +  -  - ]
      67         [ +  - ]:         172 :   zoomOutBtn->setText(QStringLiteral("−"));
      68   [ +  -  +  - ]:          86 :   zoomOutBtn->setToolTip(tr("Zoom out"));
      69         [ +  - ]:          86 :   zoomOutBtn->setAutoRaise(true);
      70                 :          86 :   connect(zoomOutBtn, &QToolButton::clicked, this,
      71         [ +  - ]:          86 :           [this]() { changeZoom(-25); });
      72         [ +  - ]:          86 :   toolbar->addWidget(zoomOutBtn);
      73                 :             : 
      74   [ +  -  +  -  :         172 :   m_zoomLabel = new QLabel(QStringLiteral("100%"), this);
             -  +  -  - ]
      75         [ +  - ]:          86 :   m_zoomLabel->setMinimumWidth(48);
      76         [ +  - ]:          86 :   m_zoomLabel->setAlignment(Qt::AlignCenter);
      77         [ +  - ]:          86 :   toolbar->addWidget(m_zoomLabel);
      78                 :             : 
      79   [ +  -  +  -  :          86 :   auto *zoomInBtn = m_zoomInBtn = new QToolButton(this);
             -  +  -  - ]
      80         [ +  - ]:         172 :   zoomInBtn->setText(QStringLiteral("+"));
      81   [ +  -  +  - ]:          86 :   zoomInBtn->setToolTip(tr("Zoom in"));
      82         [ +  - ]:          86 :   zoomInBtn->setAutoRaise(true);
      83                 :          86 :   connect(zoomInBtn, &QToolButton::clicked, this,
      84         [ +  - ]:          86 :           [this]() { changeZoom(25); });
      85         [ +  - ]:          86 :   toolbar->addWidget(zoomInBtn);
      86                 :             : 
      87         [ +  - ]:          86 :   layout->addLayout(toolbar);
      88                 :             : 
      89                 :             :   // T-71.6: QPdfView/QPdfDocument are created lazily in ensureView() on the
      90                 :             :   // first load() call. This keeps MailView construction (and thus every mail
      91                 :             :   // open) fast — no PDF engine init until a PDF is actually viewed.
      92                 :          86 : }
      93                 :             : 
      94                 :          68 : PdfViewerWidget::~PdfViewerWidget() = default;
      95                 :             : 
      96                 :        1765 : void PdfViewerWidget::changeEvent(QEvent *event) {
      97         [ +  + ]:        1765 :   if (event->type() == QEvent::LanguageChange)
      98                 :          90 :     retranslateUi();
      99                 :        1765 :   QWidget::changeEvent(event);
     100                 :        1765 : }
     101                 :             : 
     102                 :          90 : void PdfViewerWidget::retranslateUi() {
     103   [ +  -  +  - ]:          90 :   m_backBtn->setText(tr("← Back"));
     104   [ +  -  +  - ]:          90 :   m_backBtn->setToolTip(tr("Back to message"));
     105   [ +  -  +  - ]:          90 :   m_saveBtn->setText(tr("Save…"));
     106   [ +  -  +  - ]:          90 :   m_saveBtn->setToolTip(tr("Save PDF to disk"));
     107   [ +  -  +  - ]:          90 :   m_zoomOutBtn->setToolTip(tr("Zoom out"));
     108   [ +  -  +  - ]:          90 :   m_zoomInBtn->setToolTip(tr("Zoom in"));
     109                 :          90 : }
     110                 :             : 
     111                 :           0 : void PdfViewerWidget::ensureView() {
     112         [ #  # ]:           0 :   if (m_pdfView) return;
     113                 :             : 
     114   [ #  #  #  #  :           0 :   m_document = new QPdfDocument(this);
                   #  # ]
     115   [ #  #  #  #  :           0 :   m_pdfView = new QPdfView(this);
                   #  # ]
     116                 :           0 :   m_pdfView->setDocument(m_document);
     117                 :           0 :   m_pdfView->setZoomMode(QPdfView::ZoomMode::Custom);
     118                 :           0 :   m_pdfView->setZoomFactor(1.0);
     119         [ #  # ]:           0 :   qobject_cast<QVBoxLayout *>(layout())->addWidget(m_pdfView, 1);
     120                 :             : }
     121                 :             : 
     122                 :           0 : void PdfViewerWidget::load(const QByteArray &data,
     123                 :             :                            const QString &filename) {
     124                 :           0 :   ensureView();
     125                 :           0 :   m_currentData = data;
     126                 :           0 :   m_currentFilename = filename;
     127                 :           0 :   setZoomDisplay(100);
     128                 :           0 :   m_pdfView->setZoomFactor(1.0);
     129                 :             : 
     130                 :             :   // Write to a temp file with .pdf extension (QPdfDocument::load takes a
     131                 :             :   // file path, not a byte array).
     132         [ #  # ]:           0 :   delete m_tempFile;
     133         [ #  # ]:           0 :   m_tempFile = new QTemporaryFile(
     134   [ #  #  #  # ]:           0 :       QDir::temp().absoluteFilePath(QStringLiteral("mailjd_pdf_XXXXXX.pdf")),
     135   [ #  #  #  # ]:           0 :       this);
     136         [ #  # ]:           0 :   if (!m_tempFile->open()) {
     137   [ #  #  #  #  :           0 :     qCWarning(lcPdfViewer) << "cannot create temp file";
             #  #  #  # ]
     138                 :           0 :     return;
     139                 :             :   }
     140                 :           0 :   m_tempFile->write(data);
     141                 :           0 :   m_tempFile->close();
     142                 :             : 
     143   [ #  #  #  # ]:           0 :   m_document->load(m_tempFile->fileName());
     144                 :             : }
     145                 :             : 
     146                 :           0 : void PdfViewerWidget::clear() {
     147                 :           0 :   m_currentData.clear();
     148                 :           0 :   m_currentFilename.clear();
     149                 :           0 :   setZoomDisplay(100);
     150         [ #  # ]:           0 :   if (m_pdfView) m_pdfView->setZoomFactor(1.0);
     151         [ #  # ]:           0 :   if (m_document) m_document->close();
     152         [ #  # ]:           0 :   delete m_tempFile;
     153                 :           0 :   m_tempFile = nullptr;
     154                 :           0 : }
     155                 :             : 
     156                 :           0 : void PdfViewerWidget::setZoomDisplay(int percent) {
     157                 :           0 :   m_zoomPercent = percent;
     158   [ #  #  #  # ]:           0 :   m_zoomLabel->setText(QStringLiteral("%1%").arg(percent));
     159                 :           0 : }
     160                 :             : 
     161                 :           0 : void PdfViewerWidget::changeZoom(int deltaPercent) {
     162                 :           0 :   int next = m_zoomPercent + deltaPercent;
     163         [ #  # ]:           0 :   next = qBound(25, next, 500);
     164         [ #  # ]:           0 :   if (next == m_zoomPercent) return;
     165         [ #  # ]:           0 :   setZoomDisplay(next);
     166         [ #  # ]:           0 :   m_pdfView->setZoomFactor(next / 100.0);
     167                 :             : }
        

Generated by: LCOV version 2.0-1