FotoBox
preferences.cpp
Go to the documentation of this file.
1 /* preferences.cpp
2  *
3  * Copyright (c) 2018 Thomas Kais
4  *
5  * This file is subject to the terms and conditions defined in
6  * file 'COPYING', which is part of this source code package.
7  */
8 #include "fotobox.h"
9 
10 #include "buzzer.h"
11 #include "preferenceprovider.h"
12 #include "preferences.h"
13 #include "ui_commandlineoptions.h"
14 #include "ui_preferences.h"
15 
16 #include <QColorDialog>
17 #include <QDesktopServices>
18 #include <QFileDialog>
19 #include <QMessageBox>
20 #include <QPrinterInfo>
21 #include <QProcess>
22 #include <QScreen>
23 #include <QStandardPaths>
24 
25 namespace FotoBox {
26 
27 Preferences::Preferences(QWidget *parent)
28  : QDialog(parent, Qt::Window)
29  , m_ui(new Ui::PreferencesDialog)
30  , m_settings(QSettings::IniFormat, QSettings::UserScope, QCoreApplication::applicationName(), QCoreApplication::applicationName(), this)
31  , m_countdown(this, COUNTDOWN_START_VALUE)
32 {
33  //setup UI
34  m_ui->setupUi(this);
35 
36  //set icons for QToolButtons
38 
39  //set window position
41 
42  //delete everything on close
43  setAttribute(Qt::WA_DeleteOnClose);
44 
45  //DON'T CHANGE ORDER!
46  //Signal & Slot
47  connectUi();
48  //restore default values
50  //load settings from ini file
52 
53  //auto accept Dialog
54  connect(&m_countdown, &Countdown::elapsed, this, [&]() {
55  //start FotoBox
56  startFotoBox();
57  });
59 
60  //update window title
61  connect(&m_countdown, &Countdown::update, this, [&](unsigned int i_timeLeft) {
62  //: %1 FotoBox %2 application version %3 countdown (number)
63  setWindowTitle(tr("launching %1 v%2 in %3 seconds").arg(QApplication::applicationName(), QApplication::applicationVersion()).arg(i_timeLeft));
64  });
65 
66  //check if pigpio deamon is reachable
67  pigpioDeamon();
68 }
69 
71 {
72  delete m_ui;
73 }
74 
76 {
77  const auto availableGeometry = QGuiApplication::primaryScreen()->availableGeometry();
78  if (frameGeometry().height() > availableGeometry.height()) {
79  //start maximized to be able to reach the dialog buttons
80  showMaximized();
81  } else {
82  //enough space, center dialog
83  setGeometry(QStyle::alignedRect(Qt::LeftToRight, Qt::AlignCenter, size(), availableGeometry));
84  }
85 }
86 
88 {
89  if (Buzzer::checkDeamon()) {
90  m_ui->lblPigpioDeamon->setText(tr("'pigpio' deamon is reachable"));
91  } else {
92  m_ui->lblPigpioDeamon->setStyleSheet(QStringLiteral("QLabel { color : red; }"));
93  m_ui->lblPigpioDeamon->setText(tr("'pigpio' deamon is unreachable"));
94  }
95 }
96 
98 {
99  //stop countdown if the application isn't visible and selected to be in front.
100  connect(qobject_cast<QApplication*>(QCoreApplication::instance()), &QGuiApplication::applicationStateChanged, this, [&](const Qt::ApplicationState state) {
101  if (state != Qt::ApplicationActive) {
103  }
104  });
105 
106  //connect UI to preferences
107  connect(m_ui->txtPhotoFolder, &QLineEdit::textChanged, &PreferenceProvider::instance(), &PreferenceProvider::setPhotoFolder);
108  connect(m_ui->txtPhotoFolder, &QLineEdit::textChanged, this, &Preferences::verifyPath);
109  connect(m_ui->btnChooseDirectory, &QPushButton::clicked, this, &Preferences::chooseDirectory);
110  connect(m_ui->btnClearDirectoryContent, &QPushButton::clicked, this, &Preferences::clearDirectoryContent);
111  connect(m_ui->txtPhotoName, &QLineEdit::textChanged, &PreferenceProvider::instance(), &PreferenceProvider::setPhotoName);
112  connect(m_ui->spbCountdown, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), &PreferenceProvider::instance(), &PreferenceProvider::setCountdown);
113  connect(m_ui->btnChooseColorCD, &QPushButton::clicked, this, &Preferences::colorDialog);
114  connect(m_ui->txtShowColorCD, &QLineEdit::textChanged, &PreferenceProvider::instance(), &PreferenceProvider::setCountdownColor);
115  connect(m_ui->txtShowColorCD, &QLineEdit::textChanged, m_ui->txtShowColorCD, &QLineEdit::setToolTip);
116  connect(m_ui->txtShowColorCD, &QLineEdit::textChanged, this, &Preferences::showColor);
117  connect(m_ui->chbButtons, &QAbstractButton::toggled, &PreferenceProvider::instance(), &PreferenceProvider::setShowButtons);
118  connect(m_ui->btnChooseColorBG, &QPushButton::clicked, this, &Preferences::colorDialog);
119  connect(m_ui->txtShowColorBG, &QLineEdit::textChanged, &PreferenceProvider::instance(), &PreferenceProvider::setBackgroundColor);
120  connect(m_ui->txtShowColorBG, &QLineEdit::textChanged, m_ui->txtShowColorBG, &QLineEdit::setToolTip);
121  connect(m_ui->txtShowColorBG, &QLineEdit::textChanged, this, &Preferences::showColor);
122  connect(m_ui->spbInputPin, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), &PreferenceProvider::instance(), &PreferenceProvider::setInputPin);
123  connect(m_ui->spbOutputPin, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), &PreferenceProvider::instance(), &PreferenceProvider::setOutputPin);
124  connect(m_ui->spbQueryInterval, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), &PreferenceProvider::instance(), &PreferenceProvider::setQueryInterval);
125  connect(m_ui->cmbCameraMode, &QComboBox::currentTextChanged, &PreferenceProvider::instance(), &PreferenceProvider::setCameraMode);
126  connect(m_ui->cmbCameraMode, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, [&]() {
127  //QComboBox has changed, show stored data to QLineEdit
128  m_ui->txtArgumentLine->setText(m_ui->cmbCameraMode->currentData().toString());
129  });
130  connect(m_ui->cmbCameraMode, &QComboBox::currentTextChanged, this, &Preferences::verifyApplication);
131  connect(m_ui->btnCameraModeReload, &QAbstractButton::clicked, this, [&]() {
132  verifyApplication(m_ui->cmbCameraMode->currentText());
133  });
134  connect(m_ui->txtArgumentLine, &QLineEdit::textChanged, &PreferenceProvider::instance(), &PreferenceProvider::setArgumentLine);
135  connect(m_ui->txtArgumentLine, &QLineEdit::textChanged, this, [&](const QString &i_value) {
136  //save changed text in QComboBox model
137  m_ui->cmbCameraMode->setItemData(m_ui->cmbCameraMode->currentIndex(), i_value);
138  });
139  connect(m_ui->btnArgumentLineHelp, &QAbstractButton::clicked, this, &Preferences::commandLineOptionsDialog);
140  connect(m_ui->spbTimout, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), &PreferenceProvider::instance(), &PreferenceProvider::setTimeoutValue);
141  connect(m_ui->chbGrayscale, &QAbstractButton::toggled, &PreferenceProvider::instance(), &PreferenceProvider::setGrayscale);
142  connect(m_ui->chbPrint, &QAbstractButton::toggled, &PreferenceProvider::instance(), &PreferenceProvider::setPrint);
143  connect(m_ui->cmbPrinterName, &QComboBox::currentTextChanged, &PreferenceProvider::instance(), &PreferenceProvider::setPrinterName);
144 
145  //connect buttons
146  connect(m_ui->buttonBox, &QDialogButtonBox::accepted, this, &Preferences::startFotoBox);
147  connect(m_ui->buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
148  connect(m_ui->buttonBox, &QDialogButtonBox::clicked, this, [&](QAbstractButton *button) {
149  //identify restore button, restore defaults and save it
150  if (button == m_ui->buttonBox->button(QDialogButtonBox::RestoreDefaults)) {
151  restoreDefaultPreferences();
152  m_settings.sync();
153  }
154  });
155  connect(m_ui->buttonBox, &QDialogButtonBox::helpRequested, this, [&]() {
156  //request OS to open the URL
157  QDesktopServices::openUrl( { QStringLiteral("https://gitlab.com/tomikais/fotobox/blob/master/README.md") } );
158  });
159 }
160 
161 void Preferences::setButtonIcons()
162 {
163  //picture of all Qt standard icons: https://joekuan.files.wordpress.com/2015/09/screen3.png
164  m_ui->btnChooseDirectory->setIcon(style()->standardIcon(QStyle::SP_DirOpenIcon));
165  m_ui->btnClearDirectoryContent->setIcon(style()->standardIcon(QStyle::SP_DialogDiscardButton));
166  m_ui->btnCameraModeReload->setIcon(style()->standardIcon(QStyle::SP_BrowserReload));
167  m_ui->btnArgumentLineHelp->setIcon(style()->standardIcon(QStyle::SP_TitleBarContextHelpButton));
168 }
169 
170 void Preferences::startFotoBox()
171 {
172  //save settings to ini file
173  m_countdown.stop();
174  savePreferences();
175 
176  //Start FotoBox;
177  auto *dialog = new FotoBox;
178 
179  //close dialog and start fotobox
180  reject();
181  dialog->showFullScreen();
182 }
183 
184 void Preferences::mouseMoveEvent(QMouseEvent *event)
185 {
186  stopCountdownMode();
187 
188  //call base class method
189  QWidget::mouseMoveEvent(event);
190 }
191 
192 void Preferences::stopCountdownMode()
193 {
194  if (m_countdown.isActive()) {
195  //stop countdown
196  m_countdown.stop();
197 
198  //disable mouse tracking (not needed anymore)
199  setMouseTracking(false);
200  m_ui->scrollArea->setMouseTracking(false);
201  m_ui->scrollAreaWidgetContents->setMouseTracking(false);
202  m_ui->tabWidget->setMouseTracking(false);
203  m_ui->tabGeneral->setMouseTracking(false);
204  m_ui->tabExpert->setMouseTracking(false);
205  m_ui->buttonBox->setMouseTracking(false);
206 
207  //set normal window title
208  setWindowTitle(QStringLiteral("%1 v%2 (Copyright 2016 %3) - ").arg(QApplication::applicationName(), QApplication::applicationVersion(), QApplication::organizationName()) + tr("preferences"));
209  }
210 }
211 
212 void Preferences::loadPreferences()
213 {
214  m_settings.beginGroup(QStringLiteral("FotoBox"));
215  m_ui->txtPhotoFolder->setText(m_settings.value(m_ui->txtPhotoFolder->objectName(), m_ui->txtPhotoFolder->text()).toString());
216  m_ui->txtPhotoName->setText(m_settings.value(m_ui->txtPhotoName->objectName(), m_ui->txtPhotoName->text()).toString());
217  m_ui->spbCountdown->setValue(m_settings.value(m_ui->spbCountdown->objectName(), m_ui->spbCountdown->value()).toInt());
218  m_ui->txtShowColorCD->setText(m_settings.value(m_ui->txtShowColorCD->objectName(), m_ui->txtShowColorCD->text()).toString());
219  m_ui->chbButtons->setChecked(m_settings.value(m_ui->chbButtons->objectName(), m_ui->chbButtons->isChecked()).toBool());
220  m_ui->txtShowColorBG->setText(m_settings.value(m_ui->txtShowColorBG->objectName(), m_ui->txtShowColorBG->text()).toString());
221  m_settings.endGroup();
222 
223  m_settings.beginGroup(QStringLiteral("Buzzer"));
224  m_ui->spbInputPin->setValue(m_settings.value(m_ui->spbInputPin->objectName(), m_ui->spbInputPin->value()).toInt());
225  m_ui->spbOutputPin->setValue(m_settings.value(m_ui->spbOutputPin->objectName(), m_ui->spbOutputPin->value()).toInt());
226  m_ui->spbQueryInterval->setValue(m_settings.value(m_ui->spbQueryInterval->objectName(), m_ui->spbQueryInterval->value()).toInt());
227  m_settings.endGroup();
228 
229  m_settings.beginGroup(QStringLiteral("Camera"));
230  //restore QComboBox model
231  const auto data = m_settings.value(m_ui->cmbCameraMode->objectName() + QStringLiteral("Data")).toStringList();
232  const auto text = m_settings.value(m_ui->cmbCameraMode->objectName() + QStringLiteral("Text")).toStringList();
233  if (!data.empty()) {
234  m_ui->cmbCameraMode->clear();
235  for (int i = 0; i < data.count(); ++i) {
236  m_ui->cmbCameraMode->addItem(text.at(i), data.at(i));
237  }
238  }
239  m_ui->cmbCameraMode->setCurrentText(m_settings.value(m_ui->cmbCameraMode->objectName(), m_ui->cmbCameraMode->currentText()).toString());
240 
241  m_ui->spbTimout->setValue(m_settings.value(m_ui->spbTimout->objectName(), m_ui->spbTimout->value()).toInt());
242  m_ui->chbGrayscale->setChecked(m_settings.value(m_ui->chbGrayscale->objectName(), m_ui->chbGrayscale->isChecked()).toBool());
243  m_settings.endGroup();
244 
245  m_settings.beginGroup(QStringLiteral("PrintSetup"));
246  m_ui->chbPrint->setChecked(m_settings.value(m_ui->chbPrint->objectName(), m_ui->chbPrint->isChecked()).toBool());
247  const auto &printerName = m_settings.value(m_ui->cmbPrinterName->objectName(), m_ui->cmbPrinterName->currentText()).toString();
248  const auto printer = m_ui->cmbPrinterName->findText(printerName);
249  if (printer >= 0) {
250  //printer still available so set it
251  m_ui->cmbPrinterName->setCurrentIndex(printer);
252  }
253  m_settings.endGroup();
254 }
255 
256 void Preferences::colorDialog()
257 {
258  //"Color Picker" Dialog
259  QColorDialog dialog(this);
260 
261  if (dialog.exec() == QDialog::Accepted) {
262  //show the color which the user has selected
263  const auto *button = qobject_cast<QToolButton *>(sender());
264  if (button == m_ui->btnChooseColorCD) {
265  //font countdown
266  m_ui->txtShowColorCD->setText(dialog.selectedColor().name());
267  }
268  if (button == m_ui->btnChooseColorBG) {
269  //background color
270  m_ui->txtShowColorBG->setText(dialog.selectedColor().name());
271  }
272  }
273 }
274 
275 void Preferences::commandLineOptionsDialog()
276 {
277  //'Qt::Tool' act like a window 'Qt::ToolTip' always on top
278  auto *dialog = new QDialog(this, Qt::SplashScreen);
279  Ui::CommandLineOptionsDialog ui;
280 
281  //setup UI
282  ui.setupUi(dialog);
283 
284  //blocking until the user closes it
285  dialog->exec();
286 }
287 
288 void Preferences::chooseDirectory()
289 {
290  //File Dialog to choose photo folder
291  QFileDialog dialog(this, tr("choose directory"), m_ui->txtPhotoFolder->text());
292  dialog.setFileMode(QFileDialog::Directory);
293  dialog.setOptions(QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
294 
295  //only set it if user don't abort dialog
296  if (dialog.exec() == QDialog::Accepted) {
297  const auto path = dialog.directory().absolutePath();
298  if (!verifyPath(path)) {
299  return;
300  }
301  //set path will again call verifyPath() see Signal&Slot connection
302  m_ui->txtPhotoFolder->setText(QDir::toNativeSeparators(path));
303  }
304 }
305 
306 void Preferences::clearDirectoryContent()
307 {
308  //get photo folder from preferences
309  const QString photoFolder(PreferenceProvider::instance().PreferenceProvider::photoFolder());
310 
311  //ask user
312  const auto &text = tr("Clear all JPEGs in the photo folder (leave subfolders untouched)?") + QStringLiteral("\n\"") + photoFolder + '\"';
313  const auto &result = QMessageBox::warning(this, tr("WARNING: clear directory content"), text, QMessageBox::Yes | QMessageBox::No);
314 
315  if (result == QMessageBox::Yes) {
316  //photo folder
317  QDir dir(photoFolder);
318 
319  //JPEG file extension https://en.wikipedia.org/wiki/JPEG
320  dir.setNameFilters({ QStringLiteral("*.jpg"), QStringLiteral("*.jpeg"), QStringLiteral("*.jpe"), QStringLiteral("*.jif"), QStringLiteral("*.jfif"), QStringLiteral("*.jfi") });
321 
322  const auto &entryList = dir.entryList(QDir::NoDotAndDotDot | QDir::Files);
323  for(const auto &dirItem : entryList)
324  {
325  //remove all files
326  dir.remove(dirItem);
327  }
328  }
329 }
330 
331 auto Preferences::verifyPath(const QString &i_path) -> bool
332 {
333  QFileInfo path(i_path);
334 
335  //check if path exists
336  if (!path.exists()) {
337  //create dir
338  QDir dir(i_path);
339  if (!dir.mkpath(QStringLiteral("."))) {
340  QMessageBox::warning(this, tr("photo folder") , tr("The directory doesn't exist and also couldn't be created."));
341  return false;
342  }
343  }
344 
345  //check if a directory
346  if (!path.isDir()) {
347  QMessageBox::warning(this, tr("photo folder") , tr("Please select a directory and not a file."));
348  return false;
349  }
350 
351  //check if readale and writable
352  if (!path.isReadable() || !path.isWritable()) {
353  QMessageBox::warning(this, tr("photo folder") , tr("Write and read rights are required. Please check the permission of the directory."));
354  return false;
355  }
356 
357  return true;
358 }
359 
360 void Preferences::showColor(const QString &i_colorName)
361 {
362  //create color
363  QColor color(i_colorName);
364 
365  //set color (text + background)
366  auto *lineEdit = qobject_cast<QLineEdit *>(sender());
367  if (lineEdit != nullptr) {
368  auto palette = lineEdit->palette();
369  palette.setColor(QPalette::Text, color);
370  palette.setColor(QPalette::Base, color);
371  lineEdit->setPalette(palette);
372  //force repaint (Restore Default issue)
373  lineEdit->repaint();
374  }
375 }
376 
377 void Preferences::savePreferences()
378 {
379  m_settings.beginGroup(QStringLiteral("FotoBox"));
380  m_settings.setValue(m_ui->txtPhotoFolder->objectName(), PreferenceProvider::instance().photoFolder());
381  m_settings.setValue(m_ui->txtPhotoName->objectName(), PreferenceProvider::instance().photoName());
382  m_settings.setValue(m_ui->spbCountdown->objectName(), PreferenceProvider::instance().countdown());
383  m_settings.setValue(m_ui->txtShowColorCD->objectName(), PreferenceProvider::instance().countdownColor());
384  m_settings.setValue(m_ui->chbButtons->objectName(), PreferenceProvider::instance().showButtons());
385  m_settings.setValue(m_ui->txtShowColorBG->objectName(), PreferenceProvider::instance().backgroundColor());
386  m_settings.endGroup();
387 
388  m_settings.beginGroup(QStringLiteral("Buzzer"));
389  m_settings.setValue(m_ui->spbInputPin->objectName(), PreferenceProvider::instance().inputPin());
390  m_settings.setValue(m_ui->spbOutputPin->objectName(), PreferenceProvider::instance().outputPin());
391  m_settings.setValue(m_ui->spbQueryInterval->objectName(), PreferenceProvider::instance().queryInterval());
392  m_settings.endGroup();
393 
394  m_settings.beginGroup(QStringLiteral("Camera"));
395  //save QComboBox model
396  QStringList itemText;
397  QStringList itemData;
398  const auto size = m_ui->cmbCameraMode->count();
399  itemText.reserve(size);
400  itemData.reserve(size);
401  for (int i = 0; i < size; ++i) {
402  itemText << m_ui->cmbCameraMode->itemText(i);
403  itemData << m_ui->cmbCameraMode->itemData(i).toString();
404  }
405  m_settings.setValue(m_ui->cmbCameraMode->objectName() + QStringLiteral("Text"), itemText);
406  m_settings.setValue(m_ui->cmbCameraMode->objectName() + QStringLiteral("Data"), itemData);
407  m_settings.setValue(m_ui->cmbCameraMode->objectName(), PreferenceProvider::instance().cameraMode());
408 
409  m_settings.setValue(m_ui->spbTimout->objectName(), PreferenceProvider::instance().timeoutValue());
410  m_settings.setValue(m_ui->chbGrayscale->objectName(), PreferenceProvider::instance().grayscale());
411  m_settings.endGroup();
412 
413  m_settings.beginGroup(QStringLiteral("PrintSetup"));
414  m_settings.setValue(m_ui->chbPrint->objectName(), PreferenceProvider::instance().print());
415  m_settings.setValue(m_ui->cmbPrinterName->objectName(), PreferenceProvider::instance().printerName());
416  m_settings.endGroup();
417 }
418 
419 void Preferences::restoreDefaultPreferences()
420 {
421  //FotoBox
422  m_ui->txtPhotoFolder->setText(QDir::toNativeSeparators(QStandardPaths::writableLocation(QStandardPaths::PicturesLocation)) + QDir::separator() + QApplication::applicationName());
423  m_ui->txtPhotoName->setText(QStringLiteral("eventname.jpg"));
424  m_ui->spbCountdown->setValue(DEFAULT_COUNTDOWN_START_VALUE);
425  m_ui->txtShowColorCD->setText(QStringLiteral("#ff0000"));
426  m_ui->chbButtons->setChecked(true);
427  m_ui->txtShowColorBG->setText(QStringLiteral("#000000"));
428 
429  //Buzzer
430  m_ui->spbInputPin->setValue(DEFAULT_INPUT_PIN);
431  m_ui->spbOutputPin->setValue(DEFAULT_OUTPUT_PIN);
432  m_ui->spbQueryInterval->setValue(DEFAULT_QUERY_INTERVAL);
433 
434  //Camera
435  m_ui->cmbCameraMode->clear();
436  m_ui->cmbCameraMode->addItem(QStringLiteral("gphoto2"), "--capture-image-and-download --keep --force-overwrite --filename %1");
437  m_ui->cmbCameraMode->addItem(QStringLiteral("raspistill"), "--output %1 --width 1920 --height 1080 --quality 75 --nopreview --timeout 1");
438  m_ui->spbTimout->setValue(DEFAULT_TIMEOUT);
439  m_ui->chbGrayscale->setChecked(false);
440 
441  //Print Setup
442  //get all printers and preselect default printer
443  m_ui->cmbPrinterName->clear();
444  m_ui->cmbPrinterName->addItems(QPrinterInfo::availablePrinterNames());
445  auto defaultPrinter = m_ui->cmbPrinterName->findText(QPrinterInfo::defaultPrinterName());
446  m_ui->cmbPrinterName->setCurrentIndex(defaultPrinter);
447  m_ui->chbPrint->setChecked(true);
448 }
449 
450 void Preferences::verifyApplication(const QString &i_name)
451 {
452  //stop here when clearing the camera mode QComboBox
453  if (i_name.isEmpty()) {
454  return;
455  }
456 
457  //gphoto2
458  if (i_name == QStringLiteral("gphoto2")) {
459  const auto message = tr("'%1' is missing%2")
460  .arg(i_name, tr(": <a href='https://github.com/gonzalo/gphoto2-updater/'>Linux (gphoto2 updater)</a>"
461  "/<a href='https://brew.sh/'>macOS (Homebrew)</a>"));
462  if (applicationAvailable(i_name, message)) {
463  //add info about gphoto2
464  m_ui->lblCameraModeInfo->setText(gphotoInfo(i_name));
465  }
466  return;
467  }
468 
469  //Raspberry Pi Camera Module
470  if (i_name == QStringLiteral("raspistill")) {
471  const auto message = tr("'%1' is missing%2")
472  .arg(i_name, tr(": <a href='https://www.raspberrypi.org/documentation/usage/camera/'>"
473  "Raspberry Pi Camera Module - enabling the camera</a>"));
474  applicationAvailable(i_name, message);
475  return;
476  }
477 
478  //Other Applications
479  const auto message = tr("'%1' is missing%2").arg(i_name, QLatin1String(""));
480  applicationAvailable(i_name, message);
481 }
482 
483 auto Preferences::applicationAvailable(const QString &i_name, const QString &i_message) -> bool
484 {
485  //If the process cannot be started, -2 is returned. If the process crashes, -1 is returned.
486  QProcess process;
487  process.start(i_name, {}, QIODevice::NotOpen);
488  process.waitForFinished();
489  const auto EXIT_CODE_OUT_OF_RANGE = 255;
490  if (process.exitCode() == EXIT_CODE_OUT_OF_RANGE) {
491  //set error message
492  m_ui->lblCameraModeInfo->setStyleSheet(QStringLiteral("QLabel { color : red; }"));
493  m_ui->lblCameraModeInfo->setText(i_message);
494  m_ui->cmbCameraMode->setItemData(m_ui->cmbCameraMode->currentIndex(), QBrush(Qt::red), Qt::ForegroundRole);
495  return false;
496  }
497  //application is available reset style and content
498  m_ui->lblCameraModeInfo->setStyleSheet(QLatin1String(""));
499  m_ui->lblCameraModeInfo->clear();
500  m_ui->cmbCameraMode->setItemData(m_ui->cmbCameraMode->currentIndex(), QBrush(Qt::black), Qt::ForegroundRole);
501  return true;
502 }
503 
504 auto Preferences::gphotoInfo(const QString &i_name) -> QString
505 {
506  QString result;
507 
508  //call 'gphoto2 --version --summary' and get output in english
509  QProcess process(this);
510  auto env = QProcessEnvironment::systemEnvironment();
511  env.insert(QStringLiteral("LC_ALL"), QStringLiteral("C"));
512  process.setProcessEnvironment(env);
513  process.start(i_name, {QStringLiteral("--version"), QStringLiteral("--summary")});
514  process.waitForFinished();
515  const auto output = QString::fromLatin1(process.readAllStandardOutput());
516 
517  //^gphoto2\s{2,}(?<gphoto2>\d+\.\d+\.\d+).*\n^libgphoto2\s{2,}(?<libgphoto2>\d+\.\d+\.\d+)
518  QString pattern(QStringLiteral("^gphoto2\\s{2,}(?<gphoto2>\\d+\\.\\d+\\.\\d+).*\\n^libgphoto2\\s{2,}(?<libgphoto2>\\d+\\.\\d+\\.\\d+)"));
519  //use regex to get version string
520  QRegularExpression regex(pattern, QRegularExpression::MultilineOption);
521  auto match = regex.match(output);
522  QString gphoto2(i_name);
523  QString libgphoto2(QStringLiteral("libgphoto2"));
524  if (match.hasMatch()) {
525  gphoto2 += QStringLiteral(" v") + match.captured(gphoto2);
526  libgphoto2 += QStringLiteral(" v") + match.captured(libgphoto2);
527  result = gphoto2 + QStringLiteral(" / ") + libgphoto2;
528 
529  //^[Mm]odel:\s(.*$)
530  pattern = QStringLiteral("^[Mm]odel:\\s(.*$)");
531  //get camera model
532  regex.setPattern(pattern);
533  match = regex.match(output);
534  result += QStringLiteral("\n");
535  if (match.hasMatch()) {
536  const auto matches = match.lastCapturedIndex();
537  result += tr("camera model: %1").arg(match.captured(1));
538  //more then one camera detected ('0' full match, '1' first match, '2' second match,...)
539  if (matches > 2) {
540  for (int i = 2; i <= matches; ++i) {
541  result += QStringLiteral(" / ") + match.captured(i);
542  }
543  }
544  } else {
545  result += tr("camera model: %1").arg(tr("NOT DETECTED"));
546  }
547  }
548 
549  return result;
550 }
551 
552 } // end namespace FotoBox
static auto checkDeamon() -> bool
Check if pigpio daemon is reachable.
Definition: buzzer.cpp:78
auto start() -> bool
Start countdown.
Definition: countdown.cpp:57
void elapsed()
Countdown elapsed.
void update(unsigned int)
Update countdown.
void setOutputPin(unsigned int i_value)
set pigpio GPIO output pin
void setInputPin(unsigned int i_value)
set pigpio GPIO input pin
void setQueryInterval(unsigned int i_value)
set how often the pin should be queried
void setTimeoutValue(int i_value)
set timeout value for the camera framework
void setCountdown(int i_value)
set countdown until photo is taken
void setCameraMode(const QString &i_value)
set the camera framework to be used
void setArgumentLine(const QString &i_value)
set camera framework arguments
void setPhotoFolder(const QString &i_value)
set photo output directory
void setPhotoName(const QString &i_value)
set photo name template
void setPrinterName(const QString &i_value)
set printer name
void setShowButtons(bool i_value)
set whether buttons are displayed on the UI
void setCountdownColor(const QString &i_value)
set font color of the countdown
static PreferenceProvider & instance()
get instance (Meyers Singleton)
void setGrayscale(bool i_value)
set grayscale bool (monochrome photography)
void setPrint(bool i_value)
set print on or off
void setBackgroundColor(const QString &i_value)
set background color of the FotoBox UI
Preferences(QWidget *parent=nullptr)
Preferences constructor.
Definition: preferences.cpp:27
void pigpioDeamon()
Check if pigpio deamon is reachable.
Definition: preferences.cpp:87
void clearDirectoryContent()
Clear directory content of the photo directory.
void commandLineOptionsDialog()
Show help dialog for gphoto2/raspistill command line options.
Ui::PreferencesDialog * m_ui
Definition: preferences.h:190
void chooseDirectory()
Open a QFileDialog to choose the photo directory.
void restoreDefaultPreferences()
Restore default preferences.
void loadPreferences()
Load application settings from INI file.
void stopCountdownMode()
Stop countdown, stop mouse tracking and set normal window title name.
void showColor(const QString &i_colorName)
Show the given color in QLineEdit.
void connectUi()
Signal & Slot connect.
Definition: preferences.cpp:97
void windowPosition()
Set the window position.
Definition: preferences.cpp:75
void verifyApplication(const QString &i_name)
Check camera application availability and provide help if needed.
void setButtonIcons()
Set icons for all QToolButtons.
void colorDialog()
Open a color picker to choose background color for FotoBox.
~Preferences() override
Preferences destructor.
Definition: preferences.cpp:70
bool verifyPath(const QString &i_path)
Check if the path is useable.
void startFotoBox()
Start the FotoBox.
Definition: fotobox.h:20