Browse Source

rework of NewFlight Dialog and addition of runguard class

fiffty-50 4 years ago
parent
commit
05d640ddbc

+ 8 - 0
main.cpp

@@ -17,6 +17,7 @@
  */
 #include "mainwindow.h"
 #include "src/gui/dialogues/firstrundialog.h"
+#include "src/classes/runguard.h"
 #include <QApplication>
 #include <QProcess>
 #include <QSettings>
@@ -41,6 +42,13 @@ bool setup()
 
 int main(int argc, char *argv[])
 {
+    //sqlite does not deal well with multiple connections, ensure only one instance is running
+    RunGuard guard("opl_single_key");
+        if ( !guard.tryToRun() ){
+            qDebug() << "Another Instance is already running. Exiting.";
+            return 0;
+        }
+
     QCoreApplication::setOrganizationName("openPilotLog");
     QCoreApplication::setOrganizationDomain("https://github.com/fiffty-50/openpilotlog");
     QCoreApplication::setApplicationName("openPilotLog");

+ 2 - 11
mainwindow.cpp

@@ -100,17 +100,8 @@ void MainWindow::on_actionSettings_triggered()
 
 void MainWindow::on_actionNewFlight_triggered()
 {
-    /*
-       QVector<QStringList> lineEdit_completionLists = {
-           QStringList(),//empty dummy list for TimeLineEdits
-           dbAirport::retreiveIataIcaoList(),
-           dbAircraft::retreiveRegistrationList(),
-           dbPilots::retreivePilotList()
-       };
-
-       NewFlight nf(this, lineEdit_completionLists);
-       nf.exec();
-       */
+    NewFlight nf(this);
+    nf.exec();
 }
 
 void MainWindow::on_actionAircraft_triggered()

+ 5 - 0
openPilotLog.pro

@@ -23,6 +23,7 @@ SOURCES += \
     src/classes/completionlist.cpp \
     src/classes/flight.cpp \
     src/classes/pilot.cpp \
+    src/classes/runguard.cpp \
     src/classes/settings.cpp \
     src/classes/stat.cpp \
     src/classes/strictrxvalidator.cpp \
@@ -30,6 +31,7 @@ SOURCES += \
     src/database/dbinfo.cpp \
     src/database/entry.cpp \
     src/gui/dialogues/firstrundialog.cpp \
+    src/gui/dialogues/newflight.cpp \
     src/gui/dialogues/newpilot.cpp \
     src/gui/dialogues/newtail.cpp \
     src/gui/widgets/aircraftwidget.cpp \
@@ -46,6 +48,7 @@ HEADERS += \
     src/classes/completionlist.h \
     src/classes/flight.h \
     src/classes/pilot.h \
+    src/classes/runguard.h \
     src/classes/settings.h \
     src/classes/stat.h \
     src/classes/strictrxvalidator.h \
@@ -53,6 +56,7 @@ HEADERS += \
     src/database/dbinfo.h \
     src/database/entry.h \
     src/gui/dialogues/firstrundialog.h \
+    src/gui/dialogues/newflight.h \
     src/gui/dialogues/newpilot.h \
     src/gui/dialogues/newtail.h \
     src/gui/widgets/aircraftwidget.h \
@@ -65,6 +69,7 @@ HEADERS += \
 FORMS += \
     mainwindow.ui \
     src/gui/dialogues/firstrundialog.ui \
+    src/gui/dialogues/newflight.ui \
     src/gui/dialogues/newpilot.ui \
     src/gui/dialogues/newtail.ui \
     src/gui/widgets/aircraftwidget.ui \

+ 1 - 1
openPilotLog.pro.user

@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <!DOCTYPE QtCreatorProject>
-<!-- Written by QtCreator 4.11.0, 2020-11-08T19:27:35. -->
+<!-- Written by QtCreator 4.11.0, 2020-11-17T21:22:09. -->
 <qtcreator>
  <data>
   <variable>EnvironmentId</variable>

+ 21 - 0
src/classes/calc.cpp

@@ -92,6 +92,7 @@ int Calc::stringToMinutes(QString timestring)
     return minutes;
 }
 
