/*
*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 .
*/
#include "newflight.h"
#include "ui_newflight.h"
#include "newacft.h"
#include "calc.h"
#include "dbman.cpp"
#include
#include
#include
#include
#include
#include
#include
void NewFlight::on_verifyButton_clicked()//debug
{
/*on_newDoft_editingFinished();// - activate slots in case user has been active in last input before clicking submit
on_newTonb_editingFinished();
on_newTofb_editingFinished();
on_newDept_editingFinished();
on_newDest_editingFinished();
on_newAcft_editingFinished();
on_newPic_editingFinished();
verifyInput();*/
fillExtrasLineEdits();
}
/*
* Initialise variables
*/
QDate date(QDate::currentDate());
QString doft(QDate::currentDate().toString(Qt::ISODate));
QString dept;
QString dest;
QTime tofb;
QTime tonb;
QTime tblk;
QString pic;
QString acft;
QVector flight;
// extras
QString PilotFunction;
QString PilotTask;
QString TakeOff;
QString Landing;
QString Autoland;
QString ApproachType;
/*
* Window
*/
NewFlight::NewFlight(QWidget *parent) :
QDialog(parent),
ui(new Ui::NewFlight)
{
ui->setupUi(this);
ui->newDoft->setDate(QDate::currentDate());
bool hasoldinput = db::CheckScratchpad();
qDebug() << "Hasoldinput? = " << hasoldinput;
if(hasoldinput) // Re-populate the Form
{
flight = db::RetreiveScratchpad();
qDebug() << "Re-Filling Form from Scratchpad";
returnInput(flight);
}
// Validators for Line Edits
QRegExp icao_rx("[a-zA-Z]?[a-zA-Z]?[a-zA-Z]?[a-zA-Z]"); // allow only letters (upper and lower)
QValidator *ICAOvalidator = new QRegExpValidator(icao_rx, this);
ui->newDept->setValidator(ICAOvalidator);
ui->newDest->setValidator(ICAOvalidator);
QRegExp timehhmm("([01]?[0-9]|2[0-3]):?[0-5][0-9]"); //allows time in 24h format with optional leading 0 and with or without seperator
QValidator *timeInputValidator = new QRegExpValidator(timehhmm, this);
ui->newTofb->setValidator(timeInputValidator);
ui->newTonb->setValidator(timeInputValidator);
ui->spseTimeLineEdit->setValidator(timeInputValidator);
ui->spmeTimeLineEdit->setValidator(timeInputValidator);
ui->mpTimeLineEdit->setValidator(timeInputValidator);
ui->totalTimeLineEdit->setValidator(timeInputValidator);
ui->ifrTimeLineEdit->setValidator(timeInputValidator);
ui->vfrTimeLineEdit->setValidator(timeInputValidator);
ui->nightTimeLineEdit->setValidator(timeInputValidator);
ui->xcTimeLineEdit->setValidator(timeInputValidator);
ui->picTimeLineEdit->setValidator(timeInputValidator);
ui->copTimeLineEdit->setValidator(timeInputValidator);
ui->dualTimeLineEdit->setValidator(timeInputValidator);
ui->fiTimeLineEdit->setValidator(timeInputValidator);
ui->simTimeLineEdit->setValidator(timeInputValidator);
QRegExp picname("^[a-zA-Z_]+,?( [a-zA-Z_]+)*$");// allow only lastname, firstname or lastname firstname with one whitespace
QValidator *picNameValidator = new QRegExpValidator(picname, this);
ui->newPic->setValidator(picNameValidator);
// 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);
restoreSettings();
ui->deptTZ->setFocusPolicy(Qt::NoFocus);
ui->destTZ->setFocusPolicy(Qt::NoFocus);
ui->newDept->setFocus();
}
NewFlight::~NewFlight()
{
delete ui;
}
/*
* Functions
*/
void NewFlight::nope()
{
QMessageBox nope(this); //error box
nope.setText("This feature is not yet available!");
nope.exec();
}
/*!
* \brief NewFlight::validateTimeInput verifies user input and formats to hh:mm
* \param userinput from a QLineEdit
* \return formatted QString "hh:mm"
*/
QString NewFlight::validateTimeInput(QString userinput)
{
QString output;
QTime temptime;
if(userinput.length() <3)
{
QMessageBox timeformat(this);
timeformat.setText("Please enter a valid time. Any of these formats is valid:\n845 0845 8:45 08:45");
timeformat.exec();
}
bool containsSeperator = userinput.contains(":");
if(userinput.length() == 4 && !containsSeperator)
{
temptime = QTime::fromString(userinput,"hhmm");
}else if(userinput.length() == 3 && !containsSeperator)
{
if(userinput.toInt() < 240) //Qtime is invalid if time is between 000 and 240 for this case
{
QString tempstring = userinput.prepend("0");
temptime = QTime::fromString(tempstring,"hhmm");
}else
{
temptime = QTime::fromString(userinput,"Hmm");
}
}else if(userinput.length() == 4 && containsSeperator)
{
temptime = QTime::fromString(userinput,"h:mm");
}else if(userinput.length() == 5 && containsSeperator)
{
temptime = QTime::fromString(userinput,"hh:mm");
}
return temptime.toString("hh:mm");
}
/*!
* \brief NewFlight::fillExtrasLineEdits Fills the flight time line edits according to ui selections
*/
void NewFlight::fillExtrasLineEdits()
{
// SP SE
// SP ME
// MP
// TOTAL
if(tofb.isValid() && tonb.isValid()) {
ui->totalTimeLineEdit->setText(calc::blocktime(tofb,tonb).toString("hh:mm"));
}
// IFR
// VFR
// Night
if(ui->autoNightCheckBox->isChecked() && tofb.isValid() && tonb.isValid() && dept.length() == 4 && dest.length() == 4) {
QString deptDate = date.toString(Qt::ISODate) + 'T' + tofb.toString("hh:mm");
qDebug() << "Departure Date: " << deptDate;
QDateTime deptDateTime = QDateTime::fromString(deptDate,"yyyy-MM-ddThh:mm");
qDebug() << "Departure DateTime " << deptDateTime;
int blocktime = calc::time_to_minutes(calc::blocktime(tofb,tonb));
qDebug() << "Blocktime: " << blocktime;
//qDebug() << calc::calculateNightTime(dept, dest, deptDateTime, blocktime);
//qDebug() << calc::minutes_to_string(QString::number(calc::calculateNightTime(dept, dest, deptDateTime, blocktime)));
ui->nightTimeLineEdit->setText(calc::minutes_to_string(QString::number(calc::calculateNightTime(dept, dest, deptDateTime, blocktime))));
}else if(!ui->autoNightCheckBox->isChecked()) {
ui->nightTimeLineEdit->setText("");
}
// XC
// PIC
// Co-Pilot
// Dual
// FI
// SIM
}
QVector NewFlight::collectInput()
{
// Collect input from the user fields and return a vector containing the flight information
QString doft = date.toString(Qt::ISODate); // Format Date
QTime tblk = calc::blocktime(tofb,tonb); // Calculate Blocktime
// Prepare Vector for commit to database
flight = db::CreateFlightVectorFromInput(doft, dept, tofb, dest, tonb, tblk, pic, acft);
qDebug() << "Created flight vector:" << flight;
return flight;
}
bool NewFlight::verifyInput()
//check if the input is correctly formatted and all required fields are filled
{
bool deptValid = false;
bool tofbValid = false;
bool destValid = false;
bool tonbValid = false;
bool tblkValid = false;
bool picValid = false;
bool acftValid = false;
QTime tblk = calc::blocktime(tofb,tonb);
int checktblk = calc::time_to_minutes(tblk);
bool doftValid = true; //doft assumed to be always valid due to QDateTimeEdit constraints
qDebug() << "NewFlight::verifyInput() says: Date:" << doft << " - Valid?\t" << doftValid;
deptValid = db::CheckICAOValid(dept);
qDebug() << "NewFlight::verifyInput() says: Departure is:\t" << dept << " - Valid?\t" << deptValid;
destValid = db::CheckICAOValid(dest);
qDebug() << "NewFlight::verifyInput() says: Destination is:\t" << dest << " - Valid?\t" << destValid;
tofbValid = (unsigned)(calc::time_to_minutes(tofb)-0) <= (1440-0) && tofb.toString("hh:mm") != ""; // Make sure time is within range, DB 1 day = 1440 minutes. 0 is allowed (midnight) & that it is not empty.
qDebug() << "NewFlight::verifyInput() says: tofb is:\t\t" << tofb.toString("hh:mm") << " - Valid?\t" << tofbValid;
tonbValid = (unsigned)(calc::time_to_minutes(tonb)-0) <= (1440-0) && tonb.toString("hh:mm") != ""; // Make sure time is within range, DB 1 day = 1440 minutes
qDebug() << "NewFlight::verifyInput() says: tonb is:\t\t" << tonb.toString("hh:mm")<< " - Valid?\t" << tonbValid;
picValid = (pic.toInt() > 0); // pic should be a pilot_id retreived from the database
qDebug() << "NewFlight::verifyInput() says: pic is pilotd_id:\t" << pic << " - Valid?\t" << picValid;
if(!picValid)
{
QMessageBox msgBox(this);
msgBox.setText("You cannot log a flight without a valid pilot");
msgBox.exec();
}
acftValid = (acft.toInt() > 0);
qDebug() << "NewFlight::verifyInput() says: acft is tail_id:\t" << acft << " - Valid?\t" << acftValid;
if(!acftValid)
{
QMessageBox msgBox(this);
msgBox.setText("You cannot log a flight without a valid aircraft");
msgBox.exec();
}
tblkValid = checktblk != 0;
qDebug() << "NewFlight::verifyInput() says: tblk is:\t\t" << tblk.toString("hh:mm") << " - Valid?\t" << tblkValid;
if(deptValid && tofbValid && destValid && tonbValid
&& tblkValid && picValid && acftValid)
{
qDebug() << "====================================================";
qDebug() << "NewFlight::verifyInput() says: All checks passed! Very impressive. ";
return 1;
}else
{
qDebug() << "====================================================";
qDebug() << "NewFlight::verifyInput() says: Flight is invalid.";
qDebug() << "NewFlight::verifyInput() says: I will call the cops.";
return 0;
}
return 0;
}
void NewFlight::returnInput(QVector flight)
{
// Re-populates the input masks with the selected fields if input was erroneous to allow for corrections to be made
qDebug() << "return Input: " << flight;
ui->newDoft->setDate(QDate::fromString(flight[1],Qt::ISODate));
ui->newDept->setText(flight[2]);
ui->newTofb->setText(flight[3]);
ui->newDest->setText(flight[4]);
ui->newTonb->setText(flight[5]);
// flight[6] is blocktime
ui->newPic->setText(db::RetreivePilotNameFromID(flight[7]));
ui->newAcft->setText(db::RetreiveRegistration(flight[8]));
}
void NewFlight::storeSettings()
{
qDebug() << "Storing Settings...";
db::storesetting(100, ui->FunctionComboBox->currentText());
db::storesetting(101, ui->ApproachComboBox->currentText());
db::storesetting(102, QString::number(ui->PilotFlyingCheckBox->isChecked()));
db::storesetting(103, QString::number(ui->PilotMonitoringCheckBox->isChecked()));
db::storesetting(104, QString::number(ui->TakeoffSpinBox->value()));
db::storesetting(105, QString::number(ui->TakeoffCheckBox->isChecked()));
db::storesetting(106, QString::number(ui->LandingSpinBox->value()));
db::storesetting(107, QString::number(ui->LandingCheckBox->isChecked()));
db::storesetting(108, QString::number(ui->AutolandSpinBox->value()));
db::storesetting(109, QString::number(ui->AutolandCheckBox->isChecked()));
db::storesetting(110, QString::number(ui->IfrCheckBox->isChecked()));
db::storesetting(111, QString::number(ui->VfrCheckBox->isChecked()));
db::storesetting(112, QString::number(ui->autoNightCheckBox->isChecked()));
}
void NewFlight::restoreSettings()
{
qDebug() << "Restoring Settings...";//crashes if db is empty due to QVector index out of range.
ui->FunctionComboBox->setCurrentText(db::retreiveSetting("100")[1]);
ui->ApproachComboBox->setCurrentText(db::retreiveSetting("101")[1]);
ui->PilotFlyingCheckBox->setChecked(db::retreiveSetting("102")[1].toInt());
ui->PilotMonitoringCheckBox->setChecked(db::retreiveSetting("103")[1].toInt());
ui->TakeoffSpinBox->setValue(db::retreiveSetting("104")[1].toInt());
ui->TakeoffCheckBox->setChecked(db::retreiveSetting("105")[1].toInt());
ui->LandingSpinBox->setValue(db::retreiveSetting("106")[1].toInt());
ui->LandingCheckBox->setChecked(db::retreiveSetting("107")[1].toInt());
ui->AutolandSpinBox->setValue(db::retreiveSetting("108")[1].toInt());
ui->AutolandCheckBox->setChecked(db::retreiveSetting("109")[1].toInt());
ui->IfrCheckBox->setChecked(db::retreiveSetting("110")[1].toInt());
ui->VfrCheckBox->setChecked(db::retreiveSetting("111")[1].toInt());
ui->autoNightCheckBox->setChecked(db::retreiveSetting("112")[1].toInt());
//qDebug() << "restore Settings ifr to int: " << db::retreiveSetting("110")[1].toInt();
/*
*
* QString PilotFunction;
QString PilotTask;
QString TakeOff;
QString Landing;
QString Autoland;
QString ApproachType;
100 PIC NewFlight::FunctionComboBox
101 ILS CAT I NewFlight::ApproachComboBox
102 Qt::Checked NewFlight::PilotFlyingCheckBox
103 Qt::Unchecked NewFlight::PilotMonitoringCheckBox
104 1 NewFlight::TakeoffSpinBox
105 Qt::Checked NewFlight::TakeoffCheckBox
106 1 NewFlight::LandingSpinBox
107 Qt::Checked NewFlight::LandingCheckBox
108 0 NewFlight::AutolandSpinBox
109 Qt::Unchecked NewFlight::AutolandCheckBox
110 Qt::Checked NewFlight::IfrCheckBox
111 Qt::Unchecked NewFlight::VfrCheckBox
*/
}
/*
* Slots
*/
void NewFlight::on_deptTZ_currentTextChanged(const QString &arg1)
{
if(arg1 == "Local"){nope();}
ui->deptTZ->setCurrentIndex(0);
}
void NewFlight::on_destTZ_currentIndexChanged(const QString &arg1)
{
if(arg1 == "Local"){nope();}
ui->destTZ->setCurrentIndex(0);
}
void NewFlight::on_newDept_textEdited(const QString &arg1)
{
ui->newDept->setText(arg1.toUpper());
if(arg1.length()>2)
{
QStringList deptList = db::CompleteIcaoOrIata(arg1);
qDebug() << "deptList = " << deptList;
QCompleter *deptCompleter = new QCompleter(deptList, this);
deptCompleter->setCaseSensitivity(Qt::CaseInsensitive);
deptCompleter->setCompletionMode(QCompleter::UnfilteredPopupCompletion);
ui->newDept->setCompleter(deptCompleter);
}
}
void NewFlight::on_newDept_editingFinished()
{
if(ui->newDept->text().length()<3)
{
QMessageBox msgBox(this);
msgBox.setText("Please enter a 3- or 4-letter code.");
msgBox.exec();
ui->newDept->setText("");
ui->newDept->setFocus();
}
QStringList deptList;
if(ui->newDept->text().length()>1)
{
QStringList deptList = db::CompleteIcaoOrIata(ui->newDept->text());
if(deptList.length() != 0)
{
dept = deptList.first();
ui->newDept->setText(dept);
}else
{
QMessageBox msgBox(this);
msgBox.setText("No Airport with that name found.");
msgBox.exec();
ui->newDept->setText("");
ui->newDept->setFocus();
}
}
}
void NewFlight::on_newDest_textEdited(const QString &arg1)
{
ui->newDest->setText(arg1.toUpper());
if(arg1.length()>2)
{
QStringList destList = db::CompleteIcaoOrIata(arg1);
QCompleter *destCompleter = new QCompleter(destList, this);
destCompleter->setCaseSensitivity(Qt::CaseInsensitive);
destCompleter->setCompletionMode(QCompleter::UnfilteredPopupCompletion);
ui->newDest->setCompleter(destCompleter);
}
}
void NewFlight::on_newDest_editingFinished()
{
if(ui->newDest->text().length()<3)
{
QMessageBox msgBox(this);
msgBox.setText("Please enter a 3- or 4-letter code.");
msgBox.exec();
ui->newDest->setText("");
ui->newDest->setFocus();
}
QStringList destList;
if(ui->newDest->text().length()>1)
{
QStringList destList = db::CompleteIcaoOrIata(ui->newDest->text());
if(destList.length() != 0)
{
dest = destList.first();
ui->newDest->setText(dest);
}else
{
QMessageBox msgBox(this);
msgBox.setText("No Airport with that name found.");
msgBox.exec();
ui->newDest->setText("");
ui->newDest->setFocus();
}
}
}
void NewFlight::on_newDoft_editingFinished()
{
date = ui->newDoft->date();
doft = date.toString(Qt::ISODate);
}
void NewFlight::on_newTofb_editingFinished()
{
ui->newTofb->setText(validateTimeInput(ui->newTofb->text()));
tofb = QTime::fromString(ui->newTofb->text(),"hh:mm");
qDebug() << "New Time Off Blocks: " << tofb;
}
void NewFlight::on_newTonb_editingFinished()
{
ui->newTonb->setText(validateTimeInput(ui->newTonb->text()));
tonb = QTime::fromString(ui->newTonb->text(),"hh:mm");
qDebug() << "New Time On Blocks: " << tonb;
}
void NewFlight::on_newAcft_textEdited(const QString &arg1)
{
if(arg1.length()>1)
{
QStringList acftList = db::newAcftGetString(arg1);
QCompleter *acftCompleter = new QCompleter(acftList, this);
acftCompleter->setCaseSensitivity(Qt::CaseInsensitive);
acftCompleter->setCompletionMode(QCompleter::UnfilteredPopupCompletion);
ui->newAcft->setCompleter(acftCompleter);
}
}
void NewFlight::on_newAcft_editingFinished()
{
acft = "-1";// set invalid
if(ui->newAcft->text().contains(" "))// is input from QCompleter
{
QStringList input = ui->newAcft->text().split(" ");
QString registration = input[0].trimmed();
QStringList result = db::newAcftGetString(registration);
if(result.length() > 0)
{
ui->newAcft->setText(result[0]);
acft = db::newAcftGetId(registration);
}else
{
acft = "-1";
}
}else // is input from user
{
QString input = ui->newAcft->text();
QStringList result = db::newAcftGetString(input);
if(result.length() > 0)
{
ui->newAcft->setText(result[0]);
QStringList input = ui->newAcft->text().split(" ");
QString registration = input[0].trimmed();
acft = db::newAcftGetId(registration);
}else
{
acft = "-1";
}
}
if(acft == "-1")
{
QMessageBox::StandardButton reply;
reply = QMessageBox::question(this, "No aircraft found", "No aircraft found.\n Would you like to add a new aircraft to the database?",
QMessageBox::Yes|QMessageBox::No);
if (reply == QMessageBox::Yes) {
NewAcft na(this);
na.exec();
ui->newAcft->setText("");
ui->newAcft->setFocus();
}
}
qDebug() << "Editing finished. Acft: " << acft;
}
void NewFlight::on_newPic_textEdited(const QString &arg1)
{
if(arg1.length()>2)
{
QStringList picList = db::newPicGetString(arg1);
QCompleter *picCompleter = new QCompleter(picList, this);
picCompleter->setCaseSensitivity(Qt::CaseInsensitive);
picCompleter->setCompletionMode(QCompleter::UnfilteredPopupCompletion);
ui->newPic->setCompleter(picCompleter);
}
}
void NewFlight::on_newPic_editingFinished()
{
pic = "-1"; // set invalid
if(ui->newPic->text() == "self")
{
pic = "1";
}else
{
QString picname;
QStringList picList = db::newPicGetString(ui->newPic->text());
qDebug() << picList;
if(picList.length()!= 0)
{
picname = picList[0];
ui->newPic->setText(picname);
pic = db::newPicGetId(picname);
}else
{
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";
nope();
}
}
}
}
/*
* Extras
*/
void NewFlight::on_PilotFlyingCheckBox_stateChanged(int)//0, unchecked, 2 checked
{
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_setAsDefaultButton_clicked()
{
storeSettings();
}
void NewFlight::on_restoreDefaultButton_clicked()
{
restoreSettings();
}
void NewFlight::on_buttonBox_accepted()
{
on_newDoft_editingFinished();// - activate slots in case user has been active in last input before clicking submit
on_newTonb_editingFinished();
on_newTofb_editingFinished();
on_newDept_editingFinished();
on_newDest_editingFinished();
on_newAcft_editingFinished();
on_newPic_editingFinished();
QVector flight;
flight = collectInput();
if(verifyInput())
{
db::CommitFlight(flight);
qDebug() << flight << "Has been commited.";
QMessageBox msgBox(this);
msgBox.setText("Flight has been commited.");
msgBox.exec();
}else
{
qDebug() << "Invalid Input. No entry has been made in the database.";
db::CommitToScratchpad(flight);
QMessageBox msgBox(this);
msgBox.setText("Invalid entries detected. Please check your input.");
msgBox.exec();
NewFlight nf(this);
nf.exec();
}
}
void NewFlight::on_buttonBox_rejected()
{
qDebug() << "NewFlight: Rejected\n";
}
void NewFlight::on_ApproachComboBox_currentTextChanged(const QString &arg1)
{
if(arg1 == "ILS CAT III"){
ui->AutolandCheckBox->setCheckState(Qt::Checked);
ui->AutolandSpinBox->setValue(1);
}else{
ui->AutolandCheckBox->setCheckState(Qt::Unchecked);
ui->AutolandSpinBox->setValue(0);
}
ApproachType = arg1;
qDebug() << "Approach Type: " << ApproachType;
}
/*
* Times
*/
void NewFlight::on_nightTimeLineEdit_editingFinished()
{
ui->nightTimeLineEdit->setText(validateTimeInput(ui->nightTimeLineEdit->text()));
}