1 /**
2  * This file is a part of Luminance HDR package.
3  * ----------------------------------------------------------------------
4  * Copyright (C) 2006-2007 Giuseppe Rota
5  * Copyright (C) 2011-2013 Davide Anastasia
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License as published by
9  *  the Free Software Foundation; either version 2 of the License, or
10  *  (at your option) any later version.
11  *
12  *  This program is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU General Public License for more details.
16  *
17  *  You should have received a copy of the GNU General Public License
18  *  along with this program; if not, write to the Free Software
19  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  * ----------------------------------------------------------------------
21  *
22  * @author Giuseppe Rota <grota@users.sourceforge.net>
23  * Original Work
24  *
25  * @author Franco Comida <fcomida@users.sourceforge.net>
26  * Improvements, bugfixing
27  *
28  * @author Davide Anastasia <davideanastasia@users.sourceforge.net>
29  * Implementation of the SDI functionalities
30  * New Central Widget based on QTabWidget
31  * Division of the Central Widget using QSplitter
32  *
33  */
34 
35 #ifdef QT_DEBUG
36 #include <QDebug>
37 #endif
38 
39 #define BOOST_BIND_GLOBAL_PLACEHOLDERS
40 
41 #include <QDesktopServices>
42 #include <QDir>
43 #include <QFileDialog>
44 #include <QFileInfo>
45 #include <QMessageBox>
46 #include <QMimeData>
47 #include <QSignalMapper>
48 #include <QString>
49 #include <QTextStream>
50 #include <QTimer>
51 #include <QWhatsThis>
52 #include <QtConcurrentRun>
53 
54 #include <boost/bind.hpp>
55 
56 #include "MainWindow/ui_MainWindow.h"
57 
58 #include <MainWindow/DnDOption.h>
59 #include <MainWindow/DonationDialog.h>
60 #include <MainWindow/MainWindow.h>
61 #include <MainWindow/UpdateChecker.h>
62 
63 #include <Fileformat/pfsoutldrimage.h>
64 #include <Libpfs/frame.h>
65 #include <Libpfs/manip/copy.h>
66 #include <Libpfs/manip/cut.h>
67 #include <Libpfs/manip/gamma_levels.h>
68 #include <Libpfs/manip/rotate.h>
69 #include <Libpfs/params.h>
70 
71 #include <Common/CommonFunctions.h>
72 #include <Common/archs.h>
73 #include <Common/config.h>
74 #include <Common/global.h>
75 
76 #include <OsIntegration/osintegration.h>
77 
78 #include <BatchHDR/BatchHDRDialog.h>
79 #include <BatchTM/BatchTMDialog.h>
80 
81 #include <TransplantExif/TransplantExifDialog.h>
82 #include <Viewers/HdrViewer.h>
83 #include <Viewers/LdrViewer.h>
84 #include <Viewers/LuminanceRangeWidget.h>
85 
86 #include <UI/ExportToHtmlDialog.h>
87 #include <UI/GammaAndLevels.h>
88 #include <UI/ImageQualityDialog.h>
89 #include <UI/SupportedCamerasDialog.h>
90 #include <UI/TiffModeDialog.h>
91 #include <UI/UMessageBox.h>
92 
93 #ifdef HAVE_CFITSIO
94 #include <UI/FitsImporter.h>
95 #endif
96 
97 #include <Core/IOWorker.h>
98 #include <Core/TMWorker.h>
99 #include <HdrWizard/AutoAntighosting.h>
100 #include <HdrWizard/HdrWizard.h>
101 #include <HdrWizard/WhiteBalance.h>
102 #ifdef WITH_HELPBROWSER
103 #include <HelpBrowser/helpbrowser.h>
104 #endif
105 #include <LibpfsAdditions/formathelper.h>
106 #include <Preferences/PreferencesDialog.h>
107 #include <PreviewPanel/PreviewPanel.h>
108 #include <Projection/ProjectionsDialog.h>
109 #include <Resize/ResizeDialog.h>
110 #include <TonemappingPanel/TMOProgressIndicator.h>
111 #include <TonemappingPanel/TonemappingPanel.h>
112 
113 namespace {
getLdrFileNameFromSaveDialog(const QString & suggestedFileName,QWidget * parent=0)114 QString getLdrFileNameFromSaveDialog(const QString &suggestedFileName,
115                                      QWidget *parent = 0) {
116     QString filetypes = QObject::tr("All LDR formats");
117     filetypes += QLatin1String(
118         " (*.jpg *.jpeg *.png *.ppm *.pbm *.bmp *.JPG *.JPEG *.PNG *.PPM *.PBM "
119         "*.BMP);;");
120     filetypes += QLatin1String("JPEG (*.jpg *.jpeg *.JPG *.JPEG);;");
121     filetypes += QLatin1String("PNG (*.png *.PNG);;");
122     filetypes += QLatin1String("PPM PBM (*.ppm *.pbm *.PPM *.PBM);;");
123     filetypes += QLatin1String("BMP (*.bmp *.BMP);;");
124     filetypes += QLatin1String("TIFF (*.tif *.tiff *.TIF *.TIFF)");
125 
126     QFileInfo qfi(suggestedFileName);
127     QString outputFilename = QFileDialog::getSaveFileName(
128         parent, QObject::tr("Save the LDR image as..."),
129         LuminanceOptions().getDefaultPathLdrOut() + QDir::separator() +
130             qfi.completeBaseName() + "." + qfi.suffix(),
131         filetypes);
132 
133     if (!outputFilename.isEmpty()) {
134         QFileInfo qfi(outputFilename);
135 
136         LuminanceOptions().setDefaultPathLdrOut(qfi.path());
137     }
138     return outputFilename;
139 }
140 
getHdrFileNameFromSaveDialog(const QString & suggestedFileName,QWidget * parent=0)141 QString getHdrFileNameFromSaveDialog(const QString &suggestedFileName,
142                                      QWidget *parent = 0) {
143 #ifdef QT_DEBUG
144     qDebug() << "MainWindow::getHdrFileNameFromSaveDialog(" << suggestedFileName
145              << ")";
146 #endif
147 
148     QStringList validHdrExtensions;
149     validHdrExtensions << "exr"
150                        << "hdr"
151                        << "tif"
152                        << "tiff"
153                        << "pfs";
154 
155     QString filetypes = QObject::tr("All HDR formats");
156     filetypes += QLatin1String(
157         " (*.exr *.EXR *.tiff *.TIFF *.hdr *.HDR *.pic *.PIC *.pfs *.PFS);;");
158     filetypes += QLatin1String("OpenEXR (*.exr *.EXR);;");
159     filetypes += QLatin1String("HDR TIFF (*.tiff *.tif *.TIFF *.TIT);;");
160     filetypes += QLatin1String("Radiance RGBE (*.hdr *.pic *.HDR *.PIC);;");
161     filetypes += QLatin1String("PFS Stream (*.pfs *.PFS);;");
162 
163     QFileInfo qfi(suggestedFileName);
164 
165     QString suffix = qfi.suffix();
166 
167     if (suffix.isEmpty()) {
168             suffix = "exr";
169     }
170 
171     if (!validHdrExtensions.contains(suffix, Qt::CaseInsensitive)) {
172         suffix = "exr";
173     }
174 
175     QString outputFilename = QFileDialog::getSaveFileName(
176         parent, QObject::tr("Save the HDR image as..."),
177         LuminanceOptions().getDefaultPathLdrIn() + QDir::separator() +
178             qfi.completeBaseName() + "." + suffix,
179         filetypes);
180 
181     if (!outputFilename.isEmpty()) {
182         QFileInfo qfi(outputFilename);
183 
184         LuminanceOptions().setDefaultPathHdrOut(qfi.path());
185     }
186     return outputFilename;
187 }
188 
getCropCoords(GenericViewer * gv,int & x_ul,int & y_ul,int & x_br,int & y_br)189 void getCropCoords(GenericViewer *gv, int &x_ul, int &y_ul, int &x_br,
190                    int &y_br) {
191     assert(gv != nullptr);
192 
193     QRect cropRect = gv->getSelectionRect().normalized();
194     cropRect.getCoords(&x_ul, &y_ul, &x_br, &y_br);
195 }
196 
getCurrentViewerMode(const QTabWidget & curr_tab_widget)197 GenericViewer::ViewerMode getCurrentViewerMode(
198     const QTabWidget &curr_tab_widget) {
199     if (curr_tab_widget.count() <= 0) {
200         return GenericViewer::FIT_WINDOW;
201     } else {
202         GenericViewer *g_v = qobject_cast<GenericViewer *>(curr_tab_widget.currentWidget());
203         return g_v->getViewerMode();
204     }
205 }
206 }
207 
208 // static members!
209 int MainWindow::sm_NumMainWindows = 0;
210 int MainWindow::sm_counter = 0;
211 QMap<int, MainWindow *> MainWindow::sm_mainWindowMap =
212     QMap<int, MainWindow *>();
213 QScopedPointer<UpdateChecker> MainWindow::sm_updateChecker;
214 #ifdef WITH_HELPBROWSER
215 HelpBrowser *MainWindow::sm_helpBrowser = nullptr;
216 #endif
217 
MainWindow(QWidget * parent)218 MainWindow::MainWindow(QWidget *parent)
219     : QMainWindow(parent),
220       m_Ui(new Ui::MainWindow),
221       m_isFullscreenViewer(false),
222       m_exportQueueSize(0),
223       m_interpolationMethod(BilinearInterp),
224       m_firstWindow(0),
225       m_winId(0) {
226     init();
227 }
228 
MainWindow(pfs::Frame * curr_frame,const QString & new_file,const QStringList & inputFileNames,bool needSaving,QWidget * parent)229 MainWindow::MainWindow(pfs::Frame *curr_frame, const QString &new_file,
230                        const QStringList &inputFileNames, bool needSaving,
231                        QWidget *parent)
232     : QMainWindow(parent),
233       m_Ui(new Ui::MainWindow),
234       m_isFullscreenViewer(false),
235       m_exportQueueSize(0),
236       m_interpolationMethod(BilinearInterp),
237       m_firstWindow(0),
238       m_winId(0) {
239     init();
240 
241     emit load_success(curr_frame, new_file, inputFileNames, needSaving);
242 }
243 
~MainWindow()244 MainWindow::~MainWindow() {
245 }
246 
init()247 void MainWindow::init() {
248     sm_NumMainWindows++;
249     sm_counter++;
250     m_winId = sm_counter;
251     sm_mainWindowMap.insert(m_winId, this);
252     m_firstWindow = 0;
253 
254     num_ldr_generated = 0;
255     curr_num_ldr_open = 0;
256     splash = 0;
257     m_processingAWB = false;
258 
259     if (sm_NumMainWindows == 1) {
260         // Register symbols on the first activation!
261         qRegisterMetaType<QImage>("QImage");
262         qRegisterMetaType<pfs::Frame *>("pfs::Frame*");
263         qRegisterMetaType<TonemappingOptions>("TonemappingOptions");
264         qRegisterMetaType<TonemappingOptions *>("TonemappingOptions*");
265         qRegisterMetaType<HdrViewer *>("HdrViewer*");
266         qRegisterMetaType<LdrViewer *>("LdrViewer*");
267         qRegisterMetaType<GenericViewer *>("GenericViewer*");
268         qRegisterMetaType<QVector<float>>("QVector<float>");
269         qRegisterMetaType<pfs::Params>("pfs::Params");
270         qRegisterMetaType<pfs::Params *>("pfs::Params*");
271         qRegisterMetaType<InterpolationMethod>("InterpolationMethod");
272     }
273 
274     createUI();
275     loadOptions();
276     createMenus();
277     createToolBar();
278     createCentralWidget();
279     createStatusBar();
280     setupIO();
281     setupTM();
282     setupQueue();
283     createConnections();
284 
285     OsIntegration::getInstance().init(this);
286 
287     if (sm_NumMainWindows == 1) {
288         if (OsIntegration::getInstance().isRunningOnSameCpuPlatform()) {
289             sm_updateChecker.reset(new UpdateChecker(this));
290             connect(sm_updateChecker.data(), &UpdateChecker::updateAvailable,
291                     this, &MainWindow::onUpdateAvailable);
292 
293             m_firstWindow = 2;
294         } else
295             m_firstWindow = 1;
296     }
297 }
298 
createUI()299 void MainWindow::createUI() {
300     m_Ui->setupUi(this);
301     setAttribute(Qt::WA_DeleteOnClose);
302 
303     restoreState(LuminanceOptions()
304                      .value(QStringLiteral("MainWindowState"))
305                      .toByteArray());
306     restoreGeometry(LuminanceOptions()
307                         .value(QStringLiteral("MainWindowGeometry"))
308                         .toByteArray());
309 
310     if (isFullScreen()) m_Ui->actionShow_Full_Screen->setChecked(true);
311 
312     setAcceptDrops(true);
313     setWindowModified(false);
314     setWindowTitle(QString("Luminance HDR " LUMINANCEVERSION
315                            " [*]"));  // + "  " + g_GIT_SHA1);
316 }
317 
createCentralWidget()318 void MainWindow::createCentralWidget() {
319     // Central Widget Area
320     m_centralwidget_splitter = new QSplitter;  //(this);
321     m_bottom_splitter = new QSplitter;         //(this);
322     m_bottom_splitter->setOrientation(Qt::Vertical);
323 
324     setCentralWidget(m_centralwidget_splitter);
325 
326     m_PreviewPanel = new PreviewPanel();
327 
328     // create tonemapping panel
329     m_tonemapPanel = new TonemappingPanel(
330         sm_NumMainWindows, m_PreviewPanel);  //(m_centralwidget_splitter);
331 
332     connect(m_Ui->actionRealtimePreviews, &QAction::toggled, m_tonemapPanel,
333             &TonemappingPanel::setRealtimePreviews);
334     connect(m_Ui->actionRealtimePreviews, &QAction::toggled, this,
335             &MainWindow::setRealtimePreviewsActive);
336 
337     m_tabwidget = new QTabWidget;  //(m_centralwidget_splitter);
338 
339     m_tabwidget->setDocumentMode(true);
340     m_tabwidget->setTabsClosable(true);
341 
342     m_centralwidget_splitter->addWidget(m_tonemapPanel);
343     m_centralwidget_splitter->addWidget(m_bottom_splitter);
344 
345     m_bottom_splitter->addWidget(m_tabwidget);
346 
347     m_bottom_splitter->setStretchFactor(0, 10);
348     m_bottom_splitter->setStretchFactor(1, 1);
349     m_centralwidget_splitter->setStretchFactor(0, 1);
350     m_centralwidget_splitter->setStretchFactor(1, 5);
351 
352     // create preview panel
353     m_PreviewscrollArea = new QScrollArea;
354     m_PreviewscrollArea->setWidgetResizable(true);
355     m_PreviewscrollArea->setWidget(m_PreviewPanel);
356 
357     m_centralwidget_splitter->addWidget(m_PreviewscrollArea);
358     m_centralwidget_splitter->setCollapsible(2, false);
359 
360     if (LuminanceOptions().getPreviewPanelMode()) {
361         showPreviewsOnTheBottom();
362     } else {
363         showPreviewsOnTheRight();
364     }
365 
366     connect(m_tabwidget, &QTabWidget::tabCloseRequested, this,
367             &MainWindow::removeTab);
368     connect(m_tabwidget, &QTabWidget::currentChanged, this,
369             &MainWindow::updateActions);
370     connect(m_tabwidget, &QTabWidget::currentChanged, this,
371             &MainWindow::updateSoftProofing);
372     connect(m_tonemapPanel, &TonemappingPanel::startTonemapping, this,
373             &MainWindow::tonemapImage);
374     connect(m_tonemapPanel, &TonemappingPanel::startExport, this,
375             &MainWindow::exportImage);
376     connect(this, &MainWindow::updatedHDR, m_tonemapPanel,
377             &TonemappingPanel::updatedHDR);
378     connect(this, &QObject::destroyed, m_PreviewPanel, &QObject::deleteLater);
379 
380     m_centralwidget_splitter->restoreState(
381         LuminanceOptions()
382             .value(QStringLiteral("MainWindowSplitterState"))
383             .toByteArray());
384     m_centralwidget_splitter->restoreGeometry(
385         LuminanceOptions()
386             .value(QStringLiteral("MainWindowSplitterGeometry"))
387             .toByteArray());
388     m_bottom_splitter->restoreState(
389         LuminanceOptions()
390             .value(QStringLiteral("MainWindowBottomSplitterState"))
391             .toByteArray());
392     m_bottom_splitter->restoreGeometry(
393         LuminanceOptions()
394             .value(QStringLiteral("MainWindowBottomSplitterGeometry"))
395             .toByteArray());
396 
397     QPalette pal = m_tabwidget->palette();
398     pal.setColor(QPalette::Dark, Qt::darkGray);
399     m_tabwidget->setPalette(pal);
400 
401     m_tabwidget->setBackgroundRole(QPalette::Dark);
402     m_tabwidget->setAutoFillBackground(true);
403 
404     // replace with ->tabBar() one day, or subclass
405     QTabBar *tabBar = m_tabwidget->findChild<QTabBar *>(
406         QStringLiteral("qt_tabwidget_tabbar"));
407     tabBar->setAutoFillBackground(true);
408     tabBar->setBackgroundRole(QPalette::Window);
409 
410     m_PreviewscrollArea->hide();
411 }
412 
createToolBar()413 void MainWindow::createToolBar() {
414     // main toolbars setup
415     QActionGroup *toolBarOptsGroup = new QActionGroup(this);
416     toolBarOptsGroup->addAction(m_Ui->actionText_Under_Icons);
417     toolBarOptsGroup->addAction(m_Ui->actionIcons_Only);
418     toolBarOptsGroup->addAction(m_Ui->actionText_Alongside_Icons);
419     toolBarOptsGroup->addAction(m_Ui->actionText_Only);
420     m_Ui->menuToolbars->addAction(m_Ui->toolBar->toggleViewAction());
421 
422     connect(m_Ui->actionText_Under_Icons, &QAction::triggered, this,
423             &MainWindow::Text_Under_Icons);
424     connect(m_Ui->actionIcons_Only, &QAction::triggered, this,
425             &MainWindow::Icons_Only);
426     connect(m_Ui->actionText_Alongside_Icons, &QAction::triggered, this,
427             &MainWindow::Text_Alongside_Icons);
428     connect(m_Ui->actionText_Only, &QAction::triggered, this,
429             &MainWindow::Text_Only);
430 
431     // Preview Panel
432     QActionGroup *previewPanelOptsGroup = new QActionGroup(this);
433     previewPanelOptsGroup->addAction(m_Ui->actionShow_on_the_right);
434     previewPanelOptsGroup->addAction(m_Ui->actionShow_on_the_bottom);
435     connect(m_Ui->actionShow_on_the_right, &QAction::triggered, this,
436             &MainWindow::showPreviewsOnTheRight);
437     connect(m_Ui->actionShow_on_the_bottom, &QAction::triggered, this,
438             &MainWindow::showPreviewsOnTheBottom);
439 }
440 
createMenus()441 void MainWindow::createMenus() {
442     // icons (missing icons in some icon-theme)
443     if (!QIcon::hasThemeIcon(QStringLiteral("document-save-all")))
444         m_Ui->fileSaveAllAction->setIcon(
445             QIcon(":/program-icons/document-save-all"));
446     if (!QIcon::hasThemeIcon(QStringLiteral("zoom")))
447         m_Ui->fitToWindowAct->setIcon(QIcon(":/program-icons/zoom"));
448     if (!QIcon::hasThemeIcon(QStringLiteral("whitebalance")))
449         m_Ui->actionWhite_Balance->setIcon(
450             QIcon(":/program-icons/whitebalance"));
451     if (!QIcon::hasThemeIcon(QStringLiteral("transform-crop")))
452         m_Ui->cropToSelectionAction->setIcon(
453             QIcon(":/program-icons/transform-crop"));
454     if (!QIcon::hasThemeIcon(QStringLiteral("edit-selection-none")))
455         m_Ui->removeSelectionAction->setIcon(
456             QIcon(":/program-icons/edit-select-none"));
457     if (!QIcon::hasThemeIcon(QStringLiteral("globe")))
458         m_Ui->actionExportToHTML->setIcon(QIcon(":/program-icons/globe"));
459     if (!QIcon::hasThemeIcon(QStringLiteral("selection-move-to-layer-below")))
460         m_Ui->Transplant_Exif_Data_action->setIcon(
461             QIcon(":/program-icons/selection-move-to-layer-below"));
462     if (!QIcon::hasThemeIcon(QStringLiteral("tab-close")))
463         m_Ui->actionRemove_Tab->setIcon(QIcon(":/program-icons/tab-close"));
464     if (!QIcon::hasThemeIcon(QStringLiteral("help-donate")))
465         m_Ui->actionDonate->setIcon(QIcon(":/program-icons/help-donate"));
466     if (!QIcon::hasThemeIcon(QStringLiteral("document-save-as-template")))
467         m_Ui->actionSave_Hdr_Preview->setIcon(
468             QIcon(":/program-icons/document-save-as-template"));
469     if (!QIcon::hasThemeIcon(QStringLiteral("help-whatsthis")))
470         m_Ui->actionWhat_s_This->setIcon(
471             QIcon(":/program-icons/help-whatsthis"));
472 
473     // About(s)
474     connect(m_Ui->actionAbout_Qt, SIGNAL(triggered()), qApp, SLOT(aboutQt()));
475     connect(m_Ui->actionWhat_s_This, &QAction::triggered, this,
476             &MainWindow::enterWhatsThis);
477 
478     // I/O
479     connect(m_Ui->fileExitAction, &QAction::triggered, this, &QWidget::close);
480 
481     // Crop & Rotation
482     connect(m_Ui->cropToSelectionAction, &QAction::triggered, this,
483             &MainWindow::cropToSelection);
484     m_Ui->cropToSelectionAction->setEnabled(false);
485 
486     connect(m_Ui->removeSelectionAction, &QAction::triggered, this,
487             &MainWindow::disableCrop);
488 
489     connect(m_Ui->menuWindows, &QMenu::aboutToShow, this,
490             &MainWindow::updateWindowMenu);
491     connect(m_Ui->actionMinimize, &QAction::triggered, this,
492             &QWidget::showMinimized);
493     connect(m_Ui->actionMaximize, &QAction::triggered, this,
494             &QWidget::showMaximized);
495     connect(m_Ui->actionShowPreviewPanel, &QAction::toggled, this,
496             &MainWindow::showPreviewPanel);
497     connect(m_Ui->actionShowPreviewPanel, &QAction::toggled, this,
498             &MainWindow::setPreviewPanelActive);
499 
500     // recent files
501     initRecentFileActions();
502     updateRecentFileActions();
503 
504 #ifndef HAVE_CFITSIO
505     m_Ui->actionFits_Importer->setVisible(false);
506 #endif
507 }
508 
createStatusBar()509 void MainWindow::createStatusBar() {
510     statusBar()->showMessage(
511         tr("Ready. Now open an existing HDR image or create a new one!"),
512         10000);
513 }
514 
createConnections()515 void MainWindow::createConnections() {
516     windowMapper = new QSignalMapper(this);
517     connect(windowMapper, static_cast<void (QSignalMapper::*)(QWidget *)>(
518                               &QSignalMapper::mapped),
519             this, &MainWindow::setActiveMainWindow);
520     connect(&m_futureWatcher, &QFutureWatcherBase::finished, this,
521             &MainWindow::whiteBalanceDone);
522 }
523 
loadOptions()524 void MainWindow::loadOptions() {
525     // load from settings the path where hdrs have been previously opened/loaded
526 
527     // load from settings the main toolbar visualization mode
528     switch (LuminanceOptions().getMainWindowToolBarMode()) {
529         case Qt::ToolButtonIconOnly:
530             Icons_Only();
531             m_Ui->actionIcons_Only->setChecked(true);
532             break;
533         case Qt::ToolButtonTextOnly:
534             Text_Only();
535             m_Ui->actionText_Only->setChecked(true);
536             break;
537         case Qt::ToolButtonTextBesideIcon:
538             Text_Alongside_Icons();
539             m_Ui->actionText_Alongside_Icons->setChecked(true);
540             break;
541         case Qt::ToolButtonTextUnderIcon:
542             Text_Under_Icons();
543             m_Ui->actionText_Under_Icons->setChecked(true);
544             break;
545     }
546     m_Ui->actionShowPreviewPanel->setChecked(
547         LuminanceOptions().isPreviewPanelActive());
548     m_Ui->actionRealtimePreviews->setChecked(
549         LuminanceOptions().isRealtimePreviewsActive());
550     m_Ui->actionRealtimePreviews->setEnabled(
551         LuminanceOptions().isPreviewPanelActive());
552 
553     bool isPreviewPanelRight = LuminanceOptions().getPreviewPanelMode() == 0;
554     m_Ui->actionShow_on_the_bottom->setChecked(!isPreviewPanelRight);
555     m_Ui->actionShow_on_the_right->setChecked(isPreviewPanelRight);
556 }
557 
on_actionDonate_triggered()558 void MainWindow::on_actionDonate_triggered() {
559     DonationDialog::openDonationPage();
560 }
561 
on_fileNewAction_triggered()562 void MainWindow::on_fileNewAction_triggered() {
563     createNewHdr(
564         QStringList());  // redirect on createNewHdr-method to avoid moc warning
565 }
566 
createNewHdr(const QStringList & files)567 void MainWindow::createNewHdr(const QStringList &files) {
568     QScopedPointer<HdrWizard> wizard(
569         new HdrWizard(this, files, m_inputFilesName, m_inputExpoTimes,
570                       QSqlDatabase::database(m_tonemapPanel->getDatabaseConnection())));
571     if (wizard->exec() == QDialog::Accepted) {
572         emit load_success(wizard->getPfsFrameHDR(), wizard->getCaptionTEXT(),
573                           wizard->getInputFilesNames(), true);
574     }
575 }
576 
on_fileOpenAction_triggered()577 void MainWindow::on_fileOpenAction_triggered() {
578     QString filetypes = tr("All HDR formats ");
579     QStringList hdrExtensionsList = getAllHdrFileExtensions();
580     filetypes += QLatin1String("(");
581     foreach (const QString &s, hdrExtensionsList) {
582         filetypes += "*" + s + " ";
583     }
584     filetypes += QLatin1String(");;");
585     filetypes += QLatin1String("OpenEXR (*.exr *.EXR);;");
586     filetypes += QLatin1String("Radiance RGBE (*.hdr *.pic *.HDR *.PIC);;");
587     filetypes += QLatin1String("TIFF images (*.TIFF *.TIF *.tiff *.tif);;");
588 #if HAVE_CFITSIO
589     filetypes += QLatin1String("FITS (*.fit *.FIT *.fits *.FITS);;");
590 #endif
591     filetypes += QLatin1String(
592         "RAW images (*.crw *.cr2 *.nef *.dng *.mrw *.orf *.kdc *.dcr *.arw "
593         "*.raf "
594         "*.ptx *.pef *.x3f *.raw "
595         "*.rw2 *.sr2 *.3fr *.mef *.mos *.erf *.nrw *.mef *.mos *.erf *.nrw "
596         "*.srw");
597     filetypes += QLatin1String(
598         "*.CRW *.CR2 *.NEF *.DNG *.MRW *.ORF *.KDC "
599         "*.DCR *.ARW *.RAF *.PTX *.PEF "
600         "*.X3F *.RAW *.RW2 *.SR2 "
601         "*.3FR *.MEF *.MOS *.ERF *.NRW *.SRW);;");
602     filetypes += QLatin1String("PFS stream (*.pfs *.PFS)");
603 
604     QStringList files = QFileDialog::getOpenFileNames(
605         this, tr("Load one or more HDR images..."),
606         LuminanceOptions().getDefaultPathHdrIn(), filetypes);
607 
608     if (files.isEmpty()) return;
609 
610     // Update working folder
611     // All the files are in the same folder, so I pick the first as reference to
612     // update the settings
613     QFileInfo qfi(files.first());
614 
615     LuminanceOptions().setDefaultPathHdrIn(qfi.absolutePath());
616 
617     foreach (const QString &filename, files) {
618         // emit open_hdr_frame(filename);
619         QMetaObject::invokeMethod(m_IOWorker, "read_hdr_frame",
620                                   Qt::QueuedConnection,
621                                   Q_ARG(QString, filename));
622     }
623 }
624 
on_fileSaveAllAction_triggered()625 void MainWindow::on_fileSaveAllAction_triggered() {
626     if (m_tabwidget->count() <= 0) return;
627 
628     QString dir = QFileDialog::getExistingDirectory(
629         this, tr("Save files in"), LuminanceOptions().getDefaultPathLdrOut());
630 
631     if (!dir.isEmpty()) {
632         LuminanceOptions().setDefaultPathLdrOut(dir);
633 
634         for (int i = 0; i < m_tabwidget->count(); i++) {
635             QWidget *wgt = m_tabwidget->widget(i);
636             GenericViewer *g_v = qobject_cast<GenericViewer *>(wgt);
637 
638             if (!g_v->isHDR()) {
639                 LdrViewer *l_v = qobject_cast<LdrViewer *>(g_v);
640 
641                 QString ldr_name = QFileInfo(getCurrentHDRName()).baseName();
642                 QString outfname = LuminanceOptions().getDefaultPathLdrOut() +
643                                    "/" + ldr_name + "_" +
644                                    l_v->getFileNamePostFix() + ".jpg";
645 
646                 QString inputfname;
647                 if (!m_inputFilesName.isEmpty()) {
648                     inputfname = m_inputFilesName.first();
649                 } else {
650                     inputfname = "FromHdrFile";
651                 }
652 
653                 QMetaObject::invokeMethod(
654                     m_IOWorker, "write_ldr_frame", Qt::QueuedConnection,
655                     Q_ARG(GenericViewer *, l_v), Q_ARG(QString, outfname),
656                     Q_ARG(QString, inputfname),
657                     Q_ARG(QVector<float>, QVector<float>()),
658                     Q_ARG(TonemappingOptions *, l_v->getTonemappingOptions()),
659                     Q_ARG(pfs::Params, pfs::Params("quality", 100u)));
660             }
661         }
662     }
663 }
664 
on_fileSaveAsAction_triggered()665 void MainWindow::on_fileSaveAsAction_triggered() {
666     if (m_tabwidget->count() <= 0) return;
667 
668     GenericViewer *g_v = qobject_cast<GenericViewer *>(m_tabwidget->currentWidget());
669     if (g_v->isHDR()) {
670         // In this case I'm saving an HDR
671         QString separator = "";
672         if (!m_HdrCaption.isEmpty()) {
673             separator = "-";
674         }
675         QString fname = getHdrFileNameFromSaveDialog(
676             g_v->getFileName() + separator + m_HdrCaption , this);
677 
678         if (fname.isEmpty()) return;
679 
680         QFileInfo qfi(fname);
681         QString format = qfi.suffix();
682 
683         pfs::Params p;
684         if (format == QLatin1String("tif") || format == QLatin1String("tiff")) {
685             TiffModeDialog t(true, -1, this);
686             if (t.exec() == QDialog::Rejected) return;
687 
688             p.set("tiff_mode", t.getTiffWriterMode());
689         }
690 
691         // CALL m_IOWorker->write_hdr_frame(qobject_cast<HdrViewer*>(g_v),
692         // fname);
693         QMetaObject::invokeMethod(
694             m_IOWorker, "write_hdr_frame", Qt::QueuedConnection,
695             Q_ARG(GenericViewer *, qobject_cast<HdrViewer *>(g_v)),
696             Q_ARG(QString, fname), Q_ARG(pfs::Params, p));
697     } else {
698         // In this case I'm saving an LDR
699 
700         LdrViewer *l_v = qobject_cast<LdrViewer *>(g_v);
701 
702         if (l_v == nullptr) return;
703 
704         QString ldr_name = QFileInfo(getCurrentHDRName()).baseName();
705 
706         QString proposedFileName =
707             ldr_name + "_" + l_v->getFileNamePostFix() + ".jpg";
708 
709         // QString outputFilename = getLdrFileNameFromSaveDialog(ldr_name + "_"
710         // +
711         // l_v->getFileNamePostFix() + ".jpg", this);
712         QString outputFilename =
713             getLdrFileNameFromSaveDialog(proposedFileName, this);
714 
715         if (outputFilename.isEmpty()) return;
716 
717         QString format = QFileInfo(outputFilename).suffix();
718 
719         if (format.isEmpty()) {  // default as JPG
720             format = QStringLiteral("jpg");
721             outputFilename += QLatin1String(".jpg");
722         }
723 
724         pfs::Params p;
725         if (format == QLatin1String("png") || format == QLatin1String("jpg")) {
726             ImageQualityDialog savedFileQuality(l_v->getFrame(), format, -1,
727                                                 this);
728             savedFileQuality.setWindowTitle(QObject::tr("Save as...") +
729                                             format.toUpper());
730             if (savedFileQuality.exec() == QDialog::Rejected) return;
731 
732             p.set("quality", (size_t)savedFileQuality.getQuality());
733         }
734 
735         if (format == QLatin1String("tif") || format == QLatin1String("tiff")) {
736             TiffModeDialog t(false, -1, this);
737             if (t.exec() == QDialog::Rejected) return;
738 
739             p.set("tiff_mode", t.getTiffWriterMode());
740         }
741 
742         QString inputfname;
743         if (!m_inputFilesName.isEmpty()) {
744             inputfname = m_inputFilesName.first();
745         } else {
746             inputfname = "FromHdrFile";
747         }
748 
749         QMetaObject::invokeMethod(
750             m_IOWorker, "write_ldr_frame", Qt::QueuedConnection,
751             Q_ARG(GenericViewer *, l_v), Q_ARG(QString, outputFilename),
752             Q_ARG(QString, inputfname), Q_ARG(QVector<float>, m_inputExpoTimes),
753             Q_ARG(TonemappingOptions *, l_v->getTonemappingOptions()),
754             Q_ARG(pfs::Params, p));
755     }
756 }
757 
save_hdr_success(GenericViewer * saved_hdr,const QString & fname)758 void MainWindow::save_hdr_success(GenericViewer *saved_hdr,
759                                   const QString &fname) {
760     QFileInfo qfi(fname);
761 
762     setCurrentFile(qfi.absoluteFilePath());
763     setWindowModified(false);
764 
765     // update name on the tab label
766     m_tabwidget->setTabText(m_tabwidget->indexOf(saved_hdr), qfi.fileName());
767 }
768 
save_hdr_failed(const QString & fname)769 void MainWindow::save_hdr_failed(const QString &fname) {
770     // TODO give some kind of feedback to the user!
771     // TODO pass the name of the file, so the user know which file didn't save
772     // correctly
773     // DONE!!! Once again, use unified style?
774     QMessageBox::warning(0, QLatin1String(""),
775                          tr("Failed to save %1").arg(fname), QMessageBox::Ok,
776                          QMessageBox::NoButton);
777 }
778 
save_ldr_success(GenericViewer * saved_ldr,const QString & fname)779 void MainWindow::save_ldr_success(GenericViewer *saved_ldr,
780                                   const QString &fname) {
781     if (!saved_ldr->isHDR())
782         m_tabwidget->setTabText(m_tabwidget->indexOf(saved_ldr),
783                                 QFileInfo(fname).fileName());
784 }
785 
save_ldr_failed(const QString & fname)786 void MainWindow::save_ldr_failed(const QString &fname) {
787     // TODO give some kind of feedback to the user!
788     // TODO pass the name of the file, so the user know which file didn't save
789     // correctly
790     // DONE!!! Once again, use unified style?
791     QMessageBox::warning(0, QLatin1String(""),
792                          tr("Failed to save %1").arg(fname), QMessageBox::Ok,
793                          QMessageBox::NoButton);
794 }
795 
on_actionSave_Hdr_Preview_triggered()796 void MainWindow::on_actionSave_Hdr_Preview_triggered() {
797     if (m_tabwidget->count() <= 0) return;
798 
799     GenericViewer *g_v = qobject_cast<GenericViewer *>(m_tabwidget->currentWidget());
800 
801     if (!g_v->isHDR()) return;
802     try {
803         QString ldr_name = QFileInfo(getCurrentHDRName()).baseName();
804 
805         QString outfname = getLdrFileNameFromSaveDialog(
806             ldr_name + "_" + g_v->getFileNamePostFix() + ".jpg", this);
807 
808         if (outfname.isEmpty()) return;
809 
810         QString inputfname;
811         if (!m_inputFilesName.isEmpty()) {
812             inputfname = m_inputFilesName.first();
813         } else {
814             inputfname = "FromHdrFile";
815         }
816 
817         QMetaObject::invokeMethod(
818             m_IOWorker, "write_ldr_frame", Qt::QueuedConnection,
819             Q_ARG(GenericViewer *, g_v), Q_ARG(QString, outfname),
820             Q_ARG(QString, inputfname), Q_ARG(QVector<float>, QVector<float>()),
821             Q_ARG(TonemappingOptions *, nullptr),
822             Q_ARG(pfs::Params, pfs::Params("quality", 100u)));
823     } catch (...) {
824         return;
825     }
826 }
827 
updateActions(int w)828 void MainWindow::updateActions(int w) {
829 #ifdef QT_DEBUG
830     qDebug() << "MainWindow::updateActions(" << w << ")";
831 #endif
832     bool hasImage = w >= 0;
833     GenericViewer *g_v = hasImage ? qobject_cast<GenericViewer *>(m_tabwidget->widget(w)) : 0;
834     bool isHdr = g_v ? g_v->isHDR() : false;
835     bool isLdr = g_v ? !g_v->isHDR() : false;
836     LuminanceOptions luminance_opts;
837     bool hasPrinterProfile =
838         !luminance_opts.getPrinterProfileFileName().isEmpty();
839 
840     updateMagnificationButtons(g_v);  // g_v ? g_v : 0
841 
842     m_Ui->fileSaveAsAction->setEnabled(hasImage);
843     m_Ui->actionRemove_Tab->setEnabled(hasImage);
844     m_Ui->actionSave_Hdr_Preview->setEnabled(hasImage && isHdr);
845     m_Ui->fileSaveAllAction->setEnabled(hasImage && curr_num_ldr_open >= 2);
846 
847     // Histogram
848     m_Ui->menuHDR_Histogram->setEnabled(isHdr);
849     m_Ui->Low_dynamic_range->setEnabled(isHdr);
850     m_Ui->Fit_to_dynamic_range->setEnabled(isHdr);
851     m_Ui->Shrink_dynamic_range->setEnabled(isHdr);
852     m_Ui->Extend_dynamic_range->setEnabled(isHdr);
853     m_Ui->Decrease_exposure->setEnabled(isHdr);
854     m_Ui->Increase_exposure->setEnabled(isHdr);
855 
856     m_Ui->actionResizeHDR->setEnabled(isHdr);
857     m_Ui->action_Projective_Transformation->setEnabled(isHdr);
858     m_Ui->actionExportToHTML->setEnabled(isHdr);
859     m_Ui->rotateccw->setEnabled(isHdr);
860     m_Ui->rotatecw->setEnabled(isHdr);
861 
862     m_Ui->actionFix_Histogram->setEnabled(isLdr);
863     m_Ui->actionWhite_Balance->setEnabled(hasImage && !m_processingAWB);
864     m_Ui->actionSoft_Proofing->setEnabled(isLdr && hasPrinterProfile);
865     m_Ui->actionGamut_Check->setEnabled(isLdr && hasPrinterProfile);
866 
867     bool hasCropping = isHdr && tm_status.curr_tm_frame &&
868                        tm_status.curr_tm_frame->hasSelection();
869     m_Ui->cropToSelectionAction->setEnabled(hasCropping);
870     m_Ui->removeSelectionAction->setEnabled(hasCropping);
871 
872     m_Ui->actionLock->setEnabled(hasImage && curr_num_ldr_open >= 1);
873     m_Ui->actionShow_Image_Full_Screen->setEnabled(hasImage);
874 }
875 
on_rotateccw_triggered()876 void MainWindow::on_rotateccw_triggered() { dispatchrotate(false); }
877 
on_rotatecw_triggered()878 void MainWindow::on_rotatecw_triggered() { dispatchrotate(true); }
879 
dispatchrotate(bool clockwise)880 void MainWindow::dispatchrotate(bool clockwise) {
881     if (m_tabwidget->count() <= 0) return;
882 
883     GenericViewer *curr_g_v = qobject_cast<GenericViewer *>(m_tabwidget->currentWidget());
884 
885     m_Ui->rotateccw->setEnabled(false);
886     m_Ui->rotatecw->setEnabled(false);
887 
888     QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
889     pfs::Frame *rotated = pfs::rotate(curr_g_v->getFrame(), clockwise);
890 
891     curr_g_v->setFrame(rotated);
892     if (!curr_g_v->needsSaving()) {
893         curr_g_v->setNeedsSaving(true);
894 
895         int index = m_tabwidget->indexOf(curr_g_v);
896         QString text = m_tabwidget->tabText(index);
897         m_tabwidget->setTabText(index, text.prepend("(*) "));
898 
899         setWindowModified(true);
900     }
901     emit updatedHDR(curr_g_v->getFrame());
902     QApplication::restoreOverrideCursor();
903 
904     m_Ui->rotateccw->setEnabled(true);
905     m_Ui->rotatecw->setEnabled(true);
906 }
907 
on_actionResizeHDR_triggered()908 void MainWindow::on_actionResizeHDR_triggered() {
909     if (m_tabwidget->count() <= 0) return;
910 
911     GenericViewer *curr_g_v = qobject_cast<GenericViewer *>(m_tabwidget->currentWidget());
912 
913     ResizeDialog *resizedialog = new ResizeDialog(this, curr_g_v->getFrame());
914     if (resizedialog->exec() == QDialog::Accepted) {
915         QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
916 
917         curr_g_v->setFrame(resizedialog->getResizedFrame());
918         if (!curr_g_v->needsSaving()) {
919             curr_g_v->setNeedsSaving(true);
920 
921             int index = m_tabwidget->indexOf(curr_g_v);
922             QString text = m_tabwidget->tabText(index);
923             m_tabwidget->setTabText(index, text.prepend("(*) "));
924 
925             setWindowModified(true);
926         }
927         emit updatedHDR(curr_g_v->getFrame());
928         QApplication::restoreOverrideCursor();
929     }
930     delete resizedialog;
931 }
932 
on_actionExportToHTML_triggered()933 void MainWindow::on_actionExportToHTML_triggered() {
934     if (m_tabwidget->count() <= 0) return;
935 
936     GenericViewer *curr_g_v = qobject_cast<GenericViewer *>(m_tabwidget->currentWidget());
937     ExportToHtmlDialog *exportDialog =
938         new ExportToHtmlDialog(this, curr_g_v->getFrame());
939 
940     exportDialog->exec();
941     delete exportDialog;
942 }
943 
on_actionSupported_Cameras_triggered()944 void MainWindow::on_actionSupported_Cameras_triggered() {
945     SupportedCamerasDialog *supportedDialog = new SupportedCamerasDialog(this);
946 
947     supportedDialog->exec();
948     delete supportedDialog;
949 }
950 
on_action_Projective_Transformation_triggered()951 void MainWindow::on_action_Projective_Transformation_triggered() {
952     if (m_tabwidget->count() <= 0) return;
953 
954     GenericViewer *curr_g_v = qobject_cast<GenericViewer *>(m_tabwidget->currentWidget());
955 
956     ProjectionsDialog *projTranfsDialog =
957         new ProjectionsDialog(this, curr_g_v->getFrame());
958     if (projTranfsDialog->exec() == QDialog::Accepted) {
959         QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
960 
961         curr_g_v->setFrame(projTranfsDialog->getTranformedFrame());
962         if (!curr_g_v->needsSaving()) {
963             curr_g_v->setNeedsSaving(true);
964 
965             int index = m_tabwidget->indexOf(curr_g_v);
966             QString text = m_tabwidget->tabText(index);
967             m_tabwidget->setTabText(index, text.prepend("(*) "));
968 
969             setWindowModified(true);
970         }
971         emit updatedHDR(curr_g_v->getFrame());
972         QApplication::restoreOverrideCursor();
973     }
974     delete projTranfsDialog;
975 }
976 
on_Decrease_exposure_triggered()977 void MainWindow::on_Decrease_exposure_triggered() {
978     if (m_tabwidget->count() <= 0) return;
979 
980     GenericViewer *g_v = qobject_cast<GenericViewer *>(m_tabwidget->currentWidget());
981     HdrViewer *curr_hdr_v = qobject_cast<HdrViewer *>(g_v);
982     if (curr_hdr_v != nullptr) curr_hdr_v->lumRange()->decreaseExposure();
983 }
984 
on_Extend_dynamic_range_triggered()985 void MainWindow::on_Extend_dynamic_range_triggered() {
986     if (m_tabwidget->count() <= 0) return;
987 
988     GenericViewer *g_v = qobject_cast<GenericViewer *>(m_tabwidget->currentWidget());
989     HdrViewer *curr_hdr_v = qobject_cast<HdrViewer *>(g_v);
990     if (curr_hdr_v != nullptr) curr_hdr_v->lumRange()->extendRange();
991 }
992 
on_Fit_to_dynamic_range_triggered()993 void MainWindow::on_Fit_to_dynamic_range_triggered() {
994     if (m_tabwidget->count() <= 0) return;
995 
996     GenericViewer *g_v = qobject_cast<GenericViewer *>(m_tabwidget->currentWidget());
997     HdrViewer *curr_hdr_v = qobject_cast<HdrViewer *>(g_v);
998     if (curr_hdr_v != nullptr) curr_hdr_v->lumRange()->fitToDynamicRange();
999 }
1000 
on_Increase_exposure_triggered()1001 void MainWindow::on_Increase_exposure_triggered() {
1002     if (m_tabwidget->count() <= 0) return;
1003 
1004     GenericViewer *g_v = qobject_cast<GenericViewer *>(m_tabwidget->currentWidget());
1005     HdrViewer *curr_hdr_v = qobject_cast<HdrViewer *>(g_v);
1006     if (curr_hdr_v != nullptr) curr_hdr_v->lumRange()->increaseExposure();
1007 }
1008 
on_Shrink_dynamic_range_triggered()1009 void MainWindow::on_Shrink_dynamic_range_triggered() {
1010     if (m_tabwidget->count() <= 0) return;
1011 
1012     GenericViewer *g_v = qobject_cast<GenericViewer *>(m_tabwidget->currentWidget());
1013     HdrViewer *curr_hdr_v = qobject_cast<HdrViewer *>(g_v);
1014     if (curr_hdr_v != nullptr) curr_hdr_v->lumRange()->shrinkRange();
1015 }
1016 
on_Low_dynamic_range_triggered()1017 void MainWindow::on_Low_dynamic_range_triggered() {
1018     if (m_tabwidget->count() <= 0) return;
1019 
1020     GenericViewer *g_v = qobject_cast<GenericViewer *>(m_tabwidget->currentWidget());
1021     HdrViewer *curr_hdr_v = qobject_cast<HdrViewer *>(g_v);
1022     if (curr_hdr_v != nullptr) curr_hdr_v->lumRange()->lowDynamicRange();
1023 }
1024 
1025 // Zoom = Viewers (START)
on_zoomInAct_triggered()1026 void MainWindow::on_zoomInAct_triggered() {
1027     if (m_tabwidget->count() <= 0) return;
1028 
1029     GenericViewer *g_v = qobject_cast<GenericViewer *>(m_tabwidget->currentWidget());
1030 
1031     g_v->zoomIn();
1032 }
1033 
on_zoomOutAct_triggered()1034 void MainWindow::on_zoomOutAct_triggered() {
1035     if (m_tabwidget->count() <= 0) return;
1036 
1037     GenericViewer *g_v = qobject_cast<GenericViewer *>(m_tabwidget->currentWidget());
1038 
1039     g_v->zoomOut();
1040 }
1041 
on_fitToWindowAct_triggered()1042 void MainWindow::on_fitToWindowAct_triggered() {
1043     if (m_tabwidget->count() <= 0) return;
1044 
1045     GenericViewer *g_v = qobject_cast<GenericViewer *>(m_tabwidget->currentWidget());
1046 
1047     g_v->fitToWindow();
1048 }
1049 
on_actionFill_to_Window_triggered()1050 void MainWindow::on_actionFill_to_Window_triggered() {
1051     if (m_tabwidget->count() <= 0) return;
1052 
1053     GenericViewer *g_v = qobject_cast<GenericViewer *>(m_tabwidget->currentWidget());
1054 
1055     g_v->fillToWindow();
1056 }
1057 
on_normalSizeAct_triggered()1058 void MainWindow::on_normalSizeAct_triggered() {
1059     if (m_tabwidget->count() <= 0) return;
1060 
1061     GenericViewer *g_v = qobject_cast<GenericViewer *>(m_tabwidget->currentWidget());
1062 
1063     g_v->normalSize();
1064 }
1065 // Zoom = Viewers (END)
1066 
1067 #ifdef WITH_HELPBROWSER
on_documentationAction_triggered()1068 void MainWindow::on_documentationAction_triggered() {
1069     if (sm_helpBrowser == nullptr) {
1070         sm_helpBrowser =
1071             new HelpBrowser(0, QStringLiteral("Luminance HDR Help"));
1072         sm_helpBrowser->setAttribute(Qt::WA_DeleteOnClose);
1073         connect(sm_helpBrowser, &QObject::destroyed, sm_helpBrowser,
1074                 &QObject::deleteLater);
1075         connect(sm_helpBrowser, &HelpBrowser::closed, this,
1076                 &MainWindow::helpBrowserClosed);
1077         sm_helpBrowser->show();
1078     } else {
1079         sm_helpBrowser->show();
1080         sm_helpBrowser->activateWindow();
1081         sm_helpBrowser->raise();
1082     }
1083 }
1084 
helpBrowserClosed()1085 void MainWindow::helpBrowserClosed() {
1086     sm_helpBrowser = nullptr;
1087 }
1088 #endif
1089 
enterWhatsThis()1090 void MainWindow::enterWhatsThis() { QWhatsThis::enterWhatsThisMode(); }
1091 
openRecentFile()1092 void MainWindow::openRecentFile() {
1093     QAction *action = qobject_cast<QAction *>(sender());
1094     if (action) {
1095         // emit open_hdr_frame(action->data().toString());
1096         QMetaObject::invokeMethod(m_IOWorker, "read_hdr_frame",
1097                                   Qt::QueuedConnection,
1098                                   Q_ARG(QString, action->data().toString()));
1099     }
1100 }
1101 
setupIO()1102 void MainWindow::setupIO() {
1103     // progress bar
1104     m_ProgressBar = new QProgressBar(this);
1105     m_ProgressBar->hide();
1106     statusBar()->addWidget(m_ProgressBar);
1107 
1108     // Init Object/Thread
1109     m_IOThread = new QThread;
1110     m_IOWorker = new IOWorker;
1111 
1112     m_IOWorker->moveToThread(m_IOThread);
1113 
1114     // Memory Management
1115     connect(this, &QObject::destroyed, m_IOWorker, &QObject::deleteLater);
1116     connect(m_IOWorker, &QObject::destroyed, m_IOThread, &QObject::deleteLater);
1117 
1118     // Open
1119     connect(m_IOWorker, SIGNAL(read_hdr_success(pfs::Frame *, const QString &)),
1120             this, SLOT(load_success(pfs::Frame *, const QString &)));
1121     connect(m_IOWorker, &IOWorker::read_hdr_failed, this,
1122             &MainWindow::load_failed);
1123 
1124     // Save HDR
1125     connect(m_IOWorker,
1126             SIGNAL(write_hdr_success(GenericViewer *, const QString &)), this,
1127             SLOT(save_hdr_success(GenericViewer *, const QString &)));
1128     connect(m_IOWorker, &IOWorker::write_hdr_failed, this,
1129             &MainWindow::save_hdr_failed);
1130     // Save LDR
1131     connect(m_IOWorker,
1132             SIGNAL(write_ldr_success(GenericViewer *, const QString &)), this,
1133             SLOT(save_ldr_success(GenericViewer *, const QString &)));
1134     connect(m_IOWorker, &IOWorker::write_ldr_failed, this,
1135             &MainWindow::save_ldr_failed);
1136 
1137     // progress bar handling
1138     connect(m_IOWorker, &IOWorker::setValue, m_ProgressBar,
1139             &QProgressBar::setValue);
1140     connect(m_IOWorker, &IOWorker::setMaximum, m_ProgressBar,
1141             &QProgressBar::setMaximum);
1142     connect(m_IOWorker, &IOWorker::IO_init, this, &MainWindow::ioBegin);
1143     connect(m_IOWorker, &IOWorker::IO_finish, this, &MainWindow::ioEnd);
1144 
1145     // start thread waiting for signals (I/O requests)
1146     m_IOThread->start();
1147 }
1148 
ioBegin()1149 void MainWindow::ioBegin() {
1150     statusBar()->clearMessage();
1151 
1152     QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
1153 
1154     //  statusBar()->addWidget(m_ProgressBar);
1155     m_ProgressBar->setMaximum(0);
1156     m_ProgressBar->show();
1157 }
1158 
ioEnd()1159 void MainWindow::ioEnd() {
1160     // statusBar()->removeWidget(m_ProgressBar);
1161     m_ProgressBar->reset();
1162     m_ProgressBar->hide();
1163 
1164     QApplication::restoreOverrideCursor();
1165 
1166     statusBar()->showMessage(tr("Done!"), 800);
1167 }
1168 
load_failed(const QString & errorMessage)1169 void MainWindow::load_failed(const QString &errorMessage) {
1170     m_ProgressBar->reset();
1171     m_ProgressBar->hide();
1172 
1173     QApplication::restoreOverrideCursor();
1174 
1175     // TODO: use unified style?
1176     QMessageBox::critical(this, tr("Aborting..."), errorMessage,
1177                           QMessageBox::Ok, QMessageBox::NoButton);
1178 }
1179 
load_success(pfs::Frame * new_hdr_frame,const QString & new_fname,const QStringList & inputFileNames,bool needSaving)1180 void MainWindow::load_success(pfs::Frame *new_hdr_frame,
1181                               const QString &new_fname,
1182                               const QStringList &inputFileNames,
1183                               bool needSaving) {
1184     if (tm_status.is_hdr_ready) {
1185         MainWindow *other = new MainWindow(new_hdr_frame, new_fname,
1186                                            inputFileNames, needSaving);
1187         other->move(x() + 40, y() + 40);
1188         other->show();
1189     } else {
1190 #ifdef QT_DEBUG
1191         qDebug() << "Filename: " << new_fname;
1192 #endif
1193         HdrViewer *newhdr = new HdrViewer(new_hdr_frame, this, needSaving);
1194 
1195         newhdr->setAttribute(Qt::WA_DeleteOnClose);
1196 
1197         connect(newhdr, &GenericViewer::selectionReady, this,
1198                 &MainWindow::enableCrop);
1199         connect(newhdr, &GenericViewer::changed, this,
1200                 &MainWindow::syncViewers);
1201         connect(newhdr, &GenericViewer::changed, this,
1202                 &MainWindow::updateMagnificationButtons);
1203         connect(newhdr, &GenericViewer::reparent, this,
1204                 &MainWindow::reparentViewer);
1205         connect(newhdr, &GenericViewer::goNext, this,
1206                 &MainWindow::showNextViewer);
1207         connect(newhdr, &GenericViewer::goPrevious, this,
1208                 &MainWindow::showPreviousViewer);
1209         connect(newhdr, &GenericViewer::syncViewers, this,
1210                 &MainWindow::setSyncViewers);
1211 
1212         newhdr->setViewerMode(getCurrentViewerMode(*m_tabwidget));
1213 
1214         QFileInfo qfileinfo(new_fname);
1215         if (!qfileinfo.exists()) {
1216             // it doesn't exist on the file system, so I have just got back a
1217             // file from some creational operation (new hdr, crop...)
1218             m_inputFilesName = inputFileNames;
1219             QFileInfo fi1(m_inputFilesName.first());
1220 
1221             if (m_inputFilesName.first() != m_inputFilesName.last()) {
1222                 QFileInfo fi2(m_inputFilesName.last());
1223 
1224                 m_outputFileNamePrefix =
1225                     fi1.completeBaseName() + "-" + fi2.completeBaseName();
1226             }
1227             else {
1228                 m_outputFileNamePrefix = fi1.completeBaseName();
1229             }
1230             // newhdr->setFileName(QString(tr("Untitled")));
1231             newhdr->setFileName(m_outputFileNamePrefix);
1232             m_tabwidget->addTab(newhdr, QString(new_fname).prepend("(*) "));
1233             m_HdrCaption = new_fname;
1234 
1235             setWindowModified(true);
1236         } else {
1237             m_outputFileNamePrefix = new_fname;
1238             // the new file exists on the file system, so I can use this value
1239             // to set captions and so on
1240             newhdr->setFileName(new_fname);
1241             m_tabwidget->addTab(newhdr, qfileinfo.fileName());
1242 
1243             setCurrentFile(new_fname);
1244             setWindowModified(needSaving);
1245         }
1246 
1247         tm_status.is_hdr_ready = true;
1248         tm_status.curr_tm_frame = newhdr;
1249 
1250         m_tabwidget->setCurrentWidget(newhdr);
1251 
1252         m_tonemapPanel->setEnabled(true);
1253         m_tonemapPanel->updatedHDR(new_hdr_frame);
1254         m_Ui->actionShowPreviewPanel->setEnabled(true);
1255 
1256         showPreviewPanel(m_Ui->actionShowPreviewPanel->isChecked());
1257 
1258         // signal: I have a new HDR open
1259         emit updatedHDR(newhdr->getFrame());
1260     }
1261 }
1262 
on_OptionsAction_triggered()1263 void MainWindow::on_OptionsAction_triggered() {
1264     PreferencesDialog *opts = new PreferencesDialog(this);
1265     opts->setAttribute(Qt::WA_DeleteOnClose);
1266     if (opts->exec() == QDialog::Accepted) {
1267         m_Ui->actionShowPreviewPanel->setChecked(
1268             LuminanceOptions().isPreviewPanelActive());
1269     }
1270 }
1271 
on_Transplant_Exif_Data_action_triggered()1272 void MainWindow::on_Transplant_Exif_Data_action_triggered() {
1273     TransplantExifDialog *transplant = new TransplantExifDialog(this);
1274     transplant->setAttribute(Qt::WA_DeleteOnClose);
1275     transplant->exec();
1276 }
1277 
dragEnterEvent(QDragEnterEvent * event)1278 void MainWindow::dragEnterEvent(QDragEnterEvent *event) {
1279     event->acceptProposedAction();
1280 }
1281 
dropEvent(QDropEvent * event)1282 void MainWindow::dropEvent(QDropEvent *event) {
1283     if (event->mimeData()->hasUrls()) {
1284         openFiles(convertUrlListToFilenameList(event->mimeData()->urls()));
1285     }
1286     event->acceptProposedAction();
1287 }
1288 
openFile(const QString & filename)1289 void MainWindow::openFile(const QString &filename) {
1290     QMetaObject::invokeMethod(m_IOWorker, "read_hdr_frame",
1291                               Qt::QueuedConnection, Q_ARG(QString, filename));
1292 }
1293 
openFiles(const QStringList & files)1294 void MainWindow::openFiles(const QStringList &files) {
1295     if (files.size() > 0) {
1296         switch (DnDOptionDialog::showDndDialog(this, files)) {
1297             case DnDOptionDialog::ACTION_NEW_HDR: {
1298                 createNewHdr(files);
1299             } break;
1300             case DnDOptionDialog::ACTION_OPEN_HDR: {
1301                 foreach (const QString &filename, files) { openFile(filename); }
1302             } break;
1303         }
1304     }
1305 }
1306 
Text_Under_Icons()1307 void MainWindow::Text_Under_Icons() {
1308     m_Ui->toolBar->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
1309     LuminanceOptions().setMainWindowToolBarMode(Qt::ToolButtonTextUnderIcon);
1310 }
1311 
Icons_Only()1312 void MainWindow::Icons_Only() {
1313     m_Ui->toolBar->setToolButtonStyle(Qt::ToolButtonIconOnly);
1314     LuminanceOptions().setMainWindowToolBarMode(Qt::ToolButtonIconOnly);
1315 }
1316 
Text_Alongside_Icons()1317 void MainWindow::Text_Alongside_Icons() {
1318     m_Ui->toolBar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
1319     LuminanceOptions().setMainWindowToolBarMode(Qt::ToolButtonTextBesideIcon);
1320 }
1321 
Text_Only()1322 void MainWindow::Text_Only() {
1323     m_Ui->toolBar->setToolButtonStyle(Qt::ToolButtonTextOnly);
1324     LuminanceOptions().setMainWindowToolBarMode(Qt::ToolButtonTextOnly);
1325 }
1326 
onUpdateAvailable()1327 void MainWindow::onUpdateAvailable() {
1328     m_Ui->actionUpdateAvailable->setVisible(true);
1329 }
1330 
on_actionUpdateAvailable_triggered()1331 void MainWindow::on_actionUpdateAvailable_triggered() {
1332     if (sm_updateChecker) {
1333         sm_updateChecker->trayMessageClicked();
1334     }
1335 }
1336 
on_actionAbout_Luminance_triggered()1337 void MainWindow::on_actionAbout_Luminance_triggered() { UMessageBox::about(); }
1338 
1339 /*
1340  * Window Menu Display and Functionalities
1341  */
updateWindowMenu()1342 void MainWindow::updateWindowMenu() {
1343     // Remove current elements inside the menuWindows
1344     foreach (QAction *Action_MW, openMainWindows) {
1345         openMainWindows.removeAll(Action_MW);
1346         m_Ui->menuWindows->removeAction(Action_MW);
1347         delete Action_MW;
1348     }
1349 
1350     foreach (QWidget *widget, QApplication::topLevelWidgets()) {
1351         MainWindow *MW = qobject_cast<MainWindow *>(widget);
1352         if (MW != nullptr) {
1353             QAction *action =
1354                 m_Ui->menuWindows->addAction(MW->getCurrentHDRName());
1355 
1356             action->setCheckable(true);
1357             action->setChecked(MW == this);
1358             // connect(action, SIGNAL(triggered()), windowMapper, SLOT(map()));
1359             connect(action, SIGNAL(triggered()), windowMapper, SLOT(map()));
1360             windowMapper->setMapping(action, MW);
1361 
1362             openMainWindows.push_back(action);
1363         }
1364     }
1365 }
1366 
1367 /*
1368  * This function sets the active Main Window
1369  * when the file name is selected inside the "Window" menu
1370  */
setActiveMainWindow(QWidget * w)1371 void MainWindow::setActiveMainWindow(QWidget *w) {
1372     MainWindow *MW = qobject_cast<MainWindow *>(w);
1373 
1374     if (MW == nullptr) return;
1375 
1376     MW->raise();
1377     MW->activateWindow();
1378     return;
1379 }
1380 
on_actionBring_All_to_Front_triggered()1381 void MainWindow::on_actionBring_All_to_Front_triggered() {
1382     foreach (QWidget *widget, QApplication::topLevelWidgets()) {
1383         MainWindow *MW = qobject_cast<MainWindow *>(widget);
1384         if (MW != nullptr) {
1385             MW->raise();
1386         }
1387     }
1388 }
1389 
on_actionBatch_HDR_triggered()1390 void MainWindow::on_actionBatch_HDR_triggered() {
1391     BatchHDRDialog *batch_hdr_dialog = new BatchHDRDialog(this, QSqlDatabase::database(m_tonemapPanel->getDatabaseConnection()));
1392     batch_hdr_dialog->exec();
1393     delete batch_hdr_dialog;
1394 }
1395 
on_actionBatch_Tone_Mapping_triggered()1396 void MainWindow::on_actionBatch_Tone_Mapping_triggered() {
1397     BatchTMDialog *batchdialog = new BatchTMDialog(this, QSqlDatabase::database(m_tonemapPanel->getDatabaseConnection()));
1398     batchdialog->exec();
1399     delete batchdialog;
1400 }
1401 
cropToSelection()1402 void MainWindow::cropToSelection() {
1403     if (m_tabwidget->count() <= 0) return;
1404 
1405     GenericViewer *curr_g_v = qobject_cast<GenericViewer *>(m_tabwidget->currentWidget());
1406 
1407     if (!curr_g_v->isHDR()) return;
1408     if (!curr_g_v->hasSelection()) return;
1409 
1410     QRect cropRect = curr_g_v->getSelectionRect();
1411     int x_ul, y_ul, x_br, y_br;
1412     cropRect.getCoords(&x_ul, &y_ul, &x_br, &y_br);
1413     disableCrop();
1414     pfs::Frame *original_frame = curr_g_v->getFrame();
1415     pfs::Frame *cropped_frame =
1416         pfs::cut(original_frame, x_ul, y_ul, x_br, y_br);
1417 
1418     emit load_success(cropped_frame, QString(tr("Cropped Image")),
1419                       m_inputFilesName, true);
1420 
1421     curr_g_v->removeSelection();
1422 }
1423 
enableCrop(bool isReady)1424 void MainWindow::enableCrop(bool isReady) {
1425     m_Ui->cropToSelectionAction->setEnabled(isReady);
1426     m_Ui->removeSelectionAction->setEnabled(isReady);
1427 }
1428 
disableCrop()1429 void MainWindow::disableCrop() {
1430     if (m_tabwidget->count() <= 0) return;
1431 
1432     GenericViewer *curr_g_v = qobject_cast<GenericViewer *>(m_tabwidget->currentWidget());
1433 
1434     if (!curr_g_v->isHDR()) return;
1435 
1436     curr_g_v->removeSelection();
1437     m_Ui->cropToSelectionAction->setEnabled(false);
1438     m_Ui->removeSelectionAction->setEnabled(false);
1439 }
1440 
changeEvent(QEvent * event)1441 void MainWindow::changeEvent(QEvent *event) {
1442     if (event->type() == QEvent::LanguageChange) {
1443         m_Ui->retranslateUi(this);
1444         setWindowTitle(QString("Luminance HDR " LUMINANCEVERSION " [*]"));
1445     }
1446 
1447     QWidget::changeEvent(event);
1448 }
1449 
closeEvent(QCloseEvent * event)1450 void MainWindow::closeEvent(QCloseEvent *event) {
1451     if (!maybeSave()) {
1452         event->ignore();
1453         return;
1454     }
1455     if (m_isFullscreenViewer) {
1456         reparentViewer(m_g_v_fullscreen);
1457     }
1458     sm_NumMainWindows--;
1459     if (sm_NumMainWindows == 0) {
1460 #ifdef WITH_HELPBROWSER
1461         if (sm_helpBrowser) {
1462             sm_helpBrowser->close();
1463         }
1464 #endif
1465     }
1466 
1467     if (sm_NumMainWindows == 0) {
1468         // Last MainWindow is dead...
1469         LuminanceOptions().setValue(QStringLiteral("MainWindowState"),
1470                                     saveState());
1471         LuminanceOptions().setValue(QStringLiteral("MainWindowGeometry"),
1472                                     saveGeometry());
1473         LuminanceOptions().setValue(QStringLiteral("MainWindowSplitterState"),
1474                                     m_centralwidget_splitter->saveState());
1475         LuminanceOptions().setValue(
1476             QStringLiteral("MainWindowSplitterGeometry"),
1477             m_centralwidget_splitter->saveGeometry());
1478         LuminanceOptions().setValue(
1479             QStringLiteral("MainWindowBottomSplitterState"),
1480             m_bottom_splitter->saveState());
1481         LuminanceOptions().setValue(
1482             QStringLiteral("MainWindowBottomSplitterGeometry"),
1483             m_bottom_splitter->saveGeometry());
1484 
1485         sm_updateChecker.reset();
1486     } else {
1487         sm_mainWindowMap.take(m_winId);
1488         int winId = sm_mainWindowMap.firstKey();
1489         MainWindow *p = sm_mainWindowMap[winId];
1490         disconnect(sm_updateChecker.data(), &UpdateChecker::updateAvailable, p,
1491                    &MainWindow::onUpdateAvailable);
1492         sm_updateChecker->setParent(p);
1493         connect(sm_updateChecker.data(), &UpdateChecker::updateAvailable, p,
1494                 &MainWindow::onUpdateAvailable);
1495     }
1496 
1497     // Let's close all threads
1498     m_IOThread->quit();  // should be idle, quit() ok
1499     m_IOThread->wait();
1500     if (!m_TMProgressBar->isTerminated())  // MainWindow closed while
1501                                            // tonemapping is running
1502     {
1503         m_TMProgressBar->requestTermination();
1504     }
1505     m_TMThread->quit();
1506     m_TMThread->wait();
1507     m_QueueThread->quit();  // should be idle, quit() ok
1508     m_QueueThread->wait();
1509 
1510     clearRecentFileActions();
1511     QMainWindow::closeEvent(event);
1512 }
1513 
event(QEvent * event)1514 bool MainWindow::event(QEvent *event) {
1515     bool result = QMainWindow::event(event);
1516     if (event->type() == QEvent::WindowActivate && m_firstWindow == 1) {
1517         m_firstWindow = 2;
1518         if (LuminanceOptions().doShowWindowsOnWindows64Message()) {
1519             QMessageBox::warning(
1520                 this, QStringLiteral("Luminance HDR 32-bit on 64-bit"),
1521                 tr("It appears that you are running the 32-bit version "
1522                    "<strong>Luminance HDR</strong> on a 64-bit system. <br>"
1523                    "Please download the <strong>64-bit</strong> version from "
1524                    "<a "
1525                    "href=\"http://qtpfsgui.sourceforge.net\">http://"
1526                    "qtpfsgui.sourceforge.net</a> "
1527                    "to get the best Luminance HDR experience!"),
1528                 QMessageBox::Ok, QMessageBox::NoButton);
1529         }
1530     }
1531     return result;
1532 }
1533 
maybeSave()1534 bool MainWindow::maybeSave() {
1535     // if no HDR is open, return true
1536     if (!tm_status.is_hdr_ready) return true;
1537 
1538     if (tm_status.curr_tm_frame->needsSaving()) {
1539         int ret = UMessageBox::saveDialog(
1540             tr("Unsaved changes..."), tr("This HDR image has unsaved "
1541                                          "changes.<br>Do you want to save it?"),
1542             this);
1543         switch (ret) {
1544             case QMessageBox::Save: {
1545                 // if save == success return true;
1546                 // else return false;
1547                 // QString fname =
1548                 // getHdrFileNameFromSaveDialog(QStringLiteral("Untitled"),
1549                 // this);
1550                 QString fname = getHdrFileNameFromSaveDialog(
1551                     m_outputFileNamePrefix + "-" + m_HdrCaption, this);
1552 
1553                 if (!fname.isEmpty()) {
1554                     // TODO : can I launch a signal and wait that it gets
1555                     // executed
1556                     // fully?
1557                     return m_IOWorker->write_hdr_frame(
1558                         qobject_cast<HdrViewer *>(tm_status.curr_tm_frame),
1559                         fname);
1560                 } else {
1561                     return false;
1562                 }
1563             } break;
1564             case QMessageBox::Discard: {
1565                 return true;
1566             } break;
1567             case QMessageBox::Cancel:
1568             default: { return false; } break;
1569         }
1570     } else
1571         return true;
1572 }
1573 
setupTM()1574 void MainWindow::setupTM() {
1575     // TODO: Building TM Thread
1576     tm_status.is_hdr_ready = false;
1577     tm_status.curr_tm_frame = nullptr;
1578     tm_status.curr_tm_options = nullptr;
1579 
1580     m_tonemapPanel->setEnabled(false);
1581 
1582     m_TMProgressBar = new TMOProgressIndicator;
1583     m_TMProgressBar->hide();
1584     statusBar()->addWidget(m_TMProgressBar);
1585 
1586     connect(this, &QObject::destroyed, m_TMProgressBar, &QObject::deleteLater);
1587 
1588     m_TMWorker = new TMWorker;
1589     m_TMThread = new QThread;
1590 
1591     m_TMWorker->moveToThread(m_TMThread);
1592 
1593     // Memory Management
1594     connect(this, &QObject::destroyed, m_TMWorker, &QObject::deleteLater);
1595     connect(m_TMWorker, &QObject::destroyed, m_TMThread, &QObject::deleteLater);
1596 
1597     // get back result!
1598     connect(m_TMWorker, &TMWorker::tonemapSuccess, this,
1599             &MainWindow::addLdrFrame);
1600     connect(m_TMWorker, SIGNAL(tonemapFailed(QString)), this,
1601             SLOT(tonemapFailed(QString)));
1602 
1603     // progress bar handling
1604     connect(m_TMWorker, &TMWorker::tonemapBegin, this,
1605             &MainWindow::tonemapBegin);
1606     connect(m_TMWorker, &TMWorker::tonemapEnd, this, &MainWindow::tonemapEnd);
1607 
1608     connect(m_TMWorker, &TMWorker::tonemapSetValue, m_TMProgressBar,
1609             &TMOProgressIndicator::setValue);
1610     connect(m_TMWorker, &TMWorker::tonemapSetMaximum, m_TMProgressBar,
1611             &TMOProgressIndicator::setMaximum);
1612     connect(m_TMWorker, &TMWorker::tonemapSetMinimum, m_TMProgressBar,
1613             &TMOProgressIndicator::setMinimum);
1614     connect(m_TMProgressBar, &TMOProgressIndicator::terminate, m_TMWorker,
1615             &TMWorker::tonemapRequestTermination, Qt::DirectConnection);
1616 
1617     // start thread waiting for signals (I/O requests)
1618     m_TMThread->start();
1619 }
1620 
setupQueue()1621 void MainWindow::setupQueue() {
1622     m_QueueProgressBar = new TMOProgressIndicator;
1623     m_QueueProgressBar->hide();
1624     statusBar()->addWidget(m_QueueProgressBar);
1625 
1626     connect(this, &QObject::destroyed, m_QueueProgressBar,
1627             &QObject::deleteLater);
1628 
1629     m_QueueWorker = new TMWorker;
1630     m_QueueThread = new QThread;
1631 
1632     m_QueueWorker->moveToThread(m_QueueThread);
1633 
1634     // Memory Management
1635     connect(this, &QObject::destroyed, m_QueueWorker, &QObject::deleteLater);
1636     connect(m_QueueWorker, &QObject::destroyed, m_QueueThread,
1637             &QObject::deleteLater);
1638 
1639     // get back result!
1640     // connect(m_QueueWorker, SIGNAL(tonemapSuccess(pfs::Frame*,
1641     // TonemappingOptions*)),
1642     //    this, SLOT(addLdrFrame(pfs::Frame*, TonemappingOptions*)));
1643     connect(m_QueueWorker, SIGNAL(tonemapFailed(QString)), this,
1644             SLOT(tonemapFailed(QString)));
1645 
1646     // progress bar handling
1647     connect(m_QueueWorker, &TMWorker::tonemapBegin, this,
1648             &MainWindow::exportBegin);
1649     connect(m_QueueWorker, &TMWorker::tonemapEnd, this, &MainWindow::exportEnd);
1650 
1651     connect(m_QueueWorker, &TMWorker::tonemapSetValue, m_QueueProgressBar,
1652             &TMOProgressIndicator::setValue);
1653     connect(m_QueueWorker, &TMWorker::tonemapSetMaximum, m_QueueProgressBar,
1654             &TMOProgressIndicator::setMaximum);
1655     connect(m_QueueWorker, &TMWorker::tonemapSetMinimum, m_QueueProgressBar,
1656             &TMOProgressIndicator::setMinimum);
1657     connect(m_QueueProgressBar, &TMOProgressIndicator::terminate, m_QueueWorker,
1658             &TMWorker::tonemapRequestTermination, Qt::DirectConnection);
1659 
1660     // start thread waiting for signals (I/O requests)
1661     m_QueueThread->start();
1662 }
1663 
tonemapBegin()1664 void MainWindow::tonemapBegin() {
1665     // statusBar()->addWidget(m_TMProgressBar);
1666     m_TMProgressBar->setMaximum(0);
1667     m_TMProgressBar->show();
1668 }
1669 
tonemapEnd()1670 void MainWindow::tonemapEnd() {
1671     // statusBar()->removeWidget(m_TMProgressBar);
1672     m_TMProgressBar->hide();
1673     m_TMProgressBar->reset();
1674 }
1675 
exportBegin()1676 void MainWindow::exportBegin() {
1677     m_QueueProgressBar->setMaximum(0);
1678     m_QueueProgressBar->show();
1679 }
1680 
exportEnd()1681 void MainWindow::exportEnd() {
1682     m_tonemapPanel->setExportQueueSize(--m_exportQueueSize);
1683     m_QueueProgressBar->hide();
1684     m_QueueProgressBar->reset();
1685 }
1686 
tonemapImage(TonemappingOptions * opts)1687 void MainWindow::tonemapImage(TonemappingOptions *opts) {
1688 #ifdef QT_DEBUG
1689     qDebug() << "Start Tone Mapping";
1690 #endif
1691 
1692     // Warning when using size dependent TMOs with smaller sizes
1693     if ((opts->tmoperator == fattal) &&
1694         (opts->operator_options.fattaloptions.fftsolver == false) &&
1695         (opts->xsize != opts->origxsize) &&
1696         (LuminanceOptions().isShowFattalWarning())) {
1697         UMessageBox warningDialog(this);
1698         warningDialog.setText(tr("Fattal Warning"));
1699         warningDialog.setInformativeText(
1700             tr("This tonemapping operator depends on the size of the input "
1701                " image. Applying this operator on the full size image will "
1702                "most probably result in a different image. "
1703                "\n\nDo you want to continue?"));
1704         warningDialog.setStandardButtons(
1705             QMessageBox::Yes | QMessageBox::YesToAll | QMessageBox::No);
1706         warningDialog.setDefaultButton(QMessageBox::No);
1707         warningDialog.setIcon(QMessageBox::Warning);
1708 
1709         switch (warningDialog.exec()) {
1710             case QMessageBox::Yes: {
1711             } break;
1712             case QMessageBox::YesAll: {
1713                 LuminanceOptions().setShowFattalWarning(false);
1714             } break;
1715             case QMessageBox::No:
1716             default: { return; }
1717         }
1718     }
1719 
1720     m_PreviewPanel->setEnabled(false);
1721 
1722     tm_status.curr_tm_options = opts;
1723 
1724     if (tm_status.curr_tm_frame->hasSelection()) {
1725         opts->tonemapSelection = true;
1726 
1727         getCropCoords(tm_status.curr_tm_frame, opts->selection_x_up_left,
1728                       opts->selection_y_up_left, opts->selection_x_bottom_right,
1729                       opts->selection_y_bottom_right);
1730     } else
1731         opts->tonemapSelection = false;
1732 
1733     HdrViewer *hdr_viewer = qobject_cast<HdrViewer *>(tm_status.curr_tm_frame);
1734     if (hdr_viewer) {
1735 #ifdef QT_DEBUG
1736         qDebug() << "MainWindow(): emit getTonemappedFrame()";
1737 #endif
1738         // CALL m_TMWorker->getTonemappedFrame(hdr_viewer->getHDRPfsFrame(),
1739         // opts);
1740         QMetaObject::invokeMethod(
1741             m_TMWorker, "computeTonemap", Qt::QueuedConnection,
1742             Q_ARG(pfs::Frame *, hdr_viewer->getFrame()),
1743             Q_ARG(TonemappingOptions *, opts),
1744             Q_ARG(InterpolationMethod, m_interpolationMethod));
1745     }
1746 }
1747 
exportImage(TonemappingOptions * opts)1748 void MainWindow::exportImage(TonemappingOptions *opts) {
1749     HdrViewer *hdr_viewer = qobject_cast<HdrViewer *>(tm_status.curr_tm_frame);
1750     if (hdr_viewer) {
1751         Params params = pfsadditions::FormatHelper::getParamsFromSettings(
1752             KEY_FILEFORMAT_QUEUE, false);
1753         QString hdrName = QFileInfo(getCurrentHDRName()).baseName();
1754 
1755         QString inputfname;
1756         if (!m_inputFilesName.isEmpty()) inputfname = m_outputFileNamePrefix;
1757 
1758         QString exportDir = LuminanceOptions().getExportDir();
1759 
1760         m_tonemapPanel->setExportQueueSize(++m_exportQueueSize);
1761 
1762         QMetaObject::invokeMethod(
1763             m_QueueWorker, "computeTonemapAndExport", Qt::QueuedConnection,
1764             Q_ARG(pfs::Frame *, hdr_viewer->getFrame()),
1765             Q_ARG(TonemappingOptions *, opts), Q_ARG(pfs::Params, params),
1766             Q_ARG(QString, exportDir), Q_ARG(QString, hdrName),
1767             Q_ARG(QString, inputfname), Q_ARG(QVector<float>, m_inputExpoTimes),
1768             Q_ARG(InterpolationMethod, m_interpolationMethod));
1769     }
1770 }
1771 
addLdrFrame(pfs::Frame * frame,TonemappingOptions * tm_options)1772 void MainWindow::addLdrFrame(pfs::Frame *frame,
1773                              TonemappingOptions *tm_options) {
1774     if (m_tonemapPanel->doAutoLevels()) {
1775         float threshold, minL, maxL, gammaL;
1776         threshold = m_tonemapPanel->getAutoLevelsThreshold();
1777         QScopedPointer<QImage> temp_qimage(fromLDRPFStoQImage(frame));
1778         computeAutolevels(temp_qimage.data(), threshold, minL, maxL, gammaL);
1779         pfs::gammaAndLevels(frame, minL, maxL, 0.f, 1.f, gammaL);
1780     }
1781 
1782     GenericViewer *n =
1783         static_cast<GenericViewer *>(m_tabwidget->currentWidget());
1784     if (m_tonemapPanel->replaceLdr() && n != nullptr && !n->isHDR()) {
1785         n->setFrame(frame, tm_options);
1786     } else {
1787         curr_num_ldr_open++;
1788         num_ldr_generated++;
1789 
1790         n = new LdrViewer(frame, tm_options, this, true);
1791 
1792         connect(n, &GenericViewer::changed, this, &MainWindow::syncViewers);
1793         connect(n, &GenericViewer::changed, this,
1794                 &MainWindow::updateMagnificationButtons);
1795         connect(n, &GenericViewer::reparent, this, &MainWindow::reparentViewer);
1796         connect(n, &GenericViewer::goNext, this, &MainWindow::showNextViewer);
1797         connect(n, &GenericViewer::goPrevious, this,
1798                 &MainWindow::showPreviousViewer);
1799         connect(n, &GenericViewer::syncViewers, this,
1800                 &MainWindow::setSyncViewers);
1801 
1802         if (num_ldr_generated == 1)
1803             m_tabwidget->addTab(n, tr("Untitled"));
1804         else
1805             m_tabwidget->addTab(n, tr("Untitled %1").arg(num_ldr_generated));
1806 
1807         n->setViewerMode(getCurrentViewerMode(*m_tabwidget));
1808     }
1809     m_tabwidget->setCurrentWidget(n);
1810 
1811     m_PreviewPanel->setEnabled(true);
1812 
1813     if (m_Ui->actionSoft_Proofing->isChecked()) {
1814         LdrViewer *viewer = static_cast<LdrViewer *>(n);
1815         viewer->doSoftProofing(false);
1816     } else if (m_Ui->actionGamut_Check->isChecked()) {
1817         LdrViewer *viewer = static_cast<LdrViewer *>(n);
1818         viewer->doSoftProofing(true);
1819     }
1820 }
1821 
tonemapFailed(const QString & error_msg)1822 void MainWindow::tonemapFailed(const QString &error_msg) {
1823     if (error_msg != QLatin1String("Canceled")) {
1824         QMessageBox::critical(this, tr("Luminance HDR"),
1825                               tr("Error: %1").arg(error_msg), QMessageBox::Ok,
1826                               QMessageBox::NoButton);
1827     }
1828     m_tonemapPanel->setEnabled(true);
1829     m_PreviewPanel->setEnabled(true);
1830     m_TMProgressBar->hide();
1831 }
1832 
1833 /*
1834  * Lock Handling
1835  */
on_actionLock_toggled(bool)1836 void MainWindow::on_actionLock_toggled(bool /*toggled*/) {
1837     if (m_Ui->actionLock->isChecked() && m_tabwidget->count()) {
1838         syncViewers(qobject_cast<GenericViewer *>(m_tabwidget->currentWidget()));
1839     }
1840 }
1841 
syncViewers(GenericViewer * sender)1842 void MainWindow::syncViewers(GenericViewer *sender) {
1843     if (sender == nullptr) return;
1844     if (!m_Ui->actionLock->isChecked()) return;
1845 
1846     for (int idx = 0; idx < m_tabwidget->count(); idx++) {
1847         GenericViewer *viewer = qobject_cast<GenericViewer *>(m_tabwidget->widget(idx));
1848         if (viewer == nullptr)
1849             return;  // this happens when a tab is removed and sync viewers is
1850                      // active,
1851                      // fixes a crash
1852         if (sender != viewer) {
1853             viewer->blockSignals(true);
1854             viewer->syncViewer(sender);
1855             viewer->blockSignals(false);
1856         }
1857     }
1858 }
1859 
showPreviewPanel(bool b)1860 void MainWindow::showPreviewPanel(bool b) {
1861     m_Ui->actionRealtimePreviews->setEnabled(b);
1862     m_tonemapPanel->setRealtimePreviews(b && LuminanceOptions().isRealtimePreviewsActive());
1863     if (b) {
1864         if (tm_status.is_hdr_ready) {
1865             m_PreviewscrollArea->show();
1866             // ask panel to refresh itself
1867             m_PreviewPanel->setAutolevels(
1868                 m_tonemapPanel->doAutoLevels(),
1869                 m_tonemapPanel->getAutoLevelsThreshold());
1870             m_PreviewPanel->updatePreviews(tm_status.curr_tm_frame->getFrame());
1871 
1872             // connect signals
1873             connect(this, SIGNAL(updatedHDR(pfs::Frame *)), m_PreviewPanel,
1874                     SLOT(updatePreviews(pfs::Frame *)));
1875             connect(m_PreviewPanel, &PreviewPanel::startTonemapping, this,
1876                     &MainWindow::tonemapImage);
1877             connect(m_PreviewPanel, &PreviewPanel::startTonemapping,
1878                     m_tonemapPanel, &TonemappingPanel::updateTonemappingParams);
1879             connect(m_tonemapPanel, SIGNAL(autoLevels(bool, float)), this,
1880                     SLOT(updatePreviews(bool, float)));
1881         }
1882     } else {
1883         m_PreviewscrollArea->hide();
1884 
1885         // disconnect signals
1886         disconnect(this, SIGNAL(updatedHDR(pfs::Frame *)), m_PreviewPanel,
1887                    SLOT(updatePreviews(pfs::Frame *)));
1888         disconnect(m_PreviewPanel, &PreviewPanel::startTonemapping, this,
1889                    &MainWindow::tonemapImage);
1890         disconnect(m_PreviewPanel, &PreviewPanel::startTonemapping,
1891                    m_tonemapPanel, &TonemappingPanel::updateTonemappingParams);
1892         disconnect(m_tonemapPanel, SIGNAL(autoLevels(bool, float)), this,
1893                    SLOT(updatePreviews(bool, float)));
1894     }
1895 }
1896 
updatePreviews(bool b,float th)1897 void MainWindow::updatePreviews(bool b, float th) {
1898     if (m_Ui->actionShowPreviewPanel->isChecked()) {
1899         if (tm_status.is_hdr_ready) {
1900             m_PreviewPanel->setAutolevels(b, th);
1901             // ask panel to refresh itself
1902             m_PreviewPanel->updatePreviews(tm_status.curr_tm_frame->getFrame());
1903         }
1904     }
1905 }
1906 
updateMagnificationButtons(GenericViewer * c_v)1907 void MainWindow::updateMagnificationButtons(GenericViewer *c_v) {
1908     if (c_v == nullptr) return;
1909     bool isNormalSize = c_v->isNormalSize();
1910     bool isFilledToWindow = c_v->isFilledToWindow();
1911     bool isFittedToWindow = c_v->isFittedToWindow();
1912 
1913     m_Ui->zoomInAct->setChecked(isFilledToWindow || isFittedToWindow);
1914     m_Ui->zoomInAct->setEnabled(isFilledToWindow || isFittedToWindow);
1915     m_Ui->zoomOutAct->setChecked(isFittedToWindow);
1916     m_Ui->zoomOutAct->setEnabled(!isFittedToWindow);
1917 
1918     m_Ui->normalSizeAct->setChecked(isNormalSize);
1919     m_Ui->normalSizeAct->setEnabled(!isNormalSize);
1920     m_Ui->fitToWindowAct->setChecked(isFittedToWindow);
1921     m_Ui->fitToWindowAct->setEnabled(!isFittedToWindow);
1922     m_Ui->actionFill_to_Window->setChecked(isFilledToWindow);
1923     m_Ui->actionFill_to_Window->setEnabled(!isFilledToWindow);
1924 }
1925 
on_actionRemove_Tab_triggered()1926 void MainWindow::on_actionRemove_Tab_triggered() {
1927     removeTab(m_tabwidget->currentIndex());
1928 }
1929 
removeTab(int t)1930 void MainWindow::removeTab(int t) {
1931 #ifdef QT_DEBUG
1932     qDebug() << "MainWindow::remove_image(" << t << ")";
1933 #endif
1934     if (t < 0) return;
1935 
1936     GenericViewer *w = qobject_cast<GenericViewer *>(m_tabwidget->widget(t));
1937     w->blockSignals(true);
1938     if (w->isHDR()) {
1939         bool doClose = false;
1940 
1941 #ifdef QT_DEBUG
1942         qDebug() << "Remove HDR from MainWindow";
1943 #endif
1944         if (w->needsSaving()) {
1945             if (maybeSave()) {
1946                 // if discard OR saved
1947                 doClose = true;
1948             }
1949             // if FALSE, it means that the user said "Cancel"
1950             // or the saving operation went wrong
1951             // and we don't need to remove any tab
1952             else {
1953                 w->blockSignals(false);
1954             }
1955         } else
1956             doClose = true;
1957 
1958         if (doClose) {
1959             m_tabwidget->removeTab(t);
1960             w->deleteLater();  // delete yourself whenever you want
1961 
1962             showPreviewPanel(false);
1963             setWindowModified(false);
1964 
1965             tm_status.is_hdr_ready = false;
1966             tm_status.curr_tm_frame = nullptr;
1967             tm_status.curr_tm_options = nullptr;
1968 
1969             m_tonemapPanel->setEnabled(false);
1970 
1971             m_inputFilesName.clear();
1972             m_inputExpoTimes.clear();
1973 
1974             m_PreviewscrollArea->hide();
1975         }
1976     } else {
1977         curr_num_ldr_open--;
1978         m_tabwidget->removeTab(t);
1979         w->deleteLater();  // delete yourself whenever you want
1980 
1981         if (curr_num_ldr_open == 1) m_Ui->fileSaveAllAction->setEnabled(false);
1982     }
1983 }
1984 
getCurrentHDRName()1985 QString MainWindow::getCurrentHDRName() {
1986     if (tm_status.is_hdr_ready) {
1987         return tm_status.curr_tm_frame->getFileName();
1988     } else {
1989         return QString(tr("Untitled HDR"));
1990     }
1991 }
1992 
setMainWindowModified(bool b)1993 void MainWindow::setMainWindowModified(bool b) {
1994     if (b) {
1995         if (tm_status.is_hdr_ready) {
1996             tm_status.curr_tm_frame->setNeedsSaving(true);
1997             setWindowModified(true);
1998         }
1999     } else {
2000         if (tm_status.is_hdr_ready) {
2001             tm_status.curr_tm_frame->setNeedsSaving(false);
2002         }
2003         setWindowModified(false);
2004     }
2005 }
2006 
2007 /*
2008  * Recent File Handling
2009  */
setCurrentFile(const QString & fileName)2010 void MainWindow::setCurrentFile(const QString &fileName) {
2011     QStringList files =
2012         LuminanceOptions().value(KEY_RECENT_FILES).toStringList();
2013     files.removeAll(fileName);
2014     files.prepend(fileName);
2015     while (files.size() > MAX_RECENT_FILES) {
2016         files.removeLast();
2017     }
2018 
2019     LuminanceOptions().setValue(KEY_RECENT_FILES, files);
2020 
2021     // Update ALL MainWindow
2022     foreach (QWidget *widget, QApplication::topLevelWidgets()) {
2023         MainWindow *mainWin = qobject_cast<MainWindow *>(widget);
2024         if (mainWin) mainWin->updateRecentFileActions();
2025     }
2026 
2027     OsIntegration::getInstance().addRecentFile(fileName);
2028 }
2029 
updateRecentFileActions()2030 void MainWindow::updateRecentFileActions() {
2031     QStringList files =
2032         LuminanceOptions().value(KEY_RECENT_FILES).toStringList();
2033 
2034     int numRecentFiles = qMin(files.size(), (int)MAX_RECENT_FILES);
2035     separatorRecentFiles->setVisible(numRecentFiles > 0);
2036 
2037     for (int i = 0; i < numRecentFiles; ++i) {
2038         QString text = QStringLiteral("&%1 %2").arg(i + 1).arg(
2039             QFileInfo(files[i]).fileName());
2040         recentFileActs[i]->setText(text);
2041         recentFileActs[i]->setData(files[i]);
2042         recentFileActs[i]->setVisible(true);
2043     }
2044     for (int j = numRecentFiles; j < MAX_RECENT_FILES; ++j) {
2045         recentFileActs[j]->setVisible(false);
2046     }
2047 }
2048 
initRecentFileActions()2049 void MainWindow::initRecentFileActions() {
2050     separatorRecentFiles = m_Ui->menuFile->addSeparator();
2051 
2052     for (int i = 0; i < MAX_RECENT_FILES; ++i) {
2053         recentFileActs[i] = new QAction(this);
2054         recentFileActs[i]->setVisible(false);
2055         m_Ui->menuFile->addAction(recentFileActs[i]);
2056         connect(recentFileActs[i], &QAction::triggered, this,
2057                 &MainWindow::openRecentFile);
2058     }
2059 }
2060 
clearRecentFileActions()2061 void MainWindow::clearRecentFileActions() {
2062     for (int i = 0; i < MAX_RECENT_FILES; ++i) {
2063         delete recentFileActs[i];
2064     }
2065 }
2066 
on_actionFix_Histogram_toggled(bool checked)2067 void MainWindow::on_actionFix_Histogram_toggled(bool checked) {
2068     if (checked) {
2069         GenericViewer *current = qobject_cast<GenericViewer *>(m_tabwidget->currentWidget());
2070         if (current == nullptr) return;
2071         if (current->isHDR()) return;
2072 
2073         QScopedPointer<GammaAndLevels> g_n_l(
2074             new GammaAndLevels(this, current->getQImage()));
2075 
2076         m_Ui->actionFix_Histogram->setDisabled(true);
2077 
2078         connect(g_n_l.data(), SIGNAL(updateQImage(QImage)), current,
2079                 SLOT(setQImage(QImage)));
2080         int exit_status = g_n_l->exec();
2081 
2082         if (exit_status == 1) {
2083 #ifdef QT_DEBUG
2084             qDebug() << "GammaAndLevels accepted!";
2085 #endif
2086             // pfs::Frame * frame = current->getFrame();
2087             pfs::gammaAndLevels(
2088                 current->getFrame(), g_n_l->getBlackPointInput(),
2089                 g_n_l->getWhitePointInput(), g_n_l->getBlackPointOutput(),
2090                 g_n_l->getWhitePointOutput(), g_n_l->getGamma());
2091 
2092             // current->setFrame(frame);
2093         } else {
2094 #ifdef QT_DEBUG
2095             qDebug() << "GammaAndLevels refused!";
2096 #endif
2097             current->setQImage(g_n_l->getReferenceQImage());
2098         }
2099 
2100         m_Ui->actionFix_Histogram->setDisabled(false);
2101         m_Ui->actionFix_Histogram->setChecked(false);
2102     }
2103 }
2104 
2105 
on_actionWhite_Balance_triggered()2106 void MainWindow::on_actionWhite_Balance_triggered() {
2107     QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
2108     m_Ui->actionWhite_Balance->setEnabled(false);
2109     m_processingAWB = true;
2110     m_viewerToProcess = qobject_cast<GenericViewer *>(m_tabwidget->currentWidget());
2111     m_tabwidget->setTabEnabled(m_tabwidget->currentIndex(), false);
2112 
2113     Frame *frame = m_viewerToProcess->getFrame();
2114 
2115     m_futureWatcher.setFuture(QtConcurrent::run(
2116         boost::bind(whiteBalance, boost::ref(*frame), WB_COLORBALANCE)));
2117 }
2118 
whiteBalanceDone()2119 void MainWindow::whiteBalanceDone() {
2120     QApplication::restoreOverrideCursor();
2121     m_processingAWB = false;
2122     m_Ui->actionWhite_Balance->setEnabled(true);
2123     m_viewerToProcess->setEnabled(true);
2124     m_tabwidget->setTabEnabled(m_tabwidget->indexOf(m_viewerToProcess), true);
2125     m_tabwidget->setCurrentWidget(m_viewerToProcess);
2126     m_viewerToProcess->updatePixmap();
2127     if (m_viewerToProcess->isHDR()) {
2128         m_viewerToProcess->setNeedsSaving(true);
2129         m_PreviewPanel->updatePreviews(tm_status.curr_tm_frame->getFrame());
2130     }
2131 }
2132 
on_actionSoft_Proofing_toggled(bool doProof)2133 void MainWindow::on_actionSoft_Proofing_toggled(bool doProof) {
2134     GenericViewer *current = qobject_cast<GenericViewer *>(m_tabwidget->currentWidget());
2135     if (current == nullptr) return;
2136     if (current->isHDR()) return;
2137     LdrViewer *viewer = static_cast<LdrViewer *>(current);
2138     if (doProof) {
2139 #ifdef QT_DEBUG
2140         qDebug() << "MainWindow:: do soft proofing";
2141 #endif
2142         if (m_Ui->actionGamut_Check->isChecked())
2143             m_Ui->actionGamut_Check->setChecked(false);
2144         viewer->doSoftProofing(false);
2145     } else {
2146 #ifdef QT_DEBUG
2147         qDebug() << "MainWindow:: undo soft proofing";
2148 #endif
2149         viewer->undoSoftProofing();
2150     }
2151 }
2152 
on_actionGamut_Check_toggled(bool doGamut)2153 void MainWindow::on_actionGamut_Check_toggled(bool doGamut) {
2154     GenericViewer *current = qobject_cast<GenericViewer *>(m_tabwidget->currentWidget());
2155     if (current == nullptr) return;
2156     if (current->isHDR()) return;
2157     LdrViewer *viewer = static_cast<LdrViewer *>(current);
2158     if (doGamut) {
2159 #ifdef QT_DEBUG
2160         qDebug() << "MainWindow:: do gamut check";
2161 #endif
2162         if (m_Ui->actionSoft_Proofing->isChecked())
2163             m_Ui->actionSoft_Proofing->setChecked(false);
2164         viewer->doSoftProofing(true);
2165     } else {
2166 #ifdef QT_DEBUG
2167         qDebug() << "MainWindow:: undo gamut check";
2168 #endif
2169         viewer->undoSoftProofing();
2170     }
2171 }
2172 
updateSoftProofing(int i)2173 void MainWindow::updateSoftProofing(int i) {
2174     QWidget *wgt = m_tabwidget->widget(i);
2175     GenericViewer *g_v = qobject_cast<GenericViewer *>(wgt);
2176 
2177     if (g_v == nullptr) return;
2178     if (!g_v->isHDR()) {
2179         LdrViewer *l_v = static_cast<LdrViewer *>(g_v);
2180         if (!m_Ui->actionSoft_Proofing->isChecked() &&
2181             !m_Ui->actionGamut_Check->isChecked()) {
2182             l_v->undoSoftProofing();
2183         } else if (m_Ui->actionSoft_Proofing->isChecked()) {
2184             l_v->doSoftProofing(false);
2185         } else if (m_Ui->actionGamut_Check->isChecked()) {
2186             l_v->doSoftProofing(true);
2187         }
2188     }
2189 }
2190 
showPreviewsOnTheRight()2191 void MainWindow::showPreviewsOnTheRight() {
2192     m_PreviewscrollArea->setParent(m_centralwidget_splitter);
2193     LuminanceOptions().setPreviewPanelMode(0);
2194 }
2195 
showPreviewsOnTheBottom()2196 void MainWindow::showPreviewsOnTheBottom() {
2197     m_PreviewscrollArea->setParent(m_bottom_splitter);
2198     LuminanceOptions().setPreviewPanelMode(1);
2199 }
2200 
on_actionFits_Importer_triggered()2201 void MainWindow::on_actionFits_Importer_triggered() {
2202 #ifdef HAVE_CFITSIO
2203     FitsImporter importer;
2204 
2205     if (importer.exec() == QDialog::Accepted) {
2206         emit load_success(importer.getFrame(), tr("FITS Image"), importer.getFilenames(), true);
2207     }
2208 #endif
2209 }
2210 
on_actionShow_Full_Screen_toggled(bool b)2211 void MainWindow::on_actionShow_Full_Screen_toggled(bool b) {
2212     b ? this->showFullScreen() : this->showMaximized();
2213 }
2214 
on_actionShow_Image_Full_Screen_triggered()2215 void MainWindow::on_actionShow_Image_Full_Screen_triggered() {
2216     if (m_isFullscreenViewer) {
2217         return;
2218     }
2219     m_isFullscreenViewer = true;
2220     m_fullscreenViewerIndex = m_tabwidget->currentIndex();
2221     m_tabText = m_tabwidget->tabText(m_fullscreenViewerIndex);
2222     m_g_v_fullscreen = qobject_cast<GenericViewer *>(m_tabwidget->currentWidget());
2223     m_g_v_fullscreen->setParent(0);
2224     m_g_v_fullscreen->showFullScreen();
2225 }
2226 
reparentViewer(GenericViewer * g_v,bool close)2227 void MainWindow::reparentViewer(GenericViewer *g_v, bool close) {
2228     m_tabwidget->insertTab(m_fullscreenViewerIndex, g_v, m_tabText);
2229     m_tabwidget->setCurrentIndex(m_fullscreenViewerIndex);
2230     g_v->showNormal();
2231     m_isFullscreenViewer = false;
2232     if (close) {
2233         on_actionRemove_Tab_triggered();
2234     }
2235 }
2236 
showNextViewer(GenericViewer * g_v)2237 void MainWindow::showNextViewer(GenericViewer *g_v) {
2238     int count = m_tabwidget->count();
2239     if (count >= 1) {
2240         reparentViewer(g_v);
2241         int idx = m_tabwidget->currentIndex();
2242         int next = (idx + 1) % (count + 1);
2243         m_tabwidget->setCurrentIndex(next);
2244         on_actionShow_Image_Full_Screen_triggered();
2245     }
2246 }
2247 
showPreviousViewer(GenericViewer * g_v)2248 void MainWindow::showPreviousViewer(GenericViewer *g_v) {
2249     int count = m_tabwidget->count();
2250     if (count >= 1) {
2251         reparentViewer(g_v);
2252         int idx = m_tabwidget->currentIndex();
2253         int previous;
2254         if (idx == 0) {
2255             previous = count;
2256         } else {
2257             previous = (idx - 1) % (count + 1);
2258         }
2259         m_tabwidget->setCurrentIndex(previous);
2260         on_actionShow_Image_Full_Screen_triggered();
2261     }
2262 }
2263 
setSyncViewers(GenericViewer * g_v)2264 void MainWindow::setSyncViewers(GenericViewer *g_v) {
2265     if (g_v == nullptr) return;
2266     m_Ui->actionLock->setChecked(!m_Ui->actionLock->isChecked());
2267     if (m_Ui->actionLock->isChecked() && (m_tabwidget->count() - 1)) {
2268         syncViewers(g_v);
2269     }
2270 }
2271 
on_actionSelect_Interpolation_Method_toggled(bool b)2272 void MainWindow::on_actionSelect_Interpolation_Method_toggled(bool b) {
2273     m_interpolationMethod = b ? LanczosInterp : BilinearInterp;
2274 }
2275 
on_actionOnline_Documentation_triggered()2276 void MainWindow::on_actionOnline_Documentation_triggered() {
2277     QDesktopServices::openUrl(
2278         QUrl(QStringLiteral("http://luminancehdr.readthedocs.io/en/latest/")));
2279 }
2280 
on_actionDevelopers_Website_triggered()2281 void MainWindow::on_actionDevelopers_Website_triggered() {
2282     QDesktopServices::openUrl(
2283         QUrl(QStringLiteral("https://github.com/LuminanceHDR/")));
2284 }
2285 
on_actionLuminance_HDR_Website_triggered()2286 void MainWindow::on_actionLuminance_HDR_Website_triggered() {
2287     QDesktopServices::openUrl(
2288         QUrl(QStringLiteral("http://qtpfsgui.sourceforge.net/")));
2289 }
2290 
setRealtimePreviewsActive(bool b)2291 void MainWindow::setRealtimePreviewsActive(bool b) {
2292     LuminanceOptions().setRealtimePreviewsActive(b);
2293 }
2294 
setPreviewPanelActive(bool b)2295 void MainWindow::setPreviewPanelActive(bool b) {
2296     LuminanceOptions().setPreviewPanelActive(b);
2297 }
2298