+
 /*!
  * The purpose of the following functions is to provide functionality enabling the Calculation of
  * night flying time. EASA defines night as follows:
@@ -381,6 +382,26 @@ int Calc::calculateNightTime(QString dept, QString dest, QDateTime departureTime
     return nightTime;
 }
 
+bool Calc::isNight(QString icao, QDateTime eventTime, int nightAngle)
+{
+    QVector<QString> columns = {"lat", "long"};
+    QVector<QString> coordinates = Db::multiSelect(columns, "airports", "icao", icao,
+                                                       Db::exactMatch);
+    if (coordinates.isEmpty()) {
+        DEB("invalid input. aborting.");
+        return false;
+    }
+
+    double lat = degToRad(coordinates[0].toDouble());
+    double lon = degToRad(coordinates[1].toDouble());
+
+    if(solarElevation(eventTime, lat, lon) < nightAngle){
+        return true;
+    } else {
+        return false;
+    }
+}
+
 /*!
  * \brief Calc::formatTimeInput verifies user input and formats to hh:mm
  * if the output is not a valid time, an empty string is returned. Accepts

+ 2 - 0
src/classes/calc.h

@@ -63,6 +63,8 @@ public:
 
     static int calculateNightTime(QString dept, QString dest, QDateTime departureTime, int tblk, int nightAngle);
 
+    static bool isNight(QString icao, QDateTime eventTime, int nightAngle);
+
     static QString formatTimeInput(QString userinput);
 
     static void updateAutoTimes(int acft_id);

+ 80 - 0
src/classes/runguard.cpp

@@ -0,0 +1,80 @@
+#include "runguard.h"
+
+#include <QCryptographicHash>
+
+
+namespace
+{
+
+QString generateKeyHash( const QString& key, const QString& salt )
+{
+    QByteArray data;
+
+    data.append( key.toUtf8() );
+    data.append( salt.toUtf8() );
+    data = QCryptographicHash::hash( data, QCryptographicHash::Sha1 ).toHex();
+
+    return data;
+}
+
+}
+
+
+RunGuard::RunGuard( const QString& key )
+    : key( key )
+    , memLockKey( generateKeyHash( key, "_memLockKey" ) )
+    , sharedmemKey( generateKeyHash( key, "_sharedmemKey" ) )
+    , sharedMem( sharedmemKey )
+    , memLock( memLockKey, 1 )
+{
+    memLock.acquire();
+    {
+        QSharedMemory fix( sharedmemKey );    // Fix for *nix: http://habrahabr.ru/post/173281/
+        fix.attach();
+    }
+    memLock.release();
+}
+
+RunGuard::~RunGuard()
+{
+    release();
+}
+
+bool RunGuard::isAnotherRunning()
+{
+    if ( sharedMem.isAttached() )
+        return false;
+
+    memLock.acquire();
+    const bool isRunning = sharedMem.attach();
+    if ( isRunning )
+        sharedMem.detach();
+    memLock.release();
+
+    return isRunning;
+}
+
+bool RunGuard::tryToRun()
+{
+    if ( isAnotherRunning() )   // Extra check
+        return false;
+
+    memLock.acquire();
+    const bool result = sharedMem.create( sizeof( quint64 ) );
+    memLock.release();
+    if ( !result )
+    {
+        release();
+        return false;
+    }
+
+    return true;
+}
+
+void RunGuard::release()
+{
+    memLock.acquire();
+    if ( sharedMem.isAttached() )
+        sharedMem.detach();
+    memLock.release();
+}

+ 35 - 0
src/classes/runguard.h

@@ -0,0 +1,35 @@
+#ifndef RUNGUARD_H
+#define RUNGUARD_H
+
+#include <QObject>
+#include <QSharedMemory>
+#include <QSystemSemaphore>
+
+/*!
+ * \brief The RunGuard class ensures only a single instance of the application
+ * is running simultaneously.
+ */
+class RunGuard
+{
+
+public:
+    RunGuard( const QString& key );
+    ~RunGuard();
+
+    bool isAnotherRunning();
+    bool tryToRun();
+    void release();
+
+private:
+    const QString key;
+    const QString memLockKey;
+    const QString sharedmemKey;
+
+    QSharedMemory sharedMem;
+    QSystemSemaphore memLock;
+
+    Q_DISABLE_COPY( RunGuard )
+};
+
+
+#endif // RUNGUARD_H

+ 1179 - 0
src/gui/dialogues/newflight.cpp

@@ -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());
+    }
+}

+ 190 - 0
src/gui/dialogues/newflight.h

