AstRawDark
Manage your astrophoto dark frames
 All Classes Functions Variables Enumerations Enumerator Pages
mainWindow.cpp
1 /*
2  * AstRawDark
3  *
4  * Copyright (C) 2015 - Frédéric CORNU
5  *
6  * This program is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program. If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include "mainWindow.h"
21 #include "prefDialog.h"
22 #include "ui_mainWindow.h"
23 #include "globals.h"
24 #include "data/dataStore.h"
25 #include "aboutDialog.h"
26 #include "commands/signalDispatcher.h"
27 #include "commandReportDisplay.h"
28 
29 #ifndef QT_NO_DEBUG
30 #include <QDebug>
31 #endif
32 
33 MainWindow::MainWindow(QWidget *parent)
34 : QMainWindow(parent),
35  LBL_DARKCOUNT_BASETEXT(tr("Displayed darks count")),
36  LBL_LIGHTSCOUNT_BASETEXT(tr("Displayed lights count : %1")),
37  ui(new Ui::MainWindow),
38  _dataStore(DataStore::getInstance())
39 
40 {
41  ui->setupUi(this);
42 
43  _plotManager = new PlotManager(ui->pltDarkTempPlot,
44  ui->pltDarkTempDistriPlot,
45  ui->pltLightsTempPlot,
46  ui->pltLightsTempDistriPlot,
47  this);
48 
49  setWindowTitle(Globals::APPLICATION_NAME);
50 
51  ui->tblDarkView->setModel(_dataStore->getDarkModel());
52  QHeaderView* darkHv = ui->tblDarkView->horizontalHeader();
53  darkHv->setSectionResizeMode(0, QHeaderView::Stretch);
54  darkHv->setSectionResizeMode(1, QHeaderView::ResizeToContents);
55  darkHv->setSectionResizeMode(2, QHeaderView::ResizeToContents);
56  darkHv->setSectionResizeMode(3, QHeaderView::ResizeToContents);
57  darkHv->setSectionResizeMode(4, QHeaderView::ResizeToContents);
58  darkHv->setSectionResizeMode(5, QHeaderView::ResizeToContents);
59  QHeaderView* darkVv = ui->tblDarkView->verticalHeader();
60  darkVv->hide();
61 
62  ui->tblLightsList->setModel(_dataStore->getLightsModel());
63  QHeaderView* lightHv = ui->tblLightsList->horizontalHeader();
64  lightHv->setSectionResizeMode(0, QHeaderView::Stretch);
65  lightHv->setSectionResizeMode(1, QHeaderView::ResizeToContents);
66  lightHv->setSectionResizeMode(2, QHeaderView::ResizeToContents);
67  lightHv->setSectionResizeMode(3, QHeaderView::ResizeToContents);
68  lightHv->setSectionResizeMode(4, QHeaderView::ResizeToContents);
69  lightHv->setSectionResizeMode(5, QHeaderView::ResizeToContents);
70  QHeaderView* lightVv = ui->tblLightsList->verticalHeader();
71  lightVv->hide();
72 
73  ui->tblCommandView->setModel(_dataStore->getCommandListModel());
74  QHeaderView* commandHv = ui->tblCommandView->horizontalHeader();
75  commandHv->setSectionResizeMode(0, QHeaderView::ResizeToContents);
76  commandHv->setSectionResizeMode(1, QHeaderView::ResizeToContents);
77  commandHv->setSectionResizeMode(2, QHeaderView::ResizeToContents);
78  commandHv->setSectionResizeMode(3, QHeaderView::ResizeToContents);
79  commandHv->setSectionResizeMode(4, QHeaderView::ResizeToContents);
80  commandHv->setSectionResizeMode(5, QHeaderView::ResizeToContents);
81  commandHv->setSectionResizeMode(6, QHeaderView::Stretch);
82  QHeaderView* commandVv = ui->tblCommandView->verticalHeader();
83  commandVv->setSectionResizeMode(QHeaderView::ResizeToContents);
84  commandVv->hide();
85 
86  ui->treeDarkView->setModel(_dataStore->getDarkTreeModel());
87  QHeaderView* darkTreeHv = ui->treeDarkView->header();
88  darkTreeHv->setSectionResizeMode(0, QHeaderView::Stretch);
89  darkTreeHv->hide();
90 
91  ui->btnRescanDarks->setEnabled( !_dataStore->getDarkSources().empty() );
92  ui->actionRescanDarksLibrary->setEnabled( !_dataStore->getDarkSources().empty() );
93 
96  this,
97  &MainWindow::on_darkSourcesChanged);
98 
101  this,
102  &MainWindow::on_darkScanStart);
103 
106  this,
107  &MainWindow::on_darkScanDone);
108 
109  connect(this,
113 
114  connect(this,
118 
121  this,
122  &MainWindow::on_darkListModelChanged);
123 
126  this,
127  &MainWindow::on_lightsScanStart);
128 
131  this,
132  &MainWindow::on_lightsScanDone);
133 
134  connect(this,
138 
139  connect(this,
143 
146  this,
147  &MainWindow::on_consistencyResult);
148 
151  this,
152  &MainWindow::on_commandCreated);
153 
154  connect(this,
158 
159  connect(this,
163 
166  this,
167  &MainWindow::on_bestMatchCount);
168 
171  this,
172  &MainWindow::on_matchFound);
173 
176  this,
177  &MainWindow::on_commandStatusChange);
178 
179  _commandManager = new CommandManager(this);
180 
181  ui->tabDarkDetailsWidget->setCurrentIndex(0);
182  ui->tabMainWidget->setCurrentIndex(0);
183  ui->tabLightsDetailsWidget->setCurrentIndex(0);
184 
185  if ( 0 == _dataStore->getDarkSources().count() ) {
186 
187  #ifndef QT_NO_DEBUG
188  qDebug() << "No dark sources set yet";
189  #endif
190 
191  QMessageBox messageBox(QMessageBox::Question,
192  tr("AstRawDark : No dark sources set"),
193  QString("<h3>")
194  .append(tr("Your darks library sources are not configured"))
195  .append("</h3>")
196  .append(tr("Would you like to review your darks library settings ?")),
197  QMessageBox::Yes | QMessageBox::No,
198  this);
199 
200  messageBox.setButtonText(QMessageBox::Yes, tr("Yes"));
201  messageBox.setButtonText(QMessageBox::No, tr("No"));
202 
203  if ( QMessageBox::Yes == messageBox.exec() ) {
204 
205  PrefDialog(this).exec();
206  }
207  }
208 
209  updateLightsContentCount();
210 }
211 
213 {
214  delete ui;
215 }
216 
217 void MainWindow::changeEvent(QEvent *e)
218 {
220  switch (e->type()) {
221  case QEvent::LanguageChange:
222  ui->retranslateUi(this);
223  break;
224  default:
225  break;
226  }
227 }
228 
229 void MainWindow::on_actionQuit_triggered()
230 {
231  this->close();
232 }
233 
234 void MainWindow::on_btnRescanDarks_clicked()
235 {
236  emit scanDarkLibrary();
237 }
238 
239 void MainWindow::on_actionPrefs_triggered()
240 {
241  PrefDialog(this).exec();
242 }
243 
244 void MainWindow::on_actionCommandLog_toggled(bool checked)
245 {
246  ui->dckCommands->setVisible(checked);
247 }
248 
249 void MainWindow::on_actionAbout_triggered()
250 {
251  AboutDialog(this).exec();
252 }
253 
254 void MainWindow::on_tblCommandView_doubleClicked(const QModelIndex &index)
255 {
256  int commandSerial = index.model()->data(index.model()->index(index.row(), 0)).toInt() -1;
257 
258  const AbstractCommand* command = _commandManager->getCommand(commandSerial);
259 
260  CommandReportDisplay* d = new CommandReportDisplay(command);
261  d->show();
262 }
263 
264 void MainWindow::updateDarkContentCount()
265 {
266  QString darkContentTabText = LBL_DARKCOUNT_BASETEXT;
267  int darkLibrarySize = _dataStore->getDarkLibrarySize();
268  int darkModelSize = _dataStore->getDarkModel()->rowCount();
269 
270  if ( darkLibrarySize != darkModelSize ) {
271 
272  darkContentTabText.append(tr(" (Filtered)"));
273  }
274 
275  darkContentTabText.append(tr(" : %1 / %2").arg(darkModelSize).arg(darkLibrarySize));
276 
277  ui->lblDarkCount->setText(darkContentTabText);
278 }
279 
280 void MainWindow::updateLightsContentCount()
281 {
282  ui->lblLightsCount->setText(LBL_LIGHTSCOUNT_BASETEXT.arg(_dataStore->getLightsCount()));
283 }
284 
285 void MainWindow::on_treeDarkView_clicked(const QModelIndex &index)
286 {
287  ui->btnDarkFilterClear->setEnabled(true);
288 
289  QModelIndex targetNode;
290 
291  if ( index.column() != 0 ) {
292 
293  targetNode = index.sibling(index.row(), 0);
294 
295  } else {
296 
297  targetNode = index;
298  }
299 
300  _dataStore->setDarkDisplayFilter(targetNode.data(Qt::UserRole).toString());
301 }
302 
303 void MainWindow::on_btnDarkFilterClear_clicked()
304 {
305  ui->treeDarkView->clearSelection();
306  ui->btnDarkFilterClear->setDisabled(true);
307  _dataStore->setDarkDisplayFilter("");
308 }
309 
310 void MainWindow::on_darkListModelChanged()
311 {
312  updateDarkContentCount();
313  ui->tblDarkView->scrollToTop();
314 }
315 
316 void MainWindow::on_actionRescanDarksLibrary_triggered()
317 {
318  emit scanDarkLibrary();
319 }
320 
321 void MainWindow::on_btnChooseLightsFolder_clicked()
322 {
323  QString startFolder = ui->lineCurrentLightsFolderPath->text();
324 
325  if ( startFolder.isEmpty() || ! QDir(startFolder).exists() ) {
326 
327  startFolder = QDir::homePath();
328  }
329 
330  QString lightsFolder = QFileDialog::getExistingDirectory(this,
331  tr("Please select lights folder"),
332  startFolder,
333  QFileDialog::ShowDirsOnly);
334 
335  if ( ! lightsFolder.isEmpty() && lightsFolder != startFolder ) {
336 
337  ui->lineCurrentLightsFolderPath->setText(lightsFolder);
338  _dataStore->setLightsFolder(lightsFolder);
339 
340  emit scanLightsFolder();
341  }
342 
343 }
344 
345 void MainWindow::on_darkSourcesChanged(const QStringList& sources)
346 {
347  ui->btnRescanDarks->setEnabled( !sources.empty() );
348  ui->actionRescanDarksLibrary->setEnabled( !sources.empty() );
349 }
350 
351 void MainWindow::on_darkScanStart()
352 {
353  ui->lblDarkCount->setText(LBL_DARKCOUNT_BASETEXT + tr(" : Scan in progress..."));
354  ui->btnRescanDarks->setDisabled(true);
355  ui->btnDarkFilterClear->setDisabled(true);
356  ui->actionRescanDarksLibrary->setDisabled(true);
357 }
358 
359 void MainWindow::on_darkScanDone()
360 {
361 
362  ui->btnRescanDarks->setEnabled(true);
363  ui->actionRescanDarksLibrary->setEnabled(true);
364 }
365 
366 void MainWindow::on_lightsScanStart()
367 {
368  ui->lblLightsCount->setText(LBL_LIGHTSCOUNT_BASETEXT.arg("Scan in progress..."));
369  ui->btnChooseLightsFolder->setDisabled(true);
370  ui->btnRescanLights->setDisabled(true);
371  ui->btnLightsMatch->setDisabled(true);
372  ui->sldDarkMatchers->setDisabled(true);
373  ui->sldDarkMatchers->setValue(0);
374  ui->btnExportDarks->setDisabled(true);
375 }
376 
377 void MainWindow::on_lightsScanDone()
378 {
379  ui->btnChooseLightsFolder->setEnabled(true);
380  ui->btnRescanLights->setEnabled(true);
381 
382  updateLightsContentCount();
383  ui->tblLightsList->scrollToTop();
384 
385  if ( _dataStore->getLightsCount() > 0 ) {
386 
387  emit checkLights();
388  }
389 
390 }
391 
392 void MainWindow::on_consistencyResult(bool consistent)
393 {
394  if ( consistent ) {
395 
396  emit computeBestMatch();
397 
398  } else {
399 
400  QMessageBox::warning(this,
401  tr("Lights are not consistent"),
402  tr("These lights have not been shot with the same camera"
403  " or have different ISO settings and exposure times.")
404  .append("\n\n")
405  .append(tr("Temperature matching cannot be performed")));
406  }
407 }
408 
409 void MainWindow::createProgressBarForCommand(AbstractCommand *command)
410 {
411  QProgressBar* progBar = new QProgressBar(this);
412  progBar->setMinimum(0);
413  progBar->setMaximum(0);
414  progBar->setMinimumWidth(Globals::COMMAND_LOG_PROGRESS_WIDTH);
415 
416  connect(command,
418  progBar,
419  &QProgressBar::setValue);
420 
421  connect(command,
423  progBar,
424  &QProgressBar::setMaximum);
425 
426  #ifndef QT_NO_DEBUG
427  qDebug() << "Command" << command->getSerial() << "connected to its progressBar";
428  #endif
429 
430  QAbstractItemModel* model = ui->tblCommandView->model();
431  ui->tblCommandView->setIndexWidget(model->index(model->rowCount() - command->getSerial() -1, 4, QModelIndex()), progBar);
432 }
433 
434 void MainWindow::on_commandStatusChange(AbstractCommand* command) {
435 
436  // if command is complete, we force its progressBar to full 100%
437  if ( AbstractCommand::COMPLETE == command->getStatus() ) {
438 
439  QAbstractItemModel* model = ui->tblCommandView->model();
440  QProgressBar* pBar = static_cast<QProgressBar*>(
441  ui->tblCommandView->indexWidget(
442  model->index(model->rowCount() - command->getSerial() -1,
443  4,
444  QModelIndex())));
445 
446  pBar->setMaximum(1);
447  pBar->setValue(pBar->maximum());
448  }
449 }
450 
451 void MainWindow::on_commandCreated(AbstractCommand *command)
452 {
453  ui->tblCommandView->scrollToTop();
454 
455  createProgressBarForCommand(command);
456 }
457 
458 void MainWindow::on_btnRescanLights_clicked()
459 {
460  emit scanLightsFolder();
461 }
462 
463 void MainWindow::on_btnLightsMatch_clicked() {
464 
465  _dataStore->setNeededDarks4Matching(ui->sldDarkMatchers->value());
466  emit matchLights();
467 }
468 
469 void MainWindow::on_sldDarkMatchers_valueChanged(int value) {
470 
471  ui->btnLightsMatch->setEnabled(0 < value && _dataStore->getLightsCount() > 0 );
472  ui->btnExportDarks->setDisabled(true);
473 }
474 
475 void MainWindow::on_bestMatchCount(int bestMatch) {
476 
477  ui->sldDarkMatchers->setEnabled(true);
478  ui->sldDarkMatchers->setRange(0, bestMatch);
479  ui->sldDarkMatchers->setValue(bestMatch);
480  ui->btnExportDarks->setEnabled(true);
481 }
482 
483 void MainWindow::on_matchFound() {
484 
485  ui->btnExportDarks->setEnabled(true);
486 }
487 
488 
489 void MainWindow::on_btnExportDarks_clicked() {
490 
491 
492  QString darksCopyFolder = QFileDialog::getExistingDirectory(this,
493  tr("Please select matched darks copy destination folder"),
494  QDir::homePath(),
495  QFileDialog::ShowDirsOnly);
496 
497  if ( ! ( darksCopyFolder.isEmpty() || darksCopyFolder.isNull() ) ) {
498 
499  _dataStore->setDarkCopyFolderPath(darksCopyFolder);
500 
501  /*
502  * check if folder is empty
503  *
504  * We count all files in folder except for '.' & '..'
505  * If we see any other file, warn user
506  */
507  QDir destFolder(darksCopyFolder);
508  QStringList list = destFolder.entryList();
509 
510  int count = 0;
511 
512  foreach (QString entry, list)
513  {
514  if(entry != "." && entry != "..")
515  {
516  count++;
517  }
518  }
519 
520  if ( 0 == count ) {
521 
522  emit copyDarks();
523 
524  } else {
525 
526  QMessageBox::warning(this,
527  tr("Destination folder is not empty"),
528  tr("As we don't want to ever risk of erasing / damaging your astro shots, "
529  "an empty target folder is required.\n\n"
530  "Please choose an empty target folder."));
531  }
532  }
533 }