|  | @@ -0,0 +1,1179 @@
 | 
	
		
			
				|  |  | +/*
 | 
	
		
			
				|  |  | + *openPilot Log - A FOSS Pilot Logbook Application
 | 
	
		
			
				|  |  | + *Copyright (C) 2020  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 "newflight.h"
 | 
	
		
			
				|  |  | +#include "ui_newflight.h"
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#include <QSqlRelationalTableModel>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/// =======================================================
 | 
	
		
			
				|  |  | +/// Debug / WIP section
 | 
	
		
			
				|  |  | +/// =======================================================
 | 
	
		
			
				|  |  | +#define DEBUG(expr) \
 | 
	
		
			
				|  |  | +    qDebug() << "~DEBUG" << __func__ << expr
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void NewFlight::on_verifyButton_clicked()//debug button
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    //fillExtrasLineEdits();
 | 
	
		
			
				|  |  | +    collectBasicData();
 | 
	
		
			
				|  |  | +    collectAdditionalData();
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +/*!
 | 
	
		
			
				|  |  | + * \brief NewFlight::nope for features that are not yet implemented
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +void NewFlight::nope()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    QMessageBox nope(this); //error box
 | 
	
		
			
				|  |  | +    nope.setText("This feature is not yet available!");
 | 
	
		
			
				|  |  | +    nope.exec();
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static const auto IATA = QLatin1String("[a-zA-Z0-9]{3}");
 | 
	
		
			
				|  |  | +static const auto ICAO = QLatin1String("[a-zA-Z0-9]{4}");
 | 
	
		
			
				|  |  | +static const auto name = QLatin1String("(\\p{L}+(\\s|'|\\-)?\\s?(\\p{L}+)?\\s?)");
 | 
	
		
			
				|  |  | +static const auto self = QLatin1String("(self|SELF)");
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/// Raw Input validation
 | 
	
		
			
				|  |  | +const auto TIME_VALID_RGX       = QRegularExpression("([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
 | 
	
		
			
				|  |  | +const auto LOC_VALID_RGX        = QRegularExpression(IATA + "|" + ICAO);
 | 
	
		
			
				|  |  | +const auto AIRCRAFT_VALID_RGX   = QRegularExpression("[A-Z0-9]+-?[A-Z0-9]+");
 | 
	
		
			
				|  |  | +const auto PILOT_NAME_VALID_RGX = QRegularExpression(self + QLatin1Char('|')
 | 
	
		
			
				|  |  | +                                                     + name + name + name + name + ",\\s+" // up to 4 first names
 | 
	
		
			
				|  |  | +                                                     + name + name + name + name);// up to 4 last names
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/// Invalid characters (validators keep text even if it returns Invalid, see `onInputRejected` below)
 | 
	
		
			
				|  |  | +const auto TIME_INVALID_RGX       = QRegularExpression("[^0-9:]");
 | 
	
		
			
				|  |  | +const auto LOC_INVALID_RGX        = QRegularExpression("[^a-zA-Z0-9]");
 | 
	
		
			
				|  |  | +const auto AIRCRAFT_INVALID_RGX   = QRegularExpression("[^a-zA-Z0-9-]");
 | 
	
		
			
				|  |  | +const auto PILOT_NAME_INVALID_RGX = QRegularExpression("[^\\p{L}|\\s|,]");
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/// Sql columns
 | 
	
		
			
				|  |  | +const auto LOC_SQL_COL        = SqlColumnNum(1);  // TODO: locations are iata/icao so 1,2 merge columns in sql?
 | 
	
		
			
				|  |  | +const auto AIRCRAFT_SQL_COL   = SqlColumnNum(4);
 | 
	
		
			
				|  |  | +const auto PILOT_NAME_SQL_COL = SqlColumnNum(6);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/*
 | 
	
		
			
				|  |  | + * Window Construction
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +NewFlight::NewFlight(QWidget *parent) :
 | 
	
		
			
				|  |  | +    QDialog(parent),
 | 
	
		
			
				|  |  | +    ui(new Ui::NewFlight)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    ui->setupUi(this);
 | 
	
		
			
				|  |  | +    auto db = QSqlDatabase::database("qt_sql_default_connection");
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    const auto location_settings = \
 | 
	
		
			
				|  |  | +         LineEditSettings(LOC_VALID_RGX, LOC_INVALID_RGX, LOC_SQL_COL);
 | 
	
		
			
				|  |  | +    const auto aircraft_settings = \
 | 
	
		
			
				|  |  | +         LineEditSettings(AIRCRAFT_VALID_RGX, AIRCRAFT_INVALID_RGX, AIRCRAFT_SQL_COL);
 | 
	
		
			
				|  |  | +    const auto pilot_name_settings = \
 | 
	
		
			
				|  |  | +         LineEditSettings(PILOT_NAME_VALID_RGX, PILOT_NAME_INVALID_RGX, PILOT_NAME_SQL_COL);
 | 
	
		
			
				|  |  | +    const auto time_settings = \
 | 
	
		
			
				|  |  | +         LineEditSettings(TIME_VALID_RGX, TIME_INVALID_RGX, SqlColumnNum());
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +//     Set up Line Edits with QValidators, QCompleters
 | 
	
		
			
				|  |  | +    auto line_edits = ui->flightDataTab->findChildren<QLineEdit*>();
 | 
	
		
			
				|  |  | +    auto le_size = line_edits.size();
 | 
	
		
			
				|  |  | +    for(auto i = 0; i < le_size; ++i){
 | 
	
		
			
				|  |  | +//        auto bit_array = new QBitArray(le_size);
 | 
	
		
			
				|  |  | +//        bit_array->setBit(i, true);
 | 
	
		
			
				|  |  | +        this->lineEditBitMap[line_edits[i]] = i;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    this->allOkBits.resize(line_edits.size());
 | 
	
		
			
				|  |  | +    this->mandatoryLineEdits = {
 | 
	
		
			
				|  |  | +        ui->newDeptLocLineEdit,
 | 
	
		
			
				|  |  | +        ui->newDestLocLineEdit,
 | 
	
		
			
				|  |  | +        ui->newDeptTimeLineEdit,
 | 
	
		
			
				|  |  | +        ui->newDestTimeLineEdit,
 | 
	
		
			
				|  |  | +        ui->newPicNameLineEdit,
 | 
	
		
			
				|  |  | +        ui->newAcft,
 | 
	
		
			
				|  |  | +    };
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    for(auto line_edit : line_edits)
 | 
	
		
			
				|  |  | +    {
 | 
	
		
			
				|  |  | +        auto le_name = line_edit->objectName();
 | 
	
		
			
				|  |  | +        if(QRegularExpression("Loc").match(le_name).hasMatch()){
 | 
	
		
			
				|  |  | +            setupLineEdit(line_edit, location_settings);
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        else if (QRegularExpression("Time").match(le_name).hasMatch())
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            setupLineEdit(line_edit, time_settings);
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        else if (QRegularExpression("Acft").match(le_name).hasMatch())
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            setupLineEdit(line_edit, aircraft_settings);
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        else if (QRegularExpression("Name").match(le_name).hasMatch())
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            setupLineEdit(line_edit, pilot_name_settings);
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    //fill Lists
 | 
	
		
			
				|  |  | +    pilots = CompletionList(CompleterTarget::pilots).list;
 | 
	
		
			
				|  |  | +    tails = CompletionList(CompleterTarget::registrations).list;
 | 
	
		
			
				|  |  | +    airports = CompletionList(CompleterTarget::airports).list;
 | 
	
		
			
				|  |  | +    QString statement = "SELECT iata, icao FROM airports";
 | 
	
		
			
				|  |  | +    auto result = Db::customQuery(statement,2);
 | 
	
		
			
				|  |  | +    for(int i=0; i<result.length()-2; i += 2){
 | 
	
		
			
				|  |  | +        airportMap.insert(result[i],result[i+1]);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // Groups for CheckBoxes
 | 
	
		
			
				|  |  | +    QButtonGroup *FlightRulesGroup = new QButtonGroup(this);
 | 
	
		
			
				|  |  | +    FlightRulesGroup->addButton(ui->IfrCheckBox);
 | 
	
		
			
				|  |  | +    FlightRulesGroup->addButton(ui->VfrCheckBox);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    QButtonGroup *PilotTaskGroup = new QButtonGroup(this);
 | 
	
		
			
				|  |  | +    PilotTaskGroup->addButton(ui->PilotFlyingCheckBox);
 | 
	
		
			
				|  |  | +    PilotTaskGroup->addButton(ui->PilotMonitoringCheckBox);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    ui->deptTZ->setFocusPolicy(Qt::NoFocus);
 | 
	
		
			
				|  |  | +    ui->destTZ->setFocusPolicy(Qt::NoFocus);
 | 
	
		
			
				|  |  | +    //set date for new object
 | 
	
		
			
				|  |  | +    auto date = QDate::currentDate();
 | 
	
		
			
				|  |  | +    ui->newDoft->setDate(date);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // Visually mark mandatory fields
 | 
	
		
			
				|  |  | +    ui->newDeptLocLineEdit->setStyleSheet("border: 1px solid orange");
 | 
	
		
			
				|  |  | +    ui->newDestLocLineEdit->setStyleSheet("border: 1px solid orange");
 | 
	
		
			
				|  |  | +    ui->newDeptTimeLineEdit->setStyleSheet("border: 1px solid orange");
 | 
	
		
			
				|  |  | +    ui->newDestTimeLineEdit->setStyleSheet("border: 1px solid orange");
 | 
	
		
			
				|  |  | +    ui->newPicNameLineEdit->setStyleSheet("border: 1px solid orange");
 | 
	
		
			
				|  |  | +    ui->newAcft->setStyleSheet("border: 1px solid orange");
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    readSettings();
 | 
	
		
			
				|  |  | +    ui->tabWidget->setCurrentIndex(0);
 | 
	
		
			
				|  |  | +    ui->newDeptLocLineEdit->setFocus();
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +NewFlight::~NewFlight()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    delete ui;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/*
 | 
	
		
			
				|  |  | + * ============================================================================
 | 
	
		
			
				|  |  | + * Functions
 | 
	
		
			
				|  |  | + * ============================================================================
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/*!
 | 
	
		
			
				|  |  | + * \brief setLineEditValidator set Validators for QLineEdits that end with Time, Loc,
 | 
	
		
			
				|  |  | + * Aircraft or Name
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +inline void NewFlight::setupLineEdit(QLineEdit* line_edit, LineEditSettings settings)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    auto db = QSqlDatabase::database("qt_sql_default_connection");
 | 
	
		
			
				|  |  | +    auto line_edit_objectName = line_edit->objectName();
 | 
	
		
			
				|  |  | +    DEBUG("Setting validators for " << line_edit_objectName);
 | 
	
		
			
				|  |  | +    auto [valid_rgx, invalid_rgx, sql_col] = settings.getAll();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    auto validator = new StrictRxValidator(valid_rgx, line_edit);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    auto comp_model = new QSqlRelationalTableModel(line_edit, db);
 | 
	
		
			
				|  |  | +    comp_model->database().open();
 | 
	
		
			
				|  |  | +    comp_model->setTable("QCompleterView");
 | 
	
		
			
				|  |  | +    comp_model->select();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    auto completer = new QCompleter(comp_model, line_edit);
 | 
	
		
			
				|  |  | +    completer->setCaseSensitivity(Qt::CaseInsensitive);
 | 
	
		
			
				|  |  | +    completer->setCompletionMode(QCompleter::PopupCompletion);
 | 
	
		
			
				|  |  | +    completer->setCompletionColumn(sql_col.column());
 | 
	
		
			
				|  |  | +    completer->setFilterMode(Qt::MatchContains);
 | 
	
		
			
				|  |  | +    /*if(QRegularExpression("\\w+Loc").match(line_edit_objectName).hasMatch()) { completer->setFilterMode(Qt::MatchContains); }
 | 
	
		
			
				|  |  | +    if(QRegularExpression("\\w+Acft").match(line_edit_objectName).hasMatch()) { completer->setFilterMode(Qt::MatchContains); }
 | 
	
		
			
				|  |  | +    if(QRegularExpression("\\w+Name").match(line_edit_objectName).hasMatch()) { completer->setFilterMode(Qt::MatchContains); }*/
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    line_edit->setValidator(validator);
 | 
	
		
			
				|  |  | +    line_edit->setCompleter(completer);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/*!
 | 
	
		
			
				|  |  | + * \brief NewFlight::writeSettings Writes current selection for auto-logging
 | 
	
		
			
				|  |  | + * to settings file.
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +void NewFlight::writeSettings()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    DEBUG("Writing Settings...");
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    Settings::write("NewFlight/FunctionComboBox",ui->FunctionComboBox->currentText());
 | 
	
		
			
				|  |  | +    Settings::write("NewFlight/ApproachComboBox",ui->ApproachComboBox->currentText());
 | 
	
		
			
				|  |  | +    Settings::write("NewFlight/PilotFlyingCheckBox",ui->PilotFlyingCheckBox->isChecked());
 | 
	
		
			
				|  |  | +    Settings::write("NewFlight/PilotMonitoringCheckBox",ui->PilotMonitoringCheckBox->isChecked());
 | 
	
		
			
				|  |  | +    Settings::write("NewFlight/TakeoffSpinBox",ui->TakeoffSpinBox->value());
 | 
	
		
			
				|  |  | +    Settings::write("NewFlight/TakeoffCheckBox",ui->TakeoffCheckBox->isChecked());
 | 
	
		
			
				|  |  | +    Settings::write("NewFlight/LandingSpinBox",ui->LandingSpinBox->value());
 | 
	
		
			
				|  |  | +    Settings::write("NewFlight/LandingCheckBox",ui->LandingCheckBox->isChecked());
 | 
	
		
			
				|  |  | +    Settings::write("NewFlight/AutolandSpinBox",ui->AutolandSpinBox->value());
 | 
	
		
			
				|  |  | +    Settings::write("NewFlight/AutolandCheckBox",ui->AutolandCheckBox->isChecked());
 | 
	
		
			
				|  |  | +    Settings::write("NewFlight/IfrCheckBox",ui->IfrCheckBox->isChecked());
 | 
	
		
			
				|  |  | +    Settings::write("NewFlight/VfrCheckBox",ui->VfrCheckBox->isChecked());
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/*!
 | 
	
		
			
				|  |  | + * \brief NewFlight::readSettings Retreives auto-logging settings
 | 
	
		
			
				|  |  | + * and sets up ui accordingly
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +void NewFlight::readSettings()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    DEBUG("Reading Settings...");
 | 
	
		
			
				|  |  | +    QSettings settings;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    ui->FunctionComboBox->setCurrentText(Settings::read("NewFlight/FunctionComboBox").toString());
 | 
	
		
			
				|  |  | +    ui->ApproachComboBox->setCurrentText(Settings::read("NewFlight/ApproachComboBox").toString());
 | 
	
		
			
				|  |  | +    ui->PilotFlyingCheckBox->setChecked(Settings::read("NewFlight/PilotFlyingCheckBox").toInt());
 | 
	
		
			
				|  |  | +    ui->PilotMonitoringCheckBox->setChecked(Settings::read("NewFlight/PilotMonitoringCheckBox").toInt());
 | 
	
		
			
				|  |  | +    ui->TakeoffSpinBox->setValue(Settings::read("NewFlight/TakeoffSpinBox").toInt());
 | 
	
		
			
				|  |  | +    ui->TakeoffCheckBox->setChecked(Settings::read("NewFlight/TakeoffCheckBox").toInt());
 | 
	
		
			
				|  |  | +    ui->LandingSpinBox->setValue(Settings::read("NewFlight/LandingSpinBox").toInt());
 | 
	
		
			
				|  |  | +    ui->LandingCheckBox->setChecked(Settings::read("NewFlight/LandingCheckBox").toInt());
 | 
	
		
			
				|  |  | +    ui->AutolandSpinBox->setValue(Settings::read("NewFlight/AutolandSpinBox").toInt());
 | 
	
		
			
				|  |  | +    ui->AutolandCheckBox->setChecked(Settings::read("NewFlight/AutolandCheckBox").toInt());
 | 
	
		
			
				|  |  | +    ui->IfrCheckBox->setChecked(Settings::read("NewFlight/IfrCheckBox").toInt());
 | 
	
		
			
				|  |  | +    ui->VfrCheckBox->setChecked(Settings::read("NewFlight/VfrCheckBox").toInt());
 | 
	
		
			
				|  |  | +    ui->flightNumberPrefixLabel->setText(Settings::read("userdata/flightnumberPrefix").toString() + QLatin1Char('-'));
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if(Settings::read("NewFlight/FunctionComboBox").toString() == "PIC"){
 | 
	
		
			
				|  |  | +        ui->newPicNameLineEdit->setText("self");
 | 
	
		
			
				|  |  | +        ui->secondPilotNameLineEdit->setText("");
 | 
	
		
			
				|  |  | +    }else if (Settings::read("NewFlight/FunctionComboBox").toString() == "Co-Pilot") {
 | 
	
		
			
				|  |  | +        ui->newPicNameLineEdit->setText("");
 | 
	
		
			
				|  |  | +        ui->secondPilotNameLineEdit->setText("self");
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +/*!
 | 
	
		
			
				|  |  | + * \brief NewFlight::addNewPilotMessageBox If the user input is not in the pilotNameList, the user
 | 
	
		
			
				|  |  | + * is prompted if he wants to add a new entry to the database
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +void NewFlight::addNewPilotMessageBox()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    QMessageBox::StandardButton reply;
 | 
	
		
			
				|  |  | +    reply = QMessageBox::question(this, "No Pilot found",
 | 
	
		
			
				|  |  | +                                  "No pilot found.\n Would you like to add a new pilot to the database?",
 | 
	
		
			
				|  |  | +                                  QMessageBox::Yes|QMessageBox::No);
 | 
	
		
			
				|  |  | +    if (reply == QMessageBox::Yes)
 | 
	
		
			
				|  |  | +    {
 | 
	
		
			
				|  |  | +        qDebug() << "Add new pilot selected";
 | 
	
		
			
				|  |  | +        DEBUG("This feature is not yet available.");
 | 
	
		
			
				|  |  | +        // create and open new pilot dialog
 | 
	
		
			
				|  |  | +        auto np = NewPilot(Db::createNew, this);
 | 
	
		
			
				|  |  | +        np.open();
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/// Input Verification and Collection
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/*!
 | 
	
		
			
				|  |  | + * \brief NewFlight::update check if needed inputs are available and update form
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +void NewFlight::update()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    QVector<QLineEdit*> notFilled;
 | 
	
		
			
				|  |  | +    for(auto lineEdit : mandatoryLineEdits)
 | 
	
		
			
				|  |  | +    {
 | 
	
		
			
				|  |  | +        if(!allOkBits.testBit(lineEditBitMap[lineEdit]))
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            notFilled.push_back(lineEdit);
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    if(notFilled.empty()){
 | 
	
		
			
				|  |  | +        collectBasicData();
 | 
	
		
			
				|  |  | +        fillExtras();
 | 
	
		
			
				|  |  | +    } else {
 | 
	
		
			
				|  |  | +        DEBUG("No update - not enough variables known.");
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/*!
 | 
	
		
			
				|  |  | + * \brief NewFlight::collectBasicInput After mandatory inputs have passed
 | 
	
		
			
				|  |  | + * validation, collect values from line edits and combo boxes to create new Data
 | 
	
		
			
				|  |  | + * for flight object.
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +void NewFlight::collectBasicData()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    DEBUG("Collecting Basic Input...");
 | 
	
		
			
				|  |  | +    // Date of Flight
 | 
	
		
			
				|  |  | +    auto date = ui->newDoft->date();
 | 
	
		
			
				|  |  | +    auto doft = date.toString(Qt::ISODate);
 | 
	
		
			
				|  |  | +    newData.insert("doft",doft);
 | 
	
		
			
				|  |  | +    // Departure Loc
 | 
	
		
			
				|  |  | +    newData.insert("dept",ui->newDeptLocLineEdit->text());
 | 
	
		
			
				|  |  | +    // Time Off Blocks
 | 
	
		
			
				|  |  | +    auto timeOff = QTime::fromString(ui->newDeptTimeLineEdit->text(),"hh:mm");
 | 
	
		
			
				|  |  | +    if(timeOff.isValid()){
 | 
	
		
			
				|  |  | +        int tofb = timeOff.hour() * 60 + timeOff.minute();
 | 
	
		
			
				|  |  | +        newData.insert("tofb",QString::number(tofb));
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    // Destination Loc
 | 
	
		
			
				|  |  | +    newData.insert("dest",ui->newDestLocLineEdit->text());
 | 
	
		
			
				|  |  | +    // Time On Blocks
 | 
	
		
			
				|  |  | +    auto timeOn = QTime::fromString(ui->newDestTimeLineEdit->text(),"hh:mm");
 | 
	
		
			
				|  |  | +    if(timeOn.isValid()){
 | 
	
		
			
				|  |  | +        int tonb = timeOn.hour() * 60 + timeOn.minute();
 | 
	
		
			
				|  |  | +        newData.insert("tonb",QString::number(tonb));
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // Aircraft
 | 
	
		
			
				|  |  | +    QString reg = ui->newAcft->text();
 | 
	
		
			
				|  |  | +    QString acft = Db::singleSelect("tail_id","tails","registration",reg,Db::exactMatch);
 | 
	
		
			
				|  |  | +    if(!acft.isEmpty()){
 | 
	
		
			
				|  |  | +        newData.insert("acft",acft);
 | 
	
		
			
				|  |  | +    } else {
 | 
	
		
			
				|  |  | +        emit ui->newAcft->inputRejected();
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    // Pilot
 | 
	
		
			
				|  |  | +    if(ui->newPicNameLineEdit->text() == "self" || ui->newPicNameLineEdit->text() == "self"){
 | 
	
		
			
				|  |  | +        newData.insert("pic","1");
 | 
	
		
			
				|  |  | +    } else {
 | 
	
		
			
				|  |  | +        QString name = ui->newPicNameLineEdit->text();
 | 
	
		
			
				|  |  | +        QStringList names = name.split(',');
 | 
	
		
			
				|  |  | +        if(names.length()==2){
 | 
	
		
			
				|  |  | +            QString firstNames = names[1].simplified();
 | 
	
		
			
				|  |  | +            QString lastNames = names[0].simplified();
 | 
	
		
			
				|  |  | +            QString query = "SELECT pilot_id FROM pilots WHERE piclastname = \"" + lastNames
 | 
	
		
			
				|  |  | +                    + "\" AND picfirstname = \"" + firstNames + "\"";
 | 
	
		
			
				|  |  | +            QVector<QString> pic = Db::customQuery(query,1);
 | 
	
		
			
				|  |  | +            if(!pic.isEmpty()){
 | 
	
		
			
				|  |  | +                newData.insert("pic",pic.first());
 | 
	
		
			
				|  |  | +            }else {
 | 
	
		
			
				|  |  | +                emit ui->newPicNameLineEdit->inputRejected();
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    DEBUG(newData);
 | 
	
		
			
				|  |  | +    DEBUG("Basic Input Collected. Should be 7 items. is:" << newData.count());
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void NewFlight::collectAdditionalData()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    // Pilot 2
 | 
	
		
			
				|  |  | +    if(!ui->secondPilotNameLineEdit->text().isEmpty()){
 | 
	
		
			
				|  |  | +        if(ui->secondPilotNameLineEdit->text() == "self" || ui->secondPilotNameLineEdit->text() == "self"){
 | 
	
		
			
				|  |  | +            newData.insert("secondPilot","1");
 | 
	
		
			
				|  |  | +        } else {
 | 
	
		
			
				|  |  | +            QString name = ui->secondPilotNameLineEdit->text();
 | 
	
		
			
				|  |  | +            QStringList names = name.split(',');
 | 
	
		
			
				|  |  | +            if(names.length()==2){
 | 
	
		
			
				|  |  | +                QString firstNames = names[1].simplified();
 | 
	
		
			
				|  |  | +                QString lastNames = names[0].simplified();
 | 
	
		
			
				|  |  | +                QString query = "SELECT pilot_id FROM pilots WHERE piclastname = \"" + lastNames
 | 
	
		
			
				|  |  | +                        + "\" AND picfirstname = \"" + firstNames + "\"";
 | 
	
		
			
				|  |  | +                QVector<QString> pic = Db::customQuery(query,1);
 | 
	
		
			
				|  |  | +                if(!pic.isEmpty()){
 | 
	
		
			
				|  |  | +                    newData.insert("secondPilot",pic.first());
 | 
	
		
			
				|  |  | +                }else {
 | 
	
		
			
				|  |  | +                    emit ui->secondPilotNameLineEdit->inputRejected();
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // Pilot 3
 | 
	
		
			
				|  |  | +    if(!ui->thirdPilotNameLineEdit->text().isEmpty()){
 | 
	
		
			
				|  |  | +        if(ui->thirdPilotNameLineEdit->text() == "self" || ui->thirdPilotNameLineEdit->text() == "self"){
 | 
	
		
			
				|  |  | +            newData.insert("thirdPilot","1");
 | 
	
		
			
				|  |  | +        } else {
 | 
	
		
			
				|  |  | +            QString name = ui->thirdPilotNameLineEdit->text();
 | 
	
		
			
				|  |  | +            QStringList names = name.split(',');
 | 
	
		
			
				|  |  | +            if(names.length()==2){
 | 
	
		
			
				|  |  | +                QString firstNames = names[1].simplified();
 | 
	
		
			
				|  |  | +                QString lastNames = names[0].simplified();
 | 
	
		
			
				|  |  | +                QString query = "SELECT pilot_id FROM pilots WHERE piclastname = \"" + lastNames
 | 
	
		
			
				|  |  | +                        + "\" AND picfirstname = \"" + firstNames + "\"";
 | 
	
		
			
				|  |  | +                QVector<QString> pic = Db::customQuery(query,1);
 | 
	
		
			
				|  |  | +                if(!pic.isEmpty()){
 | 
	
		
			
				|  |  | +                    newData.insert("thirdPilot",pic.first());
 | 
	
		
			
				|  |  | +                }else {
 | 
	
		
			
				|  |  | +                    emit ui->thirdPilotNameLineEdit->inputRejected();
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // Extra Times
 | 
	
		
			
				|  |  | +    auto tofb = QTime::fromString(ui->newDeptTimeLineEdit->text(),"hh:mm");
 | 
	
		
			
				|  |  | +    auto tonb = QTime::fromString(ui->newDestTimeLineEdit->text(),"hh:mm");
 | 
	
		
			
				|  |  | +    QString blockTime = Calc::blocktime(tofb, tonb).toString("hh:mm");
 | 
	
		
			
				|  |  | +    QString blockMinutes = QString::number(Calc::stringToMinutes(blockTime));
 | 
	
		
			
				|  |  | +    DEBUG("Blocktime: " << blockTime << " (" << blockMinutes << " minutes)");
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    auto acft = Aircraft(newData.value("acft").toInt());
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    DEBUG("aircraftDetails: " << acft);
 | 
	
		
			
				|  |  | +    if(!acft.data.isEmpty()){// valid aircraft
 | 
	
		
			
				|  |  | +        // SP SE
 | 
	
		
			
				|  |  | +        if(acft.data.value("singlepilot") == "1" && acft.data.value("singleengine") == "1"){
 | 
	
		
			
				|  |  | +            DEBUG("SPSE yes");
 | 
	
		
			
				|  |  | +            newData.insert("tSPSE", blockMinutes);
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        // SP ME
 | 
	
		
			
				|  |  | +        if(acft.data.value("singlepilot") == "1" && acft.data.value("multiengine") == "1"){
 | 
	
		
			
				|  |  | +            DEBUG("SP ME yes");
 | 
	
		
			
				|  |  | +            newData.insert("tSPME", blockMinutes);
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        // MP
 | 
	
		
			
				|  |  | +        if(acft.data.value("multipilot") == "1"){
 | 
	
		
			
				|  |  | +            DEBUG("Multipilot yes");
 | 
	
		
			
				|  |  | +            newData.insert("tMP", blockMinutes);
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +    }else{DEBUG("Aircraft Details Empty");}//invalid aircraft
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // TOTAL
 | 
	
		
			
				|  |  | +    newData.insert("tblk",blockMinutes);
 | 
	
		
			
				|  |  | +    // IFR
 | 
	
		
			
				|  |  | +    if(ui->IfrCheckBox->isChecked()){
 | 
	
		
			
				|  |  | +        newData.insert("tIFR",blockMinutes);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    // Night
 | 
	
		
			
				|  |  | +    QString deptDate = ui->newDoft->date().toString(Qt::ISODate) + 'T' + tofb.toString("hh:mm");
 | 
	
		
			
				|  |  | +    QDateTime deptDateTime = QDateTime::fromString(deptDate,"yyyy-MM-ddThh:mm");
 | 
	
		
			
				|  |  | +    int tblk = blockMinutes.toInt();
 | 
	
		
			
				|  |  | +    const int nightAngle = Settings::read("flightlogging/nightangle").toInt();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    QString nightTime = QString::number(
 | 
	
		
			
				|  |  | +                        Calc::calculateNightTime(
 | 
	
		
			
				|  |  | +                        newData.value("dept"), newData.value("dest"),
 | 
	
		
			
				|  |  | +                        deptDateTime, tblk, nightAngle));
 | 
	
		
			
				|  |  | +    newData.insert("tNIGHT", nightTime);
 | 
	
		
			
				|  |  | +    // Function times
 | 
	
		
			
				|  |  | +    switch (ui->FunctionComboBox->currentIndex()) {
 | 
	
		
			
				|  |  | +    case 0://PIC
 | 
	
		
			
				|  |  | +        newData.insert("tPIC",blockMinutes);
 | 
	
		
			
				|  |  | +        break;
 | 
	
		
			
				|  |  | +    case 1://Co-Pilot
 | 
	
		
			
				|  |  | +        newData.insert("tSIC",blockMinutes);
 | 
	
		
			
				|  |  | +        break;
 | 
	
		
			
				|  |  | +    case 2://Dual
 | 
	
		
			
				|  |  | +        newData.insert("tDual", blockMinutes);
 | 
	
		
			
				|  |  | +        break;
 | 
	
		
			
				|  |  | +    case 3://Instructor
 | 
	
		
			
				|  |  | +        newData.insert("tFI", blockMinutes);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    // Auto-Logging
 | 
	
		
			
				|  |  | +    newData.insert("pilotFlying", QString::number(ui->PilotFlyingCheckBox->isChecked()));
 | 
	
		
			
				|  |  | +    if(nightTime == "0"){ // all day
 | 
	
		
			
				|  |  | +        DEBUG("All Day.");
 | 
	
		
			
				|  |  | +        newData.insert("toDay", QString::number(ui->TakeoffSpinBox->value()));
 | 
	
		
			
				|  |  | +        newData.insert("ldgDay", QString::number(ui->LandingSpinBox->value()));
 | 
	
		
			
				|  |  | +        newData.insert("toNight", "0");
 | 
	
		
			
				|  |  | +        newData.insert("ldgNight", "0");
 | 
	
		
			
				|  |  | +    }else if (nightTime == blockTime) { // all night
 | 
	
		
			
				|  |  | +        DEBUG("All Night.");
 | 
	
		
			
				|  |  | +        newData.insert("toNight", QString::number(ui->TakeoffSpinBox->value()));
 | 
	
		
			
				|  |  | +        newData.insert("ldgNight", QString::number(ui->LandingSpinBox->value()));
 | 
	
		
			
				|  |  | +        newData.insert("toDay", "0");
 | 
	
		
			
				|  |  | +        newData.insert("ldgDay", "0");
 | 
	
		
			
				|  |  | +    } else {
 | 
	
		
			
				|  |  | +        if(Calc::isNight(ui->newDeptLocLineEdit->text(), deptDateTime,  nightAngle)){
 | 
	
		
			
				|  |  | +            newData.insert("toNight", QString::number(ui->TakeoffSpinBox->value()));
 | 
	
		
			
				|  |  | +            newData.insert("toDay", "0");
 | 
	
		
			
				|  |  | +        }else{
 | 
	
		
			
				|  |  | +            newData.insert("toDay", QString::number(ui->TakeoffSpinBox->value()));
 | 
	
		
			
				|  |  | +            newData.insert("toNight", "0");
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        QString destDate = ui->newDoft->date().toString(Qt::ISODate) + 'T' + tonb.toString("hh:mm");
 | 
	
		
			
				|  |  | +        QDateTime destDateTime = QDateTime::fromString(destDate,"yyyy-MM-ddThh:mm");
 | 
	
		
			
				|  |  | +        if(Calc::isNight(ui->newDestLocLineEdit->text(), destDateTime,  nightAngle)){
 | 
	
		
			
				|  |  | +            newData.insert("ldgNight", QString::number(ui->LandingSpinBox->value()));
 | 
	
		
			
				|  |  | +            newData.insert("ldgDay", "0");
 | 
	
		
			
				|  |  | +        }else{
 | 
	
		
			
				|  |  | +            newData.insert("ldgDay", QString::number(ui->LandingSpinBox->value()));
 | 
	
		
			
				|  |  | +            newData.insert("ldgNight", "0");
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    newData.insert("autoland", QString::number(ui->AutolandSpinBox->value()));
 | 
	
		
			
				|  |  | +    newData.insert("ApproachType", ui->ApproachComboBox->currentText());
 | 
	
		
			
				|  |  | +    newData.insert("FlightNumber", ui->FlightNumberLineEdit->text());
 | 
	
		
			
				|  |  | +    newData.insert("Remarks", ui->RemarksLineEdit->text());
 | 
	
		
			
				|  |  | +    DEBUG("Collected Data: " << newData);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +/*!
 | 
	
		
			
				|  |  | + * \brief NewFlight::fillExtrasLineEdits Fills the deductable items in the newData map and
 | 
	
		
			
				|  |  | + * additional flight time line edits according to ui selections.
 | 
	
		
			
				|  |  | + * Neccessary prerequisites are valid Date, Departure Time and Place, Destination Time and Place,
 | 
	
		
			
				|  |  | + * PIC name (pilot_id) and Aircraft (tail_id)
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +void NewFlight::fillExtras()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    //Times
 | 
	
		
			
				|  |  | +    auto tofb = QTime::fromString(ui->newDeptTimeLineEdit->text(),"hh:mm");
 | 
	
		
			
				|  |  | +    auto tonb = QTime::fromString(ui->newDestTimeLineEdit->text(),"hh:mm");
 | 
	
		
			
				|  |  | +    QString blockTime = Calc::blocktime(tofb, tonb).toString("hh:mm");
 | 
	
		
			
				|  |  | +    QString blockMinutes = QString::number(Calc::stringToMinutes(blockTime));
 | 
	
		
			
				|  |  | +    DEBUG("Blocktime: " << blockTime << " (" << blockMinutes << " minutes)");
 | 
	
		
			
				|  |  | +    auto acft = Aircraft(newData.value("acft").toInt());
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    DEBUG("aircraftDetails: " << acft);
 | 
	
		
			
				|  |  | +    if(!acft.data.isEmpty()){// valid aircraft
 | 
	
		
			
				|  |  | +        // SP SE
 | 
	
		
			
				|  |  | +        if(acft.data.value("singlepilot") == "1" && acft.data.value("singleengine") == "1"){
 | 
	
		
			
				|  |  | +            ui->spseTimeLineEdit->setText(blockTime);
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        // SP ME
 | 
	
		
			
				|  |  | +        if(acft.data.value("singlepilot") == "1" && acft.data.value("multiengine") == "1"){
 | 
	
		
			
				|  |  | +            ui->spmeTimeLineEdit->setText(blockTime);
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        // MP
 | 
	
		
			
				|  |  | +        if(acft.data.value("multipilot") == "1"){
 | 
	
		
			
				|  |  | +            ui->mpTimeLineEdit->setText(blockTime);
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +    }else{DEBUG("Aircraft Details Empty");}//invalid aircraft
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // TOTAL
 | 
	
		
			
				|  |  | +    ui->totalTimeLineEdit->setText(blockTime);
 | 
	
		
			
				|  |  | +    // IFR
 | 
	
		
			
				|  |  | +    if(ui->IfrCheckBox->isChecked()){
 | 
	
		
			
				|  |  | +        ui->ifrTimeLineEdit->setText(blockTime);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    // Night
 | 
	
		
			
				|  |  | +    QString deptDate = ui->newDoft->date().toString(Qt::ISODate) + 'T' + tofb.toString("hh:mm");
 | 
	
		
			
				|  |  | +    QDateTime deptDateTime = QDateTime::fromString(deptDate,"yyyy-MM-ddThh:mm");
 | 
	
		
			
				|  |  | +    int tblk = blockMinutes.toInt();
 | 
	
		
			
				|  |  | +    const int nightAngle = Settings::read("flightlogging/nightangle").toInt();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    QString nightTime = QString::number(
 | 
	
		
			
				|  |  | +                        Calc::calculateNightTime(
 | 
	
		
			
				|  |  | +                        newData.value("dept"), newData.value("dest"),
 | 
	
		
			
				|  |  | +                        deptDateTime, tblk, nightAngle));
 | 
	
		
			
				|  |  | +    ui->nightTimeLineEdit->setText(Calc::minutesToString(nightTime));
 | 
	
		
			
				|  |  | +    // Function times
 | 
	
		
			
				|  |  | +    switch (ui->FunctionComboBox->currentIndex()) {
 | 
	
		
			
				|  |  | +    case 0://PIC
 | 
	
		
			
				|  |  | +        ui->picTimeLineEdit->setText(blockTime);
 | 
	
		
			
				|  |  | +        ui->copTimeLineEdit->setText("");
 | 
	
		
			
				|  |  | +        ui->dualTimeLineEdit->setText("");
 | 
	
		
			
				|  |  | +        ui->fiTimeLineEdit->setText("");
 | 
	
		
			
				|  |  | +        break;
 | 
	
		
			
				|  |  | +    case 1://Co-Pilot
 | 
	
		
			
				|  |  | +        ui->picTimeLineEdit->setText("");
 | 
	
		
			
				|  |  | +        ui->copTimeLineEdit->setText(blockTime);
 | 
	
		
			
				|  |  | +        ui->dualTimeLineEdit->setText("");
 | 
	
		
			
				|  |  | +        ui->fiTimeLineEdit->setText("");
 | 
	
		
			
				|  |  | +        break;
 | 
	
		
			
				|  |  | +    case 2://Dual
 | 
	
		
			
				|  |  | +        ui->picTimeLineEdit->setText("");
 | 
	
		
			
				|  |  | +        ui->copTimeLineEdit->setText("");
 | 
	
		
			
				|  |  | +        ui->dualTimeLineEdit->setText(blockTime);
 | 
	
		
			
				|  |  | +        ui->fiTimeLineEdit->setText("");
 | 
	
		
			
				|  |  | +        break;
 | 
	
		
			
				|  |  | +    case 3://Instructor
 | 
	
		
			
				|  |  | +        ui->picTimeLineEdit->setText("");
 | 
	
		
			
				|  |  | +        ui->copTimeLineEdit->setText("");
 | 
	
		
			
				|  |  | +        ui->dualTimeLineEdit->setText("");
 | 
	
		
			
				|  |  | +        ui->fiTimeLineEdit->setText(blockTime);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +bool NewFlight::verifyInput()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    QVector<QLineEdit*> notFilled;
 | 
	
		
			
				|  |  | +    for(auto lineEdit : mandatoryLineEdits)
 | 
	
		
			
				|  |  | +    {
 | 
	
		
			
				|  |  | +        if(!allOkBits.testBit(lineEditBitMap[lineEdit]))
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            notFilled.push_back(lineEdit);
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    if(!notFilled.empty()){
 | 
	
		
			
				|  |  | +        QMessageBox notFilledMessageBox(this);
 | 
	
		
			
				|  |  | +        auto errorMsg = QString("Not all required fields are filled out.\n\n"
 | 
	
		
			
				|  |  | +                                "Plase make sure the following are not empty:\n\n"
 | 
	
		
			
				|  |  | +                                "Departure\nDestination\nTime Off Blocks\nTime On Blocks\n"
 | 
	
		
			
				|  |  | +                                "Pilot in Command\nAircraft Registration\n\n");
 | 
	
		
			
				|  |  | +        notFilledMessageBox.setText(errorMsg);
 | 
	
		
			
				|  |  | +        notFilledMessageBox.exec();
 | 
	
		
			
				|  |  | +        return false;
 | 
	
		
			
				|  |  | +    } else {
 | 
	
		
			
				|  |  | +        QStringList lineEditText;
 | 
	
		
			
				|  |  | +        for(auto line_edit : mandatoryLineEdits)
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            lineEditText.push_back(line_edit->text());
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        this->result = lineEditText;
 | 
	
		
			
				|  |  | +        emit mandatoryFieldsValid(this);
 | 
	
		
			
				|  |  | +        return true;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +/*!
 | 
	
		
			
				|  |  | + * ============================================================================
 | 
	
		
			
				|  |  | + * Slots
 | 
	
		
			
				|  |  | + * ============================================================================
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +void NewFlight::on_buttonBox_accepted()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    DEBUG("OK pressed");
 | 
	
		
			
				|  |  | +    if(verifyInput()){
 | 
	
		
			
				|  |  | +        DEBUG("Input verified");
 | 
	
		
			
				|  |  | +        collectBasicData();
 | 
	
		
			
				|  |  | +        collectAdditionalData();
 | 
	
		
			
				|  |  | +        auto newFlight = Flight(newData);
 | 
	
		
			
				|  |  | +        if(newFlight.commit()){
 | 
	
		
			
				|  |  | +            accept();
 | 
	
		
			
				|  |  | +        } else {
 | 
	
		
			
				|  |  | +            auto mb = new QMessageBox(this);
 | 
	
		
			
				|  |  | +            auto errorMsg = QString("Unable to commit Flight to Logbook."
 | 
	
		
			
				|  |  | +                                    "The following error has ocurred:\n\n");
 | 
	
		
			
				|  |  | +            errorMsg.append(newFlight.error);
 | 
	
		
			
				|  |  | +            mb->setText(errorMsg);
 | 
	
		
			
				|  |  | +            mb->show();
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void NewFlight::on_buttonBox_rejected()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    DEBUG("CANCEL pressed." << newData);
 | 
	
		
			
				|  |  | +    reject();
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +/*!
 | 
	
		
			
				|  |  | + * \brief onInputRejected Set `line_edit`'s border to red and check if `rgx` matches
 | 
	
		
			
				|  |  | + * in order to keep text on line. Ensures corresponding LineEdit bit is 0.
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +void NewFlight::onInputRejected(QLineEdit* line_edit, QRegularExpression rgx){
 | 
	
		
			
				|  |  | +    DEBUG("Input rejected" << line_edit->text());
 | 
	
		
			
				|  |  | +    line_edit->setStyleSheet("border: 1px solid red");
 | 
	
		
			
				|  |  | +    this->allOkBits.setBit(this->lineEditBitMap[line_edit], false);
 | 
	
		
			
				|  |  | +    auto text = line_edit->text();
 | 
	
		
			
				|  |  | +    if(!rgx.match(text).hasMatch())
 | 
	
		
			
				|  |  | +    {
 | 
	
		
			
				|  |  | +        line_edit->setText(line_edit->text());
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/*!
 | 
	
		
			
				|  |  | + * \brief onEditingFinishedCleanup resets styles and sets the corresponding bit to 1
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +void NewFlight::onEditingFinishedCleanup(QLineEdit* line_edit)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    DEBUG("Input accepted" << line_edit << line_edit->text());
 | 
	
		
			
				|  |  | +    line_edit->setStyleSheet("");
 | 
	
		
			
				|  |  | +    this->allOkBits.setBit(this->lineEditBitMap[line_edit], true);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +QStringList* NewFlight::getResult() { return &this->result; }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void NewFlight::on_deptTZ_currentTextChanged(const QString &arg1)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    if(arg1 == "Local"){nope();}  // currently only UTC time logging is supported
 | 
	
		
			
				|  |  | +    ui->deptTZ->setCurrentIndex(0);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void NewFlight::on_destTZ_currentIndexChanged(const QString &arg1)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    if(arg1 == "Local"){nope();}  // currently only UTC time logging is supported
 | 
	
		
			
				|  |  | +    ui->destTZ->setCurrentIndex(0);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/// Departure
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void NewFlight::on_newDeptLocLineEdit_inputRejected()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    DEBUG("SENDER --->" << sender());
 | 
	
		
			
				|  |  | +    ui->newDeptLocLineEdit->setText(ui->newDeptLocLineEdit->text().toUpper());
 | 
	
		
			
				|  |  | +    onInputRejected(ui->newDeptLocLineEdit, QRegularExpression(LOC_INVALID_RGX));
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void NewFlight::on_newDeptLocLineEdit_textEdited(const QString &arg1)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    ui->newDeptLocLineEdit->setText(arg1.toUpper());
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void NewFlight::on_newDeptLocLineEdit_editingFinished()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    DEBUG(sender()->objectName() << "EDITING FINISHED");
 | 
	
		
			
				|  |  | +    auto line_edit = ui->newDeptLocLineEdit;
 | 
	
		
			
				|  |  | +    auto text = ui->newDeptLocLineEdit->text();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // check if iata exists, replace with icao code if it does.
 | 
	
		
			
				|  |  | +    if(text.length() == 3){
 | 
	
		
			
				|  |  | +        text = airportMap.value(text);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    // Check if 4-letter code is in locationList
 | 
	
		
			
				|  |  | +    if(text.length() == 4 && airports.indexOf(text) == -1){
 | 
	
		
			
				|  |  | +        DEBUG("Airport not found.");
 | 
	
		
			
				|  |  | +        emit line_edit->inputRejected();
 | 
	
		
			
				|  |  | +        return;
 | 
	
		
			
				|  |  | +    }else{
 | 
	
		
			
				|  |  | +        DEBUG("Departure accepted: " << text);
 | 
	
		
			
				|  |  | +        line_edit->setText(text);
 | 
	
		
			
				|  |  | +        onEditingFinishedCleanup(line_edit); //reset style sheet
 | 
	
		
			
				|  |  | +        update();
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void NewFlight::on_newDeptTimeLineEdit_inputRejected()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    onInputRejected(ui->newDeptTimeLineEdit, QRegularExpression(TIME_INVALID_RGX));
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void NewFlight::on_newDeptTimeLineEdit_editingFinished()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    ui->newDeptTimeLineEdit->setText(Calc::formatTimeInput(ui->newDeptTimeLineEdit->text()));
 | 
	
		
			
				|  |  | +    const auto time = QTime::fromString(ui->newDeptTimeLineEdit->text(),"hh:mm");
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    auto line_edit = ui->newDeptTimeLineEdit;
 | 
	
		
			
				|  |  | +    onEditingFinishedCleanup(line_edit);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if(time.isValid()){
 | 
	
		
			
				|  |  | +        int minutes = time.hour() * 60 + time.minute();
 | 
	
		
			
				|  |  | +        QString tofb = QString::number(minutes);
 | 
	
		
			
				|  |  | +        DEBUG("Time Off Blocks accepted: " << tofb << " minutes - " << Calc::minutesToString(tofb));
 | 
	
		
			
				|  |  | +    }else{
 | 
	
		
			
				|  |  | +        emit line_edit->inputRejected();
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    onEditingFinishedCleanup(line_edit);
 | 
	
		
			
				|  |  | +    update();
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/// Destination
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void NewFlight::on_newDestLocLineEdit_inputRejected()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    ui->newDestLocLineEdit->setText(ui->newDestLocLineEdit->text().toUpper());
 | 
	
		
			
				|  |  | +    onInputRejected(ui->newDestLocLineEdit, QRegularExpression(LOC_INVALID_RGX));
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void NewFlight::on_newDestLocLineEdit_textEdited(const QString &arg1)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    ui->newDestLocLineEdit->setText(arg1.toUpper());
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void NewFlight::on_newDestLocLineEdit_editingFinished()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    DEBUG(sender()->objectName() << "EDITING FINISHED");
 | 
	
		
			
				|  |  | +    auto line_edit = ui->newDestLocLineEdit;
 | 
	
		
			
				|  |  | +    auto text = ui->newDestLocLineEdit->text();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // check if iata exists, replace with icao code if it does.
 | 
	
		
			
				|  |  | +    if(text.length() == 3){
 | 
	
		
			
				|  |  | +        text = airportMap.value(text);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    // Check if 4-letter code is in locationList
 | 
	
		
			
				|  |  | +    if(text.length() == 4 && airports.indexOf(text) == -1){
 | 
	
		
			
				|  |  | +        DEBUG("Airport not found.");
 | 
	
		
			
				|  |  | +        emit line_edit->inputRejected();
 | 
	
		
			
				|  |  | +        return;
 | 
	
		
			
				|  |  | +    }else{
 | 
	
		
			
				|  |  | +        DEBUG("Destination accepted: " << text);
 | 
	
		
			
				|  |  | +        line_edit->setText(text);
 | 
	
		
			
				|  |  | +        onEditingFinishedCleanup(line_edit); //reset style sheet
 | 
	
		
			
				|  |  | +        update();
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void NewFlight::on_newDestTimeLineEdit_inputRejected()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    onInputRejected(ui->newDestTimeLineEdit, QRegularExpression(TIME_INVALID_RGX));
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void NewFlight::on_newDestTimeLineEdit_editingFinished()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    ui->newDestTimeLineEdit->setText(Calc::formatTimeInput(ui->newDestTimeLineEdit->text()));
 | 
	
		
			
				|  |  | +    auto line_edit = ui->newDestTimeLineEdit;
 | 
	
		
			
				|  |  | +    const auto time = QTime::fromString(ui->newDestTimeLineEdit->text(),"hh:mm");
 | 
	
		
			
				|  |  | +    if(time.isValid()){
 | 
	
		
			
				|  |  | +        int minutes = time.hour() * 60 + time.minute();
 | 
	
		
			
				|  |  | +        QString tonb = QString::number(minutes);
 | 
	
		
			
				|  |  | +        newData.insert("tonb",tonb);
 | 
	
		
			
				|  |  | +        DEBUG("Time On Blocks accepted: " << tonb << " minutes - " << Calc::minutesToString(tonb));
 | 
	
		
			
				|  |  | +    }else{
 | 
	
		
			
				|  |  | +        emit line_edit->inputRejected();
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    onEditingFinishedCleanup(line_edit);
 | 
	
		
			
				|  |  | +    update();
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/// Date
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void NewFlight::on_newDoft_editingFinished()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    update();
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/// Aircraft
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void NewFlight::on_newAcft_inputRejected()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    ui->newAcft->setText(ui->newAcft->text().toUpper());
 | 
	
		
			
				|  |  | +    onInputRejected(ui->newAcft, QRegularExpression(AIRCRAFT_INVALID_RGX));
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void NewFlight::on_newAcft_editingFinished()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    auto registrationList = CompletionList(CompleterTarget::registrations).list;
 | 
	
		
			
				|  |  | +    auto line_edit = ui->newAcft;
 | 
	
		
			
				|  |  | +    auto text = ui->newAcft->text();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    QStringList match = registrationList.filter(line_edit->text(), Qt::CaseInsensitive);
 | 
	
		
			
				|  |  | +    DEBUG("aircraft accepted: " << match);
 | 
	
		
			
				|  |  | +    if(match.length() != 0) {
 | 
	
		
			
				|  |  | +        text = match[0];
 | 
	
		
			
				|  |  | +        line_edit->setText(text.toUpper());
 | 
	
		
			
				|  |  | +        onEditingFinishedCleanup(line_edit);
 | 
	
		
			
				|  |  | +        update();
 | 
	
		
			
				|  |  | +    }else{
 | 
	
		
			
				|  |  | +        DEBUG("Registration not in List!");
 | 
	
		
			
				|  |  | +        emit line_edit->inputRejected();
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/// Pilot(s)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void NewFlight::on_newPicNameLineEdit_inputRejected()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    onInputRejected(ui->newPicNameLineEdit, QRegularExpression(PILOT_NAME_INVALID_RGX));
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void NewFlight::on_newPicNameLineEdit_editingFinished()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    auto line_edit = ui->newPicNameLineEdit;
 | 
	
		
			
				|  |  | +    auto text = line_edit->text();
 | 
	
		
			
				|  |  | +    if(text == "self" || text == "SELF") // Logbook owner is PIC
 | 
	
		
			
				|  |  | +    {
 | 
	
		
			
				|  |  | +        DEBUG("Pilot selected: " << text);
 | 
	
		
			
				|  |  | +        onEditingFinishedCleanup(line_edit);
 | 
	
		
			
				|  |  | +        ui->FunctionComboBox->setCurrentIndex(0);
 | 
	
		
			
				|  |  | +        update();
 | 
	
		
			
				|  |  | +        return;
 | 
	
		
			
				|  |  | +    }else //check if entry is in pilotList
 | 
	
		
			
				|  |  | +    {
 | 
	
		
			
				|  |  | +        QStringList pilotList = CompletionList(CompleterTarget::pilots).list;
 | 
	
		
			
				|  |  | +        QStringList match = pilotList.filter(line_edit->text(), Qt::CaseInsensitive);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        if(match.length()!= 0)
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            QString pic = match[0];
 | 
	
		
			
				|  |  | +            line_edit->setText(pic);
 | 
	
		
			
				|  |  | +            DEBUG("Pilot selected: " << pic);
 | 
	
		
			
				|  |  | +            onEditingFinishedCleanup(line_edit);
 | 
	
		
			
				|  |  | +            update();
 | 
	
		
			
				|  |  | +        }else
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            DEBUG("Pilot not found.");
 | 
	
		
			
				|  |  | +            emit line_edit->inputRejected();
 | 
	
		
			
				|  |  | +            addNewPilotMessageBox();
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/*
 | 
	
		
			
				|  |  | + * ============================================================================
 | 
	
		
			
				|  |  | + * The above entris are mandatory for logging a flight,
 | 
	
		
			
				|  |  | + * the rest of the entries are either optional or can
 | 
	
		
			
				|  |  | + * be determined from the entries already made.
 | 
	
		
			
				|  |  | + * ============================================================================
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void NewFlight::on_secondPilotNameLineEdit_inputRejected()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    onInputRejected(ui->secondPilotNameLineEdit, QRegularExpression(PILOT_NAME_INVALID_RGX));
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void NewFlight::on_secondPilotNameLineEdit_editingFinished()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    auto line_edit = ui->secondPilotNameLineEdit;
 | 
	
		
			
				|  |  | +    auto text = line_edit->text();
 | 
	
		
			
				|  |  | +    if(text == "self" || text == "SELF") // Logbook owner is Pilot
 | 
	
		
			
				|  |  | +    {
 | 
	
		
			
				|  |  | +        DEBUG("Pilot selected: " << text);
 | 
	
		
			
				|  |  | +        onEditingFinishedCleanup(line_edit);
 | 
	
		
			
				|  |  | +        ui->FunctionComboBox->setCurrentIndex(1);
 | 
	
		
			
				|  |  | +        return;
 | 
	
		
			
				|  |  | +    }else //check if entry is in pilotList
 | 
	
		
			
				|  |  | +    {
 | 
	
		
			
				|  |  | +        QStringList pilotList = CompletionList(CompleterTarget::pilots).list;
 | 
	
		
			
				|  |  | +        QStringList match = pilotList.filter(line_edit->text(), Qt::CaseInsensitive);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        if(match.length()!= 0)
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            QString pic = match[0];
 | 
	
		
			
				|  |  | +            line_edit->setText(pic);
 | 
	
		
			
				|  |  | +            DEBUG("Pilot selected: " << pic);
 | 
	
		
			
				|  |  | +            onEditingFinishedCleanup(line_edit);
 | 
	
		
			
				|  |  | +        }else
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            DEBUG("Pilot not found.");
 | 
	
		
			
				|  |  | +            emit line_edit->inputRejected();
 | 
	
		
			
				|  |  | +            addNewPilotMessageBox();
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void NewFlight::on_thirdPilotNameLineEdit_inputRejected()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    onInputRejected(ui->thirdPilotNameLineEdit, QRegularExpression(PILOT_NAME_INVALID_RGX));
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void NewFlight::on_thirdPilotNameLineEdit_editingFinished()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    auto line_edit = ui->thirdPilotNameLineEdit;
 | 
	
		
			
				|  |  | +    auto text = line_edit->text();
 | 
	
		
			
				|  |  | +    if(text == "self" || text == "SELF") // Logbook owner is Pilot
 | 
	
		
			
				|  |  | +    {
 | 
	
		
			
				|  |  | +        DEBUG("Pilot selected: " << text);
 | 
	
		
			
				|  |  | +        onEditingFinishedCleanup(line_edit);
 | 
	
		
			
				|  |  | +        return;
 | 
	
		
			
				|  |  | +    }else //check if entry is in pilotList
 | 
	
		
			
				|  |  | +    {
 | 
	
		
			
				|  |  | +        QStringList pilotList = CompletionList(CompleterTarget::pilots).list;
 | 
	
		
			
				|  |  | +        QStringList match = pilotList.filter(line_edit->text(), Qt::CaseInsensitive);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        if(match.length()!= 0)
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            QString pic = match[0];
 | 
	
		
			
				|  |  | +            line_edit->setText(pic);
 | 
	
		
			
				|  |  | +            DEBUG("Pilot selected: " << pic);
 | 
	
		
			
				|  |  | +            onEditingFinishedCleanup(line_edit);
 | 
	
		
			
				|  |  | +        }else
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            DEBUG("Pilot not found.");
 | 
	
		
			
				|  |  | +            emit line_edit->inputRejected();
 | 
	
		
			
				|  |  | +            addNewPilotMessageBox();
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void NewFlight::on_FlightNumberLineEdit_editingFinished()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    qDebug() << "tbd: FlightNumber slot";
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // Setting for optional Prefix (e.g. LH, LX etc.)
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/*
 | 
	
		
			
				|  |  | + * ============================================================================
 | 
	
		
			
				|  |  | + * Extras Tab - These are for user convenience. From many of
 | 
	
		
			
				|  |  | + * these selections, determinations can be made on how to log
 | 
	
		
			
				|  |  | + * details, so that the user does not have to enter each item
 | 
	
		
			
				|  |  | + * manually. See also fillExtrasLineEdits()
 | 
	
		
			
				|  |  | + * ============================================================================
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void NewFlight::on_setAsDefaultButton_clicked()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    writeSettings();
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void NewFlight::on_restoreDefaultButton_clicked()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    readSettings();
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/*!
 | 
	
		
			
				|  |  | + * \brief On a given flight, time can either be logged as Pilot Flying (PF) or
 | 
	
		
			
				|  |  | + * Pilot Monitoring (PM). Cases where controls are changed during the flight
 | 
	
		
			
				|  |  | + * are rare and can be logged by manually editing the extras.
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +void NewFlight::on_PilotFlyingCheckBox_stateChanged(int)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    if(ui->PilotFlyingCheckBox->isChecked()){
 | 
	
		
			
				|  |  | +        ui->TakeoffSpinBox->setValue(1);
 | 
	
		
			
				|  |  | +        ui->TakeoffCheckBox->setCheckState(Qt::Checked);
 | 
	
		
			
				|  |  | +        ui->LandingSpinBox->setValue(1);
 | 
	
		
			
				|  |  | +        ui->LandingCheckBox->setCheckState(Qt::Checked);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    }else if(!ui->PilotFlyingCheckBox->isChecked()){
 | 
	
		
			
				|  |  | +        ui->TakeoffSpinBox->setValue(0);
 | 
	
		
			
				|  |  | +        ui->TakeoffCheckBox->setCheckState(Qt::Unchecked);
 | 
	
		
			
				|  |  | +        ui->LandingSpinBox->setValue(0);
 | 
	
		
			
				|  |  | +        ui->LandingCheckBox->setCheckState(Qt::Unchecked);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void NewFlight::on_ApproachComboBox_currentTextChanged(const QString &arg1)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    if(arg1 == "ILS CAT III"){  //for a CAT III approach an Autoland is mandatory, so we can preselect it.
 | 
	
		
			
				|  |  | +        ui->AutolandCheckBox->setCheckState(Qt::Checked);
 | 
	
		
			
				|  |  | +        ui->AutolandSpinBox->setValue(1);
 | 
	
		
			
				|  |  | +    }else{
 | 
	
		
			
				|  |  | +        ui->AutolandCheckBox->setCheckState(Qt::Unchecked);
 | 
	
		
			
				|  |  | +        ui->AutolandSpinBox->setValue(0);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/*
 | 
	
		
			
				|  |  | + * Extra Times - These line edits should be filled out automatically,
 | 
	
		
			
				|  |  | + * based on the ui selections and the user provided input. However,
 | 
	
		
			
				|  |  | + * manual adjustments are possible to cater for situations where for
 | 
	
		
			
				|  |  | + * example one portion of the flight is logged under different rules
 | 
	
		
			
				|  |  | + * than the rest of it.
 | 
	
		
			
				|  |  | + *
 | 
	
		
			
				|  |  | + * For example,
 | 
	
		
			
				|  |  | + * if we know the aircraft details we can determine how to log these times.
 | 
	
		
			
				|  |  | + * Some times are mutually exclusive, others can be combined.
 | 
	
		
			
				|  |  | + *
 | 
	
		
			
				|  |  | + * For example,
 | 
	
		
			
				|  |  | + * for a commercial Passenger flight, the commander can log all time as
 | 
	
		
			
				|  |  | + * Total Time and PIC time. If the aircraft is a multi-engine jet he can
 | 
	
		
			
				|  |  | + * also log Multi-Pilot time, and if he is an instructor, instructor time.
 | 
	
		
			
				|  |  | + *
 | 
	
		
			
				|  |  | + * It is not possible, however to log flight time as VFR or IFR time
 | 
	
		
			
				|  |  | + * simultaneously, as a flight at any given point in time can only follow
 | 
	
		
			
				|  |  | + * one set of rules. It is possible, to change flight rules and log the first
 | 
	
		
			
				|  |  | + * x minutes as VFR and the rest of it as IFR, for example. Hence the need
 | 
	
		
			
				|  |  | + * for the possibility to edit these times manually.
 | 
	
		
			
				|  |  | + *
 | 
	
		
			
				|  |  | + * The most complex time to determine is night time, see documentation of
 | 
	
		
			
				|  |  | + * the calc class for details.
 | 
	
		
			
				|  |  | + *
 | 
	
		
			
				|  |  | + * In General, the idea is to automatically fill as much as possible, but
 | 
	
		
			
				|  |  | + * if the user decides to change these times, accept the inputs, as long as
 | 
	
		
			
				|  |  | + * they are generally valid. We cannot cater for all possibilities, so as long
 | 
	
		
			
				|  |  | + * as the time the user has put in is a valid time <= Total Time, it can be
 | 
	
		
			
				|  |  | + * accepted to the database.
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +inline bool NewFlight::isLessOrEqualToTotalTime(QString timeString)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    if(newData.value("tblk").isEmpty()){
 | 
	
		
			
				|  |  | +        DEBUG("Total Time not set.");
 | 
	
		
			
				|  |  | +        return false;
 | 
	
		
			
				|  |  | +    } else {
 | 
	
		
			
				|  |  | +        int minutes = Calc::stringToMinutes(timeString);
 | 
	
		
			
				|  |  | +        if (minutes <= newData.value("tblk").toInt()) {
 | 
	
		
			
				|  |  | +            return true;
 | 
	
		
			
				|  |  | +        } else {
 | 
	
		
			
				|  |  | +            auto mb = new QMessageBox(this);
 | 
	
		
			
				|  |  | +            mb->setText("Cannot be more than Total Time of Flight (" + Calc::minutesToString(newData.value("tblk")) + ')');
 | 
	
		
			
				|  |  | +            mb->show();
 | 
	
		
			
				|  |  | +            return false;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void NewFlight::on_spseTimeLineEdit_editingFinished()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    const auto &le = ui->spseTimeLineEdit;
 | 
	
		
			
				|  |  | +    le->setText(Calc::formatTimeInput(le->text()));
 | 
	
		
			
				|  |  | +    const auto &text = le->text();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if(isLessOrEqualToTotalTime(text)){
 | 
	
		
			
				|  |  | +        newData.insert("tSPSE",QString::number(Calc::stringToMinutes(text)));
 | 
	
		
			
				|  |  | +    } else {
 | 
	
		
			
				|  |  | +        le->setText(QString());
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void NewFlight::on_spmeTimeLineEdit_editingFinished()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    const auto &le = ui->spmeTimeLineEdit;
 | 
	
		
			
				|  |  | +    le->setText(Calc::formatTimeInput(le->text()));
 | 
	
		
			
				|  |  | +    const auto &text = le->text();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if(isLessOrEqualToTotalTime(text)){
 | 
	
		
			
				|  |  | +        newData.insert("tSPME",QString::number(Calc::stringToMinutes(text)));
 | 
	
		
			
				|  |  | +    } else {
 | 
	
		
			
				|  |  | +        le->setText(QString());
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void NewFlight::on_mpTimeLineEdit_editingFinished()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    const auto &le = ui->mpTimeLineEdit;
 | 
	
		
			
				|  |  | +    le->setText(Calc::formatTimeInput(le->text()));
 | 
	
		
			
				|  |  | +    const auto &text = le->text();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if(isLessOrEqualToTotalTime(text)){
 | 
	
		
			
				|  |  | +        newData.insert("tMP",QString::number(Calc::stringToMinutes(text)));
 | 
	
		
			
				|  |  | +    } else {
 | 
	
		
			
				|  |  | +        le->setText(QString());
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +void NewFlight::on_ifrTimeLineEdit_editingFinished()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    const auto &le = ui->ifrTimeLineEdit;
 | 
	
		
			
				|  |  | +    le->setText(Calc::formatTimeInput(le->text()));
 | 
	
		
			
				|  |  | +    const auto &text = le->text();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if(isLessOrEqualToTotalTime(text)){
 | 
	
		
			
				|  |  | +        newData.insert("tIFR",QString::number(Calc::stringToMinutes(text)));
 | 
	
		
			
				|  |  | +    } else {
 | 
	
		
			
				|  |  | +        le->setText(QString());
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void NewFlight::on_nightTimeLineEdit_editingFinished()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    const auto &le = ui->nightTimeLineEdit;
 | 
	
		
			
				|  |  | +    le->setText(Calc::formatTimeInput(le->text()));
 | 
	
		
			
				|  |  | +    const auto &text = le->text();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if(isLessOrEqualToTotalTime(text)){
 | 
	
		
			
				|  |  | +        newData.insert("tNIGHT",QString::number(Calc::stringToMinutes(text)));
 | 
	
		
			
				|  |  | +    } else {
 | 
	
		
			
				|  |  | +        le->setText(QString());
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void NewFlight::on_picTimeLineEdit_editingFinished()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    const auto &le = ui->picTimeLineEdit;
 | 
	
		
			
				|  |  | +    le->setText(Calc::formatTimeInput(le->text()));
 | 
	
		
			
				|  |  | +    const auto &text = le->text();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if(isLessOrEqualToTotalTime(text)){
 | 
	
		
			
				|  |  | +        newData.insert("tPIC",QString::number(Calc::stringToMinutes(text)));
 | 
	
		
			
				|  |  | +    } else {
 | 
	
		
			
				|  |  | +        le->setText(QString());
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void NewFlight::on_copTimeLineEdit_editingFinished()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    const auto &le = ui->copTimeLineEdit;
 | 
	
		
			
				|  |  | +    le->setText(Calc::formatTimeInput(le->text()));
 | 
	
		
			
				|  |  | +    const auto &text = le->text();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if(isLessOrEqualToTotalTime(text)){
 | 
	
		
			
				|  |  | +        newData.insert("tSIC",QString::number(Calc::stringToMinutes(text)));
 | 
	
		
			
				|  |  | +    } else {
 | 
	
		
			
				|  |  | +        le->setText(QString());
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void NewFlight::on_dualTimeLineEdit_editingFinished()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    const auto &le = ui->dualTimeLineEdit;
 | 
	
		
			
				|  |  | +    le->setText(Calc::formatTimeInput(le->text()));
 | 
	
		
			
				|  |  | +    const auto &text = le->text();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if(isLessOrEqualToTotalTime(text)){
 | 
	
		
			
				|  |  | +        newData.insert("tDual",QString::number(Calc::stringToMinutes(text)));
 | 
	
		
			
				|  |  | +    } else {
 | 
	
		
			
				|  |  | +        le->setText(QString());
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void NewFlight::on_fiTimeLineEdit_editingFinished()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    const auto &le = ui->fiTimeLineEdit;
 | 
	
		
			
				|  |  | +    le->setText(Calc::formatTimeInput(le->text()));
 | 
	
		
			
				|  |  | +    const auto &text = le->text();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if(isLessOrEqualToTotalTime(text)){
 | 
	
		
			
				|  |  | +        newData.insert("tFI",QString::number(Calc::stringToMinutes(text)));
 | 
	
		
			
				|  |  | +    } else {
 | 
	
		
			
				|  |  | +        le->setText(QString());
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +}
 |