newflight.cpp 38 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105
  1. /*
  2. *openPilot Log - A FOSS Pilot Logbook Application
  3. *Copyright (C) 2020 Felix Turowsky
  4. *
  5. *This program is free software: you can redistribute it and/or modify
  6. *it under the terms of the GNU General Public License as published by
  7. *the Free Software Foundation, either version 3 of the License, or
  8. *(at your option) any later version.
  9. *
  10. *This program is distributed in the hope that it will be useful,
  11. *but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. *MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. *GNU General Public License for more details.
  14. *
  15. *You should have received a copy of the GNU General Public License
  16. *along with this program. If not, see <https://www.gnu.org/licenses/>.
  17. */
  18. #include "newflight.h"
  19. #include "ui_newflight.h"
  20. #include "dbman.cpp"
  21. /// =======================================================
  22. /// Debug / WIP section
  23. /// =======================================================
  24. #define DEBUG(expr) \
  25. qDebug() << "~DEBUG" << __func__ << expr
  26. void NewFlight::on_verifyButton_clicked()//debug button
  27. {
  28. fillExtrasLineEdits();
  29. }
  30. /*!
  31. * \brief NewFlight::nope for features that are not yet implemented
  32. */
  33. void NewFlight::nope()
  34. {
  35. QMessageBox nope(this); //error box
  36. nope.setText("This feature is not yet available!");
  37. nope.exec();
  38. }
  39. /// =======================================================
  40. /// Initialising variables used for storing user input
  41. /// Variables are initalised invalid to later fill them with
  42. /// meaningful inputs once they have been validated
  43. QVector<QString> flight;
  44. QDate date(QDate::currentDate());
  45. QString doft(QDate::currentDate().toString(Qt::ISODate));
  46. QString dept = "INVA";
  47. QString dest = "INVA";
  48. QTime tofb;
  49. QTime tonb;
  50. QTime tblk;
  51. QString pic = "-1";
  52. QString acft = "-1";
  53. // extras
  54. QString secondPilot = "-1";
  55. QString thirdPilot = "-1";
  56. QString pilotFunction = "-1";
  57. QString pilotTask = "-1";
  58. QString takeoff = "0";
  59. QString landing = "0";
  60. QString autoland = "0";
  61. QString approachType = "-1";
  62. // extra times
  63. QString tSPSE = "00:00";
  64. QString tSPME = "00:00";
  65. QString tMP = "00:00";
  66. /* If on submitting, not all checks are passed, user input is stored
  67. * in the scratchpad table to later re-fill the form enabling correction.*/
  68. bool hasOldInput = dbFlight::checkScratchpad();
  69. /// Raw Input validation
  70. const QString TIME_REGEX_PATTERN = "([01]?[0-9]?|2[0-3]):?[0-5][0-9]?";// We only want to allow inputs that make sense as a time, e.g. 99:99 is not a valid time
  71. const QString IATA = "[\\w]{3}";
  72. const QString ICAO = "[\\w0-9]{4}";
  73. const QString LOC_REGEX_PATTERN = IATA + "|" + ICAO;
  74. const QString AIRCRAFT_REGEX_PATTERN = "([\\w0-9]+-)?[\\w0-9]+";
  75. const QString PILOT_NAME_REGEX_PATTERN = "[\\w]+,? ?[\\w]+";
  76. /// Invalid characters (validators keep text even if it returns Invalid, see `onInputRejected` below)
  77. const QString TIME_INVALID_RGX = "[^\\d:]";
  78. const QString LOC_INVALID_RGX = "[^\\w0-9]";
  79. const QString AIRCRAFT_INVALID_RGX = "[^A-Z0-9\\-]";
  80. const QString PILOT_NAME_INVALID_RGX = "[^a-zA-Z, ]";
  81. /// Input max lengths
  82. const qint8 TIME_MAX_LENGTH = 5; //to allow for ':' e.g. "08:45"
  83. const qint8 LOC_MAX_LENGTH = 4; //!
  84. const qint8 AIRCRAFT_MAX_LENGTH = 10;
  85. const qint8 PILOT_NAME_MAX_LENGTH = 15;
  86. /*!
  87. * \brief setLineEditValidator set Validators for QLineEdits that end with Time, Loc,
  88. * Aircraft or Name
  89. */
  90. static inline void setupLineEdit(QLineEdit* line_edit)
  91. {
  92. auto line_edit_objectName = line_edit->objectName();
  93. DEBUG("Setting validators for " << line_edit_objectName);
  94. static const
  95. QVector<std::tuple<QRegularExpression, QRegularExpression, qint8>> objectName_inputValidation_rgxs = {
  96. {QRegularExpression("\\w+Time"), QRegularExpression(TIME_REGEX_PATTERN), TIME_MAX_LENGTH},
  97. {QRegularExpression("\\w+Loc"), QRegularExpression(LOC_REGEX_PATTERN), LOC_MAX_LENGTH},
  98. {QRegularExpression("\\w+Acft"), QRegularExpression(AIRCRAFT_REGEX_PATTERN), AIRCRAFT_MAX_LENGTH},
  99. {QRegularExpression("\\w+Name"), QRegularExpression(PILOT_NAME_REGEX_PATTERN), PILOT_NAME_MAX_LENGTH},
  100. };
  101. auto validator = new StrictRegularExpressionValidator();
  102. for(auto tuple : objectName_inputValidation_rgxs)
  103. {
  104. auto objName_rgx = std::get<0>(tuple);
  105. auto input_rgx = std::get<1>(tuple);
  106. auto max_length = std::get<2>(tuple);
  107. if(objName_rgx.match(line_edit_objectName).hasMatch())
  108. {
  109. validator->setRegularExpression(input_rgx);
  110. line_edit->setValidator(validator);
  111. line_edit->setMaxLength(max_length);
  112. return;
  113. }
  114. }
  115. DEBUG("Couldnt find QLineEdit" << line_edit_objectName);
  116. }
  117. /*!
  118. * \brief NewFlight::storeSettings Commits current selection for auto-logging
  119. * to the database.
  120. */
  121. void NewFlight::storeSettings()
  122. {
  123. qDebug() << "Storing Settings...";
  124. dbSettings::storeSetting(100, ui->FunctionComboBox->currentText());
  125. dbSettings::storeSetting(101, ui->ApproachComboBox->currentText());
  126. dbSettings::storeSetting(102, QString::number(ui->PilotFlyingCheckBox->isChecked()));
  127. dbSettings::storeSetting(103, QString::number(ui->PilotMonitoringCheckBox->isChecked()));
  128. dbSettings::storeSetting(104, QString::number(ui->TakeoffSpinBox->value()));
  129. dbSettings::storeSetting(105, QString::number(ui->TakeoffCheckBox->isChecked()));
  130. dbSettings::storeSetting(106, QString::number(ui->LandingSpinBox->value()));
  131. dbSettings::storeSetting(107, QString::number(ui->LandingCheckBox->isChecked()));
  132. dbSettings::storeSetting(108, QString::number(ui->AutolandSpinBox->value()));
  133. dbSettings::storeSetting(109, QString::number(ui->AutolandCheckBox->isChecked()));
  134. dbSettings::storeSetting(110, QString::number(ui->IfrCheckBox->isChecked()));
  135. dbSettings::storeSetting(111, QString::number(ui->VfrCheckBox->isChecked()));
  136. }
  137. /*!
  138. * \brief NewFlight::restoreSettings Retreives auto-logging settings from database
  139. * and sets up ui accordingly
  140. */
  141. void NewFlight::restoreSettings()
  142. {
  143. qDebug() << "Restoring Settings...";//crashes if db is empty due to QVector index out of range.
  144. ui->FunctionComboBox->setCurrentText(dbSettings::retreiveSetting(100));
  145. ui->ApproachComboBox->setCurrentText(dbSettings::retreiveSetting(101));
  146. ui->PilotFlyingCheckBox->setChecked(dbSettings::retreiveSetting(102).toInt());
  147. ui->PilotMonitoringCheckBox->setChecked(dbSettings::retreiveSetting(103).toInt());
  148. ui->TakeoffSpinBox->setValue(dbSettings::retreiveSetting(104).toInt());
  149. ui->TakeoffCheckBox->setChecked(dbSettings::retreiveSetting(105).toInt());
  150. ui->LandingSpinBox->setValue(dbSettings::retreiveSetting(106).toInt());
  151. ui->LandingCheckBox->setChecked(dbSettings::retreiveSetting(107).toInt());
  152. ui->AutolandSpinBox->setValue(dbSettings::retreiveSetting(108).toInt());
  153. ui->AutolandCheckBox->setChecked(dbSettings::retreiveSetting(109).toInt());
  154. ui->IfrCheckBox->setChecked(dbSettings::retreiveSetting(110).toInt());
  155. ui->VfrCheckBox->setChecked(dbSettings::retreiveSetting(111).toInt());
  156. ui->flightNumberPrefixLabel->setText(dbSettings::retreiveSetting(50) + QLatin1Char('-'));
  157. }
  158. /*
  159. * Window Construction
  160. */
  161. NewFlight::NewFlight(QWidget *parent) :
  162. QDialog(parent),
  163. ui(new Ui::NewFlight)
  164. {
  165. ui->setupUi(this);
  166. // Set up Line Edits with QValidators and set Max length
  167. auto line_edits = ui->flightDataTab->findChildren<QLineEdit*>() +
  168. ui->extraTimes->findChildren<QLineEdit*>();
  169. for(auto line_edit : line_edits)
  170. {
  171. setupLineEdit(line_edit);
  172. }
  173. // Airport Line Edits Auto Completion
  174. QStringList locationList = dbAirport::retreiveIataIcaoList(); //To be moved outside of dialog eventually
  175. QCompleter *locationCompleter = new QCompleter(locationList);
  176. locationCompleter->setCaseSensitivity(Qt::CaseInsensitive);
  177. locationCompleter->setCompletionMode(QCompleter::PopupCompletion);
  178. ui->newDeptLocLineEdit->setCompleter(locationCompleter);
  179. ui->newDestLocLineEdit->setCompleter(locationCompleter);
  180. // To Do: Aircraft and Pilot Names Completer
  181. // Groups for CheckBoxes
  182. QButtonGroup *FlightRulesGroup = new QButtonGroup(this);
  183. FlightRulesGroup->addButton(ui->IfrCheckBox);
  184. FlightRulesGroup->addButton(ui->VfrCheckBox);
  185. QButtonGroup *PilotTaskGroup = new QButtonGroup(this);
  186. PilotTaskGroup->addButton(ui->PilotFlyingCheckBox);
  187. PilotTaskGroup->addButton(ui->PilotMonitoringCheckBox);
  188. ui->deptTZ->setFocusPolicy(Qt::NoFocus);
  189. ui->destTZ->setFocusPolicy(Qt::NoFocus);
  190. ui->newDoft->setDate(QDate::currentDate());
  191. // Visually mark mandatory fields
  192. ui->newDeptLocLineEdit->setStyleSheet("border: 1px solid orange");
  193. ui->newDestLocLineEdit->setStyleSheet("border: 1px solid orange");
  194. ui->newDeptTimeLineEdit->setStyleSheet("border: 1px solid orange");
  195. ui->newDestTimeLineEdit->setStyleSheet("border: 1px solid orange");
  196. ui->newPicNameLineEdit->setStyleSheet("border: 1px solid orange");
  197. ui->newAcft->setStyleSheet("border: 1px solid orange");
  198. restoreSettings(); // settings for auto-logging are stored in the database.
  199. //Restore inputs if commiting to DB has been rejected.
  200. qDebug() << "Hasoldinput? = " << hasOldInput;
  201. if(hasOldInput) // Re-populate the Form
  202. {
  203. flight = dbFlight::retreiveScratchpad();
  204. qDebug() << "Re-Filling Form from Scratchpad";
  205. returnInput(flight);
  206. }
  207. ui->newDeptLocLineEdit->setFocus();
  208. }
  209. NewFlight::~NewFlight()
  210. {
  211. delete ui;
  212. }
  213. /*
  214. * Slots
  215. */
  216. /*!
  217. * \brief onInputRejected Set `line_edit`'s border to red and check if `rgx` matches
  218. * in order to keep text on line.
  219. */
  220. static void onInputRejected(QLineEdit* line_edit, QRegularExpression rgx){
  221. DEBUG("Input rejected" << line_edit->text());
  222. line_edit->setStyleSheet("border: 1px solid red");
  223. if(auto text = line_edit->text();
  224. rgx.match(text).hasMatch() == false)
  225. {
  226. line_edit->setText(line_edit->text());
  227. }
  228. }
  229. /*!
  230. * \brief onEditingFinished signal is emitted if input passed raw validation
  231. */
  232. static void onEditingFinished(QLineEdit* line_edit){
  233. DEBUG("Input accepted" << line_edit->text() << line_edit->metaObject()->className());
  234. line_edit->setStyleSheet("");
  235. }
  236. void NewFlight::on_deptTZ_currentTextChanged(const QString &arg1)
  237. {
  238. if(arg1 == "Local"){nope();} // currently only UTC time logging is supported
  239. ui->deptTZ->setCurrentIndex(0);
  240. }
  241. void NewFlight::on_destTZ_currentIndexChanged(const QString &arg1)
  242. {
  243. if(arg1 == "Local"){nope();} // currently only UTC time logging is supported
  244. ui->destTZ->setCurrentIndex(0);
  245. }
  246. /// Departure
  247. void NewFlight::on_newDeptLocLineEdit_inputRejected()
  248. {
  249. ui->newDeptLocLineEdit->setText(ui->newDeptLocLineEdit->text().toUpper());
  250. onInputRejected(ui->newDeptLocLineEdit, QRegularExpression(LOC_INVALID_RGX));
  251. }
  252. void NewFlight::on_newDeptLocLineEdit_textEdited(const QString &arg1)
  253. {
  254. ui->newDeptLocLineEdit->setText(arg1.toUpper());
  255. }
  256. void NewFlight::on_newDeptLocLineEdit_editingFinished()
  257. {
  258. QStringList locationList = dbAirport::retreiveIataIcaoList(); //To be moved outside of dialog eventually
  259. auto line_edit = ui->newDeptLocLineEdit;
  260. onEditingFinished(line_edit); //reset style sheet
  261. dept = line_edit->text();
  262. // check if iata exists, replace with icao code if it does.
  263. if(dept.length() == 3){
  264. int index = locationList.indexOf(dept);
  265. if(index == -1){// Not in locationList
  266. DEBUG("Airport not found.");
  267. emit line_edit->inputRejected();
  268. }else{
  269. dept = locationList[index -1];
  270. }
  271. }
  272. // Check if 4-letter code is in locationList
  273. if(dept.length() == 4 && locationList.indexOf(dept) == -1){
  274. DEBUG("Airport not found.");
  275. emit line_edit->inputRejected();
  276. }
  277. line_edit->setText(dept);
  278. DEBUG("Departure set: " << dept);
  279. }
  280. void NewFlight::on_newDeptTimeLineEdit_inputRejected()
  281. {
  282. onInputRejected(ui->newDeptTimeLineEdit, QRegularExpression(TIME_INVALID_RGX));
  283. }
  284. void NewFlight::on_newDeptTimeLineEdit_editingFinished()
  285. {
  286. ui->newDeptTimeLineEdit->setText(calc::formatTimeInput(ui->newDeptTimeLineEdit->text()));
  287. tofb = QTime::fromString(ui->newDeptTimeLineEdit->text(),"hh:mm");
  288. auto line_edit = ui->newDeptTimeLineEdit;
  289. onEditingFinished(line_edit);
  290. if(tofb.isValid()){
  291. // continue
  292. DEBUG("Time Off Blocks is valid:" << tofb);
  293. }else{
  294. emit line_edit->inputRejected();
  295. }
  296. }
  297. /// Destination
  298. void NewFlight::on_newDestLocLineEdit_inputRejected()
  299. {
  300. ui->newDestLocLineEdit->setText(ui->newDestLocLineEdit->text().toUpper());
  301. onInputRejected(ui->newDestLocLineEdit, QRegularExpression(LOC_INVALID_RGX));
  302. }
  303. void NewFlight::on_newDestLocLineEdit_textEdited(const QString &arg1)
  304. {
  305. ui->newDestLocLineEdit->setText(arg1.toUpper());
  306. }
  307. void NewFlight::on_newDestLocLineEdit_editingFinished()
  308. {
  309. QStringList locationList = dbAirport::retreiveIataIcaoList(); //To be moved outside of dialog eventually
  310. auto line_edit = ui->newDestLocLineEdit;
  311. onEditingFinished(line_edit); //reset style sheet
  312. dest = line_edit->text();
  313. // check if iata exists, replace with icao code if it does.
  314. if(dest.length() == 3){
  315. int index = locationList.indexOf(dest);
  316. if(index == -1){// Not in locationList
  317. DEBUG("Airport not found.");
  318. emit line_edit->inputRejected();
  319. }else{
  320. dest = locationList[index -1];
  321. }
  322. }
  323. // Check if 4-letter code is in locationList
  324. if(dest.length() == 4 && locationList.indexOf(dest) == -1){
  325. DEBUG("Airport not found.");
  326. emit line_edit->inputRejected();
  327. }
  328. line_edit->setText(dest);
  329. DEBUG("Destination set: " << dest);
  330. }
  331. void NewFlight::on_newDestTimeLineEdit_inputRejected()
  332. {
  333. onInputRejected(ui->newDestTimeLineEdit, QRegularExpression(TIME_INVALID_RGX));
  334. }
  335. void NewFlight::on_newDestTimeLineEdit_editingFinished()
  336. {
  337. ui->newDestTimeLineEdit->setText(calc::formatTimeInput(ui->newDestTimeLineEdit->text()));
  338. tonb = QTime::fromString(ui->newDestTimeLineEdit->text(),"hh:mm");
  339. auto line_edit = ui->newDestTimeLineEdit;
  340. onEditingFinished(line_edit);
  341. if(tonb.isValid()){
  342. // continue
  343. DEBUG("Time On Blocks is valid:" << tonb);
  344. }else{
  345. emit line_edit->inputRejected();
  346. }
  347. }
  348. /// Date
  349. void NewFlight::on_newDoft_editingFinished()
  350. {
  351. date = ui->newDoft->date();
  352. doft = date.toString(Qt::ISODate);
  353. }
  354. /// Aircraft
  355. void NewFlight::on_newAcft_textEdited(const QString &arg1)
  356. {
  357. if(arg1.length()>1)
  358. {
  359. QStringList acftList = dbAircraft::newAcftGetString(arg1);
  360. QCompleter *acftCompleter = new QCompleter(acftList, this);
  361. acftCompleter->setCaseSensitivity(Qt::CaseInsensitive);
  362. acftCompleter->setCompletionMode(QCompleter::UnfilteredPopupCompletion);
  363. ui->newAcft->setCompleter(acftCompleter);
  364. }
  365. }
  366. void NewFlight::on_newAcft_editingFinished()
  367. {
  368. acft = "-1";// set invalid
  369. if(ui->newAcft->text().contains(" "))// is input from QCompleter
  370. {
  371. QStringList input = ui->newAcft->text().split(" ");
  372. QString registration = input[0].trimmed();
  373. QStringList result = dbAircraft::newAcftGetString(registration);
  374. if(result.length() > 0)
  375. {
  376. ui->newAcft->setText(result[0]);
  377. acft = dbAircraft::retreiveTailId(registration);
  378. }else
  379. {
  380. acft = "-1";
  381. }
  382. }else // is input from user
  383. {
  384. QString input = ui->newAcft->text();
  385. QStringList result = dbAircraft::newAcftGetString(input);
  386. if(result.length() > 0)
  387. {
  388. ui->newAcft->setText(result[0]);
  389. QStringList input = ui->newAcft->text().split(" ");
  390. QString registration = input[0].trimmed();
  391. acft = dbAircraft::retreiveTailId(registration);
  392. }else
  393. {
  394. acft = "-1";
  395. }
  396. }
  397. if(acft == "-1")
  398. {
  399. QMessageBox::StandardButton reply;
  400. reply = QMessageBox::question(this, "No aircraft found", "No aircraft found.\n Would you like to add a new aircraft to the database?",
  401. QMessageBox::Yes|QMessageBox::No);
  402. if (reply == QMessageBox::Yes) {
  403. NewAcft na(this);
  404. na.exec();
  405. ui->newAcft->setText("");
  406. ui->newAcft->setFocus();
  407. }
  408. }
  409. qDebug() << "Editing finished. Acft: " << acft;
  410. }
  411. /// Pilot(s)
  412. void NewFlight::on_newPicNameLineEdit_inputRejected()
  413. {
  414. onInputRejected(ui->newPicNameLineEdit, QRegularExpression(PILOT_NAME_INVALID_RGX));
  415. }
  416. void NewFlight::on_newPicNameLineEdit_textEdited(const QString &arg1)
  417. {
  418. if(arg1.length()>2)
  419. {
  420. QStringList picList = dbPilots::newPicGetString(arg1);
  421. QCompleter *picCompleter = new QCompleter(picList, this);
  422. picCompleter->setCaseSensitivity(Qt::CaseInsensitive);
  423. picCompleter->setCompletionMode(QCompleter::UnfilteredPopupCompletion);
  424. ui->newPicNameLineEdit->setCompleter(picCompleter);
  425. }
  426. }
  427. void NewFlight::on_newPicNameLineEdit_editingFinished()
  428. {
  429. pic = "-1"; // set invalid
  430. if(ui->newPicNameLineEdit->text() == "self")
  431. {
  432. pic = "1";
  433. }else
  434. {
  435. QString picname;
  436. QStringList picList = dbPilots::newPicGetString(ui->newPicNameLineEdit->text());
  437. qDebug() << picList;
  438. if(picList.length()!= 0)
  439. {
  440. picname = picList[0];
  441. ui->newPicNameLineEdit->setText(picname);
  442. pic = dbPilots::newPicGetId(picname);
  443. }else
  444. {
  445. QMessageBox::StandardButton reply;
  446. reply = QMessageBox::question(this, "No Pilot found", "No pilot found.\n Would you like to add a new pilot to the database?",
  447. QMessageBox::Yes|QMessageBox::No);
  448. if (reply == QMessageBox::Yes)
  449. {
  450. qDebug() << "Add new pilot selected";
  451. nope();
  452. }
  453. }
  454. }
  455. }
  456. /*!
  457. * ===================================================
  458. * The above entris are mandatory for logging a flight,
  459. * the rest of the entries are either optional or can
  460. * be determined from the entries already made.
  461. */
  462. void NewFlight::on_secondPilotNameLineEdit_textEdited(const QString &arg1)
  463. {
  464. if(arg1.length()>2)
  465. {
  466. QStringList picList = dbPilots::newPicGetString(arg1);
  467. QCompleter *picCompleter = new QCompleter(picList, this);
  468. picCompleter->setCaseSensitivity(Qt::CaseInsensitive);
  469. picCompleter->setCompletionMode(QCompleter::UnfilteredPopupCompletion);
  470. ui->secondPilotNameLineEdit->setCompleter(picCompleter);
  471. }
  472. }
  473. void NewFlight::on_secondPilotNameLineEdit_editingFinished()
  474. {
  475. secondPilot = "-1"; // set invalid
  476. if(ui->secondPilotNameLineEdit->text() == "self")
  477. {
  478. secondPilot = "1";
  479. }else
  480. {
  481. QString picname;
  482. QStringList picList = dbPilots::newPicGetString(ui->secondPilotNameLineEdit->text());
  483. qDebug() << picList;
  484. if(picList.length()!= 0)
  485. {
  486. picname = picList[0];
  487. ui->secondPilotNameLineEdit->setText(picname);
  488. secondPilot = dbPilots::newPicGetId(picname);
  489. }else
  490. {
  491. ui->secondPilotNameLineEdit->setStyleSheet("border: 1px solid red");
  492. /*QMessageBox::StandardButton reply;
  493. reply = QMessageBox::question(this, "No Pilot found", "No pilot found.\n Would you like to add a new pilot to the database?",
  494. QMessageBox::Yes|QMessageBox::No);
  495. if (reply == QMessageBox::Yes)
  496. {
  497. qDebug() << "Add new pilot selected";
  498. nope();
  499. }*/
  500. }
  501. }
  502. }
  503. void NewFlight::on_thirdPilotNameLineEdit_textEdited(const QString &arg1)
  504. {
  505. if(arg1.length()>2)
  506. {
  507. QStringList picList = dbPilots::newPicGetString(arg1);
  508. QCompleter *picCompleter = new QCompleter(picList, this);
  509. picCompleter->setCaseSensitivity(Qt::CaseInsensitive);
  510. picCompleter->setCompletionMode(QCompleter::UnfilteredPopupCompletion);
  511. ui->thirdPilotNameLineEdit->setCompleter(picCompleter);
  512. }
  513. }
  514. void NewFlight::on_thirdPilotNameLineEdit_editingFinished()
  515. {
  516. thirdPilot = "-1"; // set invalid
  517. if(ui->thirdPilotNameLineEdit->text() == "self")
  518. {
  519. thirdPilot = "1";
  520. }else
  521. {
  522. QString picname;
  523. QStringList picList = dbPilots::newPicGetString(ui->thirdPilotNameLineEdit->text());
  524. qDebug() << picList;
  525. if(picList.length()!= 0)
  526. {
  527. picname = picList[0];
  528. ui->thirdPilotNameLineEdit->setText(picname);
  529. thirdPilot = dbPilots::newPicGetId(picname);
  530. }else
  531. {
  532. ui->thirdPilotNameLineEdit->setStyleSheet("border: 1px solid red");
  533. /*QMessageBox::StandardButton reply;
  534. reply = QMessageBox::question(this, "No Pilot found", "No pilot found.\n Would you like to add a new pilot to the database?",
  535. QMessageBox::Yes|QMessageBox::No);
  536. if (reply == QMessageBox::Yes)
  537. {
  538. qDebug() << "Add new pilot selected";
  539. nope();
  540. }*/
  541. }
  542. }
  543. }
  544. void NewFlight::on_FlightNumberLineEdit_editingFinished()
  545. {
  546. qDebug() << "tbd: FlightNumber slot";
  547. // To Do: Store input in variable, perform some checks
  548. // Setting for optional Prefix (e.g. LH, LX etc.)
  549. }
  550. /*
  551. * Extras Tab - These are for user convenience. From many of
  552. * these selections, determinations can be made on how to log
  553. * details, so that the user does not have to enter each item
  554. * manually. See also fillExtrasLineEdits()
  555. */
  556. void NewFlight::on_setAsDefaultButton_clicked()
  557. {
  558. storeSettings();
  559. }
  560. void NewFlight::on_restoreDefaultButton_clicked()
  561. {
  562. restoreSettings();
  563. }
  564. /*!
  565. * \brief On a given flight, time can either be logged as Pilot Flying (PF) or
  566. * Pilot Monitoring (PM). Cases where controls are changed during the flight
  567. * are rare and can be logged by manually editing the extras.
  568. */
  569. void NewFlight::on_PilotFlyingCheckBox_stateChanged(int)
  570. {
  571. if(ui->PilotFlyingCheckBox->isChecked()){
  572. ui->TakeoffSpinBox->setValue(1);
  573. ui->TakeoffCheckBox->setCheckState(Qt::Checked);
  574. ui->LandingSpinBox->setValue(1);
  575. ui->LandingCheckBox->setCheckState(Qt::Checked);
  576. }else if(!ui->PilotFlyingCheckBox->isChecked()){
  577. ui->TakeoffSpinBox->setValue(0);
  578. ui->TakeoffCheckBox->setCheckState(Qt::Unchecked);
  579. ui->LandingSpinBox->setValue(0);
  580. ui->LandingCheckBox->setCheckState(Qt::Unchecked);
  581. }
  582. }
  583. void NewFlight::on_ApproachComboBox_currentTextChanged(const QString &arg1)
  584. {
  585. if(arg1 == "ILS CAT III"){ //for a CAT III approach an Autoland is mandatory, so we can preselect it.
  586. ui->AutolandCheckBox->setCheckState(Qt::Checked);
  587. ui->AutolandSpinBox->setValue(1);
  588. }else{
  589. ui->AutolandCheckBox->setCheckState(Qt::Unchecked);
  590. ui->AutolandSpinBox->setValue(0);
  591. }
  592. approachType = arg1;
  593. qDebug() << "Approach Type: " << approachType;
  594. }
  595. /*
  596. * Extra Times - These line edits should be filled out automatically,
  597. * based on the ui selections and the user provided input. However,
  598. * manual adjustments are possible to cater for situations where for
  599. * example one portion of the flight is logged under different rules
  600. * than the rest of it.
  601. *
  602. * For example,
  603. * if we know the aircraft details we can determine how to log these times.
  604. * Some times are mutually exclusive, others can be combined.
  605. *
  606. * For example,
  607. * for a commercial Passenger flight, the commander can log all time as
  608. * Total Time and PIC time. If the aircraft is a multi-engine jet he can
  609. * also log Multi-Pilot time, and if he is an instructor, instructor time.
  610. *
  611. * It is not possible, however to log flight time as VFR or IFR time
  612. * simultaneously, as a flight at any given point in time can only follow
  613. * one set of rules. It is possible, to change flight rules and log the first
  614. * x minutes as VFR and the rest of it as IFR, for example. Hence the need
  615. * for the possibility to edit these times manually.
  616. *
  617. * The most complex time to determine is night time, see documentation of
  618. * the calc class for details.
  619. *
  620. * In General, the idea is to automatically fill as much as possible, but
  621. * if the user decides to change these times, accept the inputs, as long as
  622. * they are generally valid. We cannot cater for all possibilities, so as long
  623. * as the time the user has input is a valid time <= Total Time, it can be
  624. * accepted to the database.
  625. */
  626. void NewFlight::on_spseTimeLineEdit_editingFinished()
  627. {
  628. ui->spseTimeLineEdit->setText(calc::formatTimeInput(ui->spseTimeLineEdit->text()));
  629. if(ui->spseTimeLineEdit->text() == ""){
  630. ui->spseTimeLineEdit->setStyleSheet("border: 1px solid red");
  631. ui->spseTimeLineEdit->setFocus();
  632. }else{
  633. ui->spseTimeLineEdit->setStyleSheet("");
  634. }
  635. }
  636. void NewFlight::on_spmeTimeLineEdit_editingFinished()
  637. {
  638. ui->spmeTimeLineEdit->setText(calc::formatTimeInput(ui->spmeTimeLineEdit->text()));
  639. if(ui->spmeTimeLineEdit->text() == ""){
  640. ui->spmeTimeLineEdit->setStyleSheet("border: 1px solid red");
  641. ui->spmeTimeLineEdit->setFocus();
  642. }else{
  643. ui->spmeTimeLineEdit->setStyleSheet("");
  644. }
  645. }
  646. void NewFlight::on_mpTimeLineEdit_editingFinished()
  647. {
  648. ui->mpTimeLineEdit->setText(calc::formatTimeInput(ui->mpTimeLineEdit->text()));
  649. if(ui->mpTimeLineEdit->text() == ""){
  650. ui->mpTimeLineEdit->setStyleSheet("border: 1px solid red");
  651. ui->mpTimeLineEdit->setFocus();
  652. }else{
  653. ui->mpTimeLineEdit->setStyleSheet("");
  654. }
  655. }
  656. void NewFlight::on_totalTimeLineEdit_editingFinished()
  657. {
  658. ui->totalTimeLineEdit->setText(calc::formatTimeInput(ui->totalTimeLineEdit->text()));
  659. if(ui->totalTimeLineEdit->text() == ""){
  660. ui->totalTimeLineEdit->setStyleSheet("border: 1px solid red");
  661. ui->totalTimeLineEdit->setFocus();
  662. }else{
  663. ui->totalTimeLineEdit->setStyleSheet("");
  664. }
  665. }
  666. void NewFlight::on_ifrTimeLineEdit_editingFinished()
  667. {
  668. ui->ifrTimeLineEdit->setText(calc::formatTimeInput(ui->ifrTimeLineEdit->text()));
  669. if(ui->ifrTimeLineEdit->text() == ""){
  670. ui->ifrTimeLineEdit->setStyleSheet("border: 1px solid red");
  671. ui->ifrTimeLineEdit->setFocus();
  672. }else{
  673. ui->ifrTimeLineEdit->setStyleSheet("");
  674. }
  675. }
  676. void NewFlight::on_vfrTimeLineEdit_editingFinished()
  677. {
  678. ui->vfrTimeLineEdit->setText(calc::formatTimeInput(ui->vfrTimeLineEdit->text()));
  679. if(ui->vfrTimeLineEdit->text() == ""){
  680. ui->vfrTimeLineEdit->setStyleSheet("border: 1px solid red");
  681. ui->vfrTimeLineEdit->setFocus();
  682. }else{
  683. ui->vfrTimeLineEdit->setStyleSheet("");
  684. }
  685. }
  686. void NewFlight::on_nightTimeLineEdit_editingFinished()
  687. {
  688. ui->nightTimeLineEdit->setText(calc::formatTimeInput(ui->nightTimeLineEdit->text()));
  689. if(ui->nightTimeLineEdit->text() == ""){
  690. ui->nightTimeLineEdit->setStyleSheet("border: 1px solid red");
  691. ui->nightTimeLineEdit->setFocus();
  692. }else{
  693. ui->nightTimeLineEdit->setStyleSheet("");
  694. }
  695. }
  696. void NewFlight::on_xcTimeLineEdit_editingFinished()
  697. {
  698. ui->xcTimeLineEdit->setText(calc::formatTimeInput(ui->xcTimeLineEdit->text()));
  699. if(ui->xcTimeLineEdit->text() == ""){
  700. ui->xcTimeLineEdit->setStyleSheet("border: 1px solid red");
  701. ui->xcTimeLineEdit->setFocus();
  702. }else{
  703. ui->xcTimeLineEdit->setStyleSheet("");
  704. }
  705. }
  706. void NewFlight::on_picTimeLineEdit_editingFinished()
  707. {
  708. ui->picTimeLineEdit->setText(calc::formatTimeInput(ui->picTimeLineEdit->text()));
  709. if(ui->picTimeLineEdit->text() == ""){
  710. ui->picTimeLineEdit->setStyleSheet("border: 1px solid red");
  711. ui->picTimeLineEdit->setFocus();
  712. }else{
  713. ui->picTimeLineEdit->setStyleSheet("");
  714. }
  715. }
  716. void NewFlight::on_copTimeLineEdit_editingFinished()
  717. {
  718. ui->copTimeLineEdit->setText(calc::formatTimeInput(ui->copTimeLineEdit->text()));
  719. if(ui->copTimeLineEdit->text() == ""){
  720. ui->copTimeLineEdit->setStyleSheet("border: 1px solid red");
  721. ui->copTimeLineEdit->setFocus();
  722. }else{
  723. ui->copTimeLineEdit->setStyleSheet("");
  724. }
  725. }
  726. void NewFlight::on_dualTimeLineEdit_editingFinished()
  727. {
  728. ui->dualTimeLineEdit->setText(calc::formatTimeInput(ui->dualTimeLineEdit->text()));
  729. if(ui->dualTimeLineEdit->text() == ""){
  730. ui->dualTimeLineEdit->setStyleSheet("border: 1px solid red");
  731. ui->dualTimeLineEdit->setFocus();
  732. }else{
  733. ui->dualTimeLineEdit->setStyleSheet("");
  734. }
  735. }
  736. void NewFlight::on_fiTimeLineEdit_editingFinished()
  737. {
  738. ui->fiTimeLineEdit->setText(calc::formatTimeInput(ui->fiTimeLineEdit->text()));
  739. if(ui->fiTimeLineEdit->text() == ""){
  740. ui->fiTimeLineEdit->setStyleSheet("border: 1px solid red");
  741. ui->fiTimeLineEdit->setFocus();
  742. }else{
  743. ui->fiTimeLineEdit->setStyleSheet("");
  744. }
  745. }
  746. void NewFlight::on_simTimeLineEdit_editingFinished()
  747. {
  748. ui->simTimeLineEdit->setText(calc::formatTimeInput(ui->simTimeLineEdit->text()));
  749. if(ui->simTimeLineEdit->text() == ""){
  750. ui->simTimeLineEdit->setStyleSheet("border: 1px solid red");
  751. ui->simTimeLineEdit->setFocus();
  752. }else{
  753. ui->simTimeLineEdit->setStyleSheet("");
  754. }
  755. }
  756. /*
  757. * Control Buttons
  758. */
  759. void NewFlight::on_buttonBox_accepted()
  760. {
  761. on_newDoft_editingFinished();// - activate slots in case user has been active in last input before clicking submit
  762. //on_newTonb_editingFinished();
  763. //on_newTofb_editingFinished();
  764. //on_newDept_editingFinished();
  765. //on_newDest_editingFinished();
  766. on_newAcft_editingFinished();
  767. on_newPicNameLineEdit_editingFinished();
  768. QVector<QString> flight;
  769. flight = collectInput();
  770. if(verifyInput())
  771. {
  772. dbFlight::commitFlight(flight);
  773. qDebug() << flight << "Has been commited.";
  774. QMessageBox msgBox(this);
  775. msgBox.setText("Flight has been commited.");
  776. msgBox.exec();
  777. }else
  778. {
  779. qDebug() << "Invalid Input. No entry has been made in the database.";
  780. dbFlight::commitToScratchpad(flight);
  781. QMessageBox msgBox(this);
  782. msgBox.setText("Invalid entries detected. Please check your input.");
  783. msgBox.exec();
  784. NewFlight nf(this);
  785. nf.exec();
  786. }
  787. }
  788. void NewFlight::on_buttonBox_rejected()
  789. {
  790. qDebug() << "NewFlight: Rejected\n";
  791. }
  792. /// Input Verification and Collection
  793. QVector<QString> NewFlight::collectInput()
  794. {
  795. // Collect input from the user fields and return a vector containing the flight information
  796. QString doft = date.toString(Qt::ISODate); // Format Date
  797. QTime tblk = calc::blocktime(tofb,tonb); // Calculate Blocktime
  798. // Prepare Vector for commit to database
  799. flight = dbFlight::createFlightVectorFromInput(doft, dept, tofb, dest, tonb, tblk, pic, acft);
  800. qDebug() << "Created flight vector:" << flight;
  801. return flight;
  802. }
  803. /*!
  804. * \brief NewFlight::verifyInput checks if input exists in database.
  805. * \return
  806. */
  807. bool NewFlight::verifyInput()
  808. {
  809. bool deptValid = false;
  810. bool tofbValid = false;
  811. bool destValid = false;
  812. bool tonbValid = false;
  813. bool tblkValid = false;
  814. bool picValid = false;
  815. bool acftValid = false;
  816. QTime tblk = calc::blocktime(tofb,tonb);
  817. int checktblk = calc::time_to_minutes(tblk);
  818. bool doftValid = true; //doft assumed to be always valid due to QDateTimeEdit constraints
  819. qDebug() << "NewFlight::verifyInput() says: Date:" << doft << " - Valid?\t" << doftValid;
  820. deptValid = dbAirport::checkICAOValid(dept);
  821. qDebug() << "NewFlight::verifyInput() says: Departure is:\t" << dept << " - Valid?\t" << deptValid;
  822. destValid = dbAirport::checkICAOValid(dest);
  823. qDebug() << "NewFlight::verifyInput() says: Destination is:\t" << dest << " - Valid?\t" << destValid;
  824. tofbValid = (unsigned)(calc::time_to_minutes(tofb)-0) <= (1440-0) && tofb.toString("hh:mm") != ""; // Make sure time is within range, DB 1 day = 1440 minutes. 0 is allowed (midnight) & that it is not empty.
  825. qDebug() << "NewFlight::verifyInput() says: tofb is:\t\t" << tofb.toString("hh:mm") << " - Valid?\t" << tofbValid;
  826. tonbValid = (unsigned)(calc::time_to_minutes(tonb)-0) <= (1440-0) && tonb.toString("hh:mm") != ""; // Make sure time is within range, DB 1 day = 1440 minutes
  827. qDebug() << "NewFlight::verifyInput() says: tonb is:\t\t" << tonb.toString("hh:mm")<< " - Valid?\t" << tonbValid;
  828. picValid = (pic.toInt() > 0); // pic should be a pilot_id retreived from the database
  829. qDebug() << "NewFlight::verifyInput() says: pic is pilotd_id:\t" << pic << " - Valid?\t" << picValid;
  830. if(!picValid)
  831. {
  832. QMessageBox msgBox(this);
  833. msgBox.setText("You cannot log a flight without a valid pilot");
  834. msgBox.exec();
  835. }
  836. acftValid = (acft.toInt() > 0);
  837. qDebug() << "NewFlight::verifyInput() says: acft is tail_id:\t" << acft << " - Valid?\t" << acftValid;
  838. if(!acftValid)
  839. {
  840. QMessageBox msgBox(this);
  841. msgBox.setText("You cannot log a flight without a valid aircraft");
  842. msgBox.exec();
  843. }
  844. tblkValid = checktblk != 0;
  845. qDebug() << "NewFlight::verifyInput() says: tblk is:\t\t" << tblk.toString("hh:mm") << " - Valid?\t" << tblkValid;
  846. if(deptValid && tofbValid && destValid && tonbValid
  847. && tblkValid && picValid && acftValid)
  848. {
  849. qDebug() << "====================================================";
  850. qDebug() << "NewFlight::verifyInput() says: All checks passed! Very impressive. ";
  851. return 1;
  852. }else
  853. {
  854. qDebug() << "====================================================";
  855. qDebug() << "NewFlight::verifyInput() says: Flight is invalid.";
  856. return 0;
  857. }
  858. return 0;
  859. }
  860. void NewFlight::returnInput(QVector<QString> flight)
  861. {
  862. // Re-populates the input masks with the selected fields if input was erroneous to allow for corrections to be made
  863. qDebug() << "return Input: " << flight;
  864. ui->newDoft->setDate(QDate::fromString(flight[1],Qt::ISODate));
  865. ui->newDeptLocLineEdit->setText(flight[2]);
  866. ui->newDeptTimeLineEdit->setText(flight[3]);
  867. ui->newDestLocLineEdit->setText(flight[4]);
  868. ui->newDestTimeLineEdit->setText(flight[5]);
  869. // flight[6] is blocktime
  870. ui->newPicNameLineEdit->setText(dbPilots::retreivePilotNameFromID(flight[7]));
  871. ui->newAcft->setText(dbAircraft::retreiveRegistration(flight[8]));
  872. }
  873. /*!
  874. * \brief NewFlight::fillExtrasLineEdits Fills the flight time line edits according to ui selections.
  875. * Neccessary inputs are valid Date, Departure Time and Place, Destination Time and Place,
  876. * PIC name (pilot_id) and Aircraft (tail_id)
  877. */
  878. void NewFlight::fillExtrasLineEdits()
  879. {
  880. QString blockTime = calc::blocktime(tofb,tonb).toString("hh:mm");
  881. DEBUG(blockTime);
  882. QVector<QString> aircraftDetails = dbAircraft::retreiveAircraftDetails(dbAircraft::retreiveAircraftId(acft));
  883. DEBUG("aircraftDetails: " << aircraftDetails);
  884. if(!aircraftDetails.isEmpty()){// valid aircraft
  885. // SP SE
  886. if(aircraftDetails[0] == "1" && aircraftDetails[2] == "1"){
  887. DEBUG("SPSE yes");
  888. tSPSE = blockTime;
  889. ui->spseTimeLineEdit->setText(blockTime);
  890. }
  891. // SP ME
  892. if(aircraftDetails[0] == "1" && aircraftDetails[3] == "1"){
  893. DEBUG("SP ME yes");
  894. tSPME = blockTime;
  895. ui->spmeTimeLineEdit->setText(blockTime);
  896. }
  897. // MP
  898. if(aircraftDetails[1] == "1"){
  899. DEBUG("Multipilot yes");
  900. tMP = blockTime;
  901. ui->mpTimeLineEdit->setText(blockTime);
  902. }
  903. }else{DEBUG("Aircraft Details Empty");}//invalid aircraft
  904. // TOTAL
  905. ui->totalTimeLineEdit->setText(blockTime);
  906. // IFR
  907. if(ui->IfrCheckBox->isChecked()){
  908. ui->ifrTimeLineEdit->setText(blockTime);
  909. ui->vfrTimeLineEdit->setText("");
  910. }
  911. // VFR
  912. if(ui->VfrCheckBox->isChecked()){
  913. ui->vfrTimeLineEdit->setText(blockTime);
  914. ui->ifrTimeLineEdit->setText("");
  915. }
  916. // Night
  917. QString deptDate = date.toString(Qt::ISODate) + 'T' + tofb.toString("hh:mm");
  918. QDateTime deptDateTime = QDateTime::fromString(deptDate,"yyyy-MM-ddThh:mm");
  919. int tblk = calc::time_to_minutes(calc::blocktime(tofb,tonb));
  920. QString nightTime = calc::minutes_to_string(
  921. QString::number(
  922. calc::calculateNightTime(
  923. dept, dest, deptDateTime, tblk)));
  924. ui->nightTimeLineEdit->setText(nightTime);
  925. // XC - Cross-country flight, if more than 50nm long
  926. if(calc::greatCircleDistanceBetweenAirports(dept,dest) >= 50){
  927. qDebug() << "Cross-country Flight: nm = " << calc::greatCircleDistanceBetweenAirports(dept,dest);
  928. ui->xcTimeLineEdit->setText(blockTime);
  929. }else{ui->xcTimeLineEdit->setText("00:00");}
  930. // Function times
  931. switch (ui->FunctionComboBox->currentIndex()) {
  932. case 0://PIC
  933. ui->picTimeLineEdit->setText(blockTime);
  934. ui->copTimeLineEdit->setText("");
  935. ui->dualTimeLineEdit->setText("");
  936. ui->fiTimeLineEdit->setText("");
  937. break;
  938. case 1://Co-Pilot
  939. ui->picTimeLineEdit->setText("");
  940. ui->copTimeLineEdit->setText(blockTime);
  941. ui->dualTimeLineEdit->setText("");
  942. ui->fiTimeLineEdit->setText("");
  943. break;
  944. case 2://Dual
  945. ui->picTimeLineEdit->setText("");
  946. ui->copTimeLineEdit->setText("");
  947. ui->dualTimeLineEdit->setText(blockTime);
  948. ui->fiTimeLineEdit->setText("");
  949. break;
  950. case 3://Instructor
  951. ui->picTimeLineEdit->setText("");
  952. ui->copTimeLineEdit->setText("");
  953. ui->dualTimeLineEdit->setText("");
  954. ui->fiTimeLineEdit->setText(blockTime);
  955. }
  956. // SIM
  957. }
  958. /*!
  959. * \brief In case the user wants to manually edit the extra times
  960. * he can do so in this tab.
  961. */
  962. void NewFlight::on_tabWidget_currentChanged(int index)
  963. {
  964. if(index == 1){// Edit Details tab
  965. if(verifyInput()){
  966. fillExtrasLineEdits();
  967. }else{
  968. auto errorbox = new QMessageBox;
  969. errorbox->setText("Invalid Inputs. Unable to determine times automatically.\nPlease verify your inputs.");
  970. errorbox->exec();
  971. }
  972. }
  973. }