@@ -0,0 +1,190 @@
+/*
+ *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/>.
+ */
+#ifndef NEWFLIGHT_H
+#define NEWFLIGHT_H
+
+#include <QDialog>
+#include <QRegularExpression>
+#include <QMessageBox>
+#include <QDebug>
+#include <QCompleter>
+#include <QLatin1Char>
+#include <QStringList>
+#include <QStringListModel>
+#include <QSortFilterProxyModel>
+#include <QButtonGroup>
+#include <QBitArray>
+#include <QLineEdit>
+
+
+#include "src/database/db.h"
+#include "src/classes/flight.h"
+#include "src/classes/aircraft.h"
+#include "src/classes/strictrxvalidator.h"
+#include "src/classes/settings.h"
+#include "src/classes/completionlist.h"
+#include "src/classes/calc.h"
+
+#include "src/gui/dialogues/newpilot.h"
+
+class SqlColumnNum{
+public:
+    SqlColumnNum() : _column(-1) {}
+    explicit
+    SqlColumnNum(int column) : _column(column) {}
+    int column() const { return _column; }
+private:
+    int _column;
+};
+
+class LineEditSettings {
+public:
+    LineEditSettings() = default;
+    explicit LineEditSettings(QRegularExpression input_valid_rgx, QRegularExpression input_invalid_rgx,
+                              SqlColumnNum sql_column)
+        : _input_valid_rgx(input_valid_rgx), _input_invalid_rgx(input_invalid_rgx),
+          _sql_column(sql_column) {}
+
+    const std::tuple<QRegularExpression, QRegularExpression, SqlColumnNum> getAll() const
+    {
+        return {_input_valid_rgx, _input_invalid_rgx, _sql_column};
+    }
+private:
+    QRegularExpression _input_valid_rgx = QRegularExpression("");
+    QRegularExpression _input_invalid_rgx = QRegularExpression("");
+    SqlColumnNum _sql_column = SqlColumnNum(-1);
+};
+
+namespace Ui {
+class NewFlight;
+}
+
+class NewFlight : public QDialog
+{
+    Q_OBJECT
+
+public:
+    explicit NewFlight(QWidget *parent);
+    ~NewFlight();
+
+    QStringList* getResult();
+
+private:
+
+    void setupLineEdit(QLineEdit* line_edit, LineEditSettings settings);
+
+    void nope();//error box
+
+    void addNewPilotMessageBox();
+
+    void readSettings();
+
+    void writeSettings();
+
+    void collectBasicData();
+
+    void collectAdditionalData();
+
+    void fillExtras();
+
+    bool verifyInput();
+
+    void onInputRejected(QLineEdit* line_edit, QRegularExpression rgx);
+
+    void onEditingFinishedCleanup(QLineEdit* line_edit);
+
+    void update();
+
+    bool isLessOrEqualToTotalTime(QString timeString);
+
+private slots:
+
+    void on_verifyButton_clicked(); //debug button
+
+    void on_deptTZ_currentTextChanged(const QString &arg1);
+    void on_destTZ_currentIndexChanged(const QString &arg1);
+
+    void on_newDeptTimeLineEdit_editingFinished();
+    void on_newDestTimeLineEdit_editingFinished();
+    void on_newDeptTimeLineEdit_inputRejected();
+    void on_newDestTimeLineEdit_inputRejected();
+
+    void on_newDeptLocLineEdit_editingFinished();
+    void on_newDestLocLineEdit_editingFinished();
+    void on_newDestLocLineEdit_inputRejected();
+    void on_newDeptLocLineEdit_inputRejected();
+
+    void on_newDeptLocLineEdit_textEdited(const QString &arg1);
+    void on_newDestLocLineEdit_textEdited(const QString &arg1);
+
+    void on_newDoft_editingFinished();
+
+    void on_newAcft_inputRejected();
+    void on_newAcft_editingFinished();
+
+    void on_newPicNameLineEdit_inputRejected();
+    void on_newPicNameLineEdit_editingFinished();
+    void on_secondPilotNameLineEdit_editingFinished();
+    void on_secondPilotNameLineEdit_inputRejected();
+    void on_thirdPilotNameLineEdit_editingFinished();
+    void on_thirdPilotNameLineEdit_inputRejected();
+
+    void on_setAsDefaultButton_clicked();
+    void on_restoreDefaultButton_clicked();
+
+    void on_buttonBox_accepted();
+    void on_buttonBox_rejected();
+
+    void on_PilotFlyingCheckBox_stateChanged(int);
+
+    void on_ApproachComboBox_currentTextChanged(const QString &arg1);
+
+    void on_spseTimeLineEdit_editingFinished();
+    void on_spmeTimeLineEdit_editingFinished();
+
+    void on_mpTimeLineEdit_editingFinished();
+
+    void on_ifrTimeLineEdit_editingFinished();
+    void on_nightTimeLineEdit_editingFinished();
+    //void on_xcTimeLineEdit_editingFinished();
+    void on_picTimeLineEdit_editingFinished();
+    void on_copTimeLineEdit_editingFinished();
+    void on_dualTimeLineEdit_editingFinished();
+    void on_fiTimeLineEdit_editingFinished();
+    //void on_simTimeLineEdit_editingFinished();
+    void on_FlightNumberLineEdit_editingFinished();
+
+signals:
+    void mandatoryFieldsValid(NewFlight* nf);
+
+private:
+    Ui::NewFlight *ui;
+    QMap<QLineEdit*, int> lineEditBitMap;
+    QVector<QLineEdit*> mandatoryLineEdits;
+    QBitArray allOkBits;
+    QMessageBox messageBox;
+    QStringList result;
+    // For Flight Object
+    QMap<QString, QString> airportMap;
+    QStringList airports;
+    QStringList pilots;
+    QStringList tails;
+    QMap<QString, QString> newData;
+};
+
+#endif // NEWFLIGHT_H

+ 738 - 0
src/gui/dialogues/newflight.ui

