123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723 |
- /*
- *openPilotLog - A FOSS Pilot Logbook Application
- *Copyright (C) 2020-2022 Felix Turowsky
- *
- *This program is free software: you can redistribute it and/or modify
- *it under the terms of the GNU General Public License as published by
- *the Free Software Foundation, either version 3 of the License, or
- *(at your option) any later version.
- *
- *This program is distributed in the hope that it will be useful,
- *but WITHOUT ANY WARRANTY; without even the implied warranty of
- *MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- *GNU General Public License for more details.
- *
- *You should have received a copy of the GNU General Public License
- *along with this program. If not, see <https://www.gnu.org/licenses/>.
- */
- #include "newflightdialog.h"
- #include "src/classes/time.h"
- #include "src/database/databasecache.h"
- #include "src/gui/verification/airportinput.h"
- #include "src/gui/verification/completerprovider.h"
- #include "src/gui/verification/pilotinput.h"
- #include "src/gui/verification/tailinput.h"
- #include "src/gui/verification/timeinput.h"
- #include "ui_newflightdialog.h"
- #include "src/opl.h"
- #include "src/functions/datetime.h"
- #include "src/classes/settings.h"
- #include "src/functions/calc.h"
- #include "src/gui/dialogues/newtaildialog.h"
- #include "src/gui/dialogues/newpilotdialog.h"
- #include <QDateTime>
- #include <QCompleter>
- #include <QKeyEvent>
- NewFlightDialog::NewFlightDialog(QWidget *parent)
- : QDialog(parent),
- ui(new Ui::NewFlightDialog)
- {
- init();
- // Set up UI (New Flight)
- LOG << Settings::read(Settings::FlightLogging::Function);
- if(Settings::read(Settings::FlightLogging::Function).toInt() == static_cast<int>(OPL::PilotFunction::PIC)){
- ui->picNameLineEdit->setText(self);
- ui->functionComboBox->setCurrentIndex(0);
- emit ui->picNameLineEdit->editingFinished();
- }
- if (Settings::read(Settings::FlightLogging::Function).toInt() == static_cast<int>(OPL::PilotFunction::SIC)) {
- ui->sicNameLineEdit->setText(self);
- ui->functionComboBox->setCurrentIndex(2);
- emit ui->sicNameLineEdit->editingFinished();
- }
- ui->doftLineEdit->setText(OPL::DateTime::currentDate());
- emit ui->doftLineEdit->editingFinished();
- }
- NewFlightDialog::NewFlightDialog(int row_id, QWidget *parent)
- : QDialog(parent),
- ui(new Ui::NewFlightDialog)
- {
- init();
- flightEntry = DB->getFlightEntry(row_id);
- fillWithEntryData();
- }
- NewFlightDialog::~NewFlightDialog()
- {
- delete ui;
- }
- void NewFlightDialog::init()
- {
- // Setup UI
- ui->setupUi(this);
- // Initialise line edit lists
- auto time_line_edits = new QList<QLineEdit*>{ui->tofbTimeLineEdit, ui->tonbTimeLineEdit};
- timeLineEdits = time_line_edits;
- auto location_line_edits = new QList<QLineEdit*>{ui->deptLocationLineEdit, ui->destLocationLineEdit};
- locationLineEdits = location_line_edits;
- auto pilot_name_line_edits = new QList<QLineEdit*>{ui->picNameLineEdit, ui->sicNameLineEdit, ui->thirdPilotNameLineEdit};
- pilotNameLineEdits = pilot_name_line_edits;
- auto mandatory_line_edits = new QList<QLineEdit*>{ui->doftLineEdit, ui->deptLocationLineEdit, ui->destLocationLineEdit,
- ui->tofbTimeLineEdit, ui->tonbTimeLineEdit,
- ui->picNameLineEdit, ui->acftLineEdit};
- // {doft = 0, dept = 1, dest = 2, tofb = 3, tonb = 4, pic = 5, acft = 6}
- mandatoryLineEdits = mandatory_line_edits;
- for (const auto& line_edit : *mandatoryLineEdits)
- line_edit->installEventFilter(this);
- // Approach Combo Box and Function Combo Box
- OPL::GLOBALS->loadApproachTypes(ui->approachComboBox);
- OPL::GLOBALS->loadPilotFunctios(ui->functionComboBox);
- setupRawInputValidation();
- setupSignalsAndSlots();
- readSettings();
- }
- /*!
- * \brief NewFlightDialog::setupRawInputValidation outfits the line edits with QRegularExpresionValidators and QCompleters
- */
- void NewFlightDialog::setupRawInputValidation()
- {
- // Time Line Edits
- for (const auto& line_edit : *timeLineEdits) {
- auto validator = new QRegularExpressionValidator(QRegularExpression("([01]?[0-9]|2[0-3]):?[0-5][0-9]?"), line_edit);
- line_edit->setValidator(validator);
- }
- // Location Line Edits
- for (const auto& line_edit : *locationLineEdits) {
- auto validator = new QRegularExpressionValidator(QRegularExpression("[a-zA-Z0-9]{1,4}"), line_edit);
- line_edit->setValidator(validator);
- line_edit->setCompleter(QCompleterProvider.getCompleter(CompleterProvider::Airports));
- }
- // Name Line Edits
- for (const auto& line_edit : *pilotNameLineEdits) {
- line_edit->setCompleter(QCompleterProvider.getCompleter(CompleterProvider::Pilots));
- }
- // Acft Line Edit
- ui->acftLineEdit->setCompleter(QCompleterProvider.getCompleter(CompleterProvider::Tails));
- }
- void NewFlightDialog::setupSignalsAndSlots()
- {
- for (const auto& line_edit : *timeLineEdits)
- QObject::connect(line_edit, &QLineEdit::editingFinished,
- this, &NewFlightDialog::onTimeLineEdit_editingFinished);
- // Change text to upper case for location and acft line edits
- QObject::connect(ui->acftLineEdit, &QLineEdit::textChanged,
- this, &NewFlightDialog::toUpper);
- for (const auto& line_edit : *locationLineEdits) {
- QObject::connect(line_edit, &QLineEdit::textChanged,
- this, &NewFlightDialog::toUpper);
- QObject::connect(line_edit, &QLineEdit::editingFinished,
- this, &NewFlightDialog::onLocationLineEdit_editingFinished);
- }
- for (const auto& line_edit : *pilotNameLineEdits)
- QObject::connect(line_edit, &QLineEdit::editingFinished,
- this, &NewFlightDialog::onPilotNameLineEdit_editingFinshed);
- }
- /*!
- * \brief NewFlightDialog::eventFilter invalidates mandatory line edits on focus in.
- * \details Some of the QLineEdits have validators set that provide raw input validation. These validators have the side effect
- * that if an input does not meet the raw input validation criteria, onEditingFinished() is not emitted when the line edit loses
- * focus. This could lead to a line edit that previously had good input to be changed to bad input without the validation bit
- * in validationState being unset, because the second step of input validation is only triggered when editingFinished() is emitted.
- */
- bool NewFlightDialog::eventFilter(QObject *object, QEvent *event)
- {
- auto line_edit = qobject_cast<QLineEdit*>(object);
- if (line_edit != nullptr) {
- if (mandatoryLineEdits->contains(line_edit) && event->type() == QEvent::FocusIn) {
- // set verification bit to false when entering a mandatory line edit
- validationState.invalidate(mandatoryLineEdits->indexOf(line_edit));
- return false;
- }
- }
- return false;
- }
- /*!
- * \brief NewFlightDialog::readSettings Reads user-defined settings from an INI file.
- */
- void NewFlightDialog::readSettings()
- {
- ui->functionComboBox->setCurrentIndex(Settings::read(Settings::FlightLogging::Function).toInt());
- ui->approachComboBox->setCurrentIndex(Settings::read(Settings::FlightLogging::Approach).toInt());
- ui->pilotFlyingCheckBox->setChecked(Settings::read(Settings::FlightLogging::PilotFlying).toBool());
- ui->ifrCheckBox->setChecked(Settings::read(Settings::FlightLogging::LogIFR).toBool());
- ui->flightNumberLineEdit->setText(Settings::read(Settings::FlightLogging::FlightNumberPrefix).toString());
- }
- /*!
- * \brief NewFlightDialog::fillWithEntryData Takes an existing flight entry and fills the UI with its data
- * to enable editing an existing flight.
- */
- void NewFlightDialog::fillWithEntryData()
- {
- DEB << "Restoring Flight: ";
- DEB << flightEntry;
- const auto &flight_data = flightEntry.getData();
- // Date of Flight
- ui->doftLineEdit->setText(flight_data.value(OPL::Db::FLIGHTS_DOFT).toString());
- // Location
- ui->deptLocationLineEdit->setText(flight_data.value(OPL::Db::FLIGHTS_DEPT).toString());
- ui->destLocationLineEdit->setText(flight_data.value(OPL::Db::FLIGHTS_DEST).toString());
- // Times
- ui->tofbTimeLineEdit->setText(OPL::Time(flight_data.value(OPL::Db::FLIGHTS_TOFB).toInt()).toString());
- ui->tonbTimeLineEdit->setText(OPL::Time(flight_data.value(OPL::Db::FLIGHTS_TONB).toInt()).toString());
- ui->acftLineEdit->setText(DBCache->getTailsMap().value(flight_data.value(OPL::Db::FLIGHTS_ACFT).toInt()));
- ui->picNameLineEdit->setText(DBCache->getPilotNamesMap().value(flight_data.value(OPL::Db::FLIGHTS_PIC).toInt()));
- ui->sicNameLineEdit->setText(DBCache->getPilotNamesMap().value(flight_data.value(OPL::Db::FLIGHTS_SECONDPILOT).toInt()));
- ui->thirdPilotNameLineEdit->setText(DBCache->getPilotNamesMap().value(flight_data.value(OPL::Db::FLIGHTS_THIRDPILOT).toInt()));
- //Function
- const QHash<int, QString> functions = {
- {0, OPL::Db::FLIGHTS_TPIC},
- {1, OPL::Db::FLIGHTS_TPICUS},
- {2, OPL::Db::FLIGHTS_TSIC},
- {3, OPL::Db::FLIGHTS_TDUAL},
- {4, OPL::Db::FLIGHTS_TFI},
- };
- for (int i = 0; i < 5; i++) { // QHash::iterator not guarenteed to be in ordetr
- if(flight_data.value(functions.value(i)).toInt() != 0)
- ui->functionComboBox->setCurrentIndex(i);
- }
- // Approach ComboBox
- const QString& app = flight_data.value(OPL::Db::FLIGHTS_APPROACHTYPE).toString();
- if(app != QString()){
- ui->approachComboBox->setCurrentText(app);
- }
- // Task
- bool PF = flight_data.value(OPL::Db::FLIGHTS_PILOTFLYING).toBool();
- ui->pilotFlyingCheckBox->setChecked(PF);
- // Flight Rules
- bool time_ifr = flight_data.value(OPL::Db::FLIGHTS_TIFR).toBool();
- ui->ifrCheckBox->setChecked(time_ifr);
- // Take-Off and Landing
- int TO = flight_data.value(OPL::Db::FLIGHTS_TODAY).toInt()
- + flight_data.value(OPL::Db::FLIGHTS_TONIGHT).toInt();
- int LDG = flight_data.value(OPL::Db::FLIGHTS_LDGDAY).toInt()
- + flight_data.value(OPL::Db::FLIGHTS_LDGNIGHT).toInt();
- ui->takeOffSpinBox->setValue(TO);
- ui->landingSpinBox->setValue(LDG);
- // Remarks
- ui->remarksLineEdit->setText(flight_data.value(OPL::Db::FLIGHTS_REMARKS).toString());
- // Flight Number
- ui->flightNumberLineEdit->setText(flight_data.value(OPL::Db::FLIGHTS_FLIGHTNUMBER).toString());
- for(const auto &line_edit : *mandatoryLineEdits)
- emit line_edit->editingFinished();
- }
- bool NewFlightDialog::verifyUserInput(QLineEdit *line_edit, const UserInput &input)
- {
- DEB << "Verifying user input: " << line_edit->text();
- if(!input.isValid()) {
- QString fixed = input.fixup();
- if(fixed == QString()) {
- onBadInputReceived(line_edit);
- return false;
- } else {
- line_edit->setText(fixed);
- onGoodInputReceived(line_edit);
- return true;
- }
- }
- onGoodInputReceived(line_edit);
- return true;
- }
- void NewFlightDialog::onGoodInputReceived(QLineEdit *line_edit)
- {
- DEB << line_edit->objectName() << " - Good input received - " << line_edit->text();
- line_edit->setStyleSheet(QString());
- if (mandatoryLineEdits->contains(line_edit))
- validationState.validate(mandatoryLineEdits->indexOf(line_edit));
- if (validationState.timesValid()) {
- updateBlockTimeLabel();
- if (validationState.nightDataValid())
- updateNightCheckBoxes();
- }
- }
- void NewFlightDialog::onBadInputReceived(QLineEdit *line_edit)
- {
- DEB << line_edit->objectName() << " - Bad input received - " << line_edit->text();
- line_edit->setStyleSheet(OPL::Styles::RED_BORDER);
- line_edit->setText(QString());
- if (mandatoryLineEdits->contains(line_edit))
- validationState.invalidate(mandatoryLineEdits->indexOf(line_edit));
- validationState.printValidationStatus();
- }
- void NewFlightDialog::updateBlockTimeLabel()
- {
- const OPL::Time tofb = OPL::Time::fromString(ui->tofbTimeLineEdit->text());
- const OPL::Time tonb = OPL::Time::fromString(ui->tonbTimeLineEdit->text());
- const OPL::Time tblk = OPL::Time::blockTime(tofb, tonb);
- ui->tblkDisplayLabel->setText(tblk.toString());
- }
- /*!
- * \brief NewFlightDialog::addNewTail If the user input is not in the aircraftList, the user
- * is prompted if he wants to add a new entry to the database
- */
- bool NewFlightDialog::addNewTail(QLineEdit& parent_line_edit)
- {
- QMessageBox::StandardButton reply;
- reply = QMessageBox::question(this, tr("No Aircraft found"),
- tr("No aircraft with this registration found.<br>"
- "If this is the first time you log a flight with this aircraft, "
- "you have to add the registration to the database first."
- "<br><br>Would you like to add a new aircraft to the database?"),
- QMessageBox::Yes|QMessageBox::No);
- if (reply == QMessageBox::Yes) {
- // create and open new aircraft dialog
- NewTailDialog nt(ui->acftLineEdit->text(), this);
- int ret = nt.exec();
- // update map and list, set line edit
- if (ret == QDialog::Accepted) {
- DEB << "New Tail Entry added:";
- DEB << DB->getTailEntry(DB->getLastEntry(OPL::DbTable::Tails));
- // update Line Edit with newly added tail
- parent_line_edit.setText(DBCache->getTailsMap().value(DB->getLastEntry(OPL::DbTable::Tails)));
- emit parent_line_edit.editingFinished();
- return true;
- } else {
- return false;
- }
- } else {
- return false;
- }
- }
- /*!
- * \brief NewFlightDialog::addNewPilot If the user input is not in the pilotNameList, the user
- * is prompted if he wants to add a new entry to the database
- */
- bool NewFlightDialog::addNewPilot(QLineEdit& parent_line_edit)
- {
- QMessageBox::StandardButton reply;
- reply = QMessageBox::question(this, tr("No Pilot found"),
- tr("No pilot found.<br>Please enter the Name as"
- "<br><br><center><b>Lastname, Firstname</b></center><br><br>"
- "If this is the first time you log a flight with this pilot, "
- "you have to add the pilot to the database first."
- "<br><br>Would you like to add a new pilot to the database?"),
- QMessageBox::Yes|QMessageBox::No);
- if (reply == QMessageBox::Yes) {
- // create and open new pilot dialog
- NewPilotDialog np(this);
- int ret = np.exec();
- // update map and list, set line edit
- if (ret == QDialog::Accepted) {
- DEB << "New Pilot Entry added:";
- DEB << DB->getPilotEntry(DB->getLastEntry(OPL::DbTable::Pilots));
- // update Line Edit with newly added pilot
- parent_line_edit.setText(DBCache->getPilotNamesMap().value(DB->getLastEntry(OPL::DbTable::Pilots)));
- emit parent_line_edit.editingFinished();
- return true;
- } else {
- return false;
- }
- } else
- return false;
- }
- /*!
- * \brief NewFlightDialog::prepareFlightEntryData reads the user input from the UI and converts it into
- * the database format.
- * \return OPL::RowData_T a map containing a row ready for database submission
- */
- OPL::RowData_T NewFlightDialog::prepareFlightEntryData()
- {
- if(!validationState.allValid())
- return {};
- // prepare the entry data
- OPL::RowData_T new_data;
- // Calculate Block and Night Time
- const OPL::Time tofb = OPL::Time::fromString(ui->tofbTimeLineEdit->text());
- const OPL::Time tonb = OPL::Time::fromString(ui->tonbTimeLineEdit->text());
- const int block_minutes = OPL::Time::blockMinutes(tofb, tonb);
- QDateTime departure_date_time = OPL::DateTime::fromString(ui->doftLineEdit->text() + ui->tofbTimeLineEdit->text());
- const auto night_time_data = OPL::Calc::NightTimeValues(ui->deptLocationLineEdit->text(), ui->destLocationLineEdit->text(),
- departure_date_time, block_minutes, Settings::read(Settings::FlightLogging::NightAngle).toInt());
- // Mandatory data
- new_data.insert(OPL::Db::FLIGHTS_DOFT, ui->doftLineEdit->text());
- new_data.insert(OPL::Db::FLIGHTS_DEPT, ui->deptLocationLineEdit->text());
- new_data.insert(OPL::Db::FLIGHTS_TOFB, tofb.toMinutes());
- new_data.insert(OPL::Db::FLIGHTS_DEST, ui->destLocationLineEdit->text());
- new_data.insert(OPL::Db::FLIGHTS_TONB, tonb.toMinutes());
- new_data.insert(OPL::Db::FLIGHTS_TBLK, block_minutes);
- // Night
- new_data.insert(OPL::Db::FLIGHTS_TNIGHT, night_time_data.nightMinutes);
- // Aircraft
- int acft_id = DBCache->getTailsMap().key(ui->acftLineEdit->text());
- new_data.insert(OPL::Db::FLIGHTS_ACFT, acft_id);
- const OPL::TailEntry acft_data = DB->getTailEntry(acft_id);
- bool multi_pilot = acft_data.getData().value(OPL::Db::TAILS_MULTIPILOT).toBool();
- bool multi_engine = acft_data.getData().value(OPL::Db::TAILS_MULTIENGINE).toBool();
- if (multi_pilot) {
- new_data.insert(OPL::Db::FLIGHTS_TMP, block_minutes);
- new_data.insert(OPL::Db::FLIGHTS_TSPSE, QString());
- new_data.insert(OPL::Db::FLIGHTS_TSPME, QString());
- } else if (!multi_pilot && !multi_engine) {
- new_data.insert(OPL::Db::FLIGHTS_TMP, QString());
- new_data.insert(OPL::Db::FLIGHTS_TSPSE, block_minutes);
- new_data.insert(OPL::Db::FLIGHTS_TSPME, QString());
- } else if (!multi_pilot && multi_engine) {
- new_data.insert(OPL::Db::FLIGHTS_TMP, QString());
- new_data.insert(OPL::Db::FLIGHTS_TSPSE, QString());
- new_data.insert(OPL::Db::FLIGHTS_TSPME, block_minutes);
- }
- // Pilots
- new_data.insert(OPL::Db::FLIGHTS_PIC, DBCache->getPilotNamesMap().key(ui->picNameLineEdit->text()));
- new_data.insert(OPL::Db::FLIGHTS_SECONDPILOT, DBCache->getPilotNamesMap().key(ui->sicNameLineEdit->text()));
- new_data.insert(OPL::Db::FLIGHTS_THIRDPILOT, DBCache->getPilotNamesMap().key(ui->thirdPilotNameLineEdit->text()));
- // IFR time
- if (ui->ifrCheckBox->isChecked()) {
- new_data.insert(OPL::Db::FLIGHTS_TIFR, block_minutes);
- } else {
- new_data.insert(OPL::Db::FLIGHTS_TIFR, QString());
- }
- // Function Times
- QStringList function_times = {
- OPL::Db::FLIGHTS_TPIC,
- OPL::Db::FLIGHTS_TPICUS,
- OPL::Db::FLIGHTS_TSIC,
- OPL::Db::FLIGHTS_TDUAL,
- OPL::Db::FLIGHTS_TFI,
- };
- // Determine function times, zero out all values except one (use QString() iso 0 for correct handling of NULL in DB
- // Log Instructor Time as PIC time as well
- const int& function_index = ui->functionComboBox->currentIndex();
- switch (function_index) {
- case 4:
- LOG << "Function FI";
- for (int i = 0; i < 5; i++){
- if(i == 0 || i == 4)
- new_data.insert(function_times[i], block_minutes);
- else
- new_data.insert(function_times[i], QString());
- }
- break;
- default:
- for (int i = 0; i < 5; i++){
- if(i == function_index)
- new_data.insert(function_times[i], block_minutes);
- else
- new_data.insert(function_times[i], QString());
- }
- break;
- }
- // Pilot flying / Pilot monitoring
- new_data.insert(OPL::Db::FLIGHTS_PILOTFLYING, ui->pilotFlyingCheckBox->isChecked());
- // Take-Off and Landing
- if (ui->toNightCheckBox->isChecked()) {
- new_data.insert(OPL::Db::FLIGHTS_TONIGHT, ui->takeOffSpinBox->value());
- new_data.insert(OPL::Db::FLIGHTS_TODAY, 0);
- } else {
- new_data.insert(OPL::Db::FLIGHTS_TONIGHT, 0);
- new_data.insert(OPL::Db::FLIGHTS_TODAY, ui->takeOffSpinBox->value());
- }
- if (ui->ldgNightCheckBox->isChecked()) {
- new_data.insert(OPL::Db::FLIGHTS_LDGNIGHT, ui->landingSpinBox->value());
- new_data.insert(OPL::Db::FLIGHTS_LDGDAY, 0);
- } else {
- new_data.insert(OPL::Db::FLIGHTS_LDGNIGHT, 0);
- new_data.insert(OPL::Db::FLIGHTS_LDGDAY, ui->landingSpinBox->value());
- }
- if (ui->approachComboBox->currentText() == CAT_3) // ILS CAT III
- new_data.insert(OPL::Db::FLIGHTS_AUTOLAND, ui->landingSpinBox->value());
- // Additional Data
- new_data.insert(OPL::Db::FLIGHTS_APPROACHTYPE, ui->approachComboBox->currentText());
- new_data.insert(OPL::Db::FLIGHTS_FLIGHTNUMBER, ui->flightNumberLineEdit->text());
- new_data.insert(OPL::Db::FLIGHTS_REMARKS, ui->remarksLineEdit->text());
- return new_data;
- }
- /*!
- * \brief NewFlightDialog::updateNightCheckBoxes updates the check boxes for take-off and landing
- * at night. Returns the number of minutes of night time.
- * \return
- */
- void NewFlightDialog::updateNightCheckBoxes()
- {
- // calculate Block Time
- const OPL::Time tofb = OPL::Time::fromString(ui->tofbTimeLineEdit->text());
- const OPL::Time tonb = OPL::Time::fromString(ui->tonbTimeLineEdit->text());
- const int block_minutes = OPL::Time::blockMinutes(tofb, tonb);
- // Calculate Night Time
- const QString dept_date = (ui->doftLineEdit->text() + ui->tofbTimeLineEdit->text());
- const auto dept_date_time = OPL::DateTime::fromString(dept_date);
- const int night_angle = Settings::read(Settings::FlightLogging::NightAngle).toInt();
- const auto night_values = OPL::Calc::NightTimeValues(
- ui->deptLocationLineEdit->text(),
- ui->destLocationLineEdit->text(),
- dept_date_time,
- block_minutes,
- night_angle);
- // set check boxes
- if (night_values.takeOffNight)
- ui->toNightCheckBox->setCheckState(Qt::Checked);
- else
- ui->toNightCheckBox->setCheckState(Qt::Unchecked);
- if (night_values.landingNight)
- ui->ldgNightCheckBox->setCheckState(Qt::Checked);
- else
- ui->ldgNightCheckBox->setCheckState(Qt::Unchecked);
- }
- /*!
- * \brief NewFlightDialog::toUpper - changes inserted text to upper case for IATA/ICAO airport codes and registrations.
- */
- void NewFlightDialog::toUpper(const QString &text)
- {
- const auto line_edit = this->findChild<QLineEdit*>(sender()->objectName());
- {
- const QSignalBlocker blocker(line_edit);
- line_edit->setText(text.toUpper());
- }
- }
- void NewFlightDialog::onTimeLineEdit_editingFinished()
- {
- auto line_edit = this->findChild<QLineEdit*>(sender()->objectName());
- verifyUserInput(line_edit, TimeInput(line_edit->text()));
- }
- void NewFlightDialog::onPilotNameLineEdit_editingFinshed()
- {
- auto line_edit = this->findChild<QLineEdit*>(sender()->objectName());
- if(!verifyUserInput(line_edit, PilotInput(line_edit->text()))) {
- if(!addNewPilot(*line_edit))
- onBadInputReceived(line_edit);
- }
- }
- void NewFlightDialog::onLocationLineEdit_editingFinished()
- {
- const QString& line_edit_name = sender()->objectName();
- const auto line_edit = this->findChild<QLineEdit*>(line_edit_name);
- QLabel* name_label;
- if (line_edit_name.contains(QLatin1String("dept")))
- name_label = ui->deptNameLabel;
- else
- name_label = ui->destNameLabel;
- if(verifyUserInput(line_edit, AirportInput(line_edit->text())) ) {
- // Match ICAO code with Airport Name and display on label
- name_label->setText(DBCache->getAirportsMapNames().value(
- DBCache->getAirportsMapICAO().key(
- line_edit->text())));
- } else
- name_label->setText("Unknown Airport");
- }
- void NewFlightDialog::on_acftLineEdit_editingFinished()
- {
- const auto line_edit = ui->acftLineEdit;
- if(!verifyUserInput(line_edit, TailInput(line_edit->text())))
- if(!addNewTail(*line_edit))
- onBadInputReceived(line_edit);
- const auto space = QLatin1Char(' ');
- if(line_edit->text().contains(space))
- line_edit->setText(line_edit->text().split(space)[0]); // strip out autocomplete suggestion
- }
- void NewFlightDialog::on_doftLineEdit_editingFinished()
- {
- const auto line_edit = ui->doftLineEdit;
- auto text = ui->doftLineEdit->text();
- auto label = ui->doftDisplayLabel;
- TODO << "Non-default Date formats not implemented yet.";
- OPL::DateFormat date_format = OPL::DateFormat::ISODate;
- auto date = OPL::DateTime::parseInput(text, date_format);
- if (date.isValid()) {
- label->setText(date.toString(Qt::TextDate));
- line_edit->setText(OPL::DateTime::dateToString(date, date_format));
- onGoodInputReceived(line_edit);
- return;
- }
- label->setText(tr("Invalid Date."));
- onBadInputReceived(line_edit);
- }
- void NewFlightDialog::on_pilotFlyingCheckBox_stateChanged(int arg1)
- {
- if (arg1 == Qt::CheckState::Checked) {
- ui->takeOffSpinBox->setValue(1);
- ui->landingSpinBox->setValue(1);
- } else {
- ui->takeOffSpinBox->setValue(0);
- ui->landingSpinBox->setValue(0);
- }
- }
- void NewFlightDialog::on_approachComboBox_currentTextChanged(const QString &arg1)
- {
- if (arg1 == CAT_3)
- ui->remarksLineEdit->setText(QStringLiteral("Autoland"));
- else if (arg1 == QLatin1String("OTHER"))
- INFO(tr("Please specify the approach type in the remarks field."));
- }
- /*!
- * \brief NewFlightDialog::on_functionComboBox_currentIndexChanged
- * If the Function Combo Box is selected to be either PIC or SIC, fill the corresponding
- * nameLineEdit with the logbook owner's name, then check for duplication.
- */
- void NewFlightDialog::on_functionComboBox_currentIndexChanged(int index)
- {
- if (index == static_cast<int>(OPL::PilotFunction::PIC)) {
- ui->picNameLineEdit->setText(self);
- emit ui->picNameLineEdit->editingFinished();
- if (DBCache->getPilotNamesMap().key(ui->picNameLineEdit->text())
- == DBCache->getPilotNamesMap().key(ui->sicNameLineEdit->text()))
- ui->sicNameLineEdit->setText(QString());
- } else if (index == static_cast<int>(OPL::PilotFunction::SIC)) {
- ui->sicNameLineEdit->setText(self);
- emit ui->sicNameLineEdit->editingFinished();
- if (DBCache->getPilotNamesMap().key(ui->picNameLineEdit->text())
- == DBCache->getPilotNamesMap().key(ui->sicNameLineEdit->text()))
- ui->picNameLineEdit->setText(QString());
- }
- }
- /*!
- * \brief NewFlightDialog::checkPilotFunctionsValid checks if there are incompatible selections made on Pilot Function.
- * \details Checks for 2 cases in which there might be a discrepancy between the PilotNameLineEdit and the functionComboBox:
- * - If the pilotNameLineEdit's value is self, but the functionComboBox has been manually selected to be different from either
- * PIC or FI
- * - If the functionComboBox has been set to PIC but the pilotNameLineEdit is not self
- * \param error_msg - the error string displayed to the user
- * \return
- */
- bool NewFlightDialog::checkPilotFunctionsValid()
- {
- int pic_id = DBCache->getPilotNamesMap().key(ui->picNameLineEdit->text());
- int function_index = ui->functionComboBox->currentIndex();
- if (pic_id == 1) {
- if (!(function_index == static_cast<int>(OPL::PilotFunction::PIC) || function_index == static_cast<int>(OPL::PilotFunction::FI))) {
- INFO(tr("The PIC is set to %1 but the Pilot Function is set to %2")
- .arg(ui->picNameLineEdit->text(), ui->functionComboBox->currentText()));
- return false;
- }
- } else {
- if (function_index == static_cast<int>(OPL::PilotFunction::PIC) || function_index == static_cast<int>(OPL::PilotFunction::FI)) {
- INFO(tr("The Pilot Function is set to %1, but the PIC is set to %2")
- .arg(ui->functionComboBox->currentText(), ui->picNameLineEdit->text()));
- return false;
- }
- }
- return true;
- }
- /*!
- * \brief NewFlightDialog::on_buttonBox_accepted - checks for validity and commits the form data to the database
- * \details When the user is ready to submit a flight entry, a final check for valid entries is made, and the user
- * is prompted to correct unsatisfactory inputs. When this is done, prepareFlightEntryData() collects the input from
- * the user interface and converts it to database format. The data is then stored in a QHash<QString, QVariant>.
- * This data is then used to create a AFlightEntry object, which is then commited to the database by Database::commit()
- */
- void NewFlightDialog::on_buttonBox_accepted()
- {
- // Debug
- validationState.printValidationStatus();
- for (const auto& le : *mandatoryLineEdits)
- emit le->editingFinished();
- // If input verification is passed, continue, otherwise prompt user to correct
- if (!validationState.allValid()) {
- const auto display_names = QHash<ValidationState::ValidationItem, QString> {
- {ValidationState::ValidationItem::doft, QObject::tr("Date of Flight")}, {ValidationState::ValidationItem::dept, QObject::tr("Departure Airport")},
- {ValidationState::ValidationItem::dest, QObject::tr("Destination Airport")}, {ValidationState::ValidationItem::tofb, QObject::tr("Time Off Blocks")},
- {ValidationState::ValidationItem::tonb, QObject::tr("Time on Blocks")}, {ValidationState::ValidationItem::pic, QObject::tr("PIC Name")},
- {ValidationState::ValidationItem::acft, QObject::tr("Aircraft Registration")}
- };
- QString missing_items;
- for (int i=0; i < mandatoryLineEdits->size(); i++) {
- if (!validationState.validAt(i)){
- missing_items.append(display_names.value(static_cast<ValidationState::ValidationItem>(i)) + "<br>");
- mandatoryLineEdits->at(i)->setStyleSheet(QStringLiteral("border: 1px solid red"));
- }
- }
- INFO(tr("Not all mandatory entries are valid.<br>"
- "The following item(s) are empty or invalid:"
- "<br><br><center><b>%1</b></center><br>"
- "Please go back and fill in the required data."
- ).arg(missing_items));
- return;
- }
- if(!checkPilotFunctionsValid())
- return;
- // If input verification passed, collect input and submit to database
- const auto newData = prepareFlightEntryData();
- DEB << "Old Data: ";
- DEB << flightEntry;
- flightEntry.setData(newData);
- DEB << "Committing: ";
- DEB << flightEntry;
- if (!DB->commit(flightEntry)) {
- WARN(tr("The following error has ocurred:"
- "<br><br>%1<br><br>"
- "The entry has not been saved."
- ).arg(DB->lastError.text()));
- return;
- } else {
- QDialog::accept();
- }
- }
|