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