@@ -0,0 +1,738 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>NewFlight</class>
+ <widget class="QDialog" name="NewFlight">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>625</width>
+    <height>619</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>New Flight</string>
+  </property>
+  <layout class="QGridLayout" name="gridLayout_4">
+   <item row="0" column="0" colspan="3">
+    <widget class="QTabWidget" name="flightDataTabWidget">
+     <property name="currentIndex">
+      <number>0</number>
+     </property>
+     <widget class="QWidget" name="flightDataTab">
+      <attribute name="title">
+       <string>Flight Data</string>
+      </attribute>
+      <layout class="QGridLayout" name="gridLayout">
+       <item row="3" column="3">
+        <widget class="QLabel" name="picLabel">
+         <property name="text">
+          <string>Name PIC</string>
+         </property>
+        </widget>
+       </item>
+       <item row="3" column="0">
+        <widget class="QLabel" name="acftLabel">
+         <property name="text">
+          <string>Aircraft</string>
+         </property>
+        </widget>
+       </item>
+       <item row="2" column="2">
+        <widget class="QLineEdit" name="newDestLocLineEdit">
+         <property name="toolTip">
+          <string>Enter the ICAO 4-letter Identifier of the Airport</string>
+         </property>
+         <property name="inputMethodHints">
+          <set>Qt::ImhNone</set>
+         </property>
+         <property name="maxLength">
+          <number>4</number>
+         </property>
+         <property name="placeholderText">
+          <string>EDDF</string>
+         </property>
+        </widget>
+       </item>
+       <item row="4" column="5">
+        <widget class="QLineEdit" name="thirdPilotNameLineEdit">
+         <property name="placeholderText">
+          <string>optional</string>
+         </property>
+        </widget>
+       </item>
+       <item row="2" column="0">
+        <widget class="QLabel" name="destLabel">
+         <property name="text">
+          <string>Destination</string>
+         </property>
+        </widget>
+       </item>
+       <item row="3" column="2">
+        <widget class="QLineEdit" name="newAcft">
+         <property name="placeholderText">
+          <string>D-LMAO</string>
+         </property>
+        </widget>
+       </item>
+       <item row="1" column="0">
+        <widget class="QLabel" name="deptLabel">
+         <property name="text">
+          <string>Departure</string>
+         </property>
+        </widget>
+       </item>
+       <item row="0" column="0">
+        <widget class="QLabel" name="doftLabel">
+         <property name="text">
+          <string>Date of Flight</string>
+         </property>
+        </widget>
+       </item>
+       <item row="1" column="2">
+        <widget class="QLineEdit" name="newDeptLocLineEdit">
+         <property name="toolTip">
+          <string>Enter the ICAO 4-letter Identifier of the Airport</string>
+         </property>
+         <property name="inputMethodHints">
+          <set>Qt::ImhNone</set>
+         </property>
+         <property name="maxLength">
+          <number>4</number>
+         </property>
+         <property name="placeholderText">
+          <string>KJFK</string>
+         </property>
+        </widget>
+       </item>
+       <item row="2" column="1">
+        <widget class="QLabel" name="placeLabel2">
+         <property name="text">
+          <string>Place</string>
+         </property>
+        </widget>
+       </item>
+       <item row="5" column="0">
+        <widget class="QLabel" name="FlightNumberLabel">
+         <property name="text">
+          <string>Flight number</string>
+         </property>
+        </widget>
+       </item>
+       <item row="5" column="2">
+        <widget class="QLineEdit" name="FlightNumberLineEdit">
+         <property name="placeholderText">
+          <string>optional</string>
+         </property>
+        </widget>
+       </item>
+       <item row="2" column="4">
+        <widget class="QLabel" name="tonbLabel">
+         <property name="text">
+          <string>Time</string>
+         </property>
+        </widget>
+       </item>
+       <item row="1" column="3">
+        <widget class="QComboBox" name="deptTZ">
+         <property name="toolTip">
+          <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;UTC - Universal Time Coordinated&lt;/p&gt;&lt;p&gt;LOCAL - Local time at Airfield&lt;/p&gt;&lt;p&gt;BASE - Local time at Home Base&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+         </property>
+         <item>
+          <property name="text">
+           <string>UTC</string>
+          </property>
+         </item>
+         <item>
+          <property name="text">
+           <string>Local</string>
+          </property>
+         </item>
+        </widget>
+       </item>
+       <item row="2" column="3">
+        <widget class="QComboBox" name="destTZ">
+         <property name="toolTip">
+          <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;UTC - Universal Time Coordinated&lt;/p&gt;&lt;p&gt;LOCAL - Local time at Airfield&lt;/p&gt;&lt;p&gt;BASE - Local time at Home Base&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+         </property>
+         <item>
+          <property name="text">
+           <string>UTC</string>
+          </property>
+         </item>
+         <item>
+          <property name="text">
+           <string>Local</string>
+          </property>
+         </item>
+        </widget>
+       </item>
+       <item row="3" column="5">
+        <widget class="QLineEdit" name="newPicNameLineEdit">
+         <property name="placeholderText">
+          <string>self</string>
+         </property>
+        </widget>
+       </item>
+       <item row="5" column="5">
+        <widget class="QLineEdit" name="RemarksLineEdit">
+         <property name="placeholderText">
+          <string>optional</string>
+         </property>
+        </widget>
+       </item>
+       <item row="4" column="2">
+        <widget class="QLineEdit" name="secondPilotNameLineEdit">
+         <property name="text">
+          <string/>
+         </property>
+         <property name="placeholderText">
+          <string>optional</string>
+         </property>
+        </widget>
+       </item>
+       <item row="0" column="2">
+        <widget class="QDateEdit" name="newDoft">
+         <property name="dateTime">
+          <datetime>
+           <hour>23</hour>
+           <minute>0</minute>
+           <second>0</second>
+           <year>2019</year>
+           <month>12</month>
+           <day>7</day>
+          </datetime>
+         </property>
+         <property name="displayFormat">
+          <string>yyyy/MM/dd</string>
+         </property>
+         <property name="calendarPopup">
+          <bool>true</bool>
+         </property>
+         <property name="timeSpec">
+          <enum>Qt::UTC</enum>
+         </property>
+        </widget>
+       </item>
+       <item row="1" column="5">
+        <widget class="QLineEdit" name="newDeptTimeLineEdit">
+         <property name="toolTip">
+          <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; color:#a8abb0;&quot;&gt;Enter a valid time.&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot; color:#a8abb0;&quot;&gt;e.g.: 845 0845 8:45 08:45&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+         </property>
+         <property name="whatsThis">
+          <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+         </property>
+         <property name="maxLength">
+          <number>5</number>
+         </property>
+         <property name="placeholderText">
+          <string>00:00</string>
+         </property>
+        </widget>
+       </item>
+       <item row="1" column="1">
+        <widget class="QLabel" name="placeLabel1">
+         <property name="text">
+          <string>Place</string>
+         </property>
+        </widget>
+       </item>
+       <item row="4" column="3">
+        <widget class="QLabel" name="thirdPilotLabel">
+         <property name="text">
+          <string>Third Pilot</string>
+         </property>
+        </widget>
+       </item>
+       <item row="1" column="4">
+        <widget class="QLabel" name="tofbLabel">
+         <property name="text">
+          <string>Time</string>
+         </property>
+        </widget>
+       </item>
+       <item row="5" column="3">
+        <widget class="QLabel" name="RemarksLabel">
+         <property name="text">
+          <string>Remarks</string>
+         </property>
+        </widget>
+       </item>
+       <item row="4" column="0">
+        <widget class="QLabel" name="picLabel_2">
+         <property name="text">
+          <string>Second Pilot</string>
+         </property>
+        </widget>
+       </item>
+       <item row="2" column="5">
+        <widget class="QLineEdit" name="newDestTimeLineEdit">
+         <property name="toolTip">
+          <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; color:#a8abb0;&quot;&gt;Enter a valid time.&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot; color:#a8abb0;&quot;&gt;e.g.: 845 0845 8:45 08:45&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+         </property>
+         <property name="whatsThis">
+          <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+         </property>
+         <property name="placeholderText">
+          <string>00:00</string>
+         </property>
+        </widget>
+       </item>
+       <item row="5" column="1">
+        <widget class="QLabel" name="flightNumberPrefixLabel">
+         <property name="toolTip">
+          <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Can bet changed in Settings&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+         </property>
+         <property name="text">
+          <string/>
+         </property>
+         <property name="alignment">
+          <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+         </property>
+        </widget>
+       </item>
+      </layout>
+     </widget>
+    </widget>
+   </item>
+   <item row="2" column="0">
+    <widget class="QPushButton" name="verifyButton">
+     <property name="text">
+      <string>DebugButton</string>
+     </property>
+    </widget>
+   </item>
+   <item row="2" column="1">
+    <widget class="QLineEdit" name="verifyEdit">
+     <property name="placeholderText">
+      <string>Debug Text</string>
+     </property>
+    </widget>
+   </item>
+   <item row="2" column="2">
+    <widget class="QDialogButtonBox" name="buttonBox">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+     <property name="standardButtons">
+      <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+     </property>
+    </widget>
+   </item>
+   <item row="1" column="0" colspan="3">
+    <widget class="QTabWidget" name="tabWidget">
+     <property name="currentIndex">
+      <number>1</number>
+     </property>
+     <widget class="QWidget" name="tab">
+      <attribute name="title">
+       <string>Auto-Logging</string>
+      </attribute>
+      <layout class="QGridLayout" name="gridLayout_3">
+       <item row="4" column="1">
+        <widget class="QCheckBox" name="PilotMonitoringCheckBox">
+         <property name="text">
+          <string>PM</string>
+         </property>
+        </widget>
+       </item>
+       <item row="1" column="0">
+        <widget class="QLabel" name="label">
+         <property name="text">
+          <string>Approach </string>
+         </property>
+        </widget>
+       </item>
+       <item row="6" column="0">
+        <widget class="QLabel" name="RulesLabel">
+         <property name="text">
+          <string>Rules</string>
+         </property>
+        </widget>
+       </item>
+       <item row="6" column="1">
+        <widget class="QCheckBox" name="IfrCheckBox">
+         <property name="toolTip">
+          <string/>
+         </property>
+         <property name="text">
+          <string>IFR</string>
+         </property>
+         <property name="checked">
+          <bool>true</bool>
+         </property>
+        </widget>
+       </item>
+       <item row="8" column="1" colspan="2">
+        <widget class="QPushButton" name="setAsDefaultButton">
+         <property name="toolTip">
+          <string>Set current selection as default</string>
+         </property>
+         <property name="text">
+          <string>Set As Default</string>
+         </property>
+        </widget>
+       </item>
+       <item row="0" column="1" colspan="2">
+        <widget class="QComboBox" name="FunctionComboBox">
+         <item>
+          <property name="text">
+           <string>PIC</string>
+          </property>
+         </item>
+         <item>
+          <property name="text">
+           <string>Co-Pilot</string>
+          </property>
+         </item>
+         <item>
+          <property name="text">
+           <string>Dual</string>
+          </property>
+         </item>
+         <item>
+          <property name="text">
+           <string>Instructor</string>
+          </property>
+         </item>
+        </widget>
+       </item>
+       <item row="0" column="0">
+        <widget class="QLabel" name="FunctionLabel">
+         <property name="text">
+          <string>Function</string>
+         </property>
+        </widget>
+       </item>
+       <item row="1" column="1" colspan="2">
+        <widget class="QComboBox" name="ApproachComboBox">
+         <property name="currentText">
+          <string>ILS CAT I</string>
+         </property>
+         <item>
+          <property name="text">
+           <string>ILS CAT I</string>
+          </property>
+         </item>
+         <item>
+          <property name="text">
+           <string>ILS CAT II</string>
+          </property>
+         </item>
+         <item>
+          <property name="text">
+           <string>ILS CAT III</string>
+          </property>
+         </item>
+         <item>
+          <property name="text">
+           <string>Visual</string>
+          </property>
+         </item>
+         <item>
+          <property name="text">
+           <string>RNAV</string>
+          </property>
+         </item>
+         <item>
+          <property name="text">
+           <string>RNAV (RNP)</string>
+          </property>
+         </item>
+         <item>
+          <property name="text">
+           <string>RNAV (RNP AR)</string>
+          </property>
+         </item>
+         <item>
+          <property name="text">
+           <string>VOR</string>
+          </property>
+         </item>
+         <item>
+          <property name="text">
+           <string>NDB</string>
+          </property>
+         </item>
+         <item>
+          <property name="text">
+           <string>LOC</string>
+          </property>
+         </item>
+         <item>
+          <property name="text">
+           <string>GLS</string>
+          </property>
+         </item>
+         <item>
+          <property name="text">
+           <string>MLS</string>
+          </property>
+         </item>
+         <item>
+          <property name="text">
+           <string>SRA</string>
+          </property>
+         </item>
+        </widget>
+       </item>
+       <item row="2" column="0">
+        <widget class="QLabel" name="TaskLabel">
+         <property name="text">
+          <string>Task</string>
+         </property>
+        </widget>
+       </item>
+       <item row="2" column="1">
+        <widget class="QCheckBox" name="PilotFlyingCheckBox">
+         <property name="toolTip">
+          <string>Assumes T/O and LDG performed. If not, edit details.</string>
+         </property>
+         <property name="text">
+          <string>PF</string>
+         </property>
+         <property name="checked">
+          <bool>true</bool>
+         </property>
+         <property name="autoExclusive">
+          <bool>false</bool>
+         </property>
+         <property name="tristate">
+          <bool>false</bool>
+         </property>
+        </widget>
+       </item>
+       <item row="7" column="1">
+        <widget class="QCheckBox" name="VfrCheckBox">
+         <property name="text">
+          <string>VFR</string>
+         </property>
+        </widget>
+       </item>
+       <item row="8" column="3" colspan="2">
+        <widget class="QPushButton" name="restoreDefaultButton">
+         <property name="toolTip">
+          <string>Restore previously stored default selection</string>
+         </property>
+         <property name="text">
+          <string>Restore Default</string>
+         </property>
+        </widget>
+       </item>
+       <item row="4" column="2">
+        <widget class="QCheckBox" name="LandingCheckBox">
+         <property name="text">
+          <string>Landing</string>
+         </property>
+         <property name="checked">
+          <bool>true</bool>
+         </property>
+        </widget>
+       </item>
+       <item row="2" column="2">
+        <widget class="QCheckBox" name="TakeoffCheckBox">
+         <property name="toolTip">
+          <string/>
+         </property>
+         <property name="text">
+          <string>Take Off</string>
+         </property>
+         <property name="checked">
+          <bool>true</bool>
+         </property>
+        </widget>
+       </item>
+       <item row="2" column="3">
+        <widget class="QSpinBox" name="TakeoffSpinBox">
+         <property name="value">
+          <number>1</number>
+         </property>
+        </widget>
+       </item>
+       <item row="6" column="2">
+        <widget class="QCheckBox" name="AutolandCheckBox">
+         <property name="text">
+          <string>Autoland</string>
+         </property>
+        </widget>
+       </item>
+       <item row="6" column="3">
+        <widget class="QSpinBox" name="AutolandSpinBox"/>
+       </item>
+       <item row="4" column="3">
+        <widget class="QSpinBox" name="LandingSpinBox">
+         <property name="value">
+          <number>1</number>
+         </property>
+        </widget>
+       </item>
+      </layout>
+     </widget>
+     <widget class="QWidget" name="extraTimes">
+      <attribute name="title">
+       <string>Edit Times</string>
+      </attribute>
+      <layout class="QGridLayout" name="gridLayout_2">
+       <item row="0" column="0">
+        <widget class="QLabel" name="spse_Label">
+         <property name="text">
+          <string>SP SE</string>
+         </property>
+        </widget>
+       </item>
+       <item row="0" column="1">
+        <widget class="QLineEdit" name="spseTimeLineEdit"/>
+       </item>
+       <item row="0" column="2">
+        <widget class="QLabel" name="nightLabel">
+         <property name="text">
+          <string>Night</string>
+         </property>
+        </widget>
+       </item>
+       <item row="0" column="4">
+        <widget class="QLineEdit" name="nightTimeLineEdit"/>
+       </item>
+       <item row="1" column="0">
+        <widget class="QLabel" name="spmeLabel">
+         <property name="text">
+          <string>SP ME</string>
+         </property>
+        </widget>
+       </item>
+       <item row="1" column="1">
+        <widget class="QLineEdit" name="spmeTimeLineEdit"/>
+       </item>
+       <item row="1" column="2">
+        <widget class="QLabel" name="xcLabel">
+         <property name="text">
+          <string>XC</string>
+         </property>
+        </widget>
+       </item>
+       <item row="1" column="4">
+        <widget class="QLineEdit" name="xcTimeLineEdit"/>
+       </item>
+       <item row="2" column="0">
+        <widget class="QLabel" name="mpLabel">
+         <property name="text">
+          <string>MP</string>
+         </property>
+        </widget>
+       </item>
+       <item row="2" column="1">
+        <widget class="QLineEdit" name="mpTimeLineEdit"/>
+       </item>
+       <item row="2" column="2">
+        <widget class="QLabel" name="picTimeLabel">
+         <property name="text">
+          <string>PIC</string>
+         </property>
+        </widget>
+       </item>
+       <item row="2" column="4" rowspan="2">
+        <widget class="QLineEdit" name="picTimeLineEdit"/>
+       </item>
+       <item row="3" column="0" rowspan="2">
+        <widget class="QLabel" name="totalTimeLabel">
+         <property name="text">
+          <string>TOTAL</string>
+         </property>
+        </widget>
+       </item>
+       <item row="3" column="1" rowspan="2">
+        <widget class="QLineEdit" name="totalTimeLineEdit">
+         <property name="focusPolicy">
+          <enum>Qt::NoFocus</enum>
+         </property>
+        </widget>
+       </item>
+       <item row="4" column="2" colspan="2">
+        <widget class="QLabel" name="coPilotTimeLabel">
+         <property name="text">
+          <string>Co-Pilot</string>
+         </property>
+        </widget>
+       </item>
+       <item row="4" column="4" rowspan="2">
+        <widget class="QLineEdit" name="copTimeLineEdit"/>
+       </item>
+       <item row="5" column="0" rowspan="2">
+        <widget class="QLabel" name="ifrLabel">
+         <property name="text">
+          <string>IFR</string>
+         </property>
+        </widget>
+       </item>
+       <item row="5" column="1" rowspan="2">
+        <widget class="QLineEdit" name="ifrTimeLineEdit"/>
+       </item>
+       <item row="6" column="2">
+        <widget class="QLabel" name="dualTimeLabel">
+         <property name="text">
+          <string>Dual</string>
+         </property>
+        </widget>
+       </item>
+       <item row="6" column="4" rowspan="2">
+        <widget class="QLineEdit" name="dualTimeLineEdit"/>
+       </item>
+       <item row="8" column="2">
+        <widget class="QLabel" name="fiTimeLabel">
+         <property name="text">
+          <string>FI</string>
+         </property>
+        </widget>
+       </item>
+       <item row="8" column="4">
+        <widget class="QLineEdit" name="fiTimeLineEdit"/>
+       </item>
+       <item row="9" column="2">
+        <widget class="QLabel" name="simTimeLabel">
+         <property name="text">
+          <string>SIM</string>
+         </property>
+        </widget>
+       </item>
+       <item row="9" column="3" colspan="2">
+        <widget class="QLineEdit" name="simTimeLineEdit"/>
+       </item>
+      </layout>
+     </widget>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <tabstops>
+  <tabstop>newDeptLocLineEdit</tabstop>
+  <tabstop>newDeptTimeLineEdit</tabstop>
+  <tabstop>newDestLocLineEdit</tabstop>
+  <tabstop>newDestTimeLineEdit</tabstop>
+  <tabstop>newAcft</tabstop>
+  <tabstop>newPicNameLineEdit</tabstop>
+  <tabstop>secondPilotNameLineEdit</tabstop>
+  <tabstop>thirdPilotNameLineEdit</tabstop>
+  <tabstop>FlightNumberLineEdit</tabstop>
+  <tabstop>RemarksLineEdit</tabstop>
+  <tabstop>setAsDefaultButton</tabstop>
+  <tabstop>restoreDefaultButton</tabstop>
+  <tabstop>spseTimeLineEdit</tabstop>
+  <tabstop>spmeTimeLineEdit</tabstop>
+  <tabstop>mpTimeLineEdit</tabstop>
+  <tabstop>totalTimeLineEdit</tabstop>
+  <tabstop>ifrTimeLineEdit</tabstop>
+  <tabstop>nightTimeLineEdit</tabstop>
+  <tabstop>xcTimeLineEdit</tabstop>
+  <tabstop>picTimeLineEdit</tabstop>
+  <tabstop>copTimeLineEdit</tabstop>
+  <tabstop>dualTimeLineEdit</tabstop>
+  <tabstop>fiTimeLineEdit</tabstop>
+  <tabstop>simTimeLineEdit</tabstop>
+  <tabstop>destTZ</tabstop>
+  <tabstop>verifyButton</tabstop>
+  <tabstop>verifyEdit</tabstop>
+  <tabstop>deptTZ</tabstop>
+ </tabstops>
+ <resources/>
+ <connections/>
+</ui>

