123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840 |
- /*
- *openPilotLog - A FOSS Pilot Logbook Application
- *Copyright (C) 2020-2023 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 "QtWidgets/qcalendarwidget.h"
- #include "src/classes/time.h"
- #include "src/database/database.h"
- #include "src/database/databasecache.h"
- #include "src/gui/dialogues/newairportdialog.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/classes/date.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)
- : EntryEditDialog(parent),
- ui(new Ui::NewFlightDialog)
- {
- init();
- setPilotFunction();
- ui->doftLineEdit->setText(OPL::Date::today(m_format).toString());
- emit ui->doftLineEdit->editingFinished();
- }
- NewFlightDialog::NewFlightDialog(int row_id, QWidget *parent)
- : EntryEditDialog(parent),
- ui(new Ui::NewFlightDialog)
- {
- init();
- flightEntry = DB->getFlightEntry(row_id);
- fillWithEntryData();
- }
- NewFlightDialog::~NewFlightDialog()
- {
- delete ui;
- }
- void NewFlightDialog::setPilotFunction()
- {
- const QString &self = DBCache->getPilotNamesMap().value(1);
- if(Settings::getPilotFunction() == OPL::PilotFunction::PIC){
- ui->picNameLineEdit->setText(self);
- ui->functionComboBox->setCurrentIndex(0);
- }
- if (Settings::getPilotFunction() == OPL::PilotFunction::SIC) {
- ui->sicNameLineEdit->setText(self);
- ui->functionComboBox->setCurrentIndex(2);
- }
- ui->pilotFlyingCheckBox->setCheckState(Qt::Checked);
- }
- 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);
- // allocate a widget for date selection
- calendar = new QCalendarWidget(this);
- calendar->setVisible(false);
- calendar->setWindowFlags(Qt::Dialog); // pop-up calendar
- 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) {
- const auto validator = new QRegularExpressionValidator(OPL::RegEx::RX_TIME_ENTRY, line_edit);
- line_edit->setValidator(validator);
- }
- // Location Line Edits
- for (const auto& line_edit : *locationLineEdits) {
- const auto validator = new QRegularExpressionValidator(OPL::RegEx::RX_AIRPORT_CODE, 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);
- QObject::connect(calendar, &QCalendarWidget::selectionChanged,
- this, &NewFlightDialog::calendarDateSelected);
- QObject::connect(calendar, &QCalendarWidget::clicked,
- this, &NewFlightDialog::calendarDateSelected);
- }
- /*!
- * \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(static_cast<int>(Settings::getPilotFunction()));
- ui->approachComboBox->setCurrentText(Settings::getApproachType());
- ui->flightRulesComboBox->setCurrentIndex(Settings::getLogIfr());
- ui->flightNumberLineEdit->setText(Settings::getFlightNumberPrefix());
- m_format = Settings::getDisplayFormat();
- }
- /*!
- * \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;
- using namespace OPL;
- const auto &flight_data = flightEntry.getData();
- // Date of Flight
- const QDate date = QDate::fromJulianDay(flight_data.value(FlightEntry::DOFT).toInt());
- calendar->setSelectedDate(date);
- ui->doftLineEdit->setText(Date(date, m_format).toString());
- // Location
- ui->deptLocationLineEdit->setText(flight_data.value(OPL::FlightEntry::DEPT).toString());
- ui->destLocationLineEdit->setText(flight_data.value(OPL::FlightEntry::DEST).toString());
- // Times
- ui->tofbTimeLineEdit->setText(OPL::Time(flight_data.value(OPL::FlightEntry::TOFB).toInt(), m_format).toString());
- ui->tonbTimeLineEdit->setText(OPL::Time(flight_data.value(OPL::FlightEntry::TONB).toInt(), m_format).toString());
- ui->acftLineEdit->setText(DBCache->getTailsMap().value(flight_data.value(OPL::FlightEntry::ACFT).toInt()));
- ui->picNameLineEdit->setText(DBCache->getPilotNamesMap().value(flight_data.value(OPL::FlightEntry::PIC).toInt()));
- ui->sicNameLineEdit->setText(DBCache->getPilotNamesMap().value(flight_data.value(OPL::FlightEntry::SECONDPILOT).toInt()));
- ui->thirdPilotNameLineEdit->setText(DBCache->getPilotNamesMap().value(flight_data.value(OPL::FlightEntry::THIRDPILOT).toInt()));
- //Function
- for (int i = 0; i < 5; i++) { // QHash::iterator not guarenteed to be in ordetr
- if(flight_data.value(pilotFuncionsMap.value(i)).toInt() != 0)
- ui->functionComboBox->setCurrentIndex(i);
- }
- // Approach ComboBox
- const QString app = flight_data.value(OPL::FlightEntry::APPROACHTYPE).toString();
- if(app != QString()) {
- ui->approachComboBox->setCurrentText(app);
- }
- // Flight Rules, check if tIFR > 0
- bool time_ifr = flight_data.value(OPL::FlightEntry::TIFR).toBool();
- ui->flightRulesComboBox->setCurrentIndex(time_ifr);
- // Take-Off and Landing
- int takeOffCount = flight_data.value(OPL::FlightEntry::TODAY).toInt()
- + flight_data.value(OPL::FlightEntry::TONIGHT).toInt();
- int landingCount = flight_data.value(OPL::FlightEntry::LDGDAY).toInt()
- + flight_data.value(OPL::FlightEntry::LDGNIGHT).toInt();
- ui->takeOffSpinBox->setValue(takeOffCount);
- ui->landingSpinBox->setValue(landingCount);
- ui->pilotFlyingCheckBox->setChecked(flight_data.value(OPL::FlightEntry::PILOTFLYING).toBool());
- // Remarks and Flight Number
- ui->remarksLineEdit->setText(flight_data.value(OPL::FlightEntry::REMARKS).toString());
- ui->flightNumberLineEdit->setText(flight_data.value(OPL::FlightEntry::FLIGHTNUMBER).toString());
- // re-trigger input verification
- 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()) {
- const OPL::Time tofb = OPL::Time::fromString(ui->tofbTimeLineEdit->text(), m_format);
- const OPL::Time tonb = OPL::Time::fromString(ui->tonbTimeLineEdit->text(), m_format);
- const OPL::Time tblk = OPL::Time::blockTime(tofb, tonb);
- ui->tblkDisplayLabel->setText(tblk.toString());
- }
- }
- void NewFlightDialog::onBadInputReceived(QLineEdit *line_edit)
- {
- DEB << line_edit->objectName() << " - Bad input received - " << line_edit->text();
- line_edit->setStyleSheet(OPL::CssStyles::RED_BORDER);
- line_edit->setText(QString());
- if (mandatoryLineEdits->contains(line_edit))
- validationState.invalidate(mandatoryLineEdits->indexOf(line_edit));
- validationState.printValidationStatus();
- }
- bool NewFlightDialog::addNewDatabaseElement(QLineEdit *parent, OPL::DbTable table)
- {
- QDialog *dialog = nullptr;
- if(userWantsToAddNewEntry(table)) {
- switch (table) {
- case OPL::DbTable::Pilots:
- dialog = new NewPilotDialog(parent->text(), this);
- break;
- case OPL::DbTable::Tails:
- dialog = new NewTailDialog(ui->acftLineEdit->text(), this);
- break;
- case OPL::DbTable::Airports:
- dialog = new NewAirportDialog(this);
- break;
- default:
- return false;
- break;
- }
- } else
- return false;
- // execute the dialog and check for success. Set the line edit to the newly created entry.
- if(dialog->exec() == QDialog::Accepted) {
- delete dialog;
- int latestEntry = DB->getLastEntry(table);
- switch (table) {
- case OPL::DbTable::Pilots:
- parent->setText(DBCache->getPilotNamesMap().value(latestEntry));
- break;
- case OPL::DbTable::Tails:
- parent->setText(DBCache->getTailsMap().value(latestEntry));
- break;
- case OPL::DbTable::Airports:
- parent->setText(DBCache->getAirportsMapICAO().value(latestEntry));
- break;
- default:
- return false;
- break;
- }
- } else {
- delete dialog;
- return false;
- }
- // re-emit editing finished to trigger input validation
- emit parent->editingFinished();
- return true;
- }
- bool NewFlightDialog::userWantsToAddNewEntry(OPL::DbTable table)
- {
- QMessageBox::StandardButton reply;
- switch (table) {
- case OPL::DbTable::Pilots:
- 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, QMessageBox::StandardButton::Yes);
- break;
- case OPL::DbTable::Tails:
- 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, QMessageBox::StandardButton::Yes);
- break;
- case OPL::DbTable::Airports:
- reply = QMessageBox::question(this, tr("No Airport found"),
- tr("No Airport with this identifier found.<br>"
- "If this is the first time you log a flight to this airport, "
- "you have to add the airport to the database first."
- "<br><br>Would you like to add a new airport to the database?"),
- QMessageBox::Yes|QMessageBox::No, QMessageBox::StandardButton::Yes);
- break;
- default:
- reply = QMessageBox::No;
- break;
- }
- return reply == QMessageBox::Yes;
- }
- void NewFlightDialog::informUserAboutMissingItems()
- {
- QString missing_items;
- for (int i=0; i < mandatoryLineEdits->size(); i++) {
- if (!validationState.validAt(i)){
- missing_items.append(validationItemsDisplayNames.value(static_cast<ValidationState::ValidationItem>(i)) + QStringLiteral("<br>"));
- mandatoryLineEdits->at(i)->setStyleSheet(OPL::CssStyles::RED_BORDER);
- }
- }
- if(missing_items.isEmpty()) {
- return;
- }
- 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));
- }
- /*!
- * \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(), m_format);
- const OPL::Time tonb = OPL::Time::fromString(ui->tonbTimeLineEdit->text(), m_format);
- const int block_minutes = OPL::Time::blockMinutes(tofb, tonb);
- const 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::getNightAngle());
- // Mandatory data
- new_data.insert(OPL::FlightEntry::DOFT, QDate::fromString(ui->doftLineEdit->text(), Qt::ISODate).toJulianDay());
- new_data.insert(OPL::FlightEntry::DEPT, ui->deptLocationLineEdit->text());
- new_data.insert(OPL::FlightEntry::TOFB, tofb.toMinutes());
- new_data.insert(OPL::FlightEntry::DEST, ui->destLocationLineEdit->text());
- new_data.insert(OPL::FlightEntry::TONB, tonb.toMinutes());
- new_data.insert(OPL::FlightEntry::TBLK, block_minutes);
- // Night
- new_data.insert(OPL::FlightEntry::TNIGHT, night_time_data.nightMinutes);
- // Aircraft
- int acft_id = DBCache->getTailsMap().key(ui->acftLineEdit->text());
- new_data.insert(OPL::FlightEntry::ACFT, acft_id);
- const OPL::TailEntry acft_data = DB->getTailEntry(acft_id);
- bool multi_pilot = acft_data.getData().value(OPL::TailEntry::MULTI_PILOT).toBool();
- bool multi_engine = acft_data.getData().value(OPL::TailEntry::MULTI_ENGINE).toBool();
- if (multi_pilot) {
- new_data.insert(OPL::FlightEntry::TMP, block_minutes);
- new_data.insert(OPL::FlightEntry::TSPSE, QString());
- new_data.insert(OPL::FlightEntry::TSPME, QString());
- } else if (!multi_pilot && !multi_engine) {
- new_data.insert(OPL::FlightEntry::TMP, QString());
- new_data.insert(OPL::FlightEntry::TSPSE, block_minutes);
- new_data.insert(OPL::FlightEntry::TSPME, QString());
- } else if (!multi_pilot && multi_engine) {
- new_data.insert(OPL::FlightEntry::TMP, QString());
- new_data.insert(OPL::FlightEntry::TSPSE, QString());
- new_data.insert(OPL::FlightEntry::TSPME, block_minutes);
- }
- // Pilots
- new_data.insert(OPL::FlightEntry::PIC, DBCache->getPilotNamesMap().key(ui->picNameLineEdit->text()));
- new_data.insert(OPL::FlightEntry::SECONDPILOT, DBCache->getPilotNamesMap().key(ui->sicNameLineEdit->text()));
- new_data.insert(OPL::FlightEntry::THIRDPILOT, DBCache->getPilotNamesMap().key(ui->thirdPilotNameLineEdit->text()));
- // IFR time
- if (ui->flightRulesComboBox->currentIndex() > 0) {
- new_data.insert(OPL::FlightEntry::TIFR, block_minutes);
- } else {
- new_data.insert(OPL::FlightEntry::TIFR, QString());
- }
- // Function Times
- QStringList function_times = {
- OPL::FlightEntry::TPIC,
- OPL::FlightEntry::TPICUS,
- OPL::FlightEntry::TSIC,
- OPL::FlightEntry::TDUAL,
- OPL::FlightEntry::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;
- }
- // Take-Off and Landing
- int toDay = night_time_data.takeOffNight ? 0 : ui->takeOffSpinBox->value();
- int toNight = night_time_data.takeOffNight ? ui->takeOffSpinBox->value() : 0;
- int ldgDay = night_time_data.landingNight ? 0 : ui->landingSpinBox->value();
- int ldgNight = night_time_data.landingNight ? ui->landingSpinBox->value() : 0;
- new_data.insert(OPL::FlightEntry::TODAY, toDay);
- new_data.insert(OPL::FlightEntry::TONIGHT, toNight);
- new_data.insert(OPL::FlightEntry::LDGDAY, ldgDay);
- new_data.insert(OPL::FlightEntry::LDGNIGHT, ldgNight);
- if (ui->approachComboBox->currentText() == CAT_3) // ILS CAT III
- new_data.insert(OPL::FlightEntry::AUTOLAND, ui->landingSpinBox->value());
- // Pilot flying / Pilot monitoring
- bool isPilotFlying = toDay + toNight + ldgDay + ldgNight;
- new_data.insert(OPL::FlightEntry::PILOTFLYING, isPilotFlying);
- // Additional Data
- new_data.insert(OPL::FlightEntry::APPROACHTYPE, ui->approachComboBox->currentText());
- new_data.insert(OPL::FlightEntry::FLIGHTNUMBER, ui->flightNumberLineEdit->text());
- new_data.insert(OPL::FlightEntry::REMARKS, ui->remarksLineEdit->text());
- return new_data;
- }
- /*!
- * \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()
- {
- const auto line_edit = this->findChild<QLineEdit*>(sender()->objectName());
- if(!verifyUserInput(line_edit, TimeInput(line_edit->text(), m_format))) {
- onBadInputReceived(line_edit);
- }
- }
- void NewFlightDialog::onPilotNameLineEdit_editingFinshed()
- {
- auto line_edit = this->findChild<QLineEdit*>(sender()->objectName());
- if(line_edit->text() == QString())
- return;
- // create a copy to refill line edit and pass through to creation dialog if verification fails
- QString userInput = line_edit->text();
- if(!verifyUserInput(line_edit, PilotInput(line_edit->text()))) {
- {
- QSignalBlocker blocker(line_edit);
- line_edit->setText(userInput);
- }
- if(!addNewDatabaseElement(line_edit, OPL::DbTable::Pilots))
- 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");
- addNewDatabaseElement(line_edit, OPL::DbTable::Airports);
- }
- }
- void NewFlightDialog::on_acftLineEdit_editingFinished()
- {
- const auto line_edit = ui->acftLineEdit;
- if(line_edit->text().isEmpty()){
- return;
- }
- const QString user_input = line_edit->text(); // keep around for adding new tail if needed
- if(!verifyUserInput(line_edit, TailInput(line_edit->text()))) {
- // re-populate user input to hand through to NewTailDialog
- {
- QSignalBlocker blocker(line_edit);
- line_edit->setText(user_input);
- }
- if(!addNewDatabaseElement(line_edit, OPL::DbTable::Tails)) {
- 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;
- OPL::Date date(ui->doftLineEdit->text(), m_format);
- LOG << "Date: " << date.toString();
- LOG << "is valid? " << date.isValid();
- line_edit->setText(date.toString());
- if(ui->doftLineEdit->text().isEmpty()) {
- onBadInputReceived(line_edit);
- return;
- }
- onGoodInputReceived(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)
- {
- int picPilotId = DBCache->getPilotNamesMap().key(ui->picNameLineEdit->text());
- int sicPilotId = DBCache->getPilotNamesMap().key(ui->sicNameLineEdit->text());
- int thirdPilotId = DBCache->getPilotNamesMap().key(ui->thirdPilotNameLineEdit->text());
- const QString &self = DBCache->getPilotNamesMap().value(1);
- switch (index) {
- case static_cast<int>(OPL::PilotFunction::PIC):
- DEB << "PIC selected...";
- ui->picNameLineEdit->setText(self);
- emit ui->picNameLineEdit->editingFinished();
- picPilotId = DBCache->getPilotNamesMap().key(ui->picNameLineEdit->text());
- if (picPilotId == sicPilotId) {
- ui->sicNameLineEdit->setText(QString());
- onBadInputReceived(ui->sicNameLineEdit);
- }
- if (picPilotId == thirdPilotId) {
- ui->thirdPilotNameLineEdit->setText(QString());
- onBadInputReceived(ui->thirdPilotNameLineEdit);
- }
- break;
- case static_cast<int>(OPL::PilotFunction::SIC):
- DEB << "SIC selected...";
- ui->sicNameLineEdit->setText(self);
- emit ui->sicNameLineEdit->editingFinished();
- sicPilotId = DBCache->getPilotNamesMap().key(ui->sicNameLineEdit->text());
- if (sicPilotId == picPilotId) {
- ui->picNameLineEdit->setText(QString());
- onBadInputReceived(ui->picNameLineEdit);
- }
- if (sicPilotId == thirdPilotId) {
- ui->thirdPilotNameLineEdit->setText(QString());
- onBadInputReceived(ui->thirdPilotNameLineEdit);
- }
- break;
- default:
- break;
- }
- }
- /*!
- * \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::pilotFunctionsInvalid()
- {
- 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 true;
- }
- } 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 true;
- }
- }
- return false;
- }
- bool NewFlightDialog::duplicateNamesPresent()
- {
- const int picId = DBCache->getPilotNamesMap().key(ui->picNameLineEdit->text());
- const int sicId = DBCache->getPilotNamesMap().key(ui->sicNameLineEdit->text());
- const int thirdPilotId = DBCache->getPilotNamesMap().key(ui->thirdPilotNameLineEdit->text());
- // this is a bit explicit but better point out to the user what the case is
- if (picId == sicId) {
- INFO(tr("PIC and SIC names are the same."));
- return true;
- }
- if (picId == thirdPilotId && picId > 0) {
- INFO(tr("PIC and third Pilot names are the same."));
- return true;
- }
- if (sicId == thirdPilotId && sicId > 0) {
- INFO(tr("SIC and third Pilot names are the same."));
- return true;
- }
- return false;
- }
- bool NewFlightDialog::flightTimeIsZero()
- {
- const OPL::Time tofb = OPL::Time::fromString(ui->tofbTimeLineEdit->text(), m_format);
- const OPL::Time tonb = OPL::Time::fromString(ui->tonbTimeLineEdit->text(), m_format);
- const int block_minutes = OPL::Time::blockMinutes(tofb, tonb);
- if(block_minutes == 0) {
- INFO(tr("Total time of flight is zero."));
- return true;
- }
- return false;
- }
- /*!
- * \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()
- {
- // one item is always invalid if the user accepts when the currently edited line edit is mandatory (invalidation on focus in event)
- if(!validationState.allButOneValid()) {
- informUserAboutMissingItems();
- return;
- }
- // trigger validation for all mandatory items to toggle verification state
- for (const auto& le : *mandatoryLineEdits)
- emit le->editingFinished();
- if (!validationState.allValid()) {
- informUserAboutMissingItems();
- return;
- }
- // run a couple of reasonableness checks
- if(pilotFunctionsInvalid())
- return;
- if(duplicateNamesPresent())
- return;
- if(flightTimeIsZero())
- return;
- // 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();
- }
- }
- void NewFlightDialog::on_calendarPushButton_clicked()
- {
- calendar->setVisible(true);
- }
- void NewFlightDialog::calendarDateSelected()
- {
- calendar->setVisible(false);
- ui->doftLineEdit->setText(OPL::Date(calendar->selectedDate(), m_format).toString());
- emit ui->doftLineEdit->editingFinished();
- }
- // EntryEditDialog interface
- void NewFlightDialog::loadEntry(int rowID)
- {
- flightEntry = DB->getFlightEntry(rowID);
- fillWithEntryData();
- }
- bool NewFlightDialog::deleteEntry(int rowID)
- {
- const auto entry = DB->getFlightEntry(rowID);
- return DB->remove(entry);
- }
|