From baf95338a343c51b06f4f8c86c5c4d31dd9b605e Mon Sep 17 00:00:00 2001 From: Kellermorph Date: Sat, 22 Aug 2026 14:27:50 +0200 Subject: [PATCH 1/2] Add PDF page import as image --- cmake/qet_compilation_vars.cmake | 6 + sources/diagramevent/diagrameventaddpdf.cpp | 253 ++++++++++++++++++++ sources/diagramevent/diagrameventaddpdf.h | 55 +++++ sources/qetdiagrameditor.cpp | 15 ++ sources/qeticons.cpp | 2 + sources/qeticons.h | 1 + sources/ui/pdfpagesdialog.cpp | 150 ++++++++++++ sources/ui/pdfpagesdialog.h | 51 ++++ 8 files changed, 533 insertions(+) create mode 100644 sources/diagramevent/diagrameventaddpdf.cpp create mode 100644 sources/diagramevent/diagrameventaddpdf.h create mode 100644 sources/ui/pdfpagesdialog.cpp create mode 100644 sources/ui/pdfpagesdialog.h diff --git a/cmake/qet_compilation_vars.cmake b/cmake/qet_compilation_vars.cmake index 603345171..469405abd 100644 --- a/cmake/qet_compilation_vars.cmake +++ b/cmake/qet_compilation_vars.cmake @@ -26,6 +26,7 @@ message(" - qet_compilation_vars") set(QET_COMPONENTS LinguistTools PrintSupport + Pdf Xml Svg Sql @@ -35,6 +36,7 @@ set(QET_COMPONENTS set(QET_PRIVATE_LIBRARIES Qt::PrintSupport + Qt::Pdf Qt::Gui Qt::GuiPrivate # Required for QPdfEngine::drawHyperlink (PDF internal links) Qt::Xml @@ -307,6 +309,8 @@ set(QET_SRC_FILES ${QET_DIR}/sources/diagramevent/diagrameventaddelement.h ${QET_DIR}/sources/diagramevent/diagrameventaddimage.cpp ${QET_DIR}/sources/diagramevent/diagrameventaddimage.h + ${QET_DIR}/sources/diagramevent/diagrameventaddpdf.cpp + ${QET_DIR}/sources/diagramevent/diagrameventaddpdf.h ${QET_DIR}/sources/diagramevent/diagrameventaddshape.cpp ${QET_DIR}/sources/diagramevent/diagrameventaddshape.h ${QET_DIR}/sources/diagramevent/diagrameventaddtext.cpp @@ -713,6 +717,8 @@ set(QET_SRC_FILES ${QET_DIR}/sources/ui/formulaassistantdialog.h ${QET_DIR}/sources/ui/imagepropertieswidget.cpp ${QET_DIR}/sources/ui/imagepropertieswidget.h + ${QET_DIR}/sources/ui/pdfpagesdialog.cpp + ${QET_DIR}/sources/ui/pdfpagesdialog.h ${QET_DIR}/sources/ui/importelementdialog.cpp ${QET_DIR}/sources/ui/importelementdialog.h ${QET_DIR}/sources/ui/importelementtextpatterndialog.cpp diff --git a/sources/diagramevent/diagrameventaddpdf.cpp b/sources/diagramevent/diagrameventaddpdf.cpp new file mode 100644 index 000000000..602e48be2 --- /dev/null +++ b/sources/diagramevent/diagrameventaddpdf.cpp @@ -0,0 +1,253 @@ +/* + Copyright 2006-2026 The QElectroTech Team + This file is part of QElectroTech. + + QElectroTech is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + QElectroTech is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with QElectroTech. If not, see . +*/ +#include "diagrameventaddpdf.h" + +#include "../qetapp.h" +#include "../diagram.h" +#include "../undocommand/addgraphicsobjectcommand.h" +#include "../qetgraphicsitem/diagramimageitem.h" +#include "../ui/pdfpagesdialog.h" + +#include +#include +#include +#include + +// Target rendering DPI for PDF pages. +// 150 DPI provides good quality for screen display and printing +// while keeping file size reasonable. +static const int PDF_RENDER_DPI = 150; + +/** + @brief DiagramEventAddPdf::DiagramEventAddPdf + Constructor + @param diagram the diagram where this event operates +*/ +DiagramEventAddPdf::DiagramEventAddPdf(Diagram *diagram) : + DiagramEventInterface(diagram), + m_image(nullptr), + m_is_added(false) +{ + openDialog(); +} + +/** + @brief DiagramEventAddPdf::~DiagramEventAddPdf + Destructor +*/ +DiagramEventAddPdf::~DiagramEventAddPdf() +{ + if (m_running || m_abort) + { + if (m_is_added) m_diagram->removeItem(m_image); + delete m_image; + } + + foreach (QGraphicsView *view, m_diagram->views()) + view->setContextMenuPolicy((Qt::DefaultContextMenu)); +} + +/** + @brief DiagramEventAddPdf::mousePressEvent + Action when mouse is pressed + @param event event of mouse pressed +*/ +void DiagramEventAddPdf::mousePressEvent(QGraphicsSceneMouseEvent *event) +{ + if (m_image && event->button() == Qt::LeftButton) + { + QPointF pos = event->scenePos(); + pos.rx() -= m_image->boundingRect().width()/2; + pos.ry() -= m_image->boundingRect().height()/2; + m_diagram->undoStack().push(new AddGraphicsObjectCommand(m_image, m_diagram, pos)); + + for (QGraphicsView *view : m_diagram->views()) { + view->setContextMenuPolicy((Qt::DefaultContextMenu)); + } + + m_running = false; + emit finish(); + event->setAccepted(true); + } + else if (m_image && event->button() == Qt::RightButton) + { + m_image->setRotation(m_image->rotation() + 90); + event->setAccepted(true); + } +} + +/** + @brief DiagramEventAddPdf::mouseMoveEvent + Action when mouse moves + @param event event of mouse move +*/ +void DiagramEventAddPdf::mouseMoveEvent(QGraphicsSceneMouseEvent *event) +{ + if (!m_image || event->buttons() != Qt::NoButton) { + return; + } + + QPointF pos = event->scenePos(); + + if (!m_is_added) + { + for (QGraphicsView *view : m_diagram->views()) { + view->setContextMenuPolicy((Qt::NoContextMenu)); + } + + m_diagram->addItem(m_image); + m_is_added = true; + } + + m_image->setPos(pos - m_image->boundingRect().center()); + event->setAccepted(true); +} + +/** + @brief DiagramEventAddPdf::mouseDoubleClickEvent + Overwrite double click to prevent opening properties dialog. + @param event event of mouse double click +*/ +void DiagramEventAddPdf::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) { + event->setAccepted(true); +} + +/** + @brief DiagramEventAddPdf::wheelEvent + Action when mouse wheel is rotated (CTRL+wheel to scale) + @param event event of mouse wheel +*/ +void DiagramEventAddPdf::wheelEvent(QGraphicsSceneWheelEvent *event) +{ + if (!m_is_added || !m_image || event->modifiers() != Qt::CTRL) { + return; + } + + qreal scaling = m_image->scale(); + event->delta() > 1 ? scaling += 0.01 : scaling -= 0.01; + if (scaling > 0.01 && scaling <= 2) { + m_image->setScale(scaling); + } + + event->setAccepted(true); +} + +/** + @brief DiagramEventAddPdf::isNull + @return true if the PDF image couldn't be loaded, false otherwise +*/ +bool DiagramEventAddPdf::isNull() const +{ + if (!m_image) return true; + return false; +} + +/** + @brief DiagramEventAddPdf::openDialog + Opens a file dialog to select a PDF file, then opens a page selection + dialog. The selected page is rendered to a QImage at 150 DPI and + converted to a DiagramImageItem. +*/ +void DiagramEventAddPdf::openDialog() +{ + if (m_diagram->isReadOnly()) return; + + // Open file dialog to select a PDF file + QString pathPictures = QETApp::pictureDir(); + QString fileName = QFileDialog::getOpenFileName( + m_diagram->views().isEmpty() ? nullptr : m_diagram->views().first(), + QObject::tr("Sélectionner un fichier PDF..."), + pathPictures, + QObject::tr("Fichiers PDF (*.pdf)") + ); + + if (fileName.isEmpty()) return; + + // Load the PDF document + QPdfDocument document; + document.load(fileName); + + if (document.status() != QPdfDocument::Status::Ready) + { + QMessageBox::critical( + m_diagram->views().isEmpty() ? nullptr : m_diagram->views().first(), + QObject::tr("Erreur"), + QObject::tr("Impossible de charger le fichier PDF.") + ); + return; + } + + int pageCount = document.pageCount(); + if (pageCount <= 0) + { + QMessageBox::critical( + m_diagram->views().isEmpty() ? nullptr : m_diagram->views().first(), + QObject::tr("Erreur"), + QObject::tr("Le fichier PDF ne contient aucune page.") + ); + return; + } + + // If only one page, import directly without showing dialog + int pageIndex = 0; + if (pageCount > 1) + { + PdfPagesDialog dialog(document, + m_diagram->views().isEmpty() ? nullptr : m_diagram->views().first()); + if (dialog.exec() != QDialog::Accepted) return; + pageIndex = dialog.selectedPage() - 1; // Convert to 0-based index + } + + // Calculate pixel size from PDF points at target DPI + // PDF point = 1/72 inch + QSizeF pageSize = document.pagePointSize(pageIndex); + int pixelWidth = qRound((pageSize.width() / 72.0) * PDF_RENDER_DPI); + int pixelHeight = qRound((pageSize.height() / 72.0) * PDF_RENDER_DPI); + + if (pixelWidth <= 0 || pixelHeight <= 0) + { + QMessageBox::critical( + m_diagram->views().isEmpty() ? nullptr : m_diagram->views().first(), + QObject::tr("Erreur"), + QObject::tr("Impossible de déterminer la taille de la page PDF.") + ); + return; + } + + // Render PDF page to QImage + QImage image = document.render(pageIndex, QSize(pixelWidth, pixelHeight)); + if (image.isNull()) + { + QMessageBox::critical( + m_diagram->views().isEmpty() ? nullptr : m_diagram->views().first(), + QObject::tr("Erreur"), + QObject::tr("Impossible de rendre la page PDF.") + ); + return; + } + + // Fill white background to handle transparent PDFs + QImage background(image.size(), QImage::Format_ARGB32_Premultiplied); + background.fill(Qt::white); + QPainter painter(&background); + painter.drawImage(0, 0, image); + painter.end(); + + m_image = new DiagramImageItem(QPixmap::fromImage(background)); + m_running = true; +} diff --git a/sources/diagramevent/diagrameventaddpdf.h b/sources/diagramevent/diagrameventaddpdf.h new file mode 100644 index 000000000..9106c4b90 --- /dev/null +++ b/sources/diagramevent/diagrameventaddpdf.h @@ -0,0 +1,55 @@ +/* + Copyright 2006-2026 The QElectroTech Team + This file is part of QElectroTech. + + QElectroTech is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + QElectroTech is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with QElectroTech. If not, see . +*/ +#ifndef DIAGRAMEVENTADDPDF_H +#define DIAGRAMEVENTADDPDF_H + +#include "diagrameventinterface.h" + +class Diagram; +class DiagramImageItem; + +/** + @brief The DiagramEventAddPdf class + This diagram event handles the adding of a PDF page as an image in a diagram. + The selected PDF page is rendered to a QImage at 150 DPI and added as a + DiagramImageItem. The placement, rotation and scaling behavior is identical + to the existing image import. +*/ +class DiagramEventAddPdf : public DiagramEventInterface +{ + Q_OBJECT + + public: + DiagramEventAddPdf(Diagram *diagram); + ~DiagramEventAddPdf() override; + + void mousePressEvent (QGraphicsSceneMouseEvent *event) override; + void mouseMoveEvent (QGraphicsSceneMouseEvent *event) override; + void mouseDoubleClickEvent (QGraphicsSceneMouseEvent *event) override; + void wheelEvent (QGraphicsSceneWheelEvent *event) override; + + bool isNull() const; + + private: + void openDialog(); + + DiagramImageItem *m_image; + bool m_is_added; +}; + +#endif // DIAGRAMEVENTADDPDF_H diff --git a/sources/qetdiagrameditor.cpp b/sources/qetdiagrameditor.cpp index ed2795964..8505e6fbc 100644 --- a/sources/qetdiagrameditor.cpp +++ b/sources/qetdiagrameditor.cpp @@ -23,6 +23,7 @@ #include "conductornumexport.h" #include "diagramcommands.h" #include "diagramevent/diagrameventaddimage.h" +#include "diagramevent/diagrameventaddpdf.h" #include "diagramevent/diagrameventaddshape.h" #include "diagramevent/diagrameventaddtext.h" #include "diagramview.h" @@ -716,6 +717,7 @@ void QETDiagramEditor::setUpActions() //Adding action (add text, image, shape...) QAction *add_text = m_add_item_actions_group.addAction(QET::Icons::PartTextField, tr("Ajouter un champ de texte")); QAction *add_image = m_add_item_actions_group.addAction(QET::Icons::adding_image, tr("Ajouter une image")); + QAction *add_pdf = m_add_item_actions_group.addAction(QET::Icons::adding_pdf, tr("Ajouter un PDF")); QAction *add_line = m_add_item_actions_group.addAction(QET::Icons::PartLine, tr("Ajouter une ligne", "Draw line")); QAction *add_rectangle = m_add_item_actions_group.addAction(QET::Icons::PartRectangle, tr("Ajouter un rectangle")); QAction *add_ellipse = m_add_item_actions_group.addAction(QET::Icons::PartEllipse, tr("Ajouter une ellipse")); @@ -724,6 +726,7 @@ void QETDiagramEditor::setUpActions() add_text ->setStatusTip(tr("Ajoute un champ de texte sur le folio actuel")); add_image ->setStatusTip(tr("Ajoute une image sur le folio actuel")); + add_pdf ->setStatusTip(tr("Ajoute une page PDF sur le folio actuel")); add_line ->setStatusTip(tr("Ajoute une ligne sur le folio actuel")); add_rectangle->setStatusTip(tr("Ajoute un rectangle sur le folio actuel")); add_ellipse ->setStatusTip(tr("Ajoute une ellipse sur le folio actuel")); @@ -732,6 +735,7 @@ void QETDiagramEditor::setUpActions() add_text ->setData(QStringLiteral("text")); add_image ->setData(QStringLiteral("image")); + add_pdf ->setData(QStringLiteral("pdf")); add_line ->setData(QStringLiteral("line")); add_rectangle->setData(QStringLiteral("rectangle")); add_ellipse ->setData(QStringLiteral("ellipse")); @@ -1569,6 +1573,17 @@ void QETDiagramEditor::addItemGroupTriggered(QAction *action) else diagram_event = deai; } + else if (value == "pdf") + { + DiagramEventAddPdf *deap = new DiagramEventAddPdf(d); + if (deap->isNull()) + { + delete deap; + return; + } + else + diagram_event = deap; + } else if (value == "text") { diagram_event = new DiagramEventAddText(d); diff --git a/sources/qeticons.cpp b/sources/qeticons.cpp index 0ce89cb88..d1dca1af7 100644 --- a/sources/qeticons.cpp +++ b/sources/qeticons.cpp @@ -183,6 +183,7 @@ namespace QET { QIcon ZoomOriginal; QIcon ZoomOut; QIcon adding_image; + QIcon adding_pdf; QIcon resize_image; QIcon sa; QIcon br; @@ -453,6 +454,7 @@ void QET::Icons::initIcons() EditClear .addFile(":/ico/22x22/edit-clear.png"); EditText .addFile(":/ico/22x22/names.png"); adding_image .addFile(":/ico/22x22/insert-image.png"); + adding_pdf .addFile(":/ico/22x22/document-import.png"); if (rtl) { EditClearLocationBar.addPixmap(QPixmap(":/ico/16x16/edit-clear-locationbar-ltr.png").transformed(reverse)); diff --git a/sources/qeticons.h b/sources/qeticons.h index 227b6a8cb..a81c79e17 100644 --- a/sources/qeticons.h +++ b/sources/qeticons.h @@ -191,6 +191,7 @@ namespace QET { extern QIcon ZoomOriginal; extern QIcon ZoomOut; extern QIcon adding_image; + extern QIcon adding_pdf; extern QIcon resize_image; extern QIcon sa; extern QIcon br; diff --git a/sources/ui/pdfpagesdialog.cpp b/sources/ui/pdfpagesdialog.cpp new file mode 100644 index 000000000..a4553abb6 --- /dev/null +++ b/sources/ui/pdfpagesdialog.cpp @@ -0,0 +1,150 @@ +/* + Copyright 2006-2026 The QElectroTech Team + This file is part of QElectroTech. + + QElectroTech is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + QElectroTech is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with QElectroTech. If not, see . +*/ +#include "pdfpagesdialog.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Preview rendering DPI for the thumbnail in the dialog. +// Lower than the final render DPI to keep the dialog fast and compact. +static const int PREVIEW_DPI = 96; + +/** + @brief PdfPagesDialog::PdfPagesDialog + Constructor + @param document the loaded PDF document to preview pages from + @param parent parent widget +*/ +PdfPagesDialog::PdfPagesDialog(QPdfDocument &document, QWidget *parent) + : QDialog(parent), + m_document(document) +{ + setWindowTitle(tr("Sélectionner une page")); + setMinimumWidth(500); + setMinimumHeight(400); + + int pageCount = document.pageCount(); + + // Main layout + QVBoxLayout *main_layout = new QVBoxLayout(this); + + // Info label: "Ce document PDF contient X page(s)" + m_info_label = new QLabel( + tr("Ce document PDF contient %n page(s)", "", pageCount), + this + ); + m_info_label->setWordWrap(true); + main_layout->addWidget(m_info_label); + + // Page selection layout + QHBoxLayout *page_layout = new QHBoxLayout(); + + QLabel *select_label = new QLabel(tr("Page à importer :"), this); + page_layout->addWidget(select_label); + + // Spinbox: min=1, max=pageCount + m_page_spinbox = new QSpinBox(this); + m_page_spinbox->setMinimum(1); + m_page_spinbox->setMaximum(pageCount); + m_page_spinbox->setValue(1); + page_layout->addWidget(m_page_spinbox); + + main_layout->addLayout(page_layout); + + // Preview area + QLabel *preview_title = new QLabel(tr("Aperçu :"), this); + main_layout->addWidget(preview_title); + + QScrollArea *scroll_area = new QScrollArea(this); + scroll_area->setWidgetResizable(true); + scroll_area->setAlignment(Qt::AlignCenter); + scroll_area->setMinimumHeight(250); + + m_preview_label = new QLabel(this); + m_preview_label->setAlignment(Qt::AlignCenter); + m_preview_label->setMinimumSize(200, 200); + m_preview_label->setStyleSheet("QLabel { background-color: white; border: 1px solid #cccccc; }"); + scroll_area->setWidget(m_preview_label); + main_layout->addWidget(scroll_area, 1); + + // OK/Cancel buttons + QDialogButtonBox *button_box = new QDialogButtonBox( + QDialogButtonBox::Ok | QDialogButtonBox::Cancel, + this + ); + connect(button_box, &QDialogButtonBox::accepted, this, &QDialog::accept); + connect(button_box, &QDialogButtonBox::rejected, this, &QDialog::reject); + main_layout->addWidget(button_box); + + // Update preview when spinbox value changes + connect(m_page_spinbox, QOverload::of(&QSpinBox::valueChanged), + this, &PdfPagesDialog::updatePreview); + + // Render initial preview + updatePreview(); +} + +/** + @brief PdfPagesDialog::selectedPage + @return the selected page number (1-based) +*/ +int PdfPagesDialog::selectedPage() const +{ + return m_page_spinbox->value(); +} + +/** + @brief PdfPagesDialog::updatePreview + Renders the currently selected page as a thumbnail and displays it + in the preview label. Uses a fixed preview width of 400 pixels + while preserving the page aspect ratio. +*/ +void PdfPagesDialog::updatePreview() +{ + int pageIndex = m_page_spinbox->value() - 1; // Convert to 0-based + + // Calculate preview size: fixed width, proportional height + QSizeF pageSize = m_document.pagePointSize(pageIndex); + if (pageSize.isEmpty()) return; + + const int previewWidth = 400; + qreal ratio = pageSize.height() / pageSize.width(); + int previewHeight = qRound(previewWidth * ratio); + + // Render the page to QImage + QImage preview = m_document.render(pageIndex, QSize(previewWidth, previewHeight)); + if (preview.isNull()) return; + + // Fill white background to handle transparent PDFs + QImage background(preview.size(), QImage::Format_ARGB32_Premultiplied); + background.fill(Qt::white); + QPainter painter(&background); + painter.drawImage(0, 0, preview); + painter.end(); + + m_preview_label->setPixmap(QPixmap::fromImage(background).scaled( + previewWidth, previewHeight, + Qt::KeepAspectRatio, Qt::SmoothTransformation)); +} diff --git a/sources/ui/pdfpagesdialog.h b/sources/ui/pdfpagesdialog.h new file mode 100644 index 000000000..64b1fb676 --- /dev/null +++ b/sources/ui/pdfpagesdialog.h @@ -0,0 +1,51 @@ +/* + Copyright 2006-2026 The QElectroTech Team + This file is part of QElectroTech. + + QElectroTech is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + QElectroTech is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with QElectroTech. If not, see . +*/ +#ifndef PDFPAGESDIALOG_H +#define PDFPAGESDIALOG_H + +#include + +class QSpinBox; +class QLabel; +class QPdfDocument; + +/** + @brief The PdfPagesDialog class + Dialog for selecting a page from a PDF document. + Displays the total page count, a live preview of the selected page, + and allows the user to choose which page to import. +*/ +class PdfPagesDialog : public QDialog +{ + Q_OBJECT + + public: + explicit PdfPagesDialog(QPdfDocument &document, QWidget *parent = nullptr); + int selectedPage() const; + + private slots: + void updatePreview(); + + private: + QPdfDocument &m_document; + QLabel *m_info_label; + QLabel *m_preview_label; + QSpinBox *m_page_spinbox; +}; + +#endif // PDFPAGESDIALOG_H From ff25a7715989c28f7ccade2bf97f42b290e37959 Mon Sep 17 00:00:00 2001 From: Kellermorph Date: Sat, 22 Aug 2026 18:53:36 +0200 Subject: [PATCH 2/2] Improve PDF import: DPI selection, page preview, Qt5 compat, custom icon - Add DPI selection (150/300/600) to the page selection dialog - Add live page preview in the selection dialog - Conditionally compile PDF import only for Qt6 (#if QT_VERSION) - Add custom pdf-import icon (PDF document with + symbol) - Register new icon in qelectrotech.qrc - Qt5 builds: PDF import action is hidden, everything else works as before --- cmake/qet_compilation_vars.cmake | 26 ++++++++--- ico/22x22/pdf-import.png | Bin 0 -> 1539 bytes qelectrotech.qrc | 1 + sources/diagramevent/diagrameventaddpdf.cpp | 30 +++++-------- sources/qetdiagrameditor.cpp | 10 +++++ sources/qeticons.cpp | 2 +- sources/ui/pdfpagesdialog.cpp | 46 +++++++++++++++----- sources/ui/pdfpagesdialog.h | 5 ++- 8 files changed, 83 insertions(+), 37 deletions(-) create mode 100644 ico/22x22/pdf-import.png diff --git a/cmake/qet_compilation_vars.cmake b/cmake/qet_compilation_vars.cmake index 469405abd..36e4bb9b7 100644 --- a/cmake/qet_compilation_vars.cmake +++ b/cmake/qet_compilation_vars.cmake @@ -26,7 +26,6 @@ message(" - qet_compilation_vars") set(QET_COMPONENTS LinguistTools PrintSupport - Pdf Xml Svg Sql @@ -34,9 +33,13 @@ set(QET_COMPONENTS Widgets Concurrent) +# Qt6-only: QPdfDocument for PDF page import +if(QT_VERSION_MAJOR GREATER_EQUAL 6) + list(APPEND QET_COMPONENTS Pdf) +endif() + set(QET_PRIVATE_LIBRARIES Qt::PrintSupport - Qt::Pdf Qt::Gui Qt::GuiPrivate # Required for QPdfEngine::drawHyperlink (PDF internal links) Qt::Xml @@ -47,6 +50,11 @@ set(QET_PRIVATE_LIBRARIES Qt::Concurrent ) +# Qt6-only: QPdfDocument for PDF page import +if(QT_VERSION_MAJOR GREATER_EQUAL 6) + list(APPEND QET_PRIVATE_LIBRARIES Qt::Pdf) +endif() + set(QET_RES_FILES ${QET_DIR}/sources/autoNum/ui/autonumberingdockwidget.ui ${QET_DIR}/sources/autoNum/ui/autonumberingmanagementw.ui @@ -309,8 +317,6 @@ set(QET_SRC_FILES ${QET_DIR}/sources/diagramevent/diagrameventaddelement.h ${QET_DIR}/sources/diagramevent/diagrameventaddimage.cpp ${QET_DIR}/sources/diagramevent/diagrameventaddimage.h - ${QET_DIR}/sources/diagramevent/diagrameventaddpdf.cpp - ${QET_DIR}/sources/diagramevent/diagrameventaddpdf.h ${QET_DIR}/sources/diagramevent/diagrameventaddshape.cpp ${QET_DIR}/sources/diagramevent/diagrameventaddshape.h ${QET_DIR}/sources/diagramevent/diagrameventaddtext.cpp @@ -717,8 +723,6 @@ set(QET_SRC_FILES ${QET_DIR}/sources/ui/formulaassistantdialog.h ${QET_DIR}/sources/ui/imagepropertieswidget.cpp ${QET_DIR}/sources/ui/imagepropertieswidget.h - ${QET_DIR}/sources/ui/pdfpagesdialog.cpp - ${QET_DIR}/sources/ui/pdfpagesdialog.h ${QET_DIR}/sources/ui/importelementdialog.cpp ${QET_DIR}/sources/ui/importelementdialog.h ${QET_DIR}/sources/ui/importelementtextpatterndialog.cpp @@ -820,6 +824,16 @@ if(NOT BUILD_WITH_KF) ) endif() +# Qt6-only: PDF page import files +if(QT_VERSION_MAJOR GREATER_EQUAL 6) + list(APPEND QET_SRC_FILES + ${QET_DIR}/sources/diagramevent/diagrameventaddpdf.cpp + ${QET_DIR}/sources/diagramevent/diagrameventaddpdf.h + ${QET_DIR}/sources/ui/pdfpagesdialog.cpp + ${QET_DIR}/sources/ui/pdfpagesdialog.h + ) +endif() + set(TS_FILES ${QET_DIR}/lang/qet_ar.ts ${QET_DIR}/lang/qet_ca.ts diff --git a/ico/22x22/pdf-import.png b/ico/22x22/pdf-import.png new file mode 100644 index 0000000000000000000000000000000000000000..f84ef79ab79f98d8cd46f12d3cfa48a5ed336ad4 GIT binary patch literal 1539 zcmZ{kdoKq46SzB9Ysj)GE^?P zM9L*f3=Ohsh$z-&#Y!$=#A<)`k3DDq=>5FU`#tA<&gVS;Jy%?gACnMO5Cs58knC+- zp_JV%DJ1k}sMW+kp+d2DbpqhL1^~>T0r(7kG2a6ajR#=f9{}T<0LVq;HJvbp8pu1UpWQ&>?mX(r1=ekQ*1F+`>$;Q&%zN<5f zW>5B%@A_hJCFeAIO?{Zy6goE4*Uq@Q8^*(i&SfAgV-y9Q%Td|miG0krbqz}MZTPQRN z4IA{PH8)@;HcD6LOl!QttLr_5__i26?7imR1I97J!X{yr1P_G%MfqTryGt)WQuHbM zO!-&JBg!Jd7e~&#IV053wjkS#@JhL^QA$$T?l|)72z+9(k-o*H`A4^DcBTu3k$IRN z4E&Kv4$=wEe3nbznjm8jsB6LEPHLANDG}PIiOIYwG#~odHXPR8Bf~*+n6&D^(Yg=J zh3x*^et2AUv&q|h=0`Wr>I%7u9sZ|~&qPhdoF&^Pn=DXeuC1dj!7_?3S+-X#8mEzJ zOTfFj_6$72esQ^c8D~MAl@lPC{k<$6OGsQfVGOSJ;oa%+`1O`g>)n&x zlm3@o5=z${K5&pt=(7fMXV3#<6?du%njEJ21tU>Gd(%ewv9+t%w4%1Wc%xjFDc||; z{?UTdRtag9azRSH!iF27`9(4|^;TVT0*}YeVO36I7kXN#?+92@>K>BH^|eLbIi@AqBxBO<{fw=(NnrKnb<&ODXiO)XAtJ3{j@0OW?XwWeRs3nj z-ROto`X(i(%DiyMiA2{xD@rr>^5g_CHv%#?2734w_^}s%4ru6?Pd@SXW1PsE{wE1>@y&mn%x_SWN1c1 zBtAB}5Vig%kY-tQP-d#Ob^(P?G?zpyOedw=h@pba+Vj|HGwm#1Y2=}_VfC|D{A`M? z87xUG-AhUK7v-r`Lp4e1*ytbgJ>>*mIv&~(Qhf_~BSv-UchA*8q;?0Ky@?4bZhQ|B zjNMF%vuvGc<86>?_7e}qJ&S(}fr*ec6w5<^tWGN3TX6#~qLvEe|6)gTja86(tXN*h z&awW{7{ze7AhI=27bOt6m{bVrId4vU&?@4&Q_BgkX;tM-M|DdNuY{E4p%BUH$pZ(e`5fU-7g;VlfZ(-QEl6-u{1QP@33Yy%zkNdvs(^bRT|JQThrB6S;D zcIpgUFGgShgKA8Pq(T7*cmh!eZ>U2cxa$#(cdy}LJl+_O$Avpy{+~b#4-5&4{klLV ltQtdt)_)TiAv9_fBY+n1bw^zDico/22x22/go-up.png ico/22x22/hotspot.png ico/22x22/insert-image.png + ico/22x22/pdf-import.png ico/22x22/label.png ico/22x22/landscape.png ico/22x22/line.png diff --git a/sources/diagramevent/diagrameventaddpdf.cpp b/sources/diagramevent/diagrameventaddpdf.cpp index 602e48be2..21931c404 100644 --- a/sources/diagramevent/diagrameventaddpdf.cpp +++ b/sources/diagramevent/diagrameventaddpdf.cpp @@ -28,11 +28,6 @@ #include #include -// Target rendering DPI for PDF pages. -// 150 DPI provides good quality for screen display and printing -// while keeping file size reasonable. -static const int PDF_RENDER_DPI = 150; - /** @brief DiagramEventAddPdf::DiagramEventAddPdf Constructor @@ -160,8 +155,8 @@ bool DiagramEventAddPdf::isNull() const /** @brief DiagramEventAddPdf::openDialog Opens a file dialog to select a PDF file, then opens a page selection - dialog. The selected page is rendered to a QImage at 150 DPI and - converted to a DiagramImageItem. + dialog with DPI options. The selected page is rendered to a QImage at + the chosen DPI and converted to a DiagramImageItem. */ void DiagramEventAddPdf::openDialog() { @@ -203,21 +198,18 @@ void DiagramEventAddPdf::openDialog() return; } - // If only one page, import directly without showing dialog - int pageIndex = 0; - if (pageCount > 1) - { - PdfPagesDialog dialog(document, - m_diagram->views().isEmpty() ? nullptr : m_diagram->views().first()); - if (dialog.exec() != QDialog::Accepted) return; - pageIndex = dialog.selectedPage() - 1; // Convert to 0-based index - } + // Always show the dialog so the user can choose page and DPI + PdfPagesDialog dialog(document, + m_diagram->views().isEmpty() ? nullptr : m_diagram->views().first()); + if (dialog.exec() != QDialog::Accepted) return; + int pageIndex = dialog.selectedPage() - 1; // Convert to 0-based index + int dpi = dialog.selectedDpi(); - // Calculate pixel size from PDF points at target DPI + // Calculate pixel size from PDF points at the user-selected DPI // PDF point = 1/72 inch QSizeF pageSize = document.pagePointSize(pageIndex); - int pixelWidth = qRound((pageSize.width() / 72.0) * PDF_RENDER_DPI); - int pixelHeight = qRound((pageSize.height() / 72.0) * PDF_RENDER_DPI); + int pixelWidth = qRound((pageSize.width() / 72.0) * dpi); + int pixelHeight = qRound((pageSize.height() / 72.0) * dpi); if (pixelWidth <= 0 || pixelHeight <= 0) { diff --git a/sources/qetdiagrameditor.cpp b/sources/qetdiagrameditor.cpp index 8505e6fbc..e9e0838ee 100644 --- a/sources/qetdiagrameditor.cpp +++ b/sources/qetdiagrameditor.cpp @@ -23,7 +23,9 @@ #include "conductornumexport.h" #include "diagramcommands.h" #include "diagramevent/diagrameventaddimage.h" +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) #include "diagramevent/diagrameventaddpdf.h" +#endif #include "diagramevent/diagrameventaddshape.h" #include "diagramevent/diagrameventaddtext.h" #include "diagramview.h" @@ -717,7 +719,9 @@ void QETDiagramEditor::setUpActions() //Adding action (add text, image, shape...) QAction *add_text = m_add_item_actions_group.addAction(QET::Icons::PartTextField, tr("Ajouter un champ de texte")); QAction *add_image = m_add_item_actions_group.addAction(QET::Icons::adding_image, tr("Ajouter une image")); +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) QAction *add_pdf = m_add_item_actions_group.addAction(QET::Icons::adding_pdf, tr("Ajouter un PDF")); +#endif QAction *add_line = m_add_item_actions_group.addAction(QET::Icons::PartLine, tr("Ajouter une ligne", "Draw line")); QAction *add_rectangle = m_add_item_actions_group.addAction(QET::Icons::PartRectangle, tr("Ajouter un rectangle")); QAction *add_ellipse = m_add_item_actions_group.addAction(QET::Icons::PartEllipse, tr("Ajouter une ellipse")); @@ -726,7 +730,9 @@ void QETDiagramEditor::setUpActions() add_text ->setStatusTip(tr("Ajoute un champ de texte sur le folio actuel")); add_image ->setStatusTip(tr("Ajoute une image sur le folio actuel")); +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) add_pdf ->setStatusTip(tr("Ajoute une page PDF sur le folio actuel")); +#endif add_line ->setStatusTip(tr("Ajoute une ligne sur le folio actuel")); add_rectangle->setStatusTip(tr("Ajoute un rectangle sur le folio actuel")); add_ellipse ->setStatusTip(tr("Ajoute une ellipse sur le folio actuel")); @@ -735,7 +741,9 @@ void QETDiagramEditor::setUpActions() add_text ->setData(QStringLiteral("text")); add_image ->setData(QStringLiteral("image")); +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) add_pdf ->setData(QStringLiteral("pdf")); +#endif add_line ->setData(QStringLiteral("line")); add_rectangle->setData(QStringLiteral("rectangle")); add_ellipse ->setData(QStringLiteral("ellipse")); @@ -1573,6 +1581,7 @@ void QETDiagramEditor::addItemGroupTriggered(QAction *action) else diagram_event = deai; } +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) else if (value == "pdf") { DiagramEventAddPdf *deap = new DiagramEventAddPdf(d); @@ -1584,6 +1593,7 @@ void QETDiagramEditor::addItemGroupTriggered(QAction *action) else diagram_event = deap; } +#endif else if (value == "text") { diagram_event = new DiagramEventAddText(d); diff --git a/sources/qeticons.cpp b/sources/qeticons.cpp index d1dca1af7..6d53c46c6 100644 --- a/sources/qeticons.cpp +++ b/sources/qeticons.cpp @@ -454,7 +454,7 @@ void QET::Icons::initIcons() EditClear .addFile(":/ico/22x22/edit-clear.png"); EditText .addFile(":/ico/22x22/names.png"); adding_image .addFile(":/ico/22x22/insert-image.png"); - adding_pdf .addFile(":/ico/22x22/document-import.png"); + adding_pdf .addFile(":/ico/22x22/pdf-import.png"); if (rtl) { EditClearLocationBar.addPixmap(QPixmap(":/ico/16x16/edit-clear-locationbar-ltr.png").transformed(reverse)); diff --git a/sources/ui/pdfpagesdialog.cpp b/sources/ui/pdfpagesdialog.cpp index a4553abb6..7f6069248 100644 --- a/sources/ui/pdfpagesdialog.cpp +++ b/sources/ui/pdfpagesdialog.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -28,8 +29,10 @@ #include // Preview rendering DPI for the thumbnail in the dialog. -// Lower than the final render DPI to keep the dialog fast and compact. +// Fixed at 96 DPI to keep the preview fast and compact regardless +// of the final render DPI selected by the user. static const int PREVIEW_DPI = 96; +static const int PREVIEW_WIDTH = 400; /** @brief PdfPagesDialog::PdfPagesDialog @@ -43,7 +46,7 @@ PdfPagesDialog::PdfPagesDialog(QPdfDocument &document, QWidget *parent) { setWindowTitle(tr("Sélectionner une page")); setMinimumWidth(500); - setMinimumHeight(400); + setMinimumHeight(500); int pageCount = document.pageCount(); @@ -71,6 +74,19 @@ PdfPagesDialog::PdfPagesDialog(QPdfDocument &document, QWidget *parent) m_page_spinbox->setValue(1); page_layout->addWidget(m_page_spinbox); + page_layout->addStretch(); + + // DPI selection + QLabel *dpi_label = new QLabel(tr("Résolution :"), this); + page_layout->addWidget(dpi_label); + + m_dpi_combo = new QComboBox(this); + m_dpi_combo->addItem(tr("150 DPI (écran)"), 150); + m_dpi_combo->addItem(tr("300 DPI (impression)"), 300); + m_dpi_combo->addItem(tr("600 DPI (haute qualité)"), 600); + m_dpi_combo->setCurrentIndex(0); + page_layout->addWidget(m_dpi_combo); + main_layout->addLayout(page_layout); // Preview area @@ -98,9 +114,11 @@ PdfPagesDialog::PdfPagesDialog(QPdfDocument &document, QWidget *parent) connect(button_box, &QDialogButtonBox::rejected, this, &QDialog::reject); main_layout->addWidget(button_box); - // Update preview when spinbox value changes + // Update preview when spinbox or DPI changes connect(m_page_spinbox, QOverload::of(&QSpinBox::valueChanged), this, &PdfPagesDialog::updatePreview); + connect(m_dpi_combo, QOverload::of(&QComboBox::currentIndexChanged), + this, &PdfPagesDialog::updatePreview); // Render initial preview updatePreview(); @@ -115,11 +133,20 @@ int PdfPagesDialog::selectedPage() const return m_page_spinbox->value(); } +/** + @brief PdfPagesDialog::selectedDpi + @return the selected DPI value (150, 300, or 600) +*/ +int PdfPagesDialog::selectedDpi() const +{ + return m_dpi_combo->currentData().toInt(); +} + /** @brief PdfPagesDialog::updatePreview Renders the currently selected page as a thumbnail and displays it - in the preview label. Uses a fixed preview width of 400 pixels - while preserving the page aspect ratio. + in the preview label. The preview size scales with the selected DPI + to give a visual hint of the output quality. */ void PdfPagesDialog::updatePreview() { @@ -129,12 +156,11 @@ void PdfPagesDialog::updatePreview() QSizeF pageSize = m_document.pagePointSize(pageIndex); if (pageSize.isEmpty()) return; - const int previewWidth = 400; qreal ratio = pageSize.height() / pageSize.width(); - int previewHeight = qRound(previewWidth * ratio); + int previewHeight = qRound(PREVIEW_WIDTH * ratio); - // Render the page to QImage - QImage preview = m_document.render(pageIndex, QSize(previewWidth, previewHeight)); + // Render the page to QImage at preview DPI + QImage preview = m_document.render(pageIndex, QSize(PREVIEW_WIDTH, previewHeight)); if (preview.isNull()) return; // Fill white background to handle transparent PDFs @@ -145,6 +171,6 @@ void PdfPagesDialog::updatePreview() painter.end(); m_preview_label->setPixmap(QPixmap::fromImage(background).scaled( - previewWidth, previewHeight, + PREVIEW_WIDTH, previewHeight, Qt::KeepAspectRatio, Qt::SmoothTransformation)); } diff --git a/sources/ui/pdfpagesdialog.h b/sources/ui/pdfpagesdialog.h index 64b1fb676..f2eb2d82d 100644 --- a/sources/ui/pdfpagesdialog.h +++ b/sources/ui/pdfpagesdialog.h @@ -21,6 +21,7 @@ #include class QSpinBox; +class QComboBox; class QLabel; class QPdfDocument; @@ -28,7 +29,7 @@ class QPdfDocument; @brief The PdfPagesDialog class Dialog for selecting a page from a PDF document. Displays the total page count, a live preview of the selected page, - and allows the user to choose which page to import. + DPI options (150/300/600), and allows the user to choose which page to import. */ class PdfPagesDialog : public QDialog { @@ -37,6 +38,7 @@ class PdfPagesDialog : public QDialog public: explicit PdfPagesDialog(QPdfDocument &document, QWidget *parent = nullptr); int selectedPage() const; + int selectedDpi() const; private slots: void updatePreview(); @@ -46,6 +48,7 @@ class PdfPagesDialog : public QDialog QLabel *m_info_label; QLabel *m_preview_label; QSpinBox *m_page_spinbox; + QComboBox *m_dpi_combo; }; #endif // PDFPAGESDIALOG_H