+ 18 - 3
src/gui/dialogues/newpilot.cpp

@@ -21,17 +21,32 @@
 #define DEB(expr) \
     qDebug() << __PRETTY_FUNCTION__ << "\t" << expr
 
+/* Examples for names around the world:
+ * José Eduardo Santos Tavares Melo Silva
+ * María José Carreño Quiñones
+ * 毛泽东先生 (Mao Ze Dong xiān shēng)
+ * Борис Николаевич Ельцин (Boris Nikolayevich Yeltsin)
+ * John Q. Public
+ * Abu Karim Muhammad al-Jamil ibn Nidal ibn Abdulaziz al-Filistini
+ * Nguyễn Tấn Dũng
+ * 東海林賢蔵
+ * Chris van de Hoopen
+ * Karl-Gustav von Meiershausen
+ * Mathias d'Arras
+ * Martin Luther King, Jr.
+ */
+static const auto name = QLatin1String("(\\p{L}+(\\s|'|\\-)?\\s?(\\p{L}+)?\\s?)");
 static const auto FIRSTNAME_VALID = QPair<QString, QRegularExpression> {
-    "picfirstnameLineEdit", QRegularExpression("[a-zA-Z]+")};
+    "picfirstnameLineEdit", QRegularExpression(name + name + name)};
 static const auto LASTNAME_VALID = QPair<QString, QRegularExpression> {
-    "piclastnameLineEdit", QRegularExpression("\\w+")};
+    "piclastnameLineEdit", QRegularExpression(name + name + name)};
 static const auto PHONE_VALID = QPair<QString, QRegularExpression> {
     "phoneLineEdit", QRegularExpression("^[+]{0,1}[0-9\\-\\s]+")};
 static const auto EMAIL_VALID = QPair<QString, QRegularExpression> {
     "emailLineEdit", QRegularExpression("\\A[a-z0-9!#$%&'*+/=?^_‘{|}~-]+(?:\\.[a-z0-9!#$%&'*+/=?^_‘{|}~-]+)*@"
                                         "(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\z")};
 static const auto COMPANY_VALID = QPair<QString, QRegularExpression> {
-    "companyLineEdit", QRegularExpression("\\w+")};
+    "companyLineEdit", QRegularExpression("\\w+(\\s|\\-)?(\\w+(\\s|\\-)?)?(\\w+(\\s|\\-)?)?")};
 static const auto EMPLOYEENR_VALID = QPair<QString, QRegularExpression> {
     "employeeidLineEdit", QRegularExpression("\\w+")};
 

