File indexing completed on 2025-01-05 03:53:14

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2017-05-25
0007  * Description : a tool to print images
0008  *
0009  * SPDX-FileCopyrightText: 2017-2024 by Gilles Caulier <caulier dot gilles at gmail dot com>
0010  *
0011  * SPDX-License-Identifier: GPL-2.0-or-later
0012  *
0013  * ============================================================ */
0014 
0015 #include "advprintphotopage.h"
0016 
0017 // Qt includes
0018 
0019 #include <QFile>
0020 #include <QDir>
0021 #include <QIcon>
0022 #include <QPointer>
0023 #include <QPrinterInfo>
0024 #include <QWidget>
0025 #include <QMessageBox>
0026 #include <QApplication>
0027 #include <QStyle>
0028 #include <QMenu>
0029 #include <QAction>
0030 #include <QPageSetupDialog>
0031 #include <QXmlStreamAttributes>
0032 #include <QDomDocument>
0033 #include <QDomNode>
0034 
0035 // KDE includes
0036 
0037 #include <kdesktopfile.h>
0038 
0039 // Local includes
0040 
0041 #include "digikam_debug.h"
0042 #include "advprintwizard.h"
0043 #include "advprintcustomdlg.h"
0044 #include "templateicon.h"
0045 #include "digikam_globals_p.h"      // For KF6::Ki18n deprecated
0046 
0047 namespace DigikamGenericPrintCreatorPlugin
0048 {
0049 
0050 static const struct CustomPageLayoutName
0051 {
0052 
0053 #if KI18N_VERSION >= QT_VERSION_CHECK(5, 89, 0)
0054 
0055     const KLazyLocalizedString    title;
0056 
0057 #else
0058 
0059     const char*                   context;
0060     const char*                   title;
0061 
0062 #endif
0063 
0064 }
0065 CUSTOM_PAGE_LAYOUT_NAME =
0066 {
0067     I18NC_NOOP("@info layout page", "Custom")
0068 };
0069 
0070 class Q_DECL_HIDDEN AdvPrintPhotoPage::Private
0071 {
0072 public:
0073 
0074     template <class Ui_Class>
0075 
0076     class Q_DECL_HIDDEN WizardUI : public QWidget,
0077                                    public Ui_Class
0078     {
0079     public:
0080 
0081         explicit WizardUI(QWidget* const parent)
0082             : QWidget(parent)
0083         {
0084             this->setupUi(this);
0085         }
0086     };
0087 
0088     typedef WizardUI<Ui_AdvPrintPhotoPage> PhotoUI;
0089 
0090 public:
0091 
0092     explicit Private(QWizard* const dialog)
0093       : pageSetupDlg(nullptr),
0094         printer     (nullptr),
0095         wizard      (nullptr),
0096         settings    (nullptr),
0097         iface       (nullptr)
0098     {
0099         photoUi = new PhotoUI(dialog);
0100         wizard  = dynamic_cast<AdvPrintWizard*>(dialog);
0101 
0102         if (wizard)
0103         {
0104             settings = wizard->settings();
0105             iface    = wizard->iface();
0106         }
0107     }
0108 
0109     PhotoUI*            photoUi;
0110     QPageSetupDialog*   pageSetupDlg;
0111     QPrinter*           printer;
0112     QList<QPrinterInfo> printerList;
0113 
0114     AdvPrintWizard*     wizard;
0115     AdvPrintSettings*   settings;
0116     DInfoInterface*     iface;
0117 };
0118 
0119 AdvPrintPhotoPage::AdvPrintPhotoPage(QWizard* const wizard, const QString& title)
0120     : DWizardPage(wizard, title),
0121       d          (new Private(wizard))
0122 {
0123     d->photoUi->BtnPreviewPageUp->setIcon(QIcon::fromTheme(QLatin1String("go-next"))
0124                                           .pixmap(16, 16));
0125     d->photoUi->BtnPreviewPageDown->setIcon(QIcon::fromTheme(QLatin1String("go-previous"))
0126                                             .pixmap(16, 16));
0127 
0128     // ----------------------
0129 
0130     d->photoUi->m_printer_choice->setEditable(false);
0131     d->photoUi->m_printer_choice->setWhatsThis(i18nc("@info", "Select your preferred print output."));
0132 
0133     // Populate hardcoded printers
0134 
0135     QMap<AdvPrintSettings::Output, QString> map2                = AdvPrintSettings::outputNames();
0136     QMap<AdvPrintSettings::Output, QString>::const_iterator it2 = map2.constBegin();
0137 
0138     while (it2 != map2.constEnd())
0139     {
0140         d->photoUi->m_printer_choice->addSqueezedItem(it2.value(), (int)it2.key());
0141         ++it2;
0142     }
0143 
0144     // Populate real printers
0145 
0146     d->printerList = QPrinterInfo::availablePrinters();
0147 
0148     for (QList<QPrinterInfo>::iterator it = d->printerList.begin() ;
0149          it != d->printerList.end() ; ++it)
0150     {
0151         d->photoUi->m_printer_choice->addSqueezedItem(it->printerName());
0152     }
0153 
0154     connect(d->photoUi->m_printer_choice, SIGNAL(signalItemActivated(QString)),
0155             this, SLOT(slotOutputChanged(QString)));
0156 
0157     connect(d->photoUi->BtnPreviewPageUp, SIGNAL(clicked()),
0158             this, SLOT(slotBtnPreviewPageUpClicked()));
0159 
0160     connect(d->photoUi->BtnPreviewPageDown, SIGNAL(clicked()),
0161             this, SLOT(slotBtnPreviewPageDownClicked()));
0162 
0163     connect(d->photoUi->ListPhotoSizes, SIGNAL(currentRowChanged(int)),
0164             this, SLOT(slotListPhotoSizesSelected()));
0165 
0166     connect(d->photoUi->m_pagesetup, SIGNAL(clicked()),
0167             this, SLOT(slotPageSetup()));
0168 
0169     if (d->photoUi->mPrintList->layout())
0170     {
0171         delete d->photoUi->mPrintList->layout();
0172     }
0173 
0174     // -----------------------------------
0175 
0176     d->photoUi->mPrintList->setIface(d->iface);
0177     d->photoUi->mPrintList->setAllowDuplicate(true);
0178     d->photoUi->mPrintList->setControlButtons(DItemsList::Add      |
0179                                               DItemsList::Remove   |
0180                                               DItemsList::MoveUp   |
0181                                               DItemsList::MoveDown |
0182                                               DItemsList::Clear    |
0183                                               DItemsList::Save     |
0184                                               DItemsList::Load);
0185     d->photoUi->mPrintList->setControlButtonsPlacement(DItemsList::ControlButtonsAbove);
0186     d->photoUi->mPrintList->enableDragAndDrop(false);
0187 
0188     d->photoUi->BmpFirstPagePreview->setAlignment(Qt::AlignHCenter);
0189 
0190     connect(d->photoUi->mPrintList, SIGNAL(signalMoveDownItem()),
0191             this, SLOT(slotBtnPrintOrderDownClicked()));
0192 
0193     connect(d->photoUi->mPrintList, SIGNAL(signalMoveUpItem()),
0194             this, SLOT(slotBtnPrintOrderUpClicked()));
0195 
0196     connect(d->photoUi->mPrintList, SIGNAL(signalAddItems(QList<QUrl>)),
0197             this, SLOT(slotAddItems(QList<QUrl>)));
0198 
0199     connect(d->photoUi->mPrintList, SIGNAL(signalRemovedItems(QList<int>)),
0200             this, SLOT(slotRemovingItems(QList<int>)));
0201 
0202     connect(d->photoUi->mPrintList, SIGNAL(signalContextMenuRequested()),
0203             this, SLOT(slotContextMenuRequested()));
0204 
0205     connect(d->photoUi->mPrintList, SIGNAL(signalXMLSaveItem(QXmlStreamWriter&,int)),
0206             this, SLOT(slotXMLSaveItem(QXmlStreamWriter&,int)));
0207 
0208     connect(d->photoUi->mPrintList, SIGNAL(signalXMLCustomElements(QXmlStreamWriter&)),
0209             this, SLOT(slotXMLCustomElement(QXmlStreamWriter&)));
0210 
0211     connect(d->photoUi->mPrintList, SIGNAL(signalXMLLoadImageElement(QXmlStreamReader&)),
0212             this, SLOT(slotXMLLoadElement(QXmlStreamReader&)));
0213 
0214     connect(d->photoUi->mPrintList, SIGNAL(signalXMLCustomElements(QXmlStreamReader&)),
0215             this, SLOT(slotXMLCustomElement(QXmlStreamReader&)));
0216 
0217     // -----------------------------------
0218 
0219     setPageWidget(d->photoUi);
0220     setLeftBottomPix(QIcon::fromTheme(QLatin1String("image-stack")));
0221 
0222     slotOutputChanged(d->photoUi->m_printer_choice->itemHighlighted());
0223 }
0224 
0225 AdvPrintPhotoPage::~AdvPrintPhotoPage()
0226 {
0227     delete d->printer;
0228     delete d->pageSetupDlg;
0229     delete d;
0230 }
0231 
0232 void AdvPrintPhotoPage::initializePage()
0233 {
0234     d->photoUi->mPrintList->listView()->selectAll();
0235     d->photoUi->mPrintList->slotRemoveItems();
0236 
0237     if (d->settings->selMode == AdvPrintSettings::IMAGES)
0238     {
0239         d->photoUi->mPrintList->loadImagesFromCurrentSelection();
0240     }
0241     else
0242     {
0243         d->wizard->setItemsList(d->settings->inputImages);
0244     }
0245 
0246     initPhotoSizes(d->printer->pageLayout().pageSize().size(QPageSize::Millimeter));
0247 
0248     // restore photoSize
0249 
0250 #if KI18N_VERSION >= QT_VERSION_CHECK(5, 89, 0)
0251 
0252     if (d->settings->savedPhotoSize == CUSTOM_PAGE_LAYOUT_NAME.title.toString())
0253 
0254 #else
0255 
0256     if (d->settings->savedPhotoSize == i18nc(CUSTOM_PAGE_LAYOUT_NAME.context, CUSTOM_PAGE_LAYOUT_NAME.title))
0257 
0258 #endif
0259 
0260     {
0261         d->photoUi->ListPhotoSizes->setCurrentRow(0);
0262     }
0263     else
0264     {
0265         QList<QListWidgetItem*> list = d->photoUi->ListPhotoSizes->findItems(d->settings->savedPhotoSize, Qt::MatchExactly);
0266 
0267         if (list.count())
0268         {
0269             d->photoUi->ListPhotoSizes->setCurrentItem(list[0]);
0270         }
0271         else
0272         {
0273             d->photoUi->ListPhotoSizes->setCurrentRow(0);
0274         }
0275     }
0276 
0277     // reset preview page number
0278 
0279     d->settings->currentPreviewPage = 0;
0280 
0281     // create our photo sizes list
0282 
0283     int gid = d->photoUi->m_printer_choice->findText(d->settings->outputName(AdvPrintSettings::GIMP));
0284 
0285     if (d->settings->gimpPath.isEmpty())
0286     {
0287         // Gimp is not available : we disable the option.
0288 
0289         d->photoUi->m_printer_choice->setItemData(gid, false, Qt::UserRole-1);
0290     }
0291 
0292     int index = d->photoUi->m_printer_choice->findText(d->settings->printerName);
0293 
0294     if (index != -1)
0295     {
0296         d->photoUi->m_printer_choice->setCurrentIndex(index);
0297     }
0298 
0299     slotOutputChanged(d->photoUi->m_printer_choice->itemHighlighted());
0300 
0301     d->photoUi->ListPhotoSizes->setIconSize(QSize(32, 32));
0302     initPhotoSizes(d->printer->pageLayout().pageSize().size(QPageSize::Millimeter));
0303 
0304     d->wizard->previewPhotos();
0305 }
0306 
0307 bool AdvPrintPhotoPage::validatePage()
0308 {
0309     d->settings->inputImages = d->photoUi->mPrintList->imageUrls();
0310     d->settings->printerName = d->photoUi->m_printer_choice->itemHighlighted();
0311 
0312     if (d->photoUi->ListPhotoSizes->currentItem())
0313     {
0314         d->settings->savedPhotoSize = d->photoUi->ListPhotoSizes->currentItem()->text();
0315     }
0316 
0317     return true;
0318 }
0319 
0320 bool AdvPrintPhotoPage::isComplete() const
0321 {
0322     return (!d->photoUi->mPrintList->imageUrls().isEmpty() ||
0323             !d->wizard->itemsList().isEmpty());
0324 }
0325 
0326 QPrinter* AdvPrintPhotoPage::printer() const
0327 {
0328     return d->printer;
0329 }
0330 
0331 DItemsList* AdvPrintPhotoPage::imagesList() const
0332 {
0333     return d->photoUi->mPrintList;
0334 }
0335 
0336 Ui_AdvPrintPhotoPage* AdvPrintPhotoPage::ui() const
0337 {
0338     return d->photoUi;
0339 }
0340 
0341 void AdvPrintPhotoPage::slotOutputChanged(const QString& text)
0342 {
0343     if (AdvPrintSettings::outputNames().values().contains(text))
0344     {
0345         delete d->printer;
0346 
0347         d->printer = new QPrinter();
0348         d->printer->setOutputFormat(QPrinter::PdfFormat);
0349     }
0350     else // real printer
0351     {
0352         for (QList<QPrinterInfo>::iterator it = d->printerList.begin() ;
0353              it != d->printerList.end() ; ++it)
0354         {
0355             if (it->printerName() == text)
0356             {
0357                 qCDebug(DIGIKAM_DPLUGIN_GENERIC_LOG) << "Chosen printer: " << it->printerName();
0358                 delete d->printer;
0359                 d->printer = new QPrinter(*it);
0360             }
0361         }
0362 
0363         d->printer->setOutputFormat(QPrinter::NativeFormat);
0364     }
0365 
0366     // default no margins
0367 
0368     d->printer->setFullPage(true);
0369     QMarginsF margins(0, 0, 0, 0);
0370     d->printer->setPageMargins(margins, QPageLayout::Millimeter);
0371 }
0372 
0373 void AdvPrintPhotoPage::slotXMLLoadElement(QXmlStreamReader& xmlReader)
0374 {
0375     if (d->settings->photos.size())
0376     {
0377         // read image is the last.
0378 
0379         AdvPrintPhoto* const pPhoto = d->settings->photos[d->settings->photos.size()-1];
0380         qCDebug(DIGIKAM_DPLUGIN_GENERIC_LOG) << " invoked " << xmlReader.name();
0381 
0382         while (xmlReader.readNextStartElement())
0383         {
0384             qCDebug(DIGIKAM_DPLUGIN_GENERIC_LOG) << pPhoto->m_url << " " << xmlReader.name();
0385 
0386             if (xmlReader.name() == QLatin1String("pa_caption"))
0387             {
0388                 //useless this item has been added now
0389 
0390                 if (pPhoto->m_pAdvPrintCaptionInfo)
0391                 {
0392                     delete pPhoto->m_pAdvPrintCaptionInfo;
0393                 }
0394 
0395                 pPhoto->m_pAdvPrintCaptionInfo = new AdvPrintCaptionInfo();
0396 
0397                 // get all attributes and its value of a tag in attrs variable.
0398 
0399                 QXmlStreamAttributes attrs     = xmlReader.attributes();
0400 
0401                 // get value of each attribute from QXmlStreamAttributes
0402 
0403                 QStringView attr                = attrs.value(QLatin1String("type"));
0404                 bool ok;
0405 
0406                 if (!attr.isEmpty())
0407                 {
0408                     qCDebug(DIGIKAM_DPLUGIN_GENERIC_LOG) << " found " << attr.toString();
0409                     pPhoto->m_pAdvPrintCaptionInfo->m_captionType =
0410                         (AdvPrintSettings::CaptionType)attr.toString().toInt(&ok);
0411                 }
0412 
0413                 attr = attrs.value(QLatin1String("font"));
0414 
0415                 if (!attr.isEmpty())
0416                 {
0417                     qCDebug(DIGIKAM_DPLUGIN_GENERIC_LOG) << " found " << attr.toString();
0418                     pPhoto->m_pAdvPrintCaptionInfo->m_captionFont.fromString(attr.toString());
0419                 }
0420 
0421                 attr = attrs.value(QLatin1String("color"));
0422 
0423                 if (!attr.isEmpty())
0424                 {
0425                     qCDebug(DIGIKAM_DPLUGIN_GENERIC_LOG) << " found " << attr.toString();
0426                     pPhoto->m_pAdvPrintCaptionInfo->m_captionColor.setNamedColor(attr.toString());
0427                 }
0428 
0429                 attr = attrs.value(QLatin1String("size"));
0430 
0431                 if (!attr.isEmpty())
0432                 {
0433                     qCDebug(DIGIKAM_DPLUGIN_GENERIC_LOG) << " found " << attr.toString();
0434                     pPhoto->m_pAdvPrintCaptionInfo->m_captionSize = attr.toString().toInt(&ok);
0435                 }
0436 
0437                 attr = attrs.value(QLatin1String("text"));
0438 
0439                 if (!attr.isEmpty())
0440                 {
0441                     qCDebug(DIGIKAM_DPLUGIN_GENERIC_LOG) << " found " << attr.toString();
0442                     pPhoto->m_pAdvPrintCaptionInfo->m_captionText = attr.toString();
0443                 }
0444             }
0445         }
0446     }
0447 }
0448 
0449 void AdvPrintPhotoPage::slotXMLSaveItem(QXmlStreamWriter& xmlWriter, int itemIndex)
0450 {
0451     if (d->settings->photos.size())
0452     {
0453         AdvPrintPhoto* const pPhoto = d->settings->photos[itemIndex];
0454 
0455         // TODO: first and copies could be removed since they are not useful any more
0456 
0457         xmlWriter.writeAttribute(QLatin1String("first"),
0458                                  QString::fromUtf8("%1")
0459                                  .arg(pPhoto->m_first));
0460 
0461         xmlWriter.writeAttribute(QLatin1String("copies"),
0462                                  QString::fromUtf8("%1")
0463                                  .arg(pPhoto->m_first ? pPhoto->m_copies : 0));
0464 
0465         // additional info (caption... etc)
0466 
0467         if (pPhoto->m_pAdvPrintCaptionInfo)
0468         {
0469             xmlWriter.writeStartElement(QLatin1String("pa_caption"));
0470             xmlWriter.writeAttribute(QLatin1String("type"),
0471                                      QString::fromUtf8("%1").arg(pPhoto->m_pAdvPrintCaptionInfo->m_captionType));
0472             xmlWriter.writeAttribute(QLatin1String("font"),
0473                                      pPhoto->m_pAdvPrintCaptionInfo->m_captionFont.toString());
0474             xmlWriter.writeAttribute(QLatin1String("size"),
0475                                      QString::fromUtf8("%1").arg(pPhoto->m_pAdvPrintCaptionInfo->m_captionSize));
0476             xmlWriter.writeAttribute(QLatin1String("color"),
0477                                      pPhoto->m_pAdvPrintCaptionInfo->m_captionColor.name());
0478             xmlWriter.writeAttribute(QLatin1String("text"),
0479                                      pPhoto->m_pAdvPrintCaptionInfo->m_captionText);
0480             xmlWriter.writeEndElement(); // pa_caption
0481         }
0482     }
0483 }
0484 
0485 void AdvPrintPhotoPage::slotXMLCustomElement(QXmlStreamWriter& xmlWriter)
0486 {
0487     xmlWriter.writeStartElement(QLatin1String("pa_layout"));
0488     xmlWriter.writeAttribute(QLatin1String("Printer"),   d->photoUi->m_printer_choice->itemHighlighted());
0489     xmlWriter.writeAttribute(QLatin1String("PageSize"),  QString::fromUtf8("%1").arg(d->printer->pageLayout().pageSize().id()));
0490     xmlWriter.writeAttribute(QLatin1String("PhotoSize"), d->photoUi->ListPhotoSizes->currentItem()->text());
0491     xmlWriter.writeEndElement(); // pa_layout
0492 }
0493 
0494 void AdvPrintPhotoPage::slotContextMenuRequested()
0495 {
0496     if (d->settings->photos.size())
0497     {
0498         int itemIndex         = d->photoUi->mPrintList->listView()->currentIndex().row();
0499         d->photoUi->mPrintList->listView()->blockSignals(true);
0500         QMenu menu(d->photoUi->mPrintList->listView());
0501         QAction* const action = menu.addAction(i18n("Add again"));
0502 
0503         connect(action, SIGNAL(triggered()),
0504                 this , SLOT(slotIncreaseCopies()));
0505 
0506         AdvPrintPhoto* const pPhoto  = d->settings->photos[itemIndex];
0507 
0508         qCDebug(DIGIKAM_DPLUGIN_GENERIC_LOG) << " copies "
0509                                      << pPhoto->m_copies
0510                                      << " first "
0511                                      << pPhoto->m_first;
0512 
0513         if ((pPhoto->m_copies > 1) || !pPhoto->m_first)
0514         {
0515             QAction* const actionr = menu.addAction(i18n("Remove"));
0516 
0517             connect(actionr, SIGNAL(triggered()),
0518                     this, SLOT(slotDecreaseCopies()));
0519         }
0520 
0521         menu.exec(QCursor::pos());
0522         d->photoUi->mPrintList->listView()->blockSignals(false);
0523     }
0524 }
0525 
0526 void AdvPrintPhotoPage::slotIncreaseCopies()
0527 {
0528     if (d->settings->photos.size())
0529     {
0530         QList<QUrl> list;
0531         DItemsListViewItem* const item = dynamic_cast<DItemsListViewItem*>(d->photoUi->mPrintList->listView()->currentItem());
0532 
0533         if (!item)
0534         {
0535             return;
0536         }
0537 
0538         list.append(item->url());
0539         qCDebug(DIGIKAM_DPLUGIN_GENERIC_LOG) << " Adding a copy of " << item->url();
0540         d->photoUi->mPrintList->slotAddImages(list);
0541     }
0542 }
0543 
0544 void AdvPrintPhotoPage::slotDecreaseCopies()
0545 {
0546     if (d->settings->photos.size())
0547     {
0548         DItemsListViewItem* const item = dynamic_cast<DItemsListViewItem*>
0549             (d->photoUi->mPrintList->listView()->currentItem());
0550 
0551         if (!item)
0552         {
0553             return;
0554         }
0555 
0556         qCDebug(DIGIKAM_DPLUGIN_GENERIC_LOG) << " Removing a copy of " << item->url();
0557         d->photoUi->mPrintList->slotRemoveItems();
0558     }
0559 }
0560 
0561 void AdvPrintPhotoPage::slotAddItems(const QList<QUrl>& list)
0562 {
0563     if (list.count() == 0)
0564     {
0565         return;
0566     }
0567 
0568     QList<QUrl> urls;
0569     d->photoUi->mPrintList->blockSignals(true);
0570 
0571     for (QList<QUrl>::ConstIterator it = list.constBegin() ;
0572          it != list.constEnd() ; ++it)
0573     {
0574         QUrl imageUrl = *it;
0575 
0576         // Check if the new item already exist in the list.
0577 
0578         bool found    = false;
0579 
0580         for (int i = 0 ; i < d->settings->photos.count() && !found ; ++i)
0581         {
0582             AdvPrintPhoto* const pCurrentPhoto = d->settings->photos.at(i);
0583 
0584             if (pCurrentPhoto &&
0585                 (pCurrentPhoto->m_url == imageUrl) &&
0586                 pCurrentPhoto->m_first)
0587             {
0588                 pCurrentPhoto->m_copies++;
0589                 found                       = true;
0590                 AdvPrintPhoto* const pPhoto = new AdvPrintPhoto(*pCurrentPhoto);
0591                 pPhoto->m_first             = false;
0592                 d->settings->photos.append(pPhoto);
0593 
0594                 qCDebug(DIGIKAM_DPLUGIN_GENERIC_LOG) << "Added fileName: "
0595                                              << pPhoto->m_url.fileName()
0596                                              << " copy number "
0597                                              << pCurrentPhoto->m_copies;
0598             }
0599         }
0600 
0601         if (!found)
0602         {
0603             AdvPrintPhoto* const pPhoto = new AdvPrintPhoto(150, d->iface);
0604             pPhoto->m_url               = *it;
0605             pPhoto->m_first             = true;
0606             d->settings->photos.append(pPhoto);
0607 
0608             qCDebug(DIGIKAM_DPLUGIN_GENERIC_LOG) << "Added new fileName: "
0609                                                  << pPhoto->m_url.fileName();
0610         }
0611     }
0612 
0613     d->photoUi->mPrintList->blockSignals(false);
0614     d->photoUi->LblPhotoCount->setText(QString::number(d->settings->photos.count()));
0615 
0616     if (d->settings->photos.size())
0617     {
0618         setComplete(true);
0619     }
0620 }
0621 
0622 void AdvPrintPhotoPage::slotRemovingItems(const QList<int>& list)
0623 {
0624     if (list.count() == 0)
0625     {
0626         return;
0627     }
0628 
0629     d->photoUi->mPrintList->blockSignals(true);
0630 
0631     Q_FOREACH (int itemIndex, list)
0632     {
0633         if (d->settings->photos.size() && itemIndex >= 0)
0634         {
0635             /// Debug data: found and copies
0636 
0637             bool found = false;
0638             int copies = 0;
0639 
0640             AdvPrintPhoto* const pPhotoToRemove = d->settings->photos.at(itemIndex);
0641 
0642             // photo to be removed could be:
0643             // 1) unique => just remove it
0644             // 2) first of n, =>
0645             //    search another with the same url
0646             //    and set it a first and with a count to n-1 then remove it
0647             // 3) one of n, search the first one and set count to n-1 then remove it
0648 
0649             if (pPhotoToRemove && pPhotoToRemove->m_first)
0650             {
0651                 if (pPhotoToRemove->m_copies > 0)
0652                 {
0653                     for (int i = 0 ; i < d->settings->photos.count() && !found ; ++i)
0654                     {
0655                         AdvPrintPhoto* const pCurrentPhoto = d->settings->photos.at(i);
0656 
0657                         if (pCurrentPhoto && pCurrentPhoto->m_url == pPhotoToRemove->m_url)
0658                         {
0659                             pCurrentPhoto->m_copies = pPhotoToRemove->m_copies - 1;
0660                             copies                  = pCurrentPhoto->m_copies;
0661                             pCurrentPhoto->m_first  = true;
0662                             found                   = true;
0663                         }
0664                     }
0665                 }
0666 
0667                 // otherwise it's unique
0668             }
0669             else if (pPhotoToRemove)
0670             {
0671                 for (int i = 0 ; i < d->settings->photos.count() && !found ; ++i)
0672                 {
0673                     AdvPrintPhoto* const pCurrentPhoto = d->settings->photos.at(i);
0674 
0675                     if (pCurrentPhoto &&
0676                         pCurrentPhoto->m_url == pPhotoToRemove->m_url &&
0677                         pCurrentPhoto->m_first)
0678                     {
0679                         pCurrentPhoto->m_copies--;
0680                         copies = pCurrentPhoto->m_copies;
0681                         found  = true;
0682                     }
0683                 }
0684             }
0685             else
0686             {
0687                 qCDebug(DIGIKAM_DPLUGIN_GENERIC_LOG) << " NULL AdvPrintPhoto object ";
0688                 return;
0689             }
0690 
0691             if (pPhotoToRemove)
0692             {
0693                 qCDebug(DIGIKAM_DPLUGIN_GENERIC_LOG) << "Removed fileName: "
0694                                             << pPhotoToRemove->m_url.fileName()
0695                                             << " copy number "
0696                                             << copies;
0697             }
0698 
0699             d->settings->photos.removeAt(itemIndex);
0700             delete pPhotoToRemove;
0701         }
0702     }
0703 
0704     d->wizard->previewPhotos();
0705     d->photoUi->mPrintList->blockSignals(false);
0706     d->photoUi->LblPhotoCount->setText(QString::number(d->settings->photos.count()));
0707 
0708     if (d->settings->photos.isEmpty())
0709     {
0710         // No photos => disabling next button (e.g. crop page)
0711 
0712         setComplete(false);
0713     }
0714 }
0715 
0716 void AdvPrintPhotoPage::slotBtnPrintOrderDownClicked()
0717 {
0718     d->photoUi->mPrintList->blockSignals(true);
0719     int currentIndex = d->photoUi->mPrintList->listView()->currentIndex().row();
0720 
0721     qCDebug(DIGIKAM_DPLUGIN_GENERIC_LOG) << "Moved photo "
0722                                  << currentIndex - 1
0723                                  << " to  "
0724                                  << currentIndex;
0725 
0726     d->settings->photos.swapItemsAt(currentIndex, currentIndex - 1);
0727     d->photoUi->mPrintList->blockSignals(false);
0728     d->wizard->previewPhotos();
0729 }
0730 
0731 void AdvPrintPhotoPage::slotBtnPrintOrderUpClicked()
0732 {
0733     d->photoUi->mPrintList->blockSignals(true);
0734     int currentIndex = d->photoUi->mPrintList->listView()->currentIndex().row();
0735 
0736     qCDebug(DIGIKAM_DPLUGIN_GENERIC_LOG) << "Moved photo "
0737                                  << currentIndex
0738                                  << " to  "
0739                                  << currentIndex + 1;
0740 
0741     d->settings->photos.swapItemsAt(currentIndex, currentIndex + 1);
0742     d->photoUi->mPrintList->blockSignals(false);
0743     d->wizard->previewPhotos();
0744 }
0745 
0746 void AdvPrintPhotoPage::slotXMLCustomElement(QXmlStreamReader& xmlReader)
0747 {
0748     qCDebug(DIGIKAM_DPLUGIN_GENERIC_LOG) << " invoked " << xmlReader.name();
0749 
0750     while (!xmlReader.atEnd())
0751     {
0752         if (xmlReader.isStartElement() && xmlReader.name() == QLatin1String("pa_layout"))
0753         {
0754             bool ok;
0755             QXmlStreamAttributes attrs = xmlReader.attributes();
0756 
0757             // get value of each attribute from QXmlStreamAttributes
0758 
0759             QStringView attr            = attrs.value(QLatin1String("Printer"));
0760 
0761             if (!attr.isEmpty())
0762             {
0763                 qCDebug(DIGIKAM_DPLUGIN_GENERIC_LOG) << " found " << attr.toString();
0764                 int index = d->photoUi->m_printer_choice->findText(attr.toString());
0765 
0766                 if (index != -1)
0767                 {
0768                     d->photoUi->m_printer_choice->setCurrentIndex(index);
0769                 }
0770 
0771                 slotOutputChanged(d->photoUi->m_printer_choice->itemHighlighted());
0772             }
0773 
0774             attr = attrs.value(QLatin1String("PageSize"));
0775 
0776             if (!attr.isEmpty())
0777             {
0778                 qCDebug(DIGIKAM_DPLUGIN_GENERIC_LOG) << " found " << attr.toString();
0779                 QPageSize pageSize((QPageSize::PageSizeId)attr.toString().toInt(&ok));
0780                 d->printer->setPageSize(pageSize);
0781             }
0782 
0783             attr = attrs.value(QLatin1String("PhotoSize"));
0784 
0785             if (!attr.isEmpty())
0786             {
0787                 qCDebug(DIGIKAM_DPLUGIN_GENERIC_LOG) << " found " << attr.toString();
0788                 d->settings->savedPhotoSize = attr.toString();
0789             }
0790         }
0791 
0792         xmlReader.readNext();
0793     }
0794 
0795     // reset preview page number
0796 
0797     d->settings->currentPreviewPage = 0;
0798 
0799     initPhotoSizes(d->printer->pageLayout().pageSize().size(QPageSize::Millimeter));
0800 
0801     QList<QListWidgetItem*> list    = d->photoUi->ListPhotoSizes->findItems(d->settings->savedPhotoSize,
0802                                                                             Qt::MatchExactly);
0803 
0804     if (list.count())
0805     {
0806         qCDebug(DIGIKAM_DPLUGIN_GENERIC_LOG) << " PhotoSize " << list[0]->text();
0807         d->photoUi->ListPhotoSizes->setCurrentItem(list[0]);
0808     }
0809     else
0810     {
0811         d->photoUi->ListPhotoSizes->setCurrentRow(0);
0812     }
0813 
0814     d->wizard->previewPhotos();
0815 }
0816 
0817 void AdvPrintPhotoPage::slotBtnPreviewPageDownClicked()
0818 {
0819     if (d->settings->currentPreviewPage == 0)
0820     {
0821         return;
0822     }
0823 
0824     d->settings->currentPreviewPage--;
0825     d->wizard->previewPhotos();
0826 }
0827 
0828 void AdvPrintPhotoPage::slotBtnPreviewPageUpClicked()
0829 {
0830     if (d->settings->currentPreviewPage == getPageCount() - 1)
0831     {
0832         return;
0833     }
0834 
0835     d->settings->currentPreviewPage++;
0836     d->wizard->previewPhotos();
0837 }
0838 
0839 int AdvPrintPhotoPage::getPageCount() const
0840 {
0841     int pageCount  = 0;
0842     int photoCount = d->settings->photos.count();
0843 
0844     if (photoCount > 0)
0845     {
0846         // get the selected layout
0847 
0848         AdvPrintPhotoSize* const s = d->settings->photosizes.at(d->photoUi->ListPhotoSizes->currentRow());
0849 
0850         // how many pages?  Recall that the first layout item is the paper size
0851 
0852         int photosPerPage   = s->m_layouts.count() - 1;
0853         int remainder       = photoCount % photosPerPage;
0854         int emptySlots      = 0;
0855 
0856         if (remainder > 0)
0857         {
0858             emptySlots = photosPerPage - remainder;
0859         }
0860 
0861         pageCount = photoCount / photosPerPage;
0862 
0863         if (emptySlots > 0)
0864         {
0865             pageCount++;
0866         }
0867     }
0868 
0869     return pageCount;
0870 }
0871 
0872 void AdvPrintPhotoPage::createPhotoGrid(AdvPrintPhotoSize* const p,
0873                                         int pageWidth,
0874                                         int pageHeight,
0875                                         int rows,
0876                                         int columns,
0877                                         TemplateIcon* const iconpreview)
0878 {
0879     // To prevent divide by 0.
0880 
0881     if (!columns) columns = 1;
0882     if (!rows)    rows    = 1;
0883 
0884     int MARGIN      = (int)(((double)pageWidth + (double)pageHeight) / 2.0 * 0.04 + 0.5);
0885     int GAP         = MARGIN / 4;
0886     int photoWidth  = (pageWidth  - (MARGIN * 2) - ((columns - 1) * GAP)) / columns;
0887     int photoHeight = (pageHeight - (MARGIN * 2) - ((rows - 1)    * GAP)) / rows;
0888     int row         = 0;
0889 
0890     for (int y = MARGIN ;
0891          (row < rows) && (y < (pageHeight - MARGIN)) ;
0892          y += (photoHeight + GAP))
0893     {
0894         int col = 0;
0895 
0896         for (int x = MARGIN ;
0897              (col < columns) && (x < (pageWidth - MARGIN)) ;
0898              x += (photoWidth + GAP))
0899         {
0900             p->m_layouts.append(new QRect(x, y, photoWidth, photoHeight));
0901             iconpreview->fillRect(x, y, photoWidth, photoHeight, Qt::color1);
0902             ++col;
0903         }
0904 
0905         ++row;
0906     }
0907 }
0908 
0909 void AdvPrintPhotoPage::slotListPhotoSizesSelected()
0910 {
0911     AdvPrintPhotoSize* s = nullptr;
0912     QSizeF size, sizeManaged;
0913 
0914     // TODO FREE STYLE
0915     // check if layout is managed by templates or free one
0916     // get the selected layout
0917 
0918     int curr              = d->photoUi->ListPhotoSizes->currentRow();
0919     QListWidgetItem* item = d->photoUi->ListPhotoSizes->item(curr);
0920 
0921     // if custom page layout we launch a dialog to choose what kind
0922 
0923 #if KI18N_VERSION >= QT_VERSION_CHECK(5, 89, 0)
0924 
0925     if (item->text() == CUSTOM_PAGE_LAYOUT_NAME.title.toString())
0926 
0927 #else
0928 
0929     if (item->text() == i18nc(CUSTOM_PAGE_LAYOUT_NAME.context, CUSTOM_PAGE_LAYOUT_NAME.title))
0930 
0931 #endif
0932 
0933     {
0934         // check if a custom layout has already been added
0935 
0936         if ((curr >= 0) && (curr < d->settings->photosizes.size()))
0937         {
0938             s = d->settings->photosizes.at(curr);
0939             d->settings->photosizes.removeAt(curr);
0940             delete s;
0941             s = nullptr;
0942         }
0943 
0944         QPointer<AdvPrintCustomLayoutDlg> custDlg = new AdvPrintCustomLayoutDlg(this);
0945         custDlg->readSettings();
0946         custDlg->exec();
0947         custDlg->saveSettings();
0948 
0949         // get parameters from dialog
0950 
0951         size           = d->settings->pageSize;
0952         int scaleValue = 10; // 0.1 mm
0953 
0954         // convert to mm
0955 
0956         if (custDlg->m_photoUnits->currentText() == i18n("inches"))
0957         {
0958             size       /= 25.4;
0959             scaleValue  = 1000;
0960         }
0961         else if (custDlg->m_photoUnits->currentText() == i18n("cm"))
0962         {
0963             size       /= 10;
0964             scaleValue  = 100;
0965         }
0966 
0967         sizeManaged = size * scaleValue;
0968         s           = new AdvPrintPhotoSize;
0969         TemplateIcon iconpreview(80, sizeManaged.toSize());
0970         iconpreview.begin();
0971 
0972         if (custDlg->m_photoGridCheck->isChecked())
0973         {
0974             // custom photo grid
0975 
0976             int rows         = custDlg->m_gridRows->value();
0977             int columns      = custDlg->m_gridColumns->value();
0978 
0979             s->m_layouts.append(new QRect(0, 0,
0980                                           (int)sizeManaged.width(),
0981                                           (int)sizeManaged.height()));
0982             s->m_autoRotate  = custDlg->m_autorotate->isChecked();
0983             s->m_label       = item->text();
0984             s->m_dpi         = 0;
0985 
0986             int pageWidth  = (int)(size.width())  * scaleValue;
0987             int pageHeight = (int)(size.height()) * scaleValue;
0988             createPhotoGrid(s, pageWidth, pageHeight,
0989                             rows, columns, &iconpreview);
0990         }
0991         else if (custDlg->m_fitAsManyCheck->isChecked())
0992         {
0993             double width  = custDlg->m_photoWidth->value();
0994             double height = custDlg->m_photoHeight->value();
0995 
0996             //photo size must be less than page size
0997 
0998             static const float round_value = 0.01F;
0999 
1000             if (((height > (size.height() + round_value)) ||
1001                 (width  > (size.width()  + round_value))))
1002             {
1003                 qCDebug(DIGIKAM_DPLUGIN_GENERIC_LOG) << "photo size "
1004                                              << QSizeF(width, height)
1005                                              << "> page size "
1006                                              << size;
1007                 delete s;
1008                 s = nullptr;
1009             }
1010             else
1011             {
1012                 // fit as many photos of given size as possible
1013 
1014                 s->m_layouts.append(new QRect(0, 0, (int)sizeManaged.width(),
1015                                               (int)sizeManaged.height()));
1016                 s->m_autoRotate   = custDlg->m_autorotate->isChecked();
1017                 s->m_label        = item->text();
1018                 s->m_dpi          = 0;
1019                 int nColumns      = int(size.width()  / width);
1020                 int nRows         = int(size.height() / height);
1021                 double spareWidth = int(size.width() * scaleValue) % int(width * scaleValue);
1022                 spareWidth       /= scaleValue;
1023 
1024                 // check if there's no room left to separate photos
1025 
1026                 if ((nColumns > 1) && (spareWidth == 0.0))
1027                 {
1028                     nColumns  -= 1;
1029                     spareWidth = width;
1030                 }
1031 
1032                 double spareHeight = int(size.height() * scaleValue) % int(height * scaleValue);
1033                 spareHeight       /= scaleValue;
1034 
1035                 // check if there's no room left to separate photos
1036 
1037                 if ((nRows > 1) && (spareHeight == 0.0))
1038                 {
1039                     nRows      -= 1;
1040                     spareHeight = height;
1041                 }
1042 
1043                 if ((nRows > 0) && (nColumns > 0))
1044                 {
1045                     // n photos => dx1, photo1, dx2, photo2,... photoN, dxN+1
1046 
1047                     int dx      = spareWidth  * scaleValue / (nColumns + 1);
1048                     int dy      = spareHeight * scaleValue / (nRows    + 1);
1049                     int photoX  = 0;
1050                     int photoY  = 0;
1051                     width      *= scaleValue;
1052                     height     *= scaleValue;
1053 
1054                     for (int row = 0 ; row < nRows ; ++row)
1055                     {
1056                         photoY = dy * (row + 1) + (row * height);
1057 
1058                         for (int col = 0 ; col < nColumns ; ++col)
1059                         {
1060                             photoX = dx * (col + 1) + (col * width);
1061 
1062                             qCDebug(DIGIKAM_DPLUGIN_GENERIC_LOG) << "photo at P("
1063                                                          << photoX
1064                                                          << ", "
1065                                                          << photoY
1066                                                          << ") size("
1067                                                          << width
1068                                                          << ", "
1069                                                          << height;
1070 
1071                             s->m_layouts.append(new QRect(photoX, photoY,
1072                                                           width, height));
1073                             iconpreview.fillRect(photoX, photoY,
1074                                                  width, height, Qt::color1);
1075                         }
1076                     }
1077                 }
1078                 else
1079                 {
1080                     qCDebug(DIGIKAM_DPLUGIN_GENERIC_LOG) << "I cannot go on, rows "
1081                                                  << nRows
1082                                                  << "> columns "
1083                                                  << nColumns;
1084                     delete s;
1085                     s = nullptr;
1086                 }
1087             }
1088         }
1089         else
1090         {
1091             // Atckin's layout
1092         }
1093 
1094         // TODO not for Atckin's layout
1095 
1096         iconpreview.end();
1097 
1098         if (s)
1099         {
1100             s->m_icon = iconpreview.getIcon();
1101             d->settings->photosizes.append(s);
1102         }
1103 
1104         delete custDlg;
1105     }
1106     else
1107     {
1108         s = d->settings->photosizes.at(curr);
1109     }
1110 
1111     // reset preview page number
1112 
1113     d->settings->currentPreviewPage = 0;
1114 
1115     if (!s)
1116     {
1117         QMessageBox::warning(this, i18nc("@title:window", "Custom Layout"),
1118                              i18n("The selected custom photo size can "
1119                                   "not be applied to the paper size."));
1120 
1121         // change position to top
1122 
1123         d->photoUi->ListPhotoSizes->setCurrentRow(0);
1124     }
1125 
1126     d->wizard->previewPhotos();
1127 }
1128 
1129 void AdvPrintPhotoPage::slotPageSetup()
1130 {
1131     delete d->pageSetupDlg;
1132     QString lastSize = d->photoUi->ListPhotoSizes->currentItem()->text();
1133     d->pageSetupDlg  = new QPageSetupDialog(d->printer, this);
1134     int ret          = d->pageSetupDlg->exec();
1135 
1136     if (ret == QDialog::Accepted)
1137     {
1138         QPrinter* const printer = d->pageSetupDlg->printer();
1139 
1140         qCDebug(DIGIKAM_DPLUGIN_GENERIC_LOG) << "Dialog exit, new size "
1141                                      << printer->pageLayout().pageSize().size(QPageSize::Millimeter)
1142                                      << " internal size "
1143                                      << d->printer->pageLayout().pageSize().size(QPageSize::Millimeter);
1144 
1145         qreal left, top, right, bottom;
1146         auto margins = d->printer->pageLayout().margins(QPageLayout::Millimeter);
1147         left         = margins.left();
1148         top          = margins.top();
1149         right        = margins.right();
1150         bottom       = margins.bottom();
1151 
1152         qCDebug(DIGIKAM_DPLUGIN_GENERIC_LOG) << "Dialog exit, new margins: left "
1153                                      << left
1154                                      << " right "
1155                                      << right
1156                                      << " top "
1157                                      << top
1158                                      << " bottom "
1159                                      << bottom;
1160 
1161         // next should be useless invoke once changing wizard page
1162 /*
1163         d->wizard->initPhotoSizes(d->printer.paperSize(QPrinter::Millimeter));
1164 
1165         d->settings->pageSize = d->printer.paperSize(QPrinter::Millimeter);
1166 */
1167 
1168 #ifdef DEBUG
1169 
1170         qCDebug(DIGIKAM_DPLUGIN_GENERIC_LOG) << " dialog exited num of copies: "
1171                                      << printer->numCopies()
1172                                      << " inside:   "
1173                                      << d->printer->numCopies();
1174 
1175         qCDebug(DIGIKAM_DPLUGIN_GENERIC_LOG) << " dialog exited from : "
1176                                      << printer->fromPage()
1177                                      << " to:   "
1178                                      << d->printer->toPage();
1179 #endif
1180     }
1181 
1182     // Fix the page size dialog and preview PhotoPage
1183 
1184     initPhotoSizes(d->printer->pageLayout().pageSize().size(QPageSize::Millimeter));
1185 
1186     // restore photoSize
1187 
1188 #if KI18N_VERSION >= QT_VERSION_CHECK(5, 89, 0)
1189 
1190     if (lastSize == CUSTOM_PAGE_LAYOUT_NAME.title.toString())
1191 
1192 #else
1193 
1194     if (lastSize == i18nc(CUSTOM_PAGE_LAYOUT_NAME.context, CUSTOM_PAGE_LAYOUT_NAME.title))
1195 
1196 #endif
1197 
1198     {
1199         d->photoUi->ListPhotoSizes->setCurrentRow(0);
1200     }
1201     else
1202     {
1203         QList<QListWidgetItem*> list =
1204             d->photoUi->ListPhotoSizes->findItems(lastSize, Qt::MatchExactly);
1205 
1206         if (list.count())
1207         {
1208             d->photoUi->ListPhotoSizes->setCurrentItem(list[0]);
1209         }
1210         else
1211         {
1212             d->photoUi->ListPhotoSizes->setCurrentRow(0);
1213         }
1214     }
1215 
1216     // create our photo sizes list
1217 
1218     d->wizard->previewPhotos();
1219 }
1220 
1221 void AdvPrintPhotoPage::manageBtnPreviewPage()
1222 {
1223     if (d->settings->photos.isEmpty())
1224     {
1225         d->photoUi->BtnPreviewPageDown->setEnabled(false);
1226         d->photoUi->BtnPreviewPageUp->setEnabled(false);
1227     }
1228     else
1229     {
1230         d->photoUi->BtnPreviewPageDown->setEnabled(true);
1231         d->photoUi->BtnPreviewPageUp->setEnabled(true);
1232 
1233         if (d->settings->currentPreviewPage == 0)
1234         {
1235             d->photoUi->BtnPreviewPageDown->setEnabled(false);
1236         }
1237 
1238         if ((d->settings->currentPreviewPage + 1) == getPageCount())
1239         {
1240             d->photoUi->BtnPreviewPageUp->setEnabled(false);
1241         }
1242     }
1243 }
1244 
1245 void AdvPrintPhotoPage::initPhotoSizes(const QSizeF& pageSize)
1246 {
1247     qCDebug(DIGIKAM_DPLUGIN_GENERIC_LOG) << "New page size "
1248                                          << pageSize
1249                                          << ", old page size "
1250                                          << d->settings->pageSize;
1251 
1252     // don't refresh anything if we haven't changed page sizes.
1253 
1254     if (pageSize == d->settings->pageSize)
1255     {
1256         return;
1257     }
1258 
1259     d->settings->pageSize = pageSize;
1260 
1261     // cleaning pageSize memory before invoking clear()
1262 
1263     for (int i = 0 ; i < d->settings->photosizes.count() ; ++i)
1264     {
1265         delete d->settings->photosizes.at(i);
1266     }
1267 
1268     d->settings->photosizes.clear();
1269 
1270     // get template-files and parse them
1271 
1272     QDir dir(QStandardPaths::locate(QStandardPaths::GenericDataLocation,
1273                                     QLatin1String("digikam/templates"),
1274                                     QStandardPaths::LocateDirectory));
1275     const QStringList list = dir.entryList(QStringList() << QLatin1String("*.xml"));
1276 
1277     qCDebug(DIGIKAM_DPLUGIN_GENERIC_LOG) << "Template XML files list: "
1278                                          << list;
1279 
1280     Q_FOREACH (const QString& fn, list)
1281     {
1282         parseTemplateFile(dir.absolutePath() + QLatin1Char('/') + fn, pageSize);
1283     }
1284 
1285     qCDebug(DIGIKAM_DPLUGIN_GENERIC_LOG) << "photosizes count() ="
1286                                          << d->settings->photosizes.count();
1287     qCDebug(DIGIKAM_DPLUGIN_GENERIC_LOG) << "photosizes isEmpty() ="
1288                                          << d->settings->photosizes.isEmpty();
1289 
1290     if (d->settings->photosizes.isEmpty())
1291     {
1292         qCDebug(DIGIKAM_DPLUGIN_GENERIC_LOG) << "Empty photoSize-list, create default size";
1293 
1294         // There is no valid page size yet.  Create a default page (B10) to prevent crashes.
1295 
1296         AdvPrintPhotoSize* const p = new AdvPrintPhotoSize;
1297 
1298         // page size: B10 (32 x 45 mm)
1299 
1300         p->m_layouts.append(new QRect(0, 0, 3200, 4500));
1301         p->m_layouts.append(new QRect(0, 0, 3200, 4500));
1302 
1303         // add to the list
1304 
1305         d->settings->photosizes.append(p);
1306     }
1307 
1308     // load the photo sizes into the listbox
1309 
1310     d->photoUi->ListPhotoSizes->blockSignals(true);
1311     d->photoUi->ListPhotoSizes->clear();
1312     QList<AdvPrintPhotoSize*>::iterator it;
1313 
1314     for (it = d->settings->photosizes.begin() ;
1315          it != d->settings->photosizes.end() ; ++it)
1316     {
1317         AdvPrintPhotoSize* const s = static_cast<AdvPrintPhotoSize*>(*it);
1318 
1319         if (s)
1320         {
1321             QListWidgetItem* const pWItem = new QListWidgetItem(s->m_label);
1322             pWItem->setIcon(s->m_icon);
1323             d->photoUi->ListPhotoSizes->addItem(pWItem);
1324         }
1325     }
1326 
1327     // Adding custom choice
1328 
1329 #if KI18N_VERSION >= QT_VERSION_CHECK(5, 89, 0)
1330 
1331     QListWidgetItem* const pWItem = new QListWidgetItem(CUSTOM_PAGE_LAYOUT_NAME.title.toString());
1332 
1333 #else
1334 
1335     QListWidgetItem* const pWItem = new QListWidgetItem(i18nc(CUSTOM_PAGE_LAYOUT_NAME.context, CUSTOM_PAGE_LAYOUT_NAME.title));
1336 
1337 #endif
1338 
1339     TemplateIcon ti(80, pageSize.toSize());
1340     ti.begin();
1341     QPainter& painter             = ti.getPainter();
1342     painter.setPen(Qt::color1);
1343     painter.drawText(painter.viewport(), Qt::AlignCenter, i18n("Custom\nlayout"));
1344     ti.end();
1345 
1346     pWItem->setIcon(ti.getIcon());
1347     d->photoUi->ListPhotoSizes->addItem(pWItem);
1348     d->photoUi->ListPhotoSizes->blockSignals(false);
1349     d->photoUi->ListPhotoSizes->setCurrentRow(0, QItemSelectionModel::Select);
1350 }
1351 
1352 void AdvPrintPhotoPage::parseTemplateFile(const QString& fn, const QSizeF& pageSize)
1353 {
1354     QDomDocument doc(QLatin1String("mydocument"));
1355     qCDebug(DIGIKAM_DPLUGIN_GENERIC_LOG) << " XXX: " <<  fn;
1356 
1357     if (fn.isEmpty())
1358     {
1359         return;
1360     }
1361 
1362     QFile file(fn);
1363 
1364     if (!file.open(QIODevice::ReadOnly))
1365     {
1366         return;
1367     }
1368 
1369     if (!doc.setContent(&file))
1370     {
1371         file.close();
1372         return;
1373     }
1374 
1375     file.close();
1376 
1377     AdvPrintPhotoSize* p = nullptr;
1378 
1379     // print out the element names of all elements that are direct children
1380     // of the outermost element.
1381 
1382     QDomElement docElem  = doc.documentElement();
1383     qCDebug(DIGIKAM_DPLUGIN_GENERIC_LOG) << docElem.tagName(); // the node really is an element.
1384 
1385     QSizeF size;
1386     QString unit;
1387     int scaleValue;
1388     QDomNode n = docElem.firstChild();
1389 
1390     while (!n.isNull())
1391     {
1392         size          = QSizeF(0, 0);
1393         scaleValue    = 10; // 0.1 mm
1394         QDomElement e = n.toElement(); // try to convert the node to an element.
1395 
1396         if (!e.isNull())
1397         {
1398             if (e.tagName() == QLatin1String("paper"))
1399             {
1400                 size = QSizeF(e.attribute(QLatin1String("width"),
1401                                           QLatin1String("0")).toFloat(),
1402                               e.attribute(QLatin1String("height"),
1403                                           QLatin1String("0")).toFloat());
1404                 unit = e.attribute(QLatin1String("unit"),
1405                                    QLatin1String("mm"));
1406 
1407                 qCDebug(DIGIKAM_DPLUGIN_GENERIC_LOG) << e.tagName()
1408                                              << QLatin1String(" name=")
1409                                              << e.attribute(QLatin1String("name"),
1410                                                             QLatin1String("??"))
1411                                              << " size= " << size
1412                                              << " unit= " << unit;
1413 
1414                 if ((size == QSizeF(0.0, 0.0)) && (size == pageSize))
1415                 {
1416                     // skipping templates without page size since pageSize is not set
1417 
1418                     n = n.nextSibling();
1419                     continue;
1420                 }
1421                 else if (unit != QLatin1String("mm") &&
1422                          size != QSizeF(0.0, 0.0))      // "cm", "inches" or "inch"
1423                 {
1424                     // convert to mm
1425 
1426                     if ((unit == QLatin1String("inches")) ||
1427                         (unit == QLatin1String("inch")))
1428                     {
1429                         size      *= 25.4;
1430                         scaleValue = 1000;
1431                         qCDebug(DIGIKAM_DPLUGIN_GENERIC_LOG) << "template size "
1432                                                      << size
1433                                                      << " page size "
1434                                                      << pageSize;
1435                     }
1436                     else if (unit == QLatin1String("cm"))
1437                     {
1438                         size      *= 10;
1439                         scaleValue = 100;
1440                         qCDebug(DIGIKAM_DPLUGIN_GENERIC_LOG) << "template size "
1441                                                      << size
1442                                                      << " page size "
1443                                                      << pageSize;
1444                     }
1445                     else
1446                     {
1447                         qCWarning(DIGIKAM_DPLUGIN_GENERIC_LOG) << "Wrong unit "
1448                                                        << unit
1449                                                        << " skipping layout";
1450                         n = n.nextSibling();
1451                         continue;
1452                     }
1453                 }
1454 
1455                 static const float round_value = 0.01F;
1456 
1457                 if (size == QSizeF(0, 0))
1458                 {
1459                     size = pageSize;
1460                     unit = QLatin1String("mm");
1461                 }
1462                 else if ((pageSize != QSizeF(0, 0)) &&
1463                          ((size.height() > (pageSize.height() + round_value)) ||
1464                           (size.width()  > (pageSize.width()  + round_value))))
1465                 {
1466                     qCDebug(DIGIKAM_DPLUGIN_GENERIC_LOG) << "skipping size "
1467                                                  << size
1468                                                  << " page size "
1469                                                  << pageSize;
1470                     // skipping layout it can't fit
1471 
1472                     n = n.nextSibling();
1473                     continue;
1474                 }
1475 
1476                 // Next templates are good
1477 
1478                 qCDebug(DIGIKAM_DPLUGIN_GENERIC_LOG) << "layout size "
1479                                              << size
1480                                              << " page size "
1481                                              << pageSize;
1482                 QDomNode np = e.firstChild();
1483 
1484                 while (!np.isNull())
1485                 {
1486                     QDomElement ep = np.toElement(); // try to convert the node to an element.
1487 
1488                     if (!ep.isNull())
1489                     {
1490                         if (ep.tagName() == QLatin1String("template"))
1491                         {
1492                             p = new AdvPrintPhotoSize;
1493                             QSizeF sizeManaged;
1494 
1495                             // set page size
1496 
1497                             if (pageSize == QSizeF(0, 0))
1498                             {
1499                                 sizeManaged = size * scaleValue;
1500                             }
1501                             else if ((unit == QLatin1String("inches")) ||
1502                                      (unit == QLatin1String("inch")))
1503                             {
1504                                 sizeManaged = pageSize * scaleValue / 25.4;
1505                             }
1506                             else
1507                             {
1508                                 sizeManaged = pageSize * 10;
1509                             }
1510 
1511                             p->m_layouts.append(new QRect(0,
1512                                                           0,
1513                                                           (int)sizeManaged.width(),
1514                                                           (int)sizeManaged.height()));
1515 
1516                             // create a small preview of the template
1517 
1518                             TemplateIcon iconpreview(80, sizeManaged.toSize());
1519                             iconpreview.begin();
1520 
1521                             QString desktopFileName = ep.attribute(QLatin1String("name"),
1522                                                                    QLatin1String("XXX")) +
1523                                                                    QLatin1String(".desktop");
1524 
1525                             QDir dir(QStandardPaths::locate(QStandardPaths::GenericDataLocation,
1526                                                             QLatin1String("digikam/templates"),
1527                                                             QStandardPaths::LocateDirectory));
1528                             const QStringList list  = dir.entryList(QStringList()
1529                                                       << desktopFileName);
1530 
1531                             qCDebug(DIGIKAM_DPLUGIN_GENERIC_LOG) << "Template desktop files list: "
1532                                                          << list;
1533 
1534                             QStringList::ConstIterator it  = list.constBegin();
1535                             QStringList::ConstIterator end = list.constEnd();
1536 
1537                             if (it != end)
1538                             {
1539                                 p->m_label = KDesktopFile(dir.absolutePath() +
1540                                              QLatin1Char('/') + *it).readName();
1541                             }
1542                             else
1543                             {
1544                                 p->m_label = ep.attribute(QLatin1String("name"), QLatin1String("XXX"));
1545                                 qCWarning(DIGIKAM_DPLUGIN_GENERIC_LOG) << "missed template translation "
1546                                                                << desktopFileName;
1547                             }
1548 
1549                             p->m_dpi        = ep.attribute(QLatin1String("dpi"),
1550                                                          QLatin1String("0")).toInt();
1551                             p->m_autoRotate = (ep.attribute(QLatin1String("autorotate"),
1552                                               QLatin1String("false")) == QLatin1String("true")) ?
1553                                               true : false;
1554                             QDomNode nt     = ep.firstChild();
1555 
1556                             while (!nt.isNull())
1557                             {
1558                                 QDomElement et = nt.toElement(); // try to convert the node to an element.
1559 
1560                                 if (!et.isNull())
1561                                 {
1562                                     if (et.tagName() == QLatin1String("photo"))
1563                                     {
1564                                         float value = et.attribute(QLatin1String("width"),
1565                                                                    QLatin1String("0")).toFloat();
1566                                         int width   = (int)((value == 0 ? size.width() : value) *
1567                                                             scaleValue);
1568                                         value       = et.attribute(QLatin1String("height"),
1569                                                                    QLatin1String("0")).toFloat();
1570                                         int height  = (int)((value == 0 ? size.height() : value) *
1571                                                             scaleValue);
1572                                         int photoX  = (int)((et.attribute(QLatin1String("x"),
1573                                                       QLatin1String("0")).toFloat() * scaleValue));
1574                                         int photoY  = (int)((et.attribute(QLatin1String("y"),
1575                                                       QLatin1String("0")).toFloat() * scaleValue));
1576 
1577                                         p->m_layouts.append(new QRect(photoX,
1578                                                                       photoY,
1579                                                                       width,
1580                                                                       height));
1581                                         iconpreview.fillRect(photoX,
1582                                                              photoY,
1583                                                              width,
1584                                                              height,
1585                                                              Qt::color1);
1586                                     }
1587                                     else if (et.tagName() == QLatin1String("photogrid"))
1588                                     {
1589                                         float value    = et.attribute(QLatin1String("pageWidth"),
1590                                                                       QLatin1String("0")).toFloat();
1591                                         int pageWidth  = (int)((value == 0 ? size.width() : value) *
1592                                                                scaleValue);
1593                                         value          = et.attribute(QLatin1String("pageHeight"),
1594                                                                       QLatin1String("0")).toFloat();
1595                                         int pageHeight = (int)((value == 0 ? size.height() : value) *
1596                                                                 scaleValue);
1597                                         int rows       = et.attribute(QLatin1String("rows"),
1598                                                                       QLatin1String("0")).toInt();
1599                                         int columns    = et.attribute(QLatin1String("columns"),
1600                                                                       QLatin1String("0")).toInt();
1601 
1602                                         if (rows > 0 && columns > 0)
1603                                         {
1604                                             createPhotoGrid(p,
1605                                                             pageWidth,
1606                                                             pageHeight,
1607                                                             rows,
1608                                                             columns,
1609                                                             &iconpreview);
1610                                         }
1611                                         else
1612                                         {
1613                                             qCWarning(DIGIKAM_DPLUGIN_GENERIC_LOG)
1614                                                 << " Wrong grid configuration, rows "
1615                                                 << rows
1616                                                 << ", columns "
1617                                                 << columns;
1618                                         }
1619                                     }
1620                                     else
1621                                     {
1622                                         qCDebug(DIGIKAM_DPLUGIN_GENERIC_LOG) << "    "
1623                                                                      <<  et.tagName();
1624                                     }
1625                                 }
1626 
1627                                 nt = nt.nextSibling();
1628                             }
1629 
1630                             iconpreview.end();
1631                             p->m_icon = iconpreview.getIcon();
1632                             d->settings->photosizes.append(p);
1633                         }
1634                         else
1635                         {
1636                             qCDebug(DIGIKAM_DPLUGIN_GENERIC_LOG) << "? "
1637                                                          <<  ep.tagName()
1638                                                          << " attr="
1639                                                          << ep.attribute(QLatin1String("name"),
1640                                                                          QLatin1String("??"));
1641                         }
1642                     }
1643 
1644                     np = np.nextSibling();
1645                 }
1646             }
1647             else
1648             {
1649                 qCDebug(DIGIKAM_DPLUGIN_GENERIC_LOG) << "??"
1650                                              << e.tagName()
1651                                              << " name="
1652                                              << e.attribute(QLatin1String("name"), QLatin1String("??"));
1653             }
1654         }
1655 
1656         n = n.nextSibling();
1657     }
1658 }
1659 
1660 } // namespace DigikamGenericPrintCreatorPlugin
1661 
1662 #include "moc_advprintphotopage.cpp"