1 /* ============================================================
2  *
3  * This file is a part of digiKam project
4  * https://www.digikam.org
5  *
6  * Date        : 2009-12-13
7  * Description : a tool to blend bracketed images.
8  *
9  * Copyright (C) 2009-2021 by Gilles Caulier <caulier dot gilles at gmail dot com>
10  * Copyright (C) 2015      by Benjamin Girault <benjamin dot girault at gmail dot com>
11  *
12  * This program is free software; you can redistribute it
13  * and/or modify it under the terms of the GNU General
14  * Public License as published by the Free Software Foundation;
15  * either version 2, or (at your option)
16  * any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * ============================================================ */
24 
25 #include "expoblendingdlg.h"
26 
27 // C ANSI includes
28 
29 extern "C"
30 {
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #ifndef Q_CC_MSVC
34 #   include <unistd.h>
35 #endif
36 }
37 
38 // C++ includes
39 
40 #include <cstdio>
41 
42 // Qt includes
43 
44 #include <QPointer>
45 #include <QCloseEvent>
46 #include <QFile>
47 #include <QDir>
48 #include <QFileInfo>
49 #include <QGridLayout>
50 #include <QPushButton>
51 #include <QScrollArea>
52 #include <QApplication>
53 #include <QMenu>
54 #include <QMessageBox>
55 #include <QGroupBox>
56 #include <QWindow>
57 
58 // KDE includes
59 
60 #include <klocalizedstring.h>
61 #include <ksharedconfig.h>
62 #include <kconfiggroup.h>
63 
64 // Local includes
65 
66 #include "digikam_debug.h"
67 #include "expoblendingthread.h"
68 #include "bracketstack.h"
69 #include "enfusebinary.h"
70 #include "enfusesettings.h"
71 #include "enfusestack.h"
72 #include "dmessagebox.h"
73 #include "dpreviewmanager.h"
74 #include "dsavesettingswidget.h"
75 #include "expoblendingmanager.h"
76 #include "dfileoperations.h"
77 #include "dxmlguiwindow.h"
78 
79 using namespace Digikam;
80 
81 namespace DigikamGenericExpoBlendingPlugin
82 {
83 
84 class Q_DECL_HIDDEN ExpoBlendingDlg::Private
85 {
86 public:
87 
Private()88     explicit Private()
89       : templateFileName    (nullptr),
90         previewWidget       (nullptr),
91         enfuseSettingsBox   (nullptr),
92         saveSettingsBox     (nullptr),
93         bracketStack        (nullptr),
94         enfuseStack         (nullptr),
95         mngr                (nullptr),
96         firstImageDisplayed (false),
97         buttonBox           (nullptr),
98         previewButton       (nullptr),
99         startButton         (nullptr),
100         propagateReject     (true)
101     {
102     }
103 
104     QString               inputFileName;
105     QString               output;
106 
107     QLineEdit*            templateFileName;
108 
109     DPreviewManager*      previewWidget;
110 
111     EnfuseSettingsWidget* enfuseSettingsBox;
112 
113     DSaveSettingsWidget*  saveSettingsBox;
114 
115     BracketStackList*     bracketStack;
116     EnfuseStackList*      enfuseStack;
117 
118     ExpoBlendingManager*  mngr;
119 
120     bool                  firstImageDisplayed;
121 
122     QDialogButtonBox*     buttonBox;
123     QPushButton*          previewButton;
124     QPushButton*          startButton;
125 
126     bool                  propagateReject;
127 };
128 
ExpoBlendingDlg(ExpoBlendingManager * const mngr,QWidget * const parent)129 ExpoBlendingDlg::ExpoBlendingDlg(ExpoBlendingManager* const mngr, QWidget* const parent)
130     : QDialog(parent),
131       d      (new Private)
132 {
133     d->mngr = mngr;
134 
135     setModal(false);
136     setWindowTitle(i18nc("@title", "Exposure Blending"));
137 
138     const int spacing                = QApplication::style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing);
139 
140     d->buttonBox                     = new QDialogButtonBox(QDialogButtonBox::Close, this);
141     d->buttonBox->button(QDialogButtonBox::Close)->setDefault(true);
142 
143     d->startButton                   = new QPushButton(this);
144     d->startButton->setText(i18nc("@action: button", "&Save"));
145     d->startButton->setIcon(QIcon::fromTheme(QLatin1String("document-save")));
146     d->startButton->setToolTip(i18nc("@info: tooltip", "Process and save selected items."));
147     d->buttonBox->addButton(d->startButton, QDialogButtonBox::ActionRole);
148 
149     d->previewButton                 = new QPushButton(this);
150     d->previewButton->setText(i18nc("@action: button", "&Preview"));
151     d->previewButton->setIcon(QIcon::fromTheme(QLatin1String("system-run")));
152     d->previewButton->setToolTip(i18nc("@info: tooltip", "Process a preview of bracketed images stack with current settings."));
153     d->buttonBox->addButton(d->previewButton, QDialogButtonBox::ActionRole);
154 
155     QPushButton* const defaultButton = new QPushButton(this);
156     defaultButton->setText(i18nc("@action: button", "&Default"));
157     defaultButton->setIcon(QIcon::fromTheme(QLatin1String("document-revert")));
158     defaultButton->setToolTip(i18nc("@info:tooltip", "Revert current settings to default values."));
159     d->buttonBox->addButton(defaultButton, QDialogButtonBox::ResetRole);
160 
161     // ---------------------------------------------------------------
162 
163     d->previewWidget                 = new DPreviewManager(this);
164     d->previewWidget->setButtonText(i18nc("@action: button", "Details..."));
165 
166     // ---------------------------------------------------------------
167 
168     QScrollArea* const rightColumn   = new QScrollArea(this);
169     QWidget* const rightPanel        = new QWidget(rightColumn->viewport());
170     rightColumn->setWidget(rightPanel);
171     rightColumn->setWidgetResizable(true);
172     rightColumn->setFrameStyle(QFrame::NoFrame);
173 
174     QVBoxLayout* const panel         = new QVBoxLayout(rightPanel);
175 
176     d->bracketStack                  = new BracketStackList(rightPanel);
177     panel->addWidget(d->bracketStack, 1);
178 
179     // ---------------------------------------------------------------
180 
181     QGroupBox* const enfuse          = new QGroupBox(rightPanel);
182     enfuse->setTitle(i18nc("@title", "Enfuse Settings"));
183     QVBoxLayout* const elay          = new QVBoxLayout(enfuse);
184     enfuse->setLayout(elay);
185 
186     d->enfuseSettingsBox             = new EnfuseSettingsWidget(enfuse);
187     elay->addWidget(d->enfuseSettingsBox);
188 
189     panel->addWidget(enfuse, 1);
190 
191     // ---------------------------------------------------------------
192 
193     QGroupBox* const save            = new QGroupBox(rightPanel);
194     save->setTitle(i18nc("@title", "Save Result"));
195     QVBoxLayout* const slay = new QVBoxLayout(save);
196     save->setLayout(slay);
197 
198     d->saveSettingsBox               = new DSaveSettingsWidget(save);
199     slay->addWidget(d->saveSettingsBox);
200 
201     QHBoxLayout* const hbox          = new QHBoxLayout(save);
202 
203     QLabel* const customLabel        = new QLabel(save);
204     customLabel->setText(i18nc("@label: textbox", "File Name Template: "));
205     hbox->addWidget(customLabel);
206 
207     d->templateFileName              = new QLineEdit(save);
208     d->templateFileName->setClearButtonEnabled(true);
209     hbox->addWidget(d->templateFileName);
210 
211     d->saveSettingsBox->setCustomSettingsWidget(d->saveSettingsBox);
212     slay->addLayout(hbox);
213 
214     panel->addWidget(save, 1);
215 
216     // ---------------------------------------------------------------
217 
218     d->enfuseStack          = new EnfuseStackList(rightPanel);
219     panel->addWidget(d->enfuseStack, 1);
220 
221     rightPanel->setLayout(panel);
222     panel->setContentsMargins(QMargins());
223 
224     // ---------------------------------------------------------------
225 
226     QGridLayout* const grid = new QGridLayout(this);
227     grid->addWidget(d->previewWidget, 0, 0, 3, 1);
228     grid->addWidget(rightColumn,      0, 1, 3, 1);
229     grid->addWidget(d->buttonBox,     4, 0, 1, 2);
230     grid->setContentsMargins(spacing, spacing, spacing, spacing);
231     grid->setSpacing(spacing);
232     grid->setColumnStretch(0, 10);
233     grid->setColumnStretch(1, 5);
234     setLayout(grid);
235 
236     // ---------------------------------------------------------------
237 
238     connect(this, SIGNAL(finished(int)),
239             this, SLOT(slotFinished()));
240 
241     connect(this, SIGNAL(cancelClicked()),
242             this, SLOT(slotCancelClicked()));
243 
244     connect(defaultButton, SIGNAL(clicked()),
245             this, SLOT(slotDefault()));
246 
247     connect(d->startButton, SIGNAL(clicked()),
248             this, SLOT(slotProcess()));
249 
250     connect(d->previewButton, SIGNAL(clicked()),
251             this, SLOT(slotPreview()));
252 
253     connect(d->buttonBox, &QDialogButtonBox::rejected,
254             this, &ExpoBlendingDlg::slotCloseClicked);
255 
256     connect(d->mngr->thread(), SIGNAL(starting(DigikamGenericExpoBlendingPlugin::ExpoBlendingActionData)),
257             this, SLOT(slotExpoBlendingAction(DigikamGenericExpoBlendingPlugin::ExpoBlendingActionData)));
258 
259     connect(d->mngr->thread(), SIGNAL(finished(DigikamGenericExpoBlendingPlugin::ExpoBlendingActionData)),
260             this, SLOT(slotExpoBlendingAction(DigikamGenericExpoBlendingPlugin::ExpoBlendingActionData)));
261 
262     connect(d->bracketStack, SIGNAL(signalAddItems(QList<QUrl>)),
263             this, SLOT(slotAddItems(QList<QUrl>)));
264 
265     connect(d->bracketStack, SIGNAL(signalItemClicked(QUrl)),
266             this, SLOT(slotItemClicked(QUrl)));
267 
268     connect(d->previewWidget, SIGNAL(signalButtonClicked()),
269             this, SLOT(slotPreviewButtonClicked()));
270 
271     connect(d->enfuseStack, SIGNAL(signalItemClicked(QUrl)),
272             this, SLOT(slotLoadProcessed(QUrl)));
273 
274     connect(d->templateFileName, SIGNAL(textChanged(QString)),
275             this, SLOT(slotFileFormatChanged()));
276 
277     connect(d->saveSettingsBox, SIGNAL(signalSaveFormatChanged()),
278             this, SLOT(slotFileFormatChanged()));
279 
280     // ---------------------------------------------------------------
281 
282     busy(false);
283     readSettings();
284     loadItems(d->mngr->itemsList());
285 }
286 
~ExpoBlendingDlg()287 ExpoBlendingDlg::~ExpoBlendingDlg()
288 {
289     delete d;
290 }
291 
slotFinished()292 void ExpoBlendingDlg::slotFinished()
293 {
294     d->mngr->thread()->cancel();
295     d->mngr->cleanUp();
296     saveSettings();
297 }
298 
closeEvent(QCloseEvent * e)299 void ExpoBlendingDlg::closeEvent(QCloseEvent* e)
300 {
301     if (!e)
302     {
303         return;
304     }
305 
306     slotFinished();
307     e->accept();
308 }
309 
slotCancelClicked()310 void ExpoBlendingDlg::slotCancelClicked()
311 {
312     d->mngr->thread()->cancel();
313 }
314 
slotFileFormatChanged()315 void ExpoBlendingDlg::slotFileFormatChanged()
316 {
317     d->enfuseStack->setTemplateFileName(d->saveSettingsBox->fileFormat(), d->templateFileName->text());
318 }
319 
slotPreviewButtonClicked()320 void ExpoBlendingDlg::slotPreviewButtonClicked()
321 {
322     DMessageBox::showInformationList(QMessageBox::Information,
323                                      qApp->activeWindow(),
324                                      qApp->applicationName(),
325                                      i18nc("@title: window", "Enfuse Processing Messages"),
326                                      d->output.split(QLatin1Char('\n')));
327 }
328 
loadItems(const QList<QUrl> & urls)329 void ExpoBlendingDlg::loadItems(const QList<QUrl>& urls)
330 {
331     d->bracketStack->clear();
332     d->bracketStack->addItems(urls);
333 }
334 
slotAddItems(const QList<QUrl> & urls)335 void ExpoBlendingDlg::slotAddItems(const QList<QUrl>& urls)
336 {
337     if (!urls.isEmpty())
338     {
339         d->mngr->thread()->identifyFiles(urls);
340 
341         if (!d->mngr->thread()->isRunning())
342         {
343             d->mngr->thread()->start();
344         }
345     }
346 }
347 
slotItemClicked(const QUrl & url)348 void ExpoBlendingDlg::slotItemClicked(const QUrl& url)
349 {
350     QString fileName = url.fileName();
351 
352     if (fileName.isEmpty())
353     {
354         return;
355     }
356 
357     int dot  = fileName.lastIndexOf(QLatin1Char('.'));
358     fileName = fileName.left(dot);
359 
360     d->templateFileName->setText(fileName);
361     slotFileFormatChanged();
362 }
363 
slotLoadProcessed(const QUrl & url)364 void ExpoBlendingDlg::slotLoadProcessed(const QUrl& url)
365 {
366     d->mngr->thread()->loadProcessed(url);
367 
368     if (!d->mngr->thread()->isRunning())
369     {
370         d->mngr->thread()->start();
371     }
372 }
373 
setIdentity(const QUrl & url,const QString & identity)374 void ExpoBlendingDlg::setIdentity(const QUrl& url, const QString& identity)
375 {
376     BracketStackItem* const item = d->bracketStack->findItem(url);
377 
378     if (item)
379     {
380         item->setExposure(identity);
381     }
382 }
383 
busy(bool val)384 void ExpoBlendingDlg::busy(bool val)
385 {
386     d->enfuseSettingsBox->setEnabled(!val);
387     d->saveSettingsBox->setEnabled(!val);
388     d->bracketStack->setEnabled(!val);
389 
390     d->startButton->setEnabled(!val ? !d->enfuseStack->settingsList().isEmpty() : false);
391     d->previewButton->setEnabled(!val);
392     setRejectButtonMode(val ? QDialogButtonBox::Cancel : QDialogButtonBox::Close);
393 
394     if (val)
395     {
396         d->previewWidget->setButtonVisible(false);
397     }
398 }
399 
slotDefault()400 void ExpoBlendingDlg::slotDefault()
401 {
402     d->enfuseSettingsBox->resetToDefault();
403     d->saveSettingsBox->resetToDefault();
404     d->templateFileName->setText(QLatin1String("enfuse"));
405 }
406 
readSettings()407 void ExpoBlendingDlg::readSettings()
408 {
409     KSharedConfigPtr config = KSharedConfig::openConfig();
410     KConfigGroup group      = config->group("ExpoBlending Settings");
411 
412     d->enfuseSettingsBox->readSettings(group);
413     d->saveSettingsBox->readSettings(group);
414 
415     d->templateFileName->setText(group.readEntry("Template File Name", QString::fromLatin1("enfuse")));
416 
417     winId();
418     KConfigGroup group2 = config->group("ExpoBlending Dialog");
419     DXmlGuiWindow::restoreWindowSize(windowHandle(), group2);
420     resize(windowHandle()->size());
421 }
422 
saveSettings()423 void ExpoBlendingDlg::saveSettings()
424 {
425     KSharedConfigPtr config = KSharedConfig::openConfig();
426     KConfigGroup group      = config->group("ExpoBlending Settings");
427 
428     d->enfuseSettingsBox->writeSettings(group);
429     d->saveSettingsBox->writeSettings(group);
430 
431     group.writeEntry("Template File Name", d->templateFileName->text());
432 
433     KConfigGroup group2 = config->group("ExpoBlending Dialog");
434     DXmlGuiWindow::saveWindowSize(windowHandle(), group2);
435     config->sync();
436 }
437 
slotPreview()438 void ExpoBlendingDlg::slotPreview()
439 {
440     QList<QUrl> selectedUrl = d->bracketStack->urls();
441 
442     if (selectedUrl.isEmpty())
443     {
444         return;
445     }
446 
447     ExpoBlendingItemUrlsMap map = d->mngr->preProcessedMap();
448     QList<QUrl> preprocessedList;
449 
450     foreach (const QUrl& url, selectedUrl)
451     {
452         ExpoBlendingItemPreprocessedUrls preprocessedUrls = map.value(url);
453         preprocessedList.append(preprocessedUrls.previewUrl);
454     }
455 
456     EnfuseSettings settings = d->enfuseSettingsBox->settings();
457     settings.inputUrls      = d->bracketStack->urls();
458     settings.outputFormat   = d->saveSettingsBox->fileFormat();
459     d->mngr->thread()->enfusePreview(preprocessedList, d->mngr->itemsList()[0], settings, d->mngr->enfuseBinary().path());
460 
461     if (!d->mngr->thread()->isRunning())
462     {
463         d->mngr->thread()->start();
464     }
465 }
466 
slotProcess()467 void ExpoBlendingDlg::slotProcess()
468 {
469     QList<EnfuseSettings> list = d->enfuseStack->settingsList();
470 
471     if (list.isEmpty())
472     {
473         return;
474     }
475 
476     ExpoBlendingItemUrlsMap map = d->mngr->preProcessedMap();
477     QList<QUrl> preprocessedList;
478 
479     foreach (const EnfuseSettings& settings, list)
480     {
481         preprocessedList.clear();
482 
483         foreach (const QUrl& url, settings.inputUrls)
484         {
485             ExpoBlendingItemPreprocessedUrls preprocessedUrls = map.value(url);
486             preprocessedList.append(preprocessedUrls.preprocessedUrl);
487         }
488 
489         d->mngr->thread()->enfuseFinal(preprocessedList, d->mngr->itemsList()[0], settings, d->mngr->enfuseBinary().path());
490 
491         if (!d->mngr->thread()->isRunning())
492         {
493             d->mngr->thread()->start();
494         }
495     }
496 }
497 
saveItem(const QUrl & temp,const EnfuseSettings & settings)498 void ExpoBlendingDlg::saveItem(const QUrl& temp, const EnfuseSettings& settings)
499 {
500     QUrl newUrl = QUrl::fromLocalFile(temp.adjusted(QUrl::RemoveFilename).toLocalFile() + settings.targetFileName);
501 
502     if (d->saveSettingsBox->conflictRule() != FileSaveConflictBox::OVERWRITE)
503     {
504         newUrl = DFileOperations::getUniqueFileUrl(newUrl);
505     }
506 
507     qCDebug(DIGIKAM_DPLUGIN_GENERIC_LOG) << "Renaming " << temp << " to " << newUrl;
508 
509     if (!newUrl.isEmpty())
510     {
511         // remove newUrl file if it exist
512 
513         if (temp.toLocalFile() != newUrl.toLocalFile() && QFile::exists(temp.toLocalFile()) && QFile::exists(newUrl.toLocalFile()))
514         {
515             QFile::remove(newUrl.toLocalFile());
516         }
517 
518         if (!QFile::rename(temp.toLocalFile(), newUrl.toLocalFile()))
519         {
520             QMessageBox::critical(this, QString(), i18nc("@info", "Failed to save image to %1.", QDir::toNativeSeparators(newUrl.toLocalFile())));
521             d->enfuseStack->setOnItem(settings.previewUrl, false);
522             d->enfuseStack->processedItem(settings.previewUrl, false);
523             return;
524         }
525         else
526         {
527             d->enfuseStack->removeItem(settings.previewUrl);
528         }
529     }
530 
531     if (d->enfuseStack->settingsList().isEmpty())
532     {
533         d->startButton->setEnabled(false);
534         busy(false);
535         d->previewWidget->setBusy(false);
536     }
537 
538     emit d->mngr->updateHostApp(newUrl);
539 }
540 
slotExpoBlendingAction(const DigikamGenericExpoBlendingPlugin::ExpoBlendingActionData & ad)541 void ExpoBlendingDlg::slotExpoBlendingAction(const DigikamGenericExpoBlendingPlugin::ExpoBlendingActionData& ad)
542 {
543     QString text;
544 
545     if (ad.starting)            // Something have been started...
546     {
547         switch (ad.action)
548         {
549             case EXPOBLENDING_IDENTIFY:
550             {
551                 break;
552             }
553 
554             case EXPOBLENDING_LOAD:
555             {
556                 busy(true);
557                 break;
558             }
559 
560             case EXPOBLENDING_ENFUSEPREVIEW:
561             {
562                 busy(true);
563                 d->previewWidget->setBusy(true, i18nc("@info", "Processing preview of bracketed images..."));
564                 break;
565             }
566 
567             case EXPOBLENDING_ENFUSEFINAL:
568             {
569                 busy(true);
570                 d->previewWidget->setBusy(true, i18nc("@info", "Processing output of bracketed images..."));
571                 d->enfuseStack->processingItem(ad.enfuseSettings.previewUrl, true);
572                 break;
573             }
574 
575             default:
576             {
577                 qCWarning(DIGIKAM_DPLUGIN_GENERIC_LOG) << "Unknown action";
578                 break;
579             }
580         }
581     }
582     else
583     {
584         if (!ad.success)        // Something is failed...
585         {
586             switch (ad.action)
587             {
588                 case EXPOBLENDING_IDENTIFY:
589                 {
590                     setIdentity(ad.inUrls[0], ad.message);
591                     busy(false);
592                     break;
593                 }
594 
595                 case EXPOBLENDING_LOAD:
596                 {
597                     d->previewWidget->setText(i18nc("@info", "Failed to load processed image."), Qt::red);
598                     busy(false);
599                     break;
600                 }
601 
602                 case EXPOBLENDING_ENFUSEPREVIEW:
603                 {
604                     d->output = ad.message;
605                     d->previewWidget->setBusy(false);
606                     d->previewWidget->setButtonVisible(true);
607                     d->previewWidget->setText(i18nc("@info", "Failed to process preview of bracketed images."), Qt::red);
608                     busy(false);
609                     break;
610                 }
611 
612                 case EXPOBLENDING_ENFUSEFINAL:
613                 {
614                     slotCancelClicked();
615                     d->output = ad.message;
616                     d->previewWidget->setBusy(false);
617                     d->previewWidget->setButtonVisible(true);
618                     d->previewWidget->setText(i18nc("@info", "Failed to process output of bracketed images."), Qt::red);
619                     d->enfuseStack->processingItem(ad.enfuseSettings.previewUrl, false);
620                     d->enfuseStack->setOnItem(ad.enfuseSettings.previewUrl, false);
621                     busy(false);
622                     break;
623                 }
624 
625                 default:
626                 {
627                     qCWarning(DIGIKAM_DPLUGIN_GENERIC_LOG) << "Unknown action";
628                     break;
629                 }
630             }
631         }
632         else                    // Something is done...
633         {
634             switch (ad.action)
635             {
636                 case EXPOBLENDING_IDENTIFY:
637                 {
638                     setIdentity(ad.inUrls[0], ad.message);
639                     busy(false);
640                     break;
641                 }
642 
643                 case EXPOBLENDING_LOAD:
644                 {
645                     d->previewWidget->setImage(ad.image, !d->firstImageDisplayed);
646                     d->firstImageDisplayed |= true;
647                     d->enfuseStack->setThumbnail(ad.inUrls[0], ad.image);
648                     busy(false);
649                     break;
650                 }
651 
652                 case EXPOBLENDING_ENFUSEPREVIEW:
653                 {
654                     d->enfuseStack->addItem(ad.outUrls[0], ad.enfuseSettings);
655                     busy(false);
656                     break;
657                 }
658 
659                 case EXPOBLENDING_ENFUSEFINAL:
660                 {
661                     d->enfuseStack->processingItem(ad.enfuseSettings.previewUrl, false);
662                     saveItem(ad.outUrls[0], ad.enfuseSettings);
663                     break;
664                 }
665 
666                 default:
667                 {
668                     qCWarning(DIGIKAM_DPLUGIN_GENERIC_LOG) << "Unknown action";
669                     break;
670                 }
671             }
672         }
673     }
674 }
675 
setRejectButtonMode(QDialogButtonBox::StandardButton button)676 void ExpoBlendingDlg::setRejectButtonMode(QDialogButtonBox::StandardButton button)
677 {
678     if      (button == QDialogButtonBox::Close)
679     {
680         d->buttonBox->button(QDialogButtonBox::Close)->setText(i18nc("@action", "Close"));
681         d->buttonBox->button(QDialogButtonBox::Close)->setIcon(QIcon::fromTheme(QLatin1String("window-close")));
682         d->buttonBox->button(QDialogButtonBox::Close)->setToolTip(i18nc("@info", "Close window"));
683         d->propagateReject = true;
684     }
685     else if (button == QDialogButtonBox::Cancel)
686     {
687         d->buttonBox->button(QDialogButtonBox::Close)->setText(i18nc("@action", "Cancel"));
688         d->buttonBox->button(QDialogButtonBox::Close)->setIcon(QIcon::fromTheme(QLatin1String("dialog-cancel")));
689         d->buttonBox->button(QDialogButtonBox::Close)->setToolTip(i18nc("@info", "Cancel current operation"));
690         d->propagateReject = false;
691     }
692     else
693     {
694         qCDebug(DIGIKAM_DPLUGIN_GENERIC_LOG) << "Unexpected button mode passed";
695     }
696 }
697 
slotCloseClicked()698 void ExpoBlendingDlg::slotCloseClicked()
699 {
700     if (d->propagateReject)
701     {
702         reject();
703     }
704     else
705     {
706         emit cancelClicked();
707     }
708 }
709 
710 } // namespace DigikamGenericExpoBlendingPlugin
711