+ 2 - 21
src/gui/widgets/homewidget.cpp

@@ -38,27 +38,8 @@ HomeWidget::~HomeWidget()
 
 void HomeWidget::on_pushButton_clicked()
 {
-    //FirstRunDialog dialog;
-    //dialog.exec();
-    //for (int i=1;i<25;i++) {
-    //    Calc::updateAutoTimes(i);
-    //}
-    Calc::updateNightTimes();
-    //DEB(Flight(23));
-    //DEB(Pilot(2));
-    /*QSettings settings;
-    int nightAngle = settings.value("flightlogging/nightangle").toInt();
-    auto flt = new Flight(10);
-    auto dateTime = QDateTime(QDate::fromString(flt->data.value("doft"),Qt::ISODate),
-                              QTime().addSecs(flt->data.value("tofb").toInt() * 60),
-                              Qt::UTC);
-    DEB(QString::number(Calc::calculateNightTime(flt->data.value("dept"),
-                                                                  flt->data.value("dest"),
-                                                                  dateTime,
-                                                                  flt->data.value("tblk").toInt(),
-                                                                  nightAngle)));*/
-    //DEB(Calc::solarElevation(datetime,60.121,11.0502));
-
+    NewFlight nf(this);
+    nf.exec();
 }
 
 void HomeWidget::showTotals()

