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

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2008-01-11
0007  * Description : a tool to print images
0008  *
0009  * SPDX-FileCopyrightText: 2008-2012 by Angelo Naselli <anaselli at linux dot it>
0010  * SPDX-FileCopyrightText: 2006-2024 by Gilles Caulier <caulier dot gilles at gmail dot com>
0011  *
0012  * SPDX-License-Identifier: GPL-2.0-or-later
0013  *
0014  * ============================================================ */
0015 
0016 #include "advprintwizard.h"
0017 
0018 // C++ includes
0019 
0020 #include <memory>
0021 
0022 // Qt includes
0023 
0024 #include <QFileInfo>
0025 #include <QPalette>
0026 #include <QtGlobal>
0027 #include <QDomDocument>
0028 #include <QContextMenuEvent>
0029 #include <QStringView>
0030 #include <QStandardPaths>
0031 #include <QMenu>
0032 #include <QIcon>
0033 #include <QLocale>
0034 #include <QTemporaryDir>
0035 #include <QKeyEvent>
0036 
0037 // KDE includes
0038 
0039 #include <klocalizedstring.h>
0040 #include <ksharedconfig.h>
0041 #include <kconfiggroup.h>
0042 
0043 // Local includes
0044 
0045 #include "digikam_globals.h"
0046 #include "digikam_debug.h"
0047 #include "advprintthread.h"
0048 #include "advprintintropage.h"
0049 #include "advprintalbumspage.h"
0050 #include "advprintphotopage.h"
0051 #include "advprintcaptionpage.h"
0052 #include "advprintcroppage.h"
0053 #include "advprintoutputpage.h"
0054 #include "advprintfinalpage.h"
0055 #include "templateicon.h"
0056 #include "dwizardpage.h"
0057 #include "dfiledialog.h"
0058 #include "dmetadata.h"
0059 
0060 namespace DigikamGenericPrintCreatorPlugin
0061 {
0062 
0063 class Q_DECL_HIDDEN AdvPrintWizard::Private
0064 {
0065 public:
0066 
0067     explicit Private()
0068       : introPage    (nullptr),
0069         albumsPage   (nullptr),
0070         photoPage    (nullptr),
0071         captionPage  (nullptr),
0072         cropPage     (nullptr),
0073         outputPage   (nullptr),
0074         finalPage    (nullptr),
0075         settings     (nullptr),
0076         previewThread(nullptr),
0077         iface        (nullptr),
0078         tempPath     (nullptr)
0079     {
0080     }
0081 
0082     AdvPrintIntroPage*   introPage;
0083     AdvPrintAlbumsPage*  albumsPage;
0084     AdvPrintPhotoPage*   photoPage;
0085     AdvPrintCaptionPage* captionPage;
0086     AdvPrintCropPage*    cropPage;
0087     AdvPrintOutputPage*  outputPage;
0088     AdvPrintFinalPage*   finalPage;
0089     AdvPrintSettings*    settings;
0090     AdvPrintThread*      previewThread;
0091     DInfoInterface*      iface;
0092 
0093     QTemporaryDir*       tempPath;
0094 };
0095 
0096 AdvPrintWizard::AdvPrintWizard(QWidget* const parent, DInfoInterface* const iface)
0097     : DWizardDlg(parent, QLatin1String("PrintCreatorDialog")),
0098       d         (new Private)
0099 {
0100     setWindowTitle(i18nc("@title:window", "Print Creator"));
0101 
0102     d->iface           = iface;
0103     d->settings        = new AdvPrintSettings;
0104     d->previewThread   = new AdvPrintThread(this);
0105 
0106     KSharedConfigPtr config = KSharedConfig::openConfig();
0107     KConfigGroup group      = config->group(QLatin1String("PrintCreator"));
0108     d->settings->readSettings(group);
0109 
0110     d->introPage       = new AdvPrintIntroPage(this,   i18n("Welcome to Print Creator"));
0111     d->albumsPage      = new AdvPrintAlbumsPage(this,  i18n("Albums Selection"));
0112     d->photoPage       = new AdvPrintPhotoPage(this,   i18n("Select Page Layout"));
0113     d->captionPage     = new AdvPrintCaptionPage(this, i18n("Caption Settings"));
0114     d->cropPage        = new AdvPrintCropPage(this,    i18n("Crop and Rotate Photos"));
0115     d->outputPage      = new AdvPrintOutputPage(this,  i18n("Images Output Settings"));
0116     d->finalPage       = new AdvPrintFinalPage(this,   i18n("Render Printing"));
0117     d->finalPage->setPhotoPage(d->photoPage);
0118 
0119     // -----------------------------------
0120 
0121     connect(button(QWizard::CancelButton), SIGNAL(clicked()),
0122             this, SLOT(reject()));
0123 
0124     connect(d->photoPage->imagesList(), SIGNAL(signalImageListChanged()),
0125             d->captionPage, SLOT(slotUpdateImagesList()));
0126 
0127     connect(d->previewThread, SIGNAL(signalPreview(QImage)),
0128             this, SLOT(slotPreview(QImage)));
0129 
0130     d->tempPath           = new QTemporaryDir();
0131     d->settings->tempPath = d->tempPath->path();
0132 
0133     installEventFilter(this);
0134 }
0135 
0136 AdvPrintWizard::~AdvPrintWizard()
0137 {
0138     d->previewThread->cancel();
0139 
0140     KSharedConfigPtr config = KSharedConfig::openConfig();
0141     KConfigGroup group      = config->group(QLatin1String("PrintCreator"));
0142     d->settings->writeSettings(group);
0143 
0144     delete d->settings;
0145     delete d->tempPath;
0146     delete d;
0147 }
0148 
0149 DInfoInterface* AdvPrintWizard::iface() const
0150 {
0151     return d->iface;
0152 }
0153 
0154 AdvPrintSettings* AdvPrintWizard::settings() const
0155 {
0156     return d->settings;
0157 }
0158 
0159 int AdvPrintWizard::nextId() const
0160 {
0161     if (d->settings->selMode == AdvPrintSettings::ALBUMS)
0162     {
0163         if (currentPage() == d->introPage)
0164         {
0165             return d->albumsPage->id();
0166         }
0167     }
0168     else
0169     {
0170         if (currentPage() == d->introPage)
0171         {
0172             return d->photoPage->id();
0173         }
0174     }
0175 
0176     if (d->settings->printerName == d->settings->outputName(AdvPrintSettings::FILES))
0177     {
0178         if (currentPage() == d->cropPage)
0179         {
0180             return d->outputPage->id();
0181         }
0182     }
0183     else
0184     {
0185         if (currentPage() == d->cropPage)
0186         {
0187             return d->finalPage->id();
0188         }
0189     }
0190 
0191     return DWizardDlg::nextId();
0192 }
0193 
0194 QList<QUrl> AdvPrintWizard::itemsList() const
0195 {
0196     QList<QUrl> urls;
0197 
0198     for (QList<AdvPrintPhoto*>::iterator it = d->settings->photos.begin() ;
0199          it != d->settings->photos.end() ; ++it)
0200     {
0201         AdvPrintPhoto* const photo = static_cast<AdvPrintPhoto*>(*it);
0202         urls << photo->m_url;
0203     }
0204 
0205     return urls;
0206 }
0207 
0208 void AdvPrintWizard::setItemsList(const QList<QUrl>& fileList)
0209 {
0210     QList<QUrl> list = fileList;
0211 
0212     for (int i = 0 ; i < d->settings->photos.count() ; ++i)
0213     {
0214         delete d->settings->photos.at(i);
0215     }
0216 
0217     d->settings->photos.clear();
0218 
0219     if (list.isEmpty() && d->iface)
0220     {
0221         list = d->iface->currentSelectedItems();
0222     }
0223 
0224     for (int i = 0 ; i < list.count() ; ++i)
0225     {
0226         AdvPrintPhoto* const photo = new AdvPrintPhoto(150, d->iface);
0227         photo->m_url               = list[i];
0228         photo->m_first             = true;
0229         d->settings->photos.append(photo);
0230     }
0231 
0232     d->cropPage->ui()->BtnCropPrev->setEnabled(false);
0233 
0234     if (d->settings->photos.count() == 1)
0235     {
0236         d->cropPage->ui()->BtnCropNext->setEnabled(false);
0237     }
0238 
0239     Q_EMIT currentIdChanged(d->photoPage->id());
0240 }
0241 
0242 void AdvPrintWizard::updateCropFrame(AdvPrintPhoto* const photo, int photoIndex)
0243 {
0244     int sizeIndex              = d->photoPage->ui()->ListPhotoSizes->currentRow();
0245     AdvPrintPhotoSize* const s = d->settings->photosizes.at(sizeIndex);
0246 
0247     d->cropPage->ui()->cropFrame->init(photo,
0248                                        d->settings->getLayout(photoIndex, sizeIndex)->width(),
0249                                        d->settings->getLayout(photoIndex, sizeIndex)->height(),
0250                                        s->m_autoRotate,
0251                                        true);
0252 
0253     d->cropPage->ui()->LblCropPhoto->setText(i18n("Photo %1 of %2",
0254                                              photoIndex + 1,
0255                                              d->settings->photos.count()));
0256 }
0257 
0258 void AdvPrintWizard::previewPhotos()
0259 {
0260     if (d->settings->photosizes.isEmpty())
0261     {
0262         qCDebug(DIGIKAM_DPLUGIN_GENERIC_LOG) << "Photo sizes is null";
0263         return;
0264     }
0265 
0266     // get the selected layout
0267 
0268     int photoCount             = d->settings->photos.count();
0269     int curr1                  = d->photoPage->ui()->ListPhotoSizes->currentRow();
0270     AdvPrintPhotoSize* const s = d->settings->photosizes.at(curr1);
0271     int emptySlots             = 0;
0272     int pageCount              = 0;
0273     int photosPerPage          = 0;
0274 
0275     if (photoCount > 0)
0276     {
0277         // how many pages?  Recall that the first layout item is the paper size
0278 
0279         photosPerPage = s->m_layouts.count() - 1;
0280         int remainder = photoCount % photosPerPage;
0281 
0282         if (remainder > 0)
0283         {
0284             emptySlots = photosPerPage - remainder;
0285         }
0286 
0287         pageCount     = photoCount / photosPerPage;
0288 
0289         if (emptySlots > 0)
0290         {
0291             pageCount++;
0292         }
0293     }
0294 
0295     d->photoPage->ui()->LblPhotoCount->setText(QString::number(photoCount));
0296     d->photoPage->ui()->LblSheetsPrinted->setText(QString::number(pageCount));
0297     d->photoPage->ui()->LblEmptySlots->setText(QString::number(emptySlots));
0298 
0299     if (photoCount > 0)
0300     {
0301         // photo previews
0302         // preview the first page.
0303         // find the first page of photos
0304 
0305         int page        = 0;
0306         int count       = 0;
0307         int current     = 0;
0308         int currentPage = 0;
0309 
0310         for (QList<AdvPrintPhoto*>::iterator it = d->settings->photos.begin() ;
0311             it != d->settings->photos.end() ; ++it)
0312         {
0313             AdvPrintPhoto* const photo = static_cast<AdvPrintPhoto*>(*it);
0314 
0315             photo->m_cropRegion.setRect(-1, -1, -1, -1);
0316             photo->m_rotation  = 0;
0317             QRect* const curr2 = s->m_layouts.at(count + 1);
0318             photo->updateCropRegion(curr2->width(),
0319                                     curr2->height(),
0320                                     s->m_autoRotate);
0321 
0322             count++;
0323 
0324             if (count >= photosPerPage)
0325             {
0326                 if (page == d->settings->currentPreviewPage)
0327                 {
0328                     currentPage = current;
0329                 }
0330 
0331                 page++;
0332                 current += photosPerPage;
0333                 count    = 0;
0334             }
0335         }
0336 
0337         // send this photo list to the painter
0338 
0339         AdvPrintSettings* const pwSettings = new AdvPrintSettings;
0340         pwSettings->photos                 = d->settings->photos;
0341         pwSettings->outputLayouts          = s;
0342         pwSettings->currentPreviewPage     = currentPage;
0343         pwSettings->disableCrop            = d->cropPage->ui()->m_disableCrop->isChecked();
0344 
0345         d->previewThread->preview(pwSettings, d->photoPage->ui()->BmpFirstPagePreview->size());
0346         d->previewThread->start();
0347     }
0348     else
0349     {
0350         d->photoPage->ui()->BmpFirstPagePreview->clear();
0351         d->photoPage->ui()->LblPreview->clear();
0352         d->photoPage->ui()->LblPreview->setText(i18n("Page %1 of %2", 0, 0));
0353         d->photoPage->manageBtnPreviewPage();
0354         d->photoPage->update();
0355     }
0356 }
0357 
0358 void AdvPrintWizard::slotPreview(const QImage& img)
0359 {
0360     qCDebug(DIGIKAM_DPLUGIN_GENERIC_LOG) << "Receive Preview" << img.size();
0361 
0362     d->photoPage->ui()->BmpFirstPagePreview->clear();
0363     d->photoPage->ui()->BmpFirstPagePreview->setPixmap(QPixmap::fromImage(img));
0364     d->photoPage->ui()->LblPreview->setText(i18n("Page %1 of %2",
0365                                                  d->settings->currentPreviewPage + 1,
0366                                                  d->photoPage->getPageCount()));
0367     d->photoPage->manageBtnPreviewPage();
0368     d->photoPage->update();
0369 }
0370 
0371 int AdvPrintWizard::normalizedInt(double n)
0372 {
0373     return (int)(n + 0.5);
0374 }
0375 
0376 bool AdvPrintWizard::eventFilter(QObject* o, QEvent* e)
0377 {
0378     if (e && (e->type() == QEvent::KeyRelease))
0379     {
0380         QKeyEvent* const k = (QKeyEvent*)e;
0381 
0382         if ((k->key() == Qt::Key_PageUp)   ||
0383             (k->key() == Qt::Key_PageDown) ||
0384             (k->key() == Qt::Key_Up)       ||
0385             (k->key() == Qt::Key_Down))
0386         {
0387             if (currentPage() == d->cropPage)
0388             {
0389                 // Pass the key event to move crop frame region.
0390 
0391                 d->cropPage->ui()->cropFrame->setFocus();
0392                 QApplication::sendEvent(d->cropPage->ui()->cropFrame, e);
0393 
0394                 return true; // eat event
0395             }
0396         }
0397     }
0398 
0399     return QWizard::eventFilter(o, e);
0400 }
0401 
0402 } // namespace DigikamGenericPrintCreatorPlugin
0403 
0404 #include "moc_advprintwizard.cpp"