+ 1 - 0
src/gui/widgets/homewidget.h

@@ -32,6 +32,7 @@
 #include "src/database/entry.h"
 #include "src/gui/widgets/totalswidget.h"
 #include "src/gui/dialogues/firstrundialog.h"
+#include "src/gui/dialogues/newflight.h"
 
 
 namespace Ui {

+ 4 - 5
src/gui/widgets/logbookwidget.cpp

@@ -52,11 +52,9 @@ void LogbookWidget::tableView_selectionChanged(const QItemSelection &index,
 
 void LogbookWidget::on_newFlightButton_clicked()
 {
-    //NewFlight nf(this);
-    //nf.exec();
-    QMessageBox *nope = new QMessageBox(this);
-    nope->setText("This feature is temporarily INOP.");
-    nope->exec();
+    NewFlight nf(this);
+    nf.exec();
+    refreshView(Settings::read("logbook/view").toInt());
 }
 
 void LogbookWidget::on_editFlightButton_clicked() // To Do: Fix! - use new flight, pre-filled with entry loaded from DB
@@ -64,6 +62,7 @@ void LogbookWidget::on_editFlightButton_clicked() // To Do: Fix! - use new fligh
     QMessageBox *nope = new QMessageBox(this); // edit widget currently INOP
     nope->setText("This feature is temporarily INOP.");
     nope->exec();
+
     //EditFlight ef(this);
     //ef.exec();
 }

+ 1 - 0
src/gui/widgets/logbookwidget.h

@@ -28,6 +28,7 @@
 #include "src/classes/settings.h"
 #include "src/database/db.h"
 #include "src/classes/flight.h"
+#include "src/gui/dialogues/newflight.h"
 
 namespace Ui {
 class LogbookWidget;