Browse Source

Adjusted file names and CMAKE

Removed the old NewFlightDialog from the project and replaced it with the new NewFlightDialog as a drop-in replacement. Old dialog kept for reference as oldnewflightdialog.cpp (not part of cmake)
Felix Turo 3 years ago
parent
commit
ca9d9245c3

+ 1 - 4
CMakeLists.txt

@@ -48,7 +48,6 @@ set(PROJECT_SOURCES
     src/functions/adate.cpp
     src/gui/dialogues/firstrundialog.cpp
     src/gui/dialogues/newflightdialog.cpp
-    src/gui/dialogues/newnewflightdialog.cpp
     src/gui/dialogues/newpilotdialog.cpp
     src/gui/dialogues/newtaildialog.cpp
     src/gui/widgets/aircraftwidget.cpp
@@ -90,7 +89,6 @@ set(PROJECT_SOURCES
     src/functions/atime.h
     src/gui/dialogues/firstrundialog.h
     src/gui/dialogues/newflightdialog.h
-    src/gui/dialogues/newnewflightdialog.h
     src/gui/dialogues/newpilotdialog.h
     src/gui/dialogues/newtaildialog.h
     src/gui/widgets/aircraftwidget.h
@@ -104,8 +102,7 @@ set(PROJECT_SOURCES
     
     mainwindow.ui
     src/gui/dialogues/firstrundialog.ui
-    src/gui/dialogues/newflight.ui
-    src/gui/dialogues/newnewflightdialog.ui
+    src/gui/dialogues/newflightdialog.ui
     src/gui/dialogues/newpilot.ui
     src/gui/dialogues/newtail.ui
     src/gui/widgets/aircraftwidget.ui

+ 3 - 3
mainwindow.cpp

@@ -26,11 +26,11 @@
 
 
 // Quick and dirty Debug area
-#include "src/gui/dialogues/newnewflightdialog.h"
+#include "src/gui/dialogues/newflightdialog.h"
 #include "src/functions/adatetime.h"
 void MainWindow::doDebugStuff()
 {
-    NewNewFlightDialog nf(completionData, this);
+    NewFlightDialog nf(completionData, this);
     nf.exec();
 }
 MainWindow::MainWindow(QWidget *parent)
@@ -241,7 +241,7 @@ void MainWindow::on_actionHome_triggered()
 void MainWindow::on_actionNewFlight_triggered()
 {
     completionData.update();
-    auto* nf = new NewNewFlightDialog(completionData, this);
+    auto* nf = new NewFlightDialog(completionData, this);
     nf->exec();
 }
 

File diff suppressed because it is too large
+ 389 - 829
src/gui/dialogues/newflightdialog.cpp


+ 108 - 158
src/gui/dialogues/newflightdialog.h

@@ -15,109 +15,105 @@
  *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
+#ifndef NewFlightDialog_H
+#define NewFlightDialog_H
 
 #include <QDialog>
-#include <QRegularExpression>
-#include <QMessageBox>
 #include <QDebug>
-#include <QCompleter>
-#include <QStringList>
-#include <QButtonGroup>
-#include <QBitArray>
 #include <QLineEdit>
-#include <QCalendarWidget>
-#include <QComboBox>
-#include <QTabWidget>
-#include <QKeyEvent>
-#include "src/functions/atime.h"
+#include <QList>
+#include <QBitArray>
 
+#include "src/functions/atime.h"
+#include "src/classes/acompletiondata.h"
 #include "src/classes/aflightentry.h"
 #include "src/classes/apilotentry.h"
 #include "src/classes/atailentry.h"
 #include "src/database/adatabase.h"
-#include "src/classes/acompletiondata.h"
+#include "src/opl.h"
 
-namespace Ui {
+/*!
+ * \brief The ValidationItem enum contains the items that are mandatory for logging a flight:
+ * Date of Flight, Departure, Destination, Time Off Blocks, Time On Blocks, Pilot in Command, Aircraft Registration
+ */
+enum ValidationItem {doft = 0, dept = 1, dest = 2, tofb = 3, tonb = 4, pic = 5, acft = 6};
 
-class NewFlight;
-}
+/*!
+ * \brief The ValidationState class encapsulates a QBitArray that has a bit set (or unset) depending on wether the
+ * input for the associated index has been verified. The indexes correspond to the mandatory items enumerated in the
+ * ValidationItem enum.
+ */
+class ValidationState {
+public:
+    ValidationState() = default;
+
+    void validate(ValidationItem item)   { validationArray[item] = true;};
+    void validate(int index)                  { validationArray[index] = true;};
+    void invalidate(ValidationItem item) { validationArray[item] = false;}
+    void invalidate(int index)                { validationArray[index] = false;}
+    inline bool allValid()                           { return validationArray.count(true) == 7;};
+    inline bool timesValid()                         { return validationArray[ValidationItem::tofb] && validationArray[ValidationItem::tonb];}
+    inline bool locationsValid()                     { return validationArray[ValidationItem::dept] && validationArray[ValidationItem::dest];}
+    inline bool nightDataValid()                     { return timesValid() && locationsValid() && validationArray[ValidationItem::doft];}
+    inline bool acftValid()                          { return validationArray[ValidationItem::acft];}
+    inline bool validAt(int index)                   { return validationArray[index];}
+    inline bool validAt(ValidationItem item)         { return validationArray[item];}
+
+    // Debug
+    void printValidationStatus(){
+        QString deb_string("\033[mValidation State:\tdoft\tdept\tdest\ttofb\ttonb\tpic\tacft\n");
+        deb_string += "\t\t\t\t";
+        for (int i = 0; i < 7; i++) { //\033[32m
+            if (validationArray[i])
+                deb_string += "\t\033[32m" + QString::number(validationArray[i]);
+            else
+                deb_string += "\t\033[31m" + QString::number(validationArray[i]);
+        }
+        deb_string += QLatin1String("\u001b[38;5;75m"); // return to default DEB
+        qDebug().noquote() << deb_string;
+    }
+private:
+    QBitArray validationArray = QBitArray(7);
+};
 
 /*!
- * \brief The NewFlightDialog enables the user to add a new flight or edit an existing one.
- * \details
- * - Most line edits have validators and completers.
- * - Validators are based on regular expressions, serving as raw input validation
- * - The Completers are based off the database and provide auto-completion
- * - mandatory line edits only emit editing finished if their content has passed
- *   raw input validation or focus is lost.
- * - Editing finished triggers validating inputs by mapping them to Database values
- *   where required and results in either pass or fail.
- * - A QBitArray is mainained containing the state of validity of the mandatory line edits
- * - The deducted entries are automatically filled if the necessary mandatory entries
- * are valid.
- * - Comitting an entry to the database is only allowed if all mandatory inputs are valid.
+ * \brief The ValidationSetupData struct encapsulates the items required to initialise
+ * the line edits with QValidators and QCompleters
  */
-class NewFlightDialog : public QDialog
+struct ValidationSetupData
 {
-    Q_OBJECT
-public:
-    /*!
-     * \brief NewFlightDialog create a new flight and add it to the logbook.
-     */
-    explicit NewFlightDialog(ACompletionData &completion_data, QWidget *parent = nullptr);
-    /*!
-     * \brief NewFlightDialog Edit an existing logbook entry.
-     */
-    explicit NewFlightDialog(ACompletionData &completion_data, int row_id, QWidget *parent = nullptr);
-    ~NewFlightDialog();
+    ValidationSetupData(const QStringList& completion_data, const QRegularExpression& validation_RegEx)
+        : completionList(completion_data), validationRegEx(validation_RegEx){};
 
-    /*!
-     * \brief The ValidationSetupData struct encapsulates the items required to initialise
-     * the line edits with QValidators and QCompleters
-     */
-    struct ValidationSetupData
-    {
-        ValidationSetupData(QStringList* completion_data, const QRegularExpression* validation_RegEx)
-            : completionData(completion_data), validationRegEx(validation_RegEx){};
+    ValidationSetupData(const QStringList& completion_data)
+        : completionList(completion_data){
+    };
 
-        ValidationSetupData(const QRegularExpression* validation_RegEx)
-            : completionData(nullptr), validationRegEx(validation_RegEx){};
+    ValidationSetupData(const QRegularExpression& validation_RegEx)
+        : completionList(nullptr), validationRegEx(validation_RegEx){};
 
-        const QStringList* completionData;
-        const QRegularExpression* validationRegEx;
-    };
+    const QStringList completionList;
+    const QRegularExpression validationRegEx;
+};
 
-private slots:
+namespace Ui {
+class NewFlightDialog;
+}
 
-    void onToUpperTriggered_textChanged(const QString&);
-    void onPilotNameLineEdit_editingFinished();
-    void onLocationEditingFinished(QLineEdit*, QLabel*);
-    void onTimeLineEdit_editingFinished();
-    void onCompleter_highlighted(const QString&);
-    void onCompleter_activated(const QString &);
-    void onCalendarWidget_clicked(const QDate &date);
-    void on_doftLineEdit_editingFinished();
-    void on_cancelButton_clicked();
-    void on_submitButton_clicked();
-    void on_setAsDefaultButton_clicked();
-    void on_restoreDefaultButton_clicked();
-    void on_PilotFlyingCheckBox_stateChanged(int arg1);
-    void on_IfrCheckBox_stateChanged(int);
-    void on_manualEditingCheckBox_stateChanged(int arg1);
-    void on_ApproachComboBox_currentTextChanged(const QString &arg1);
-    void on_FunctionComboBox_currentIndexChanged(int index);
-    void on_deptLocLineEdit_editingFinished();
-    void on_destLocLineEdit_editingFinished();
-    void on_acftLineEdit_editingFinished();
-    void on_deptTZComboBox_currentIndexChanged(int index);
-    void on_destTZComboBox_currentIndexChanged(int index);
+class NewFlightDialog : public QDialog
+{
+    Q_OBJECT
 
-    void on_calendarPushButton_clicked();
+public:
+
+    explicit NewFlightDialog(ACompletionData& completion_data, QWidget *parent = nullptr);
+    explicit NewFlightDialog(ACompletionData& completion_data, RowId_T row_id, QWidget* parent = nullptr);
+    ~NewFlightDialog();
 
 private:
-    Ui::NewFlight *ui;
+    Ui::NewFlightDialog *ui;
+    ACompletionData completionData;
+    ValidationState validationState;
 
     /*!
      * \brief a AFlightEntry object that is used to store either position data
@@ -126,91 +122,45 @@ private:
      */
     AFlightEntry flightEntry;
 
-    QVector<QLineEdit*> mandatoryLineEdits;
-    QVector<QLineEdit*> primaryTimeLineEdits;
-    QVector<QLineEdit*> pilotsLineEdits;
-
-    /*!
-     * \brief mandatoryLineEditsValid holds the minimum required information to create a
-     * valid database entries.
-     */
-    QBitArray mandatoryLineEditsValid;
-    enum mandatoryLineEdit {
-        doft = 0,
-        dept = 1,
-        dest = 2,
-        tofb = 3,
-        tonb = 4,
-        pic  = 5,
-        acft = 6
-    };
-    void validateMandatoryLineEdit(mandatoryLineEdit line_edit){mandatoryLineEditsValid.setBit(line_edit, true);}
-    void invalidateMandatoryLineEdit(mandatoryLineEdit line_edit){mandatoryLineEditsValid.setBit(line_edit, false);}
-    bool timeLineEditsValid(){return mandatoryLineEditsValid[mandatoryLineEdit::tofb]
-                                  && mandatoryLineEditsValid[mandatoryLineEdit::tonb];}
-    bool acftLineEditValid(){return mandatoryLineEditsValid[mandatoryLineEdit::acft];}
-    bool locLineEditsValid(){return mandatoryLineEditsValid[mandatoryLineEdit::dept]
-                                 && mandatoryLineEditsValid[mandatoryLineEdit::dest];}
-    bool allMandatoryLineEditsValid(){return mandatoryLineEditsValid.count(true) == 7;}
-
-    //debug
-    void validationStatus();
-    /*!
-     * Contains completion data for QCompleters and mapping user input
-     */
-    ACompletionData completionData;
-
-
-    Opl::Time::FlightTimeFormat flightTimeFormat;
+    static const inline QList<QLineEdit*>* timeLineEdits;
+    static const inline QList<QLineEdit*>* locationLineEdits;
+    static const inline QList<QLineEdit*>* pilotNameLineEdits;
+    static const inline QList<QLineEdit*>* mandatoryLineEdits;
+    static const inline QLatin1String self = QLatin1String("self");
 
-    /*!
-     * \brief If the user elects to manually edit function times, automatic updating
-     * is disabled.
-     */
-    bool updateEnabled;
-
-    void setup();
-    void readSettings();
-    void setupUi();
-    void writeSettings();
-    void setupButtonGroups();
+    void init();
     void setupRawInputValidation();
     void setupSignalsAndSlots();
-    void formFiller();
-    void fillDeductibleData();
+    void readSettings();
+    void fillWithEntryData();
 
-    void onMandatoryLineEditsFilled();
-    void onGoodInputReceived(QLineEdit*);
-    void onBadInputReceived(QLineEdit *);
-    bool eventFilter(QObject *object, QEvent *event);
-    bool isLessOrEqualThanBlockTime(const QString time_string);
+    void onGoodInputReceived(QLineEdit *line_edit);
+    void onBadInputReceived(QLineEdit *line_edit);
 
-    void addNewTail(QLineEdit*);
-    void addNewPilot(QLineEdit *);
+    void updateNightCheckBoxes();
+    void setNightCheckboxes();
+    void updateBlockTimeLabel();
 
-    /*!
-     * \brief Collects user input from the line edits and processes it to be ready
-     * for database submission.
-     */
-    RowData_T collectInput();
+    void addNewTail(QLineEdit& parent_line_edit);
+    void addNewPilot(QLineEdit& parent_line_edit);
 
-    /*!
-     * \brief converts a time string as used in the UI to an integer of minutes for
-     * use in the database based on the format in use in the Dialog
-     */
-    inline int stringToMinutes(const QString &time_string, Opl::Time::FlightTimeFormat format)
-    {
-        return ATime::toMinutes(ATime::fromString(time_string, format));
-    }
+    RowData_T prepareFlightEntryData();
 
-    /*!
-     * \brief minutesToString converts an integer of minutes as received from the database
-     * to a String to be displayed in the UI, based on the format in use in the Dialog.
-     */
-    inline QString minutesToString(const int minutes, Opl::Time::FlightTimeFormat format)
-    {
-        return ATime::toString(ATime::qTimefromMinutes(minutes), format);
-    }
+
+private slots:
+    void toUpper(const QString& text);
+    void onTimeLineEdit_editingFinished();
+    void onPilotNameLineEdit_editingFinshed();
+    void onLocationLineEdit_editingFinished();
+    void on_acftLineEdit_editingFinished();
+    void on_doftLineEdit_editingFinished();
+    void on_buttonBox_accepted();
+    void on_pilotFlyingCheckBox_stateChanged(int arg1);
+    void on_approachComboBox_currentTextChanged(const QString &arg1);
+    void on_functionComboBox_currentIndexChanged(int index);
+protected:
+    bool eventFilter(QObject* object, QEvent* event) override;
 };
 
-#endif // NEWFLIGHT_H
+
+#endif // NewFlightDialog_H

+ 3 - 3
src/gui/dialogues/newnewflightdialog.ui → src/gui/dialogues/newflightdialog.ui

@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <ui version="4.0">
- <class>NewNewFlightDialog</class>
- <widget class="QDialog" name="NewNewFlightDialog">
+ <class>NewFlightDialog</class>
+ <widget class="QDialog" name="NewFlightDialog">
   <property name="geometry">
    <rect>
     <x>0</x>
@@ -644,7 +644,7 @@
   <connection>
    <sender>buttonBox</sender>
    <signal>rejected()</signal>
-   <receiver>NewNewFlightDialog</receiver>
+   <receiver>NewFlightDialog</receiver>
    <slot>reject()</slot>
    <hints>
     <hint type="sourcelabel">

+ 0 - 702
src/gui/dialogues/newnewflightdialog.cpp

@@ -1,702 +0,0 @@
-#include "newnewflightdialog.h"
-#include "ui_newnewflightdialog.h"
-#include "src/opl.h"
-#include "src/functions/alog.h"
-#include "src/functions/adate.h"
-#include "src/classes/asettings.h"
-#include "src/functions/acalc.h"
-#include "src/functions/adatetime.h"
-#include "src/gui/dialogues/newtaildialog.h"
-#include "src/gui/dialogues/newpilotdialog.h"
-#include <QDateTime>
-#include <QCompleter>
-#include <QKeyEvent>
-
-NewNewFlightDialog::NewNewFlightDialog(ACompletionData &completion_data,
-                                       QWidget *parent)
-    : QDialog(parent),
-      ui(new Ui::NewNewFlightDialog),
-      completionData(completion_data)
-{
-    init();
-    flightEntry = AFlightEntry();
-    // Set up UI (New Flight)
-    LOG << ASettings::read(ASettings::FlightLogging::Function);
-    if(ASettings::read(ASettings::FlightLogging::Function).toString() == QLatin1String("PIC")){
-        ui->picNameLineEdit->setText(self);
-        ui->functionComboBox->setCurrentIndex(0);
-        emit ui->picNameLineEdit->editingFinished();
-    }
-    if (ASettings::read(ASettings::FlightLogging::Function).toString() == QLatin1String("SIC")) {
-        ui->sicNameLineEdit->setText(self);
-        ui->functionComboBox->setCurrentIndex(2);
-        emit ui->sicNameLineEdit->editingFinished();
-    }
-
-    ui->doftLineEdit->setText(QDate::currentDate().toString(Qt::ISODate));
-    emit ui->doftLineEdit->editingFinished();
-}
-
-NewNewFlightDialog::NewNewFlightDialog(ACompletionData &completion_data, RowId_T row_id, QWidget *parent)
-    : QDialog(parent),
-      ui(new Ui::NewNewFlightDialog),
-      completionData(completion_data)
-{
-    init();
-    flightEntry = aDB->getFlightEntry(row_id);
-    fillWithEntryData();
-}
-
-NewNewFlightDialog::~NewNewFlightDialog()
-{
-    delete ui;
-}
-
-void NewNewFlightDialog::init()
-{
-    // Setup UI
-    ui->setupUi(this);
-    // Initialise line edit lists
-    auto time_line_edits = new QList<QLineEdit*>{ui->tofbTimeLineEdit, ui->tonbTimeLineEdit};
-    timeLineEdits = time_line_edits;
-    auto location_line_edits = new QList<QLineEdit*>{ui->deptLocationLineEdit, ui->destLocationLineEdit};
-    locationLineEdits = location_line_edits;
-    auto pilot_name_line_edits = new QList<QLineEdit*>{ui->picNameLineEdit, ui->sicNameLineEdit, ui->thirdPilotNameLineEdit};
-    pilotNameLineEdits = pilot_name_line_edits;
-    auto mandatory_line_edits = new QList<QLineEdit*>{ui->doftLineEdit, ui->deptLocationLineEdit, ui->destLocationLineEdit,
-            ui->tofbTimeLineEdit, ui->tonbTimeLineEdit,
-            ui->picNameLineEdit, ui->acftLineEdit};
-    // {doft = 0, dept = 1, dest = 2, tofb = 3, tonb = 4, pic = 5, acft = 6}
-    mandatoryLineEdits = mandatory_line_edits;
-
-    for (const auto& line_edit : *mandatoryLineEdits)
-        line_edit->installEventFilter(this);
-
-    for (const auto & approach : Opl::ApproachTypes){
-        ui->approachComboBox->addItem(approach);
-    }
-
-    setupRawInputValidation();
-    setupSignalsAndSlots();
-    readSettings();
-}
-
-/*!
- * \brief NewNewFlightDialog::setupRawInputValidation outfits the line edits with QRegularExpresionValidators and QCompleters
- */
-void NewNewFlightDialog::setupRawInputValidation()
-{
-    // Time Line Edits
-    for (const auto& line_edit : *timeLineEdits) {
-        auto validator = new QRegularExpressionValidator(QRegularExpression("([01]?[0-9]|2[0-3]):?[0-5][0-9]?"), line_edit);
-        line_edit->setValidator(validator);
-    }
-    // Location Line Edits
-    for (const auto& line_edit : *locationLineEdits) {
-        auto validator = new QRegularExpressionValidator(QRegularExpression("[a-zA-Z0-9]{1,4}"), line_edit);
-        line_edit->setValidator(validator);
-
-        auto completer = new QCompleter(completionData.airportList, line_edit);
-        completer->setCaseSensitivity(Qt::CaseInsensitive);
-        completer->setCompletionMode(QCompleter::PopupCompletion);
-        completer->setFilterMode(Qt::MatchContains);
-        line_edit->setCompleter(completer);
-    }
-    // Name Line Edits
-    for (const auto& line_edit : *pilotNameLineEdits) {
-        auto completer = new QCompleter(completionData.pilotList, line_edit);
-        completer->setCaseSensitivity(Qt::CaseInsensitive);
-        completer->setCompletionMode(QCompleter::PopupCompletion);
-        completer->setFilterMode(Qt::MatchContains);
-        line_edit->setCompleter(completer);
-    }
-    // Acft Line Edit
-    auto completer = new QCompleter(completionData.tailsList, ui->acftLineEdit);
-    completer->setCaseSensitivity(Qt::CaseInsensitive);
-    completer->setCompletionMode(QCompleter::PopupCompletion);
-    completer->setFilterMode(Qt::MatchContains);
-    ui->acftLineEdit->setCompleter(completer);
-
-}
-
-void NewNewFlightDialog::setupSignalsAndSlots()
-{
-    for (const auto& line_edit : *timeLineEdits)
-        QObject::connect(line_edit, &QLineEdit::editingFinished,
-                         this, &NewNewFlightDialog::onTimeLineEdit_editingFinished);
-    // Change text to upper case for location and acft line edits
-    QObject::connect(ui->acftLineEdit, &QLineEdit::textChanged,
-                     this, &NewNewFlightDialog::toUpper);
-    for (const auto& line_edit : *locationLineEdits) {
-        QObject::connect(line_edit, &QLineEdit::textChanged,
-                         this, &NewNewFlightDialog::toUpper);
-        QObject::connect(line_edit, &QLineEdit::editingFinished,
-                         this, &NewNewFlightDialog::onLocationLineEdit_editingFinished);
-    }
-    for (const auto& line_edit : *pilotNameLineEdits)
-        QObject::connect(line_edit, &QLineEdit::editingFinished,
-                         this, &NewNewFlightDialog::onPilotNameLineEdit_editingFinshed);
-}
-
-bool NewNewFlightDialog::eventFilter(QObject *object, QEvent *event)
-{
-    auto line_edit = qobject_cast<QLineEdit*>(object);
-    if (line_edit != nullptr) {
-        if (mandatoryLineEdits->contains(line_edit) && event->type() == QEvent::FocusIn) {
-            // set verification bit to false when entering a mandatory line edit
-            validationState.invalidate(mandatoryLineEdits->indexOf(line_edit));
-            DEB << "Invalidating: " << line_edit->objectName();
-            return false;
-        }
-    }
-    return false;
-}
-
-void NewNewFlightDialog::readSettings()
-{
-    ASettings settings;
-    ui->functionComboBox->setCurrentText(ASettings::read(ASettings::FlightLogging::Function).toString());
-    ui->approachComboBox->setCurrentText(ASettings::read(ASettings::FlightLogging::Approach).toString());
-    ui->pilotFlyingCheckBox->setChecked(ASettings::read(ASettings::FlightLogging::PilotFlying).toBool());
-    ui->ifrCheckBox->setChecked(ASettings::read(ASettings::FlightLogging::LogIFR).toBool());
-    ui->flightNumberLineEdit->setText(ASettings::read(ASettings::FlightLogging::FlightNumberPrefix).toString());
-
-}
-
-/*!
- * \brief NewNewFlightDialog::fillWithEntryData Takes an existing flight entry and fills the UI with its data
- * to enable editing an existing flight.
- */
-void NewNewFlightDialog::fillWithEntryData()
-{
-    DEB << "Restoring Flight: ";
-    DEB << flightEntry;
-
-    // Date of Flight
-    ui->doftLineEdit->setText(flightEntry.getData().value(Opl::Db::FLIGHTS_DOFT).toString());
-    // Location
-    ui->deptLocationLineEdit->setText(flightEntry.getData().value(Opl::Db::FLIGHTS_DEPT).toString());
-    ui->destLocationLineEdit->setText(flightEntry.getData().value(Opl::Db::FLIGHTS_DEST).toString());
-    // Times
-    ui->tofbTimeLineEdit->setText(ATime::toString(flightEntry.getData().value(Opl::Db::FLIGHTS_TOFB).toInt()));
-    ui->tonbTimeLineEdit->setText(ATime::toString(flightEntry.getData().value(Opl::Db::FLIGHTS_TONB).toInt()));
-    ui->acftLineEdit->setText(completionData.tailsIdMap.value(flightEntry.getData().value(Opl::Db::FLIGHTS_ACFT).toInt()));
-    ui->picNameLineEdit->setText(completionData.pilotsIdMap.value(flightEntry.getData().value(Opl::Db::FLIGHTS_PIC).toInt()));
-    ui->sicNameLineEdit->setText(completionData.pilotsIdMap.value(flightEntry.getData().value(Opl::Db::FLIGHTS_SECONDPILOT).toInt()));
-    ui->thirdPilotNameLineEdit->setText(completionData.pilotsIdMap.value(flightEntry.getData().value(Opl::Db::FLIGHTS_THIRDPILOT).toInt()));
-
-    for (const auto& le : *mandatoryLineEdits)
-        emit le->editingFinished();
-
-    //Function
-    const QHash<int, QLatin1String> functions = {
-        {0, Opl::Db::FLIGHTS_TPIC},
-        {1, Opl::Db::FLIGHTS_TPICUS},
-        {2, Opl::Db::FLIGHTS_TSIC},
-        {3, Opl::Db::FLIGHTS_TDUAL},
-        {4, Opl::Db::FLIGHTS_TFI},
-    };
-    for (int i = 0; i < 5; i++) { // QHash::iterator not guarenteed to be in ordetr
-        if(flightEntry.getData().value(functions.value(i)).toInt() != 0)
-            ui->functionComboBox->setCurrentIndex(i);
-    }
-    // Approach ComboBox
-    const QString& app = flightEntry.getData().value(Opl::Db::FLIGHTS_APPROACHTYPE).toString();
-    if(app != QString()){
-        ui->approachComboBox->setCurrentText(app);
-    }
-    // Task
-    bool PF = flightEntry.getData().value(Opl::Db::FLIGHTS_PILOTFLYING).toBool();
-    ui->pilotFlyingCheckBox->setChecked(PF);
-    // Flight Rules
-    bool time_ifr = flightEntry.getData().value(Opl::Db::FLIGHTS_TIFR).toBool();
-    ui->ifrCheckBox->setChecked(time_ifr);
-    // Take-Off and Landing
-    int TO = flightEntry.getData().value(Opl::Db::FLIGHTS_TODAY).toInt()
-            + flightEntry.getData().value(Opl::Db::FLIGHTS_TONIGHT).toInt();
-    int LDG = flightEntry.getData().value(Opl::Db::FLIGHTS_LDGDAY).toInt()
-            + flightEntry.getData().value(Opl::Db::FLIGHTS_LDGNIGHT).toInt();
-    ui->takeOffSpinBox->setValue(TO);
-    ui->landingSpinBox->setValue(LDG);
-    // Remarks
-    ui->remarksLineEdit->setText(flightEntry.getData().value(Opl::Db::FLIGHTS_REMARKS).toString());
-    // Flight Number
-    ui->flightNumberLineEdit->setText(flightEntry.getData().value(Opl::Db::FLIGHTS_FLIGHTNUMBER).toString());
-
-    for(const auto &line_edit : *mandatoryLineEdits)
-        emit line_edit->editingFinished();
-}
-
-void NewNewFlightDialog::onGoodInputReceived(QLineEdit *line_edit)
-{
-    DEB << line_edit->objectName() << " - Good input received - " << line_edit->text();
-    line_edit->setStyleSheet(QString());
-
-    if (mandatoryLineEdits->contains(line_edit))
-        validationState.validate(mandatoryLineEdits->indexOf(line_edit));
-
-    if (validationState.timesValid()) {
-        updateBlockTimeLabel();
-        if (validationState.nightDataValid())
-            updateNightCheckBoxes();
-    }
-        validationState.printValidationStatus();
-}
-
-void NewNewFlightDialog::onBadInputReceived(QLineEdit *line_edit)
-{
-    DEB << line_edit->objectName() << " - Bad input received - " << line_edit->text();
-    line_edit->setStyleSheet(QStringLiteral("border: 1px solid red"));
-    line_edit->setText(QString());
-
-    if (mandatoryLineEdits->contains(line_edit))
-        validationState.invalidate(mandatoryLineEdits->indexOf(line_edit));
-
-    validationState.printValidationStatus();
-}
-
-void NewNewFlightDialog::updateBlockTimeLabel()
-{
-    QTime tblk = ATime::blocktime(ui->tofbTimeLineEdit->text(), ui->tonbTimeLineEdit->text());
-    ui->tblkDisplayLabel->setText(ATime::toString(tblk));
-}
-
-/*!
- * \brief NewNewFlightDialog::addNewTail If the user input is not in the aircraftList, the user
- * is prompted if he wants to add a new entry to the database
- */
-void NewNewFlightDialog::addNewTail(QLineEdit& parent_line_edit)
-{
-    QMessageBox::StandardButton reply;
-    reply = QMessageBox::question(this, tr("No Aircraft found"),
-                                  tr("No aircraft with this registration found.<br>"
-                                     "If this is the first time you log a flight with this aircraft, "
-                                     "you have to add the registration to the database first."
-                                     "<br><br>Would you like to add a new aircraft to the database?"),
-                                  QMessageBox::Yes|QMessageBox::No);
-    if (reply == QMessageBox::Yes) {
-        // create and open new aircraft dialog
-        NewTailDialog nt(ui->acftLineEdit->text(), this);
-        int ret = nt.exec();
-        // update map and list, set line edit
-        if (ret == QDialog::Accepted) {
-            DEB << "New Tail Entry added:";
-            DEB << aDB->getTailEntry(aDB->getLastEntry(ADatabaseTable::tails));
-
-            // update completion Data and Completer
-            completionData.updateTails();
-            auto new_model = new QStringListModel(completionData.tailsList, parent_line_edit.completer());
-            parent_line_edit.completer()->setModel(new_model); //setModel deletes old model if it has the completer as parent
-
-            // update Line Edit
-            parent_line_edit.setText(completionData.tailsIdMap.value(aDB->getLastEntry(ADatabaseTable::tails)));
-            emit parent_line_edit.editingFinished();
-        } else {
-            parent_line_edit.setText(QString());
-            parent_line_edit.setFocus();
-        }
-    } else {
-        parent_line_edit.setText(QString());
-        parent_line_edit.setFocus();
-    }
-}
-
-/*!
- * \brief NewNewFlightDialog::addNewPilot If the user input is not in the pilotNameList, the user
- * is prompted if he wants to add a new entry to the database
- */
-void NewNewFlightDialog::addNewPilot(QLineEdit& parent_line_edit)
-{
-    QMessageBox::StandardButton reply;
-    reply = QMessageBox::question(this, tr("No Pilot found"),
-                                  tr("No pilot found.<br>Please enter the Name as"
-                                     "<br><br><center><b>Lastname, Firstname</b></center><br><br>"
-                                     "If this is the first time you log a flight with this pilot, "
-                                     "you have to add the pilot to the database first."
-                                     "<br><br>Would you like to add a new pilot to the database?"),
-                                  QMessageBox::Yes|QMessageBox::No);
-    if (reply == QMessageBox::Yes) {
-        // create and open new pilot dialog
-        NewPilotDialog np(this);
-        int ret = np.exec();
-        // update map and list, set line edit
-        if (ret == QDialog::Accepted) {
-            DEB << "New Pilot Entry added:";
-            DEB << aDB->getPilotEntry(aDB->getLastEntry(ADatabaseTable::pilots));
-            // update completion Data and Completer
-            completionData.updatePilots();
-            auto new_model = new QStringListModel(completionData.pilotList, parent_line_edit.completer());
-            parent_line_edit.completer()->setModel(new_model); //setModel deletes old model if it has the completer as parent
-
-            // update Line Edit
-            parent_line_edit.setText(completionData.pilotsIdMap.value(aDB->getLastEntry(ADatabaseTable::pilots)));
-            emit parent_line_edit.editingFinished();
-        } else {
-            parent_line_edit.setText(QString());
-            parent_line_edit.setFocus();
-        }
-    } else {
-        parent_line_edit.setText(QString());
-    }
-}
-
-/*!
- * \brief NewNewFlightDialog::prepareFlightEntryData reads the user input from the UI and converts it into
- * the database format.
- * \return RowData_T a map containing a row ready for database submission
- */
-RowData_T NewNewFlightDialog::prepareFlightEntryData()
-{
-    if(!validationState.allValid())
-        return {};
-
-    RowData_T new_data;
-    // Calculate Block and Night Time
-    const int block_minutes = ATime::blockMinutes(ui->tofbTimeLineEdit->text(), ui->tonbTimeLineEdit->text());
-    QDateTime departure_date_time = ADateTime::fromString(ui->doftLineEdit->text() + ui->tofbTimeLineEdit->text());
-    const auto night_time_data = ACalc::NightTimeValues(ui->deptLocationLineEdit->text(), ui->destLocationLineEdit->text(),
-                           departure_date_time, block_minutes, ASettings::read(ASettings::FlightLogging::NightAngle).toInt());
-    // Mandatory data
-    new_data.insert(Opl::Db::FLIGHTS_DOFT, ui->doftLineEdit->text());
-    new_data.insert(Opl::Db::FLIGHTS_DEPT, ui->deptLocationLineEdit->text());
-    new_data.insert(Opl::Db::FLIGHTS_TOFB, ATime::toMinutes(ui->tofbTimeLineEdit->text()));
-    new_data.insert(Opl::Db::FLIGHTS_DEST, ui->destLocationLineEdit->text());
-    new_data.insert(Opl::Db::FLIGHTS_TONB, ATime::toMinutes(ui->tonbTimeLineEdit->text()));
-    new_data.insert(Opl::Db::FLIGHTS_TBLK, block_minutes);
-    // Night
-    new_data.insert(Opl::Db::FLIGHTS_TNIGHT, night_time_data.nightMinutes);
-    // Aircraft
-    int acft_id = completionData.tailsIdMap.key(ui->acftLineEdit->text());
-    new_data.insert(Opl::Db::FLIGHTS_ACFT, acft_id);
-    const ATailEntry acft_data = aDB->getTailEntry(acft_id);
-    bool multi_pilot = acft_data.getData().value(Opl::Db::TAILS_MULTIPILOT).toBool();
-    bool multi_engine = acft_data.getData().value(Opl::Db::TAILS_MULTIENGINE).toBool();
-
-    if (multi_pilot) {
-        new_data.insert(Opl::Db::FLIGHTS_TMP, block_minutes);
-        new_data.insert(Opl::Db::FLIGHTS_TSPSE, QString());
-        new_data.insert(Opl::Db::FLIGHTS_TSPME, QString());
-    } else if (!multi_pilot && !multi_engine) {
-        new_data.insert(Opl::Db::FLIGHTS_TMP, QString());
-        new_data.insert(Opl::Db::FLIGHTS_TSPSE, block_minutes);
-        new_data.insert(Opl::Db::FLIGHTS_TSPME, QString());
-    } else if (!multi_pilot && multi_engine) {
-        new_data.insert(Opl::Db::FLIGHTS_TMP, QString());
-        new_data.insert(Opl::Db::FLIGHTS_TSPSE, QString());
-        new_data.insert(Opl::Db::FLIGHTS_TSPME, block_minutes);
-    }
-    // Pilots
-    new_data.insert(Opl::Db::FLIGHTS_PIC, completionData.pilotsIdMap.key(ui->picNameLineEdit->text()));
-    new_data.insert(Opl::Db::FLIGHTS_SECONDPILOT, completionData.pilotsIdMap.key(ui->sicNameLineEdit->text()));
-    new_data.insert(Opl::Db::FLIGHTS_THIRDPILOT, completionData.pilotsIdMap.key(ui->thirdPilotNameLineEdit->text()));
-    // IFR time
-    if (ui->ifrCheckBox->isChecked()) {
-        new_data.insert(Opl::Db::FLIGHTS_TIFR, block_minutes);
-    } else {
-        new_data.insert(Opl::Db::FLIGHTS_TIFR, QString());
-    }
-    // Function Times
-    QList<QLatin1String> function_times = {
-        Opl::Db::FLIGHTS_TPIC,
-        Opl::Db::FLIGHTS_TPICUS,
-        Opl::Db::FLIGHTS_TSIC,
-        Opl::Db::FLIGHTS_TDUAL,
-        Opl::Db::FLIGHTS_TFI,
-    };
-    for (int i = 0; i < 5; i++) {
-        if (i == ui->functionComboBox->currentIndex())
-            new_data.insert(function_times[i], block_minutes);
-        else
-            new_data.insert(function_times[i], QString());
-    }
-    if (ui->functionComboBox->currentIndex() == 4)
-        new_data.insert(Opl::Db::FLIGHTS_PIC, block_minutes); // Log FI time as PIC as well
-    // Pilot flying / Pilot monitoring
-    new_data.insert(Opl::Db::FLIGHTS_PILOTFLYING, ui->pilotFlyingCheckBox->isChecked());
-    // Take-Off and Landing
-    if (ui->toNightCheckBox->isChecked()) {
-        new_data.insert(Opl::Db::FLIGHTS_TONIGHT, ui->takeOffSpinBox->value());
-        new_data.insert(Opl::Db::FLIGHTS_TODAY, 0);
-    } else {
-        new_data.insert(Opl::Db::FLIGHTS_TONIGHT, 0);
-        new_data.insert(Opl::Db::FLIGHTS_TODAY, ui->takeOffSpinBox->value());
-    }
-    if (ui->ldgNightCheckBox->isChecked()) {
-        new_data.insert(Opl::Db::FLIGHTS_LDGNIGHT, ui->landingSpinBox->value());
-        new_data.insert(Opl::Db::FLIGHTS_LDGDAY, 0);
-    } else {
-        new_data.insert(Opl::Db::FLIGHTS_LDGNIGHT, 0);
-        new_data.insert(Opl::Db::FLIGHTS_LDGDAY, ui->landingSpinBox->value());
-    }
-    if (ui->approachComboBox->currentText() == Opl::ApproachTypes[3]) // ILS CAT III
-        new_data.insert(Opl::Db::FLIGHTS_AUTOLAND, ui->landingSpinBox->value());
-
-    // Additional Data
-    new_data.insert(Opl::Db::FLIGHTS_APPROACHTYPE, ui->approachComboBox->currentText());
-    new_data.insert(Opl::Db::FLIGHTS_FLIGHTNUMBER, ui->flightNumberLineEdit->text());
-    new_data.insert(Opl::Db::FLIGHTS_REMARKS, ui->remarksLineEdit->text());
-    return new_data;
-}
-
-/*!
- * \brief NewNewFlightDialog::updateNightCheckBoxes updates the check boxes for take-off and landing
- * at night. Returns the number of minutes of night time.
- * \return
- */
-void NewNewFlightDialog::updateNightCheckBoxes()
-{
-    // Calculate Night Time
-    const QString dept_date = (ui->doftLineEdit->text() + ui->tofbTimeLineEdit->text());
-    const auto dept_date_time = ADateTime::fromString(dept_date);
-    const int block_minutes = ATime::blockMinutes(ui->tofbTimeLineEdit->text(), ui->tonbTimeLineEdit->text());
-    const int night_angle = ASettings::read(ASettings::FlightLogging::NightAngle).toInt();
-    const auto night_values = ACalc::NightTimeValues(
-                ui->deptLocationLineEdit->text(),
-                ui->destLocationLineEdit->text(),
-                dept_date_time,
-                block_minutes,
-                night_angle);
-    // set check boxes
-    if (night_values.takeOffNight)
-        ui->toNightCheckBox->setCheckState(Qt::Checked);
-    else
-        ui->toNightCheckBox->setCheckState(Qt::Unchecked);
-
-    if (night_values.landingNight)
-        ui->ldgNightCheckBox->setCheckState(Qt::Checked);
-    else
-        ui->ldgNightCheckBox->setCheckState(Qt::Unchecked);
-}
-
-// # Slots
-void NewNewFlightDialog::toUpper(const QString &text)
-{
-    const auto line_edit = this->findChild<QLineEdit*>(sender()->objectName());
-    {
-        const QSignalBlocker blocker(line_edit);
-        line_edit->setText(text.toUpper());
-    }
-}
-
-void NewNewFlightDialog::onTimeLineEdit_editingFinished()
-{
-    auto line_edit = this->findChild<QLineEdit*>(sender()->objectName());
-    DEB << line_edit->objectName() << "Editing finished -" << line_edit->text();
-
-    const QString time_string = ATime::formatTimeInput(line_edit->text());
-    const QTime time = ATime::fromString(time_string);
-
-    if (time.isValid()) {
-        line_edit->setText(time_string);
-        onGoodInputReceived(line_edit);
-    } else {
-        onBadInputReceived(line_edit);
-        line_edit->setText(QString());
-    }
-
-}
-
-void NewNewFlightDialog::onPilotNameLineEdit_editingFinshed()
-{
-    auto line_edit = this->findChild<QLineEdit*>(sender()->objectName());
-    DEB << line_edit->objectName() << "Editing Finished -" << line_edit->text();
-
-    if(line_edit->text().contains(self, Qt::CaseInsensitive)) {
-        DEB << "self recognized.";
-        line_edit->setText(completionData.pilotsIdMap.value(1));
-        if (line_edit->objectName() == QLatin1String("picNameLineEdit"))
-            ui->functionComboBox->setCurrentIndex(0);
-
-        onGoodInputReceived(line_edit);
-        return;
-    }
-
-    int pilot_id = completionData.pilotsIdMap.key(line_edit->text());
-    if(pilot_id != 0) {
-        DEB << "Mapped: " << line_edit->text() << pilot_id;
-        if (line_edit->objectName() == QLatin1String("picNameLineEdit") && pilot_id == 1)
-            ui->functionComboBox->setCurrentIndex(0);
-        onGoodInputReceived(line_edit);
-        return;
-    }
-
-    if (line_edit->text().isEmpty()) {
-        if (line_edit->objectName() == QLatin1String("picNameLineEdit"))
-            validationState.invalidate(mandatoryLineEdits->indexOf(line_edit));
-        return;
-    }
-
-    if (!line_edit->completer()->currentCompletion().isEmpty()) {
-        DEB << "Trying to fix input...";
-        line_edit->setText(line_edit->completer()->currentCompletion());
-        emit line_edit->editingFinished();
-        return;
-    }
-
-    onBadInputReceived(line_edit);
-    addNewPilot(*line_edit);
-}
-
-void NewNewFlightDialog::onLocationLineEdit_editingFinished()
-{
-    const QString line_edit_name = sender()->objectName();
-    const auto line_edit = this->findChild<QLineEdit*>(line_edit_name);
-    DEB << line_edit->objectName() << "Editing Finished -" << line_edit->text();
-    QLabel* name_label;
-    if (line_edit_name.contains(QLatin1String("dept"))) {
-        name_label = ui->deptNameLabel;
-    } else {
-        name_label = ui->destNameLabel;
-    }
-
-    const auto &text = line_edit->text();
-    int airport_id = 0;
-
-    // try to map iata or icao code to airport id;
-    if (text.length() == 3) {
-        airport_id = completionData.airportIataIdMap.key(text);
-    } else {
-        airport_id = completionData.airportIcaoIdMap.key(text);
-    }
-    // check result
-    if (airport_id == 0) {
-        // to do: prompt user how to handle unknown airport
-        name_label->setText(tr("Unknown airport identifier"));
-        onBadInputReceived(line_edit);
-        return;
-    }
-    line_edit->setText(completionData.airportIcaoIdMap.value(airport_id));
-    name_label->setText(completionData.airportNameIdMap.value(airport_id));
-    onGoodInputReceived(line_edit);
-}
-
-void NewNewFlightDialog::on_acftLineEdit_editingFinished()
-{
-    const auto line_edit = ui->acftLineEdit;
-    int acft_id = completionData.tailsIdMap.key(line_edit->text());
-    DEB << "acft_id: " << acft_id;
-
-    if (acft_id != 0) { // Success
-        onGoodInputReceived(line_edit);
-        return;
-    }
-
-    // try to use a completion
-    if (!line_edit->completer()->currentCompletion().isEmpty() && !line_edit->text().isEmpty()) {
-        line_edit->setText(line_edit->completer()->currentCompletion().split(QLatin1Char(' ')).first());
-        emit line_edit->editingFinished();
-        return;
-    }
-
-    // Mark as bad input and prompt for adding new tail
-    onBadInputReceived(line_edit);
-    if (!(line_edit->text() == QString()))
-        addNewTail(*line_edit);
-}
-
-void NewNewFlightDialog::on_doftLineEdit_editingFinished()
-{
-    const auto line_edit = ui->doftLineEdit;
-    auto text = ui->doftLineEdit->text();
-    auto label = ui->doftDisplayLabel;
-
-    TODO << "Non-default Date formats not implemented yet.";
-    Opl::Date::ADateFormat date_format = Opl::Date::ADateFormat::ISODate;
-    auto date = ADate::parseInput(text, date_format);
-    if (date.isValid()) {
-        label->setText(date.toString(Qt::TextDate));
-        line_edit->setText(ADate::toString(date, date_format));
-        onGoodInputReceived(line_edit);
-        return;
-    }
-
-    label->setText(tr("Invalid Date."));
-    onBadInputReceived(line_edit);
-}
-
-void NewNewFlightDialog::on_pilotFlyingCheckBox_stateChanged(int arg1)
-{
-    if (arg1 == Qt::CheckState::Checked) {
-        ui->takeOffSpinBox->setValue(1);
-        ui->landingSpinBox->setValue(1);
-    } else {
-        ui->takeOffSpinBox->setValue(0);
-        ui->landingSpinBox->setValue(0);
-    }
-}
-
-void NewNewFlightDialog::on_approachComboBox_currentTextChanged(const QString &arg1)
-{
-    if (arg1 == QLatin1String("OTHER"))
-        INFO(tr("Please specify the approach type in the remarks field."));
-}
-
-/*!
- * \brief NewNewFlightDialog::on_functionComboBox_currentIndexChanged
- * If the Function Combo Box is selected to be either PIC or SIC, fill the corresponding
- * nameLineEdit with the logbook owner's name, then check for duplication.
- */
-void NewNewFlightDialog::on_functionComboBox_currentIndexChanged(int index)
-{
-    if (index == 0) {
-        ui->picNameLineEdit->setText(self);
-        emit ui->picNameLineEdit->editingFinished();
-        if (completionData.pilotsIdMap.key(ui->picNameLineEdit->text())
-         == completionData.pilotsIdMap.key(ui->sicNameLineEdit->text()))
-                ui->sicNameLineEdit->setText(QString());
-    } else if (index == 2) {
-        ui->sicNameLineEdit->setText(self);
-        emit ui->sicNameLineEdit->editingFinished();
-        if (completionData.pilotsIdMap.key(ui->picNameLineEdit->text())
-         == completionData.pilotsIdMap.key(ui->sicNameLineEdit->text()))
-            ui->picNameLineEdit->setText(QString());
-    }
-}
-
-void NewNewFlightDialog::on_buttonBox_accepted()
-{
-    for (const auto& line_edit : *mandatoryLineEdits)
-        emit line_edit->editingFinished();
-    // If input verification is passed, continue, otherwise prompt user to correct
-    if (!validationState.allValid()) {
-        const auto display_names = QMap<ValidationItem, QString> {
-            {ValidationItem::doft, QObject::tr("Date of Flight")},      {ValidationItem::dept, QObject::tr("Departure Airport")},
-            {ValidationItem::dest, QObject::tr("Destination Airport")}, {ValidationItem::tofb, QObject::tr("Time Off Blocks")},
-            {ValidationItem::tonb, QObject::tr("Time on Blocks")},      {ValidationItem::pic, QObject::tr("PIC Name")},
-            {ValidationItem::acft, QObject::tr("Aircraft Registration")}
-        };
-        QString missing_items;
-        for (int i=0; i < mandatoryLineEdits->size(); i++) {
-            if (!validationState.validAt(i)){
-                missing_items.append(display_names.value(static_cast<ValidationItem>(i)) + "<br>");
-                mandatoryLineEdits->at(i)->setStyleSheet(QStringLiteral("border: 1px solid red"));
-            }
-        }
-
-        INFO(tr("Not all mandatory entries are valid.<br>"
-                "The following item(s) are empty or invalid:"
-                "<br><br><center><b>%1</b></center><br>"
-                "Please go back and fill in the required data."
-                ).arg(missing_items));
-        return;
-    }
-
-    // If input verification passed, collect input and submit to database
-    auto newData = prepareFlightEntryData();
-    DEB << "Old Data: ";
-    DEB << flightEntry;
-
-    //DEB << "Setting Data for flightEntry...";
-    flightEntry.setData(newData);
-    DEB << "Committing: ";
-    DEB << flightEntry;
-    if (!aDB->commit(flightEntry)) {
-        WARN(tr("The following error has ocurred:"
-                               "<br><br>%1<br><br>"
-                               "The entry has not been saved."
-                               ).arg(aDB->lastError.text()));
-        return;
-    } else {
-        QDialog::accept();
-    }
-}

+ 0 - 149
src/gui/dialogues/newnewflightdialog.h

@@ -1,149 +0,0 @@
-#ifndef NEWNEWFLIGHTDIALOG_H
-#define NEWNEWFLIGHTDIALOG_H
-
-#include <QDialog>
-#include <QDebug>
-#include <QLineEdit>
-#include <QList>
-#include <QBitArray>
-
-#include "src/functions/atime.h"
-#include "src/classes/acompletiondata.h"
-#include "src/classes/aflightentry.h"
-#include "src/classes/apilotentry.h"
-#include "src/classes/atailentry.h"
-#include "src/database/adatabase.h"
-#include "src/opl.h"
-
-/*!
- * \brief The ValidationItem enum contains the items that are mandatory for logging a flight:
- * Date of Flight, Departure, Destination, Time Off Blocks, Time On Blocks, Pilot in Command, Aircraft Registration
- */
-enum ValidationItem {doft = 0, dept = 1, dest = 2, tofb = 3, tonb = 4, pic = 5, acft = 6};
-
-/*!
- * \brief The ValidationState class encapsulates a QBitArray that has a bit set (or unset) depending on wether the
- * input for the associated index has been verified. The indexes correspond to the mandatory items enumerated in the
- * ValidationItem enum.
- */
-class ValidationState {
-public:
-    ValidationState() = default;
-
-    void validate(ValidationItem item)   { validationArray[item] = true;};
-    void validate(int index)                  { validationArray[index] = true;};
-    void invalidate(ValidationItem item) { validationArray[item] = false;}
-    void invalidate(int index)                { validationArray[index] = false;}
-    inline bool allValid()                           { return validationArray.count(true) == 7;};
-    inline bool timesValid()                         { return validationArray[ValidationItem::tofb] && validationArray[ValidationItem::tonb];}
-    inline bool locationsValid()                     { return validationArray[ValidationItem::dept] && validationArray[ValidationItem::dest];}
-    inline bool nightDataValid()                     { return timesValid() && locationsValid() && validationArray[ValidationItem::doft];}
-    inline bool acftValid()                          { return validationArray[ValidationItem::acft];}
-    inline bool validAt(int index)                   { return validationArray[index];}
-    inline bool validAt(ValidationItem item)         { return validationArray[item];}
-
-    // Debug
-    void printValidationStatus(){
-        QString deb_string("\033[mValidation State:\tdoft\tdept\tdest\ttofb\ttonb\tpic\tacft\n");
-        deb_string += "\t\t\t\t";
-        for (int i = 0; i < 7; i++) { //\033[32m
-            if (validationArray[i])
-                deb_string += "\t\033[32m" + QString::number(validationArray[i]);
-            else
-                deb_string += "\t\033[31m" + QString::number(validationArray[i]);
-        }
-        deb_string += QLatin1String("\u001b[38;5;75m"); // return to default DEB
-        qDebug().noquote() << deb_string;
-    }
-private:
-    QBitArray validationArray = QBitArray(7);
-};
-
-/*!
- * \brief The ValidationSetupData struct encapsulates the items required to initialise
- * the line edits with QValidators and QCompleters
- */
-struct ValidationSetupData
-{
-    ValidationSetupData(const QStringList& completion_data, const QRegularExpression& validation_RegEx)
-        : completionList(completion_data), validationRegEx(validation_RegEx){};
-
-    ValidationSetupData(const QStringList& completion_data)
-        : completionList(completion_data){
-    };
-
-    ValidationSetupData(const QRegularExpression& validation_RegEx)
-        : completionList(nullptr), validationRegEx(validation_RegEx){};
-
-    const QStringList completionList;
-    const QRegularExpression validationRegEx;
-};
-
-namespace Ui {
-class NewNewFlightDialog;
-}
-
-class NewNewFlightDialog : public QDialog
-{
-    Q_OBJECT
-
-public:
-
-    explicit NewNewFlightDialog(ACompletionData& completion_data, QWidget *parent = nullptr);
-    explicit NewNewFlightDialog(ACompletionData& completion_data, RowId_T row_id, QWidget* parent = nullptr);
-    ~NewNewFlightDialog();
-
-private:
-    Ui::NewNewFlightDialog *ui;
-    ACompletionData completionData;
-    ValidationState validationState;
-
-    /*!
-     * \brief a AFlightEntry object that is used to store either position data
-     * from an old entry, is used to fill the form for editing an entry, or is
-     * filled with new data for adding a new entry to the logbook.
-     */
-    AFlightEntry flightEntry;
-
-    static const inline QList<QLineEdit*>* timeLineEdits;
-    static const inline QList<QLineEdit*>* locationLineEdits;
-    static const inline QList<QLineEdit*>* pilotNameLineEdits;
-    static const inline QList<QLineEdit*>* mandatoryLineEdits;
-    static const inline QLatin1String self = QLatin1String("self");
-
-    void init();
-    void setupRawInputValidation();
-    void setupSignalsAndSlots();
-    void readSettings();
-    void fillWithEntryData();
-
-    void onGoodInputReceived(QLineEdit *line_edit);
-    void onBadInputReceived(QLineEdit *line_edit);
-
-    void updateNightCheckBoxes();
-    void setNightCheckboxes();
-    void updateBlockTimeLabel();
-
-    void addNewTail(QLineEdit& parent_line_edit);
-    void addNewPilot(QLineEdit& parent_line_edit);
-
-    RowData_T prepareFlightEntryData();
-
-
-private slots:
-    void toUpper(const QString& text);
-    void onTimeLineEdit_editingFinished();
-    void onPilotNameLineEdit_editingFinshed();
-    void onLocationLineEdit_editingFinished();
-    void on_acftLineEdit_editingFinished();
-    void on_doftLineEdit_editingFinished();
-    void on_buttonBox_accepted();
-    void on_pilotFlyingCheckBox_stateChanged(int arg1);
-    void on_approachComboBox_currentTextChanged(const QString &arg1);
-    void on_functionComboBox_currentIndexChanged(int index);
-protected:
-    bool eventFilter(QObject* object, QEvent* event) override;
-};
-
-
-#endif // NEWNEWFLIGHTDIALOG_H

+ 0 - 0
src/gui/dialogues/newflight.ui → src/gui/dialogues/oldnewflight.ui


+ 1232 - 0
src/gui/dialogues/oldnewflightdialog.cpp

@@ -0,0 +1,1232 @@
+/*
+ *openPilotLog - A FOSS Pilot Logbook Application
+ *Copyright (C) 2020-2021 Felix Turowsky
+ *
+ *This program is free software: you can redistribute it and/or modify
+ *it under the terms of the GNU General Public License as published by
+ *the Free Software Foundation, either version 3 of the License, or
+ *(at your option) any later version.
+ *
+ *This program is distributed in the hope that it will be useful,
+ *but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *GNU General Public License for more details.
+ *
+ *You should have received a copy of the GNU General Public License
+ *along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+#include "newflightdialog.h"
+#include "ui_newflight.h"
+#include "src/gui/dialogues/newtaildialog.h"
+#include "src/gui/dialogues/newpilotdialog.h"
+#include "src/functions/acalc.h"
+#include "src/testing/atimer.h"
+#include "src/database/adatabase.h"
+#include "src/opl.h"
+#include "src/functions/adate.h"
+#include "src/functions/alog.h"
+
+const auto LOC_LINE_EDIT_NAME   = QLatin1String("Loc");
+const auto ACFT_LINE_EDIT_NAME  = QLatin1String("acft");
+const auto TIME_LINE_EDIT_NAME  = QLatin1String("Time");
+const auto PILOT_LINE_EDIT_NAME = QLatin1String("Name");
+const auto SELF                 = QLatin1String("self");
+
+NewFlightDialog::NewFlightDialog(ACompletionData &completion_data,
+                                 QWidget *parent)
+    : QDialog(parent),
+      ui(new Ui::NewFlight),
+      completionData(completion_data)
+{
+    ui->setupUi(this);
+    flightEntry = AFlightEntry();
+    setup();
+    if (ASettings::read(ASettings::FlightLogging::FunctionComboBox).toString() == QLatin1String("SIC")) {
+        ui->picNameLineEdit->setText(QString());
+        ui->secondPilotNameLineEdit->setText(SELF);
+    }
+    if(ASettings::read(ASettings::FlightLogging::FunctionComboBox).toString() == QLatin1String("PIC")){
+        ui->picNameLineEdit->setText(SELF);
+        emit ui->picNameLineEdit->editingFinished();
+    }
+    CRIT("Time empty bug - check verification logic");
+}
+
+NewFlightDialog::NewFlightDialog(ACompletionData &completion_data,
+                                 int row_id,
+                                 QWidget *parent)
+    : QDialog(parent),
+      ui(new Ui::NewFlight),
+      completionData(completion_data)
+{
+    ui->setupUi(this);
+    flightEntry = aDB->getFlightEntry(row_id);
+    setup();
+    formFiller();
+}
+
+NewFlightDialog::~NewFlightDialog()
+{
+    LOG << "Closing NF Dialog";
+    delete ui;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+///                        setup and maintenance of dialog                            ///
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+void NewFlightDialog::setup()
+{
+    for (const auto & approach : Opl::ApproachTypes){
+        ui->ApproachComboBox->addItem(approach);
+    }
+    updateEnabled = true;
+    setupButtonGroups();
+    setupRawInputValidation();
+    setupSignalsAndSlots();
+    readSettings();
+    setupUi();
+
+    ui->deptLocLineEdit->setFocus();
+}
+
+void NewFlightDialog::setupButtonGroups()
+{
+    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);
+}
+
+void NewFlightDialog::setupRawInputValidation()
+{
+    // Prepare Regular Expressions for QValidators
+    const auto name_rx       = QLatin1String("((\\p{L}+)?('|\\-|,)?(\\p{L}+)?)");
+    const auto add_name_rx   = QLatin1String("(\\s?(\\p{L}+('|\\-|,)?\\p{L}+?))?");
+    const auto time_valid_rx = QRegularExpression("([01]?[0-9]|2[0-3]):?[0-5][0-9]?");
+    const auto loc_valid_rx  = QRegularExpression("[a-zA-Z0-9]{1,4}");
+    const auto acft_valid_rx = QRegularExpression("\\w+\\-?(\\w+)?");
+    const auto name_valid_rx = QRegularExpression(
+                name_rx + add_name_rx + add_name_rx + add_name_rx + ",?\\s?" // up to 4 first names
+              + name_rx + add_name_rx + add_name_rx + add_name_rx );         // up to 4 last names
+
+    // create the structs holding the inititalisation data (completion lists and RXs) and store them in a map
+    const auto location_data = ValidationSetupData(&completionData.airportList, &loc_valid_rx);
+    const auto pilot_data    = ValidationSetupData(&completionData.pilotList, &name_valid_rx);
+    const auto aircraft_data = ValidationSetupData(&completionData.tailsList, &acft_valid_rx);
+    const auto time_data     = ValidationSetupData(&time_valid_rx);
+
+    const QHash<const QLatin1String*, const ValidationSetupData*> init_data_map = {
+        {&LOC_LINE_EDIT_NAME,  &location_data},
+        {&PILOT_LINE_EDIT_NAME, &pilot_data},
+        {&ACFT_LINE_EDIT_NAME, &aircraft_data},
+        {&TIME_LINE_EDIT_NAME, &time_data}
+    };
+
+    //get and set up line edits
+    const QList<QLineEdit*> line_edits = ui->flightDataTab->findChildren<QLineEdit*>();
+    const QList<const QLatin1String*> keys_list = init_data_map.keys();
+
+    for (const auto &line_edit : line_edits) {
+        for (const auto &key : keys_list ) {
+            if (line_edit->objectName().contains(*key)) {
+                // Fetch Data from the map and set up the line edit
+                const ValidationSetupData* init_data = init_data_map.value(key);
+                DEB << "Setting up: " << line_edit->objectName();
+
+                // Set Validator
+                auto validator = new QRegularExpressionValidator(*init_data->validationRegEx, line_edit);
+                line_edit->setValidator(validator);
+                // Set Completer
+                if (init_data->completionData) {
+                    auto completer = new QCompleter(*init_data->completionData, line_edit);
+                    completer->setCaseSensitivity(Qt::CaseInsensitive);
+                    completer->setCompletionMode(QCompleter::PopupCompletion);
+                    completer->setFilterMode(Qt::MatchContains);
+                    line_edit->setCompleter(completer);
+                }
+            }
+        }
+    }
+
+    // populate Mandatory Line Edits list and prepare QBitArray
+    mandatoryLineEditsValid.resize(7);
+    mandatoryLineEdits = {
+        ui->doftLineEdit,
+        ui->deptLocLineEdit,
+        ui->destLocLineEdit,
+        ui->tofbTimeLineEdit,
+        ui->tonbTimeLineEdit,
+        ui->picNameLineEdit,
+        ui->acftLineEdit,
+    };
+    primaryTimeLineEdits = {
+        ui->tofbTimeLineEdit,
+        ui->tonbTimeLineEdit
+    };
+    pilotsLineEdits = {
+        ui->picNameLineEdit,
+        ui->secondPilotNameLineEdit,
+        ui->thirdPilotNameLineEdit
+    };
+
+}
+
+void NewFlightDialog::setupSignalsAndSlots()
+{
+    const auto line_edits = this->findChildren<QLineEdit*>();
+
+    for (const auto &line_edit : line_edits){
+        line_edit->installEventFilter(this);
+        if(line_edit->objectName().contains(LOC_LINE_EDIT_NAME)){
+            QObject::connect(line_edit, &QLineEdit::textChanged,
+                             this, &NewFlightDialog::onToUpperTriggered_textChanged);
+        }
+        if(line_edit->objectName().contains(ACFT_LINE_EDIT_NAME)){
+            QObject::connect(line_edit, &QLineEdit::textChanged,
+                             this, &NewFlightDialog::onToUpperTriggered_textChanged);
+        }
+        if(line_edit->objectName().contains(PILOT_LINE_EDIT_NAME)){
+            QObject::connect(line_edit, &QLineEdit::editingFinished,
+                             this, &NewFlightDialog::onPilotNameLineEdit_editingFinished);
+        }
+        if(line_edit->objectName().contains(TIME_LINE_EDIT_NAME)){
+            QObject::connect(line_edit, &QLineEdit::editingFinished,
+                             this, &NewFlightDialog::onTimeLineEdit_editingFinished);
+        }
+    }
+#if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0)
+    for (const auto &line_edit : qAsConst(mandatoryLineEdits)) {
+        if(line_edit->objectName().contains(QStringLiteral("doft")))
+            break;
+        QObject::connect(line_edit->completer(), QOverload<const QString &>::of(&QCompleter::highlighted),
+                         this, &NewFlightDialog::onCompleter_highlighted);
+        QObject::connect(line_edit->completer(), QOverload<const QString &>::of(&QCompleter::activated),
+                         this, &NewFlightDialog::onCompleter_activated);
+    }
+#endif
+    QObject::connect(ui->calendarWidget, &QCalendarWidget::clicked,
+                     this, &NewFlightDialog::onCalendarWidget_clicked);
+}
+
+void NewFlightDialog::setupUi()
+{
+    ui->flightDataTabWidget->setCurrentIndex(0);
+    ui->flightDataTabWidget->removeTab(2); // hide calendar widget
+    ui->doftLineEdit->setText(QDate::currentDate().toString(Qt::ISODate));
+    emit ui->doftLineEdit->editingFinished();
+    ui->doftLineEdit->setToolTip(tr("Date Format: %1").arg(ADate::getFormatString(Opl::Date::ADateFormat::ISODate)));
+}
+
+void NewFlightDialog::readSettings()
+{
+    DEB << "Reading Settings...";
+    QSettings settings;
+    ui->FunctionComboBox->setCurrentText(ASettings::read(ASettings::FlightLogging::Function).toString());
+    ui->ApproachComboBox->setCurrentIndex(ASettings::read(ASettings::FlightLogging::Approach).toInt());
+
+    ASettings::read(ASettings::FlightLogging::PilotFlying).toBool() ? ui->PilotFlyingCheckBox->setChecked(true)
+                                                          : ui->PilotMonitoringCheckBox->setChecked(true);
+
+    ui->TakeoffSpinBox->setValue(ASettings::read(ASettings::FlightLogging::NumberTakeoffs).toInt());
+    ui->TakeoffSpinBox->value() > 0 ? ui->TakeoffCheckBox->setChecked(true)
+                                    : ui->TakeoffCheckBox->setChecked(false);
+    ui->LandingSpinBox->setValue(ASettings::read(ASettings::FlightLogging::NumberLandings).toInt());
+    ui->LandingSpinBox->value() > 0 ? ui->LandingCheckBox->setChecked(true)
+                                    : ui->LandingCheckBox->setChecked(false);
+    if (ASettings::read(ASettings::FlightLogging::LogIFR).toBool()) {
+        ui->IfrCheckBox->setChecked(true);
+    } else {
+        ui->VfrCheckBox->setChecked(true);
+    }
+
+    ui->FlightNumberLineEdit->setText(ASettings::read(ASettings::FlightLogging::FlightNumberPrefix).toString());
+
+    // Debug
+    ASettings::write(ASettings::FlightLogging::FlightTimeFormat, Opl::Time::Default);
+    TODO << "Support for Decimal Logging is not implemented yet.";
+    flightTimeFormat = static_cast<Opl::Time::FlightTimeFormat>(
+                ASettings::read(ASettings::FlightLogging::FlightTimeFormat).toInt());
+
+
+}
+
+void NewFlightDialog::writeSettings()
+{
+    DEB << "Writing Settings...";
+
+    ASettings::write(ASettings::FlightLogging::Function, ui->FunctionComboBox->currentText());
+    ASettings::write(ASettings::FlightLogging::Approach, ui->ApproachComboBox->currentIndex());
+    ASettings::write(ASettings::FlightLogging::PilotFlying, ui->PilotFlyingCheckBox->isChecked());
+    ASettings::write(ASettings::FlightLogging::NumberTakeoffs, ui->TakeoffSpinBox->value());
+    ASettings::write(ASettings::FlightLogging::NumberLandings, ui->LandingSpinBox->value());
+    ASettings::write(ASettings::FlightLogging::LogIFR, ui->IfrCheckBox->isChecked());
+}
+
+bool NewFlightDialog::eventFilter(QObject* object, QEvent* event)
+{
+    auto line_edit = qobject_cast<QLineEdit*>(object);
+    if (line_edit != nullptr) {
+        if (mandatoryLineEdits.contains(line_edit) && event->type() == QEvent::FocusIn) {
+            //invalidateMandatoryLineEdit(mandatoryLineEdit(mandatoryLineEdits.indexOf(line_edit)));
+            //DEB << "Editing " << line_edit->objectName();
+            // set verification bit to false when entering a mandatory line edit
+            return false;
+        }
+        if (mandatoryLineEdits.contains(line_edit) && event->type() == QEvent::KeyPress) {
+            // show completion menu when pressing down arrow
+            QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
+            if (keyEvent->key() == Qt::Key_Down) {
+                //DEB << "Key down event.";
+                line_edit->completer()->complete();
+            }
+            return false;
+        }
+        if (line_edit->objectName().contains(QStringLiteral("Name")) && event->type() == QEvent::KeyPress) {
+            // show completion menu when pressing down arrow
+            QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
+            if (keyEvent->key() == Qt::Key_Down) {
+                //DEB << "Key down event.";
+                line_edit->completer()->complete();
+            }
+            return false;
+        }
+    }
+    return false;
+}
+///////////////////////////////////////////////////////////////////////////////////////////////////
+///                                 Methods - Input Processing                                  ///
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/*!
+ * \brief Fills the deductable items in the Dialog based on mandatory data ui selections.
+ */
+void NewFlightDialog::fillDeductibleData()
+{    
+    //zero out labels and line edits to delete previous calculations
+    QList<QLineEdit*>   LE = {ui->tSPSETimeLineEdit, ui->tSPMETimeLineEdit, ui->tMPTimeLineEdit,    ui->tIFRTimeLineEdit,
+                              ui->tNIGHTTimeLineEdit,ui->tPICTimeLineEdit,  ui->tPICUSTimeLineEdit, ui->tSICTimeLineEdit,
+                              ui->tDUALTimeLineEdit, ui->tFITimeLineEdit,};
+    QList<QLabel*>      LB = {ui->tSPSELabel, ui->tSPMELabel,  ui->tMPLabel,  ui->tIFRLabel,  ui->tNIGHTLabel,
+                              ui->tPICLabel,  ui->tPICUSLabel, ui->tSICLabel, ui->tDUALLabel, ui->tFILabel};
+    for(const auto& widget : LE) {widget->setText(QString());}
+    for(const auto& widget : LB) {widget->setText(Opl::Db::NULL_TIME_hhmm);}
+    //Calculate block time
+    const auto tofb = ATime::fromString(ui->tofbTimeLineEdit->text());
+    const auto tonb = ATime::fromString(ui->tonbTimeLineEdit->text());
+    const auto tblk = ATime::blocktime(tofb, tonb);
+    const auto block_time_string = ATime::toString(tblk, flightTimeFormat);
+
+    ui->tblkTimeLineEdit->setText(block_time_string);
+    // get acft data and fill deductible entries
+    auto acft = aDB->getTailEntry(completionData.tailsIdMap.key(ui->acftLineEdit->text()));
+
+    // TOTAL
+    ui->tblkLabel->setText(QLatin1String("<b>") + block_time_string + QLatin1String("</b>"));
+    // IFR
+    if(ui->IfrCheckBox->isChecked()){
+        ui->tIFRTimeLineEdit->setText(block_time_string);
+        ui->tIFRLabel->setText(block_time_string);
+    }
+    // Function times
+    switch (ui->FunctionComboBox->currentIndex()) {
+    case 0://PIC
+        ui->tPICTimeLineEdit->setText(block_time_string);
+        ui->tPICLabel->setText(block_time_string);
+        break;
+    case 1://PICus
+        ui->tPICUSTimeLineEdit->setText(block_time_string);
+        ui->tPICUSLabel->setText(block_time_string);
+        break;
+    case 2://Co-Pilot
+        ui->tSICTimeLineEdit->setText(block_time_string);
+        ui->tSICLabel->setText(block_time_string);
+        break;
+    case 3://Dual
+        ui->tDUALTimeLineEdit->setText(block_time_string);
+        ui->tDUALLabel->setText(block_time_string);
+        break;
+    case 4://Instructor
+        ui->tFITimeLineEdit->setText(block_time_string);
+        ui->tFILabel->setText(block_time_string);
+        ui->tPICTimeLineEdit->setText(block_time_string);
+        ui->tPICLabel->setText(block_time_string);
+    }
+
+    // if location data is available, fill night time
+    if (locLineEditsValid()) {
+
+        const auto block_minutes = ATime::toMinutes(tblk);
+        QString dept_date = ui->doftLineEdit->text() + 'T' + ATime::toString(tofb);
+        auto dept_date_time = QDateTime::fromString(dept_date, QStringLiteral("yyyy-MM-ddThh:mm"));
+        const int night_angle = ASettings::read(ASettings::FlightLogging::NightAngle).toInt();
+        auto night_time = ATime::qTimefromMinutes(ACalc::calculateNightTime(
+                                                 ui->deptLocLineEdit->text(),
+                                                 ui->destLocLineEdit->text(),
+                                                 dept_date_time,
+                                                 block_minutes,
+                                                 night_angle));
+
+        ui->tNIGHTTimeLineEdit->setText(ATime::toString(night_time, flightTimeFormat));
+        ui->tNIGHTLabel->setText(ATime::toString(night_time, flightTimeFormat));
+    }
+
+    // if acft data is available, fill additional times
+    if (acftLineEditValid()) {
+
+        if (acft.getData().isEmpty())
+            WARN("Error: No valid aircraft object available, unable to deterime auto times.");
+
+        // SP SE
+        if(acft.getData().value(Opl::Db::TAILS_MULTIPILOT).toInt() == 0
+                && acft.getData().value(Opl::Db::TAILS_MULTIENGINE).toInt() == 0){
+            ui->tSPSETimeLineEdit->setText(block_time_string);
+            ui->tSPSELabel->setText(block_time_string);
+        }
+        // SP ME
+        if(acft.getData().value(Opl::Db::TAILS_MULTIPILOT).toInt() == 0
+                && acft.getData().value(Opl::Db::TAILS_MULTIENGINE).toInt() == 1){
+            ui->tSPMETimeLineEdit->setText(block_time_string);
+            ui->tSPMELabel->setText(block_time_string);
+        }
+        // MP
+        if(acft.getData().value(Opl::Db::TAILS_MULTIPILOT).toInt() == 1){
+            ui->tMPTimeLineEdit->setText(block_time_string);
+            ui->tMPLabel->setText(block_time_string);
+        }
+    }
+}
+
+/*!
+ * \brief Collect input and create a Data map for the entry object.
+ *
+ * This function should only be called if input validation has been passed, since
+ * no input validation is done in this step and input data is assumed to be valid.
+ * \return
+ */
+RowData_T NewFlightDialog::collectInput()
+{
+    RowData_T newData;
+    //DEB << "Collecting Input...";
+    //Block Time
+    const auto tofb = ATime::fromString(ui->tofbTimeLineEdit->text());
+    const auto tonb = ATime::fromString(ui->tonbTimeLineEdit->text());
+    const auto tblk = ATime::blocktime(tofb, tonb);
+    const auto block_minutes = ATime::toMinutes(tblk);
+    // Mandatory data
+    newData.insert(Opl::Db::FLIGHTS_DOFT, ui->doftLineEdit->text());
+    newData.insert(Opl::Db::FLIGHTS_DEPT, ui->deptLocLineEdit->text());
+    newData.insert(Opl::Db::FLIGHTS_TOFB, ATime::toMinutes(tofb));
+    newData.insert(Opl::Db::FLIGHTS_DEST, ui->destLocLineEdit->text());
+    newData.insert(Opl::Db::FLIGHTS_TONB, ATime::toMinutes(tonb));
+    newData.insert(Opl::Db::FLIGHTS_TBLK, block_minutes);
+    // Aircraft
+    newData.insert(Opl::Db::FLIGHTS_ACFT, completionData.tailsIdMap.key(ui->acftLineEdit->text()));
+    // Pilots
+    newData.insert(Opl::Db::FLIGHTS_PIC, completionData.pilotsIdMap.key(ui->picNameLineEdit->text()));
+    newData.insert(Opl::Db::FLIGHTS_SECONDPILOT, completionData.pilotsIdMap.key(ui->secondPilotNameLineEdit->text()));
+    newData.insert(Opl::Db::FLIGHTS_THIRDPILOT, completionData.pilotsIdMap.key(ui->thirdPilotNameLineEdit->text()));
+
+    // Extra Times
+    ui->tSPSETimeLineEdit->text().isEmpty() ?
+                newData.insert(Opl::Db::FLIGHTS_TSPSE, QString())
+              : newData.insert(Opl::Db::FLIGHTS_TSPSE, stringToMinutes(
+                                   ui->tSPSETimeLineEdit->text(), flightTimeFormat));
+
+    ui->tSPMETimeLineEdit->text().isEmpty() ?
+                newData.insert(Opl::Db::FLIGHTS_TSPME, QString())
+              : newData.insert(Opl::Db::FLIGHTS_TSPME, stringToMinutes(
+                                   ui->tSPMETimeLineEdit->text(), flightTimeFormat));
+    ui->tMPTimeLineEdit->text().isEmpty() ?
+                newData.insert(Opl::Db::FLIGHTS_TMP, QString())
+              : newData.insert(Opl::Db::FLIGHTS_TMP, stringToMinutes(
+                                   ui->tMPTimeLineEdit->text(), flightTimeFormat));
+
+    if (ui->IfrCheckBox->isChecked()) {
+        newData.insert(Opl::Db::FLIGHTS_TIFR, block_minutes);
+    } else {
+        newData.insert(Opl::Db::FLIGHTS_TIFR, QString());
+    }
+    // Night
+    const QString dept_date = ui->doftLineEdit->text() + 'T'
+            + ATime::toString(tofb);
+    const auto dept_date_time = QDateTime::fromString(dept_date, QStringLiteral("yyyy-MM-ddThh:mm"));
+    const int night_angle = ASettings::read(ASettings::FlightLogging::NightAngle).toInt();
+    const auto night_time = ATime::qTimefromMinutes(ACalc::calculateNightTime(
+                                             ui->deptLocLineEdit->text(),
+                                             ui->destLocLineEdit->text(),
+                                             dept_date_time,
+                                             block_minutes,
+                                             night_angle));
+    const auto night_minutes = ATime::toMinutes(night_time);
+    newData.insert(Opl::Db::FLIGHTS_TNIGHT, night_minutes);
+
+    // Function times - This is a little explicit but these are mutually exclusive so its better to be safe than sorry here.
+    switch (ui->FunctionComboBox->currentIndex()) {
+    case 0://PIC
+        newData.insert(Opl::Db::FLIGHTS_TPIC, block_minutes);
+        newData.insert(Opl::Db::FLIGHTS_TPICUS, QString());
+        newData.insert(Opl::Db::FLIGHTS_TSIC, QString());
+        newData.insert(Opl::Db::FLIGHTS_TDUAL, QString());
+        newData.insert(Opl::Db::FLIGHTS_TFI, QString());
+        break;
+    case 1://PICUS
+        newData.insert(Opl::Db::FLIGHTS_TPIC, QString());
+        newData.insert(Opl::Db::FLIGHTS_TPICUS, block_minutes);
+        newData.insert(Opl::Db::FLIGHTS_TSIC, QString());
+        newData.insert(Opl::Db::FLIGHTS_TDUAL, QString());
+        newData.insert(Opl::Db::FLIGHTS_TFI, QString());
+        break;
+    case 2://Co-Pilot
+        newData.insert(Opl::Db::FLIGHTS_TPIC, QString());
+        newData.insert(Opl::Db::FLIGHTS_TPICUS, QString());
+        newData.insert(Opl::Db::FLIGHTS_TSIC, block_minutes);
+        newData.insert(Opl::Db::FLIGHTS_TDUAL, QString());
+        newData.insert(Opl::Db::FLIGHTS_TFI, QString());
+        break;
+    case 3://Dual
+        newData.insert(Opl::Db::FLIGHTS_TPIC, QString());
+        newData.insert(Opl::Db::FLIGHTS_TPICUS, QString());
+        newData.insert(Opl::Db::FLIGHTS_TSIC, QString());
+        newData.insert(Opl::Db::FLIGHTS_TDUAL, block_minutes);
+        newData.insert(Opl::Db::FLIGHTS_TFI, QString());
+        break;
+    case 4://Instructor
+        newData.insert(Opl::Db::FLIGHTS_TPIC, block_minutes);
+        newData.insert(Opl::Db::FLIGHTS_TPICUS, QString());
+        newData.insert(Opl::Db::FLIGHTS_TSIC, QString());
+        newData.insert(Opl::Db::FLIGHTS_TDUAL, QString());
+        newData.insert(Opl::Db::FLIGHTS_TFI, block_minutes);
+    }
+    // Pilot Flying
+    newData.insert(Opl::Db::FLIGHTS_PILOTFLYING, ui->PilotFlyingCheckBox->isChecked());
+    // TO and LDG - again a bit explicit, but we  need to check for both night to day as well as day to night transitions.
+    if (ui->TakeoffCheckBox->isChecked()) {
+        if (night_minutes == 0) { // all day
+            newData.insert(Opl::Db::FLIGHTS_TODAY, ui->TakeoffSpinBox->value());
+            newData.insert(Opl::Db::FLIGHTS_TONIGHT, 0);
+        } else if (night_minutes == block_minutes) { // all night
+            newData.insert(Opl::Db::FLIGHTS_TODAY, 0);
+            newData.insert(Opl::Db::FLIGHTS_TONIGHT, ui->TakeoffSpinBox->value());
+        } else {
+            if(ACalc::isNight(ui->deptLocLineEdit->text(), dept_date_time,  night_angle)) {
+                newData.insert(Opl::Db::FLIGHTS_TODAY, 0);
+                newData.insert(Opl::Db::FLIGHTS_TONIGHT, ui->TakeoffSpinBox->value());
+            } else {
+                newData.insert(Opl::Db::FLIGHTS_TODAY, ui->TakeoffSpinBox->value());
+                newData.insert(Opl::Db::FLIGHTS_TONIGHT, 0);
+            }
+        }
+    } else {
+        newData.insert(Opl::Db::FLIGHTS_TODAY, 0);
+        newData.insert(Opl::Db::FLIGHTS_TONIGHT, 0);
+    }
+
+    if (ui->LandingCheckBox->isChecked()) {
+        if (night_minutes == 0) { // all day
+            newData.insert(Opl::Db::FLIGHTS_LDGDAY, ui->LandingSpinBox->value());
+            newData.insert(Opl::Db::FLIGHTS_LDGNIGHT, 0);
+        } else if (night_minutes == block_minutes) { // all night
+            newData.insert(Opl::Db::FLIGHTS_LDGDAY, 0);
+            newData.insert(Opl::Db::FLIGHTS_LDGNIGHT, ui->LandingSpinBox->value());
+        } else { //check
+            const QString dest_date = ui->doftLineEdit->text() + 'T'
+                    + ATime::toString(tonb);
+            const auto dest_date_time = QDateTime::fromString(dest_date, QStringLiteral("yyyy-MM-ddThh:mm"));
+            if (ACalc::isNight(ui->destLocLineEdit->text(), dest_date_time,  night_angle)) {
+                newData.insert(Opl::Db::FLIGHTS_LDGDAY, 0);
+                newData.insert(Opl::Db::FLIGHTS_LDGNIGHT, ui->LandingSpinBox->value());
+            } else {
+                newData.insert(Opl::Db::FLIGHTS_LDGDAY, ui->LandingSpinBox->value());
+                newData.insert(Opl::Db::FLIGHTS_LDGNIGHT, 0);
+            }
+        }
+    } else {
+        newData.insert(Opl::Db::FLIGHTS_LDGDAY, 0);
+        newData.insert(Opl::Db::FLIGHTS_LDGNIGHT, 0);
+    }
+
+    newData.insert(Opl::Db::FLIGHTS_AUTOLAND, ui->AutolandSpinBox->value());
+    newData.insert(Opl::Db::FLIGHTS_APPROACHTYPE, ui->ApproachComboBox->currentText());
+    newData.insert(Opl::Db::FLIGHTS_FLIGHTNUMBER, ui->FlightNumberLineEdit->text());
+    newData.insert(Opl::Db::FLIGHTS_REMARKS, ui->RemarksLineEdit->text());
+    DEB << "New Flight Data: " << newData;
+
+    return newData;
+}
+
+void NewFlightDialog::formFiller()
+{
+    DEB << "Filling Line Edits...";
+    // get Line Edits
+    const auto line_edits = this->findChildren<QLineEdit *>();
+    QStringList line_edits_names;
+    for (const auto& le : line_edits) {
+        line_edits_names << le->objectName();
+    }
+
+    ui->acftLineEdit->setText(flightEntry.getRegistration());
+    line_edits_names.removeOne(QStringLiteral("acftLineEdit"));
+
+    const auto data_keys = flightEntry.getData().keys();
+    for (const auto& data_key : data_keys) {
+        auto rx = QRegularExpression(data_key + QStringLiteral("LineEdit"));//acftLineEdit
+        for(const auto& leName : qAsConst(line_edits_names)){
+            if(rx.match(leName).hasMatch())  {
+                //DEB << "Loc Match found: " << key << " - " << leName);
+                auto line_edit = this->findChild<QLineEdit *>(leName);
+                if(line_edit != nullptr){
+                    line_edit->setText(flightEntry.getData().value(data_key).toString());
+                    line_edits_names.removeOne(leName);
+                }
+                break;
+            }
+        }
+        rx = QRegularExpression(data_key + QStringLiteral("Loc\\w+?"));
+        for(const auto& leName : qAsConst(line_edits_names)){
+            if(rx.match(leName).hasMatch())  {
+                //DEB << "Loc Match found: " << key << " - " << leName);
+                auto line_edit = this->findChild<QLineEdit *>(leName);
+                if(line_edit != nullptr){
+                    line_edit->setText(flightEntry.getData().value(data_key).toString());
+                    line_edits_names.removeOne(leName);
+                }
+                break;
+            }
+        }
+        rx = QRegularExpression(data_key + QStringLiteral("Time\\w+?"));
+        for(const auto& leName : qAsConst(line_edits_names)){
+            if(rx.match(leName).hasMatch())  {
+                //DEB << "Time Match found: " << key << " - " << leName);
+                auto line_edits = this->findChild<QLineEdit *>(leName);
+                if(line_edits != nullptr){
+                    DEB << "Setting " << line_edits->objectName() << " to " << ATime::toString(flightEntry.getData().value(data_key).toInt(), flightTimeFormat);
+                    line_edits->setText(ATime::toString(flightEntry.getData().value(data_key).toInt(),
+                                                        flightTimeFormat));
+                    line_edits_names.removeOne(leName);
+                }
+                break;
+            }
+        }
+        rx = QRegularExpression(data_key + QStringLiteral("Name\\w+?"));
+        for(const auto& leName : qAsConst(line_edits_names)){
+            if(rx.match(leName).hasMatch())  {
+                auto line_edits = this->findChild<QLineEdit *>(leName);
+                if(line_edits != nullptr){
+                    DEB << completionData.pilotsIdMap.value(1);
+                    line_edits->setText(completionData.pilotsIdMap.value(flightEntry.getData().value(data_key).toInt()));
+                    line_edits_names.removeOne(leName);
+                }
+                break;
+            }
+        }
+    }
+    //FunctionComboBox
+    QList<QLineEdit*> function_combo_boxes = {ui->tPICTimeLineEdit, ui->tPICUSTimeLineEdit,
+                                              ui->tSICTimeLineEdit, ui->tDUALTimeLineEdit,
+                                              ui->tFITimeLineEdit};
+    for(const auto& line_edit : function_combo_boxes){
+        if(line_edit->text() != QStringLiteral("00:00")){
+            QString name = line_edit->objectName();
+            name.chop(12);
+            name.remove(0,1);
+            ui->FunctionComboBox->setCurrentText(name);
+        }
+    }
+    // Approach Combo Box
+    const QString& app = flightEntry.getData().value(Opl::Db::FLIGHTS_APPROACHTYPE).toString();
+    if(app != QString()){
+        ui->ApproachComboBox->setCurrentText(app);
+    }
+    // Task and Rules
+    qint8 PF = flightEntry.getData().value(Opl::Db::FLIGHTS_PILOTFLYING).toInt();
+    if (PF > 0) {
+        ui->PilotFlyingCheckBox->setChecked(true);
+    } else {
+        ui->PilotMonitoringCheckBox->setChecked(true);
+    }
+    qint8 FR = flightEntry.getData().value(Opl::Db::FLIGHTS_TIFR).toInt();
+    if (FR > 0) {
+        ui->IfrCheckBox->setChecked(true);
+    } else {
+        ui->tIFRTimeLineEdit->setText(QString());
+        ui->VfrCheckBox->setChecked(true);
+    }
+    // Take Off and Landing
+    qint8 TO = flightEntry.getData().value(Opl::Db::FLIGHTS_TODAY).toInt()
+            + flightEntry.getData().value(Opl::Db::FLIGHTS_TONIGHT).toInt();
+    qint8 LDG = flightEntry.getData().value(Opl::Db::FLIGHTS_LDGDAY).toInt()
+            + flightEntry.getData().value(Opl::Db::FLIGHTS_LDGNIGHT).toInt();
+    if(TO > 0) {
+        ui->TakeoffCheckBox->setChecked(true);
+        ui->TakeoffSpinBox->setValue(TO);
+    } else {
+        ui->TakeoffCheckBox->setChecked(false);
+        ui->TakeoffSpinBox->setValue(0);
+    }
+    if(LDG > 0) {
+        ui->LandingCheckBox->setChecked(true);
+        ui->LandingSpinBox->setValue(LDG);
+    } else {
+        ui->LandingCheckBox->setChecked(false);
+        ui->LandingSpinBox->setValue(0);
+    }
+    qint8 AL = flightEntry.getData().value(Opl::Db::FLIGHTS_AUTOLAND).toInt();
+    if(AL > 0) {
+        ui->AutolandCheckBox->setChecked(true);
+        ui->AutolandSpinBox->setValue(AL);
+    }
+
+    for(const auto& le : qAsConst(mandatoryLineEdits)){
+        emit le->editingFinished();
+    }
+}
+
+bool NewFlightDialog::isLessOrEqualThanBlockTime(const QString time_string)
+{
+    if (!allMandatoryLineEditsValid()){
+        INFO(tr("Unable to determine total block time.<br>"
+                               "Please fill out all Mandatory Fields<br>"
+                               "before manually editing these times."));
+        return false;
+    }
+
+    auto extra_time = ATime::fromString(time_string, flightTimeFormat);
+    auto block_time = ATime::blocktime(ATime::fromString(
+                                           ui->tofbTimeLineEdit->text(), flightTimeFormat),
+                                       ATime::fromString(
+                                           ui->tonbTimeLineEdit->text(), flightTimeFormat));
+    if (extra_time <= block_time) {
+        return true;
+    } else {
+        WARN(tr("The flight time you have entered is longer than the total blocktime:"
+                               "<br><center><b>%1</b></center>"
+                               ).arg(ATime::toString(block_time, flightTimeFormat)));
+        return false;
+    }
+}
+
+/*!
+ * \brief NewFlight::addNewTailMessageBox If the user input is not in the aircraftList, the user
+ * is prompted if he wants to add a new entry to the database
+ */
+void NewFlightDialog::addNewTail(QLineEdit *parent_line_edit)
+{
+    QMessageBox::StandardButton reply;
+    reply = QMessageBox::question(this, tr("No Aircraft found"),
+                                  tr("No aircraft with this registration found.<br>"
+                                     "If this is the first time you log a flight with this aircraft, "
+                                     "you have to add the registration to the database first."
+                                     "<br><br>Would you like to add a new aircraft to the database?"),
+                                  QMessageBox::Yes|QMessageBox::No);
+    if (reply == QMessageBox::Yes) {
+        // create and open new aircraft dialog
+        NewTailDialog na(ui->acftLineEdit->text(), this);
+        int ret = na.exec();
+        // update map and list, set line edit
+        if (ret == QDialog::Accepted) {
+            DEB << "New Tail Entry added. Id:" << aDB->getLastEntry(ADatabaseTable::tails);
+
+            // update completion Data and Completer
+            completionData.updateTails();
+            auto new_model = new QStringListModel(completionData.tailsList, parent_line_edit->completer());
+            parent_line_edit->completer()->setModel(new_model); //setModel deletes old model if it has the completer as parent
+
+            // update Line Edit
+            parent_line_edit->setText(completionData.tailsIdMap.value(aDB->getLastEntry(ADatabaseTable::tails)));
+            emit parent_line_edit->editingFinished();
+        } else {
+            parent_line_edit->setText(QString());
+            parent_line_edit->setFocus();
+        }
+    } else {
+        parent_line_edit->setText(QString());
+        parent_line_edit->setFocus();
+    }
+}
+
+/*!
+ * \brief NewFlight::addNewPilot If the user input is not in the pilotNameList, the user
+ * is prompted if he wants to add a new entry to the database
+ */
+void NewFlightDialog::addNewPilot(QLineEdit *parent_line_edit)
+{
+    QMessageBox::StandardButton reply;
+    reply = QMessageBox::question(this, tr("No Pilot found"),
+                                  tr("No pilot found.<br>Please enter the Name as"
+                                     "<br><br><center><b>Lastname, Firstname</b></center><br><br>"
+                                     "If this is the first time you log a flight with this pilot, "
+                                     "you have to add the pilot to the database first."
+                                     "<br><br>Would you like to add a new pilot to the database?"),
+                                  QMessageBox::Yes|QMessageBox::No);
+    if (reply == QMessageBox::Yes) {
+        // create and open new pilot dialog
+        NewPilotDialog np(this);
+        int ret = np.exec();
+        // update map and list, set line edit
+        if (ret == QDialog::Accepted) {
+            DEB << "New Pilot Entry added. Id:" << aDB->getLastEntry(ADatabaseTable::pilots);
+            // update completion Data and Completer
+            completionData.updatePilots();
+            auto new_model = new QStringListModel(completionData.pilotList, parent_line_edit->completer());
+            parent_line_edit->completer()->setModel(new_model); //setModel deletes old model if it has the completer as parent
+
+            // update Line Edit
+            parent_line_edit->setText(completionData.pilotsIdMap.value(aDB->getLastEntry(ADatabaseTable::pilots)));
+            emit parent_line_edit->editingFinished();
+        } else {
+            parent_line_edit->setText(QString());
+            parent_line_edit->setFocus();
+        }
+    } else {
+        parent_line_edit->setText(QString());
+    }
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+///                               Flight Data Tab Slots                                         ///
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+void NewFlightDialog::on_cancelButton_clicked()
+{
+    DEB << "Cancel Button clicked.";
+    reject();
+}
+
+void NewFlightDialog::on_submitButton_clicked()
+{
+    // emit editing finished for all mandatory line edits to trigger input verification
+    for (const auto &line_edit : qAsConst(mandatoryLineEdits)) {
+        emit line_edit->editingFinished();
+    }
+
+    // If input verification is passed, continue, otherwise prompt user to correct
+    if (!allMandatoryLineEditsValid()) {
+        const auto display_names = QMap<int, QString> {
+            {0, QObject::tr("Date of Flight")},      {1, QObject::tr("Departure Airport")},
+            {2, QObject::tr("Destination Airport")}, {3, QObject::tr("Time Off Blocks")},
+            {4, QObject::tr("Time on Blocks")},      {5, QObject::tr("PIC Name")},
+            {6, QObject::tr("Aircraft Registration")}
+        };
+        QString missing_items;
+        for (int i=0; i < mandatoryLineEdits.size(); i++) {
+            if (!mandatoryLineEditsValid[i]){
+                missing_items.append(display_names.value(i) + "<br>");
+                mandatoryLineEdits[i]->setStyleSheet(QStringLiteral("border: 1px solid red"));
+            }
+        }
+
+        INFO(tr("Not all mandatory entries are valid.<br>"
+                "The following item(s) are empty or missing:"
+                "<br><br><center><b>%1</b></center><br>"
+                "Please go back and fill in the required data."
+                ).arg(missing_items));
+        return;
+    }
+
+    // If input verification passed, collect input and submit to database
+    auto newData = collectInput();
+    DEB << "Setting Data for flightEntry...";
+    flightEntry.setData(newData);
+    DEB << "Committing...";
+    if (!aDB->commit(flightEntry)) {
+        WARN(tr("The following error has ocurred:"
+                               "<br><br>%1<br><br>"
+                               "The entry has not been saved."
+                               ).arg(aDB->lastError.text()));
+        return;
+    } else {
+        QDialog::accept();
+    }
+}
+
+
+
+/*
+ * Shared Slots
+ */
+
+void NewFlightDialog::onGoodInputReceived(QLineEdit *line_edit)
+{
+    DEB << line_edit->objectName() << " - Good input received - " << line_edit->text();
+
+    line_edit->setStyleSheet(QString());
+
+    if (mandatoryLineEdits.contains(line_edit))
+        validateMandatoryLineEdit(mandatoryLineEdit(mandatoryLineEdits.indexOf(line_edit)));
+    validationStatus();
+
+    if (timeLineEditsValid())
+        onMandatoryLineEditsFilled();
+}
+
+void NewFlightDialog::onBadInputReceived(QLineEdit *line_edit)
+{
+    DEB << line_edit->objectName() << " - Bad input received - " << line_edit->text();
+    line_edit->setStyleSheet(QStringLiteral("border: 1px solid red"));
+
+    if (mandatoryLineEdits.contains(line_edit))
+        invalidateMandatoryLineEdit(mandatoryLineEdit(mandatoryLineEdits.indexOf(line_edit)));
+    validationStatus();
+
+}
+
+// capitalize input for dept, dest and registration input
+void NewFlightDialog::onToUpperTriggered_textChanged(const QString &text)
+{
+    auto sender_object = sender();
+    auto line_edit = this->findChild<QLineEdit*>(sender_object->objectName());
+    //DEB << "Text changed - " << line_edit->objectName() << line_edit->text();
+    {
+        const QSignalBlocker blocker(line_edit);
+        line_edit->setText(text.toUpper());
+    }
+}
+
+// update is disabled if the user chose to manually edit extra times
+void NewFlightDialog::onMandatoryLineEditsFilled()
+{
+    if (updateEnabled)
+        fillDeductibleData();
+}
+
+// make sure that when using keyboard to scroll through completer sugggestions, line edit is up to date
+void NewFlightDialog::onCompleter_highlighted(const QString &completion)
+{
+    auto sender_object = sender();
+    auto line_edit = this->findChild<QLineEdit*>(sender_object->objectName());
+    DEB << "Completer highlighted - " << line_edit->objectName() << completion;
+    line_edit->setText(completion);
+}
+
+void NewFlightDialog::onCompleter_activated(const QString &)
+{
+    auto sender_object = sender();
+    auto line_edit = this->findChild<QLineEdit*>(sender_object->objectName());
+    DEB << "Line edit " << line_edit->objectName() << "completer activated.";
+    emit line_edit->editingFinished();
+}
+
+/*
+ *  Date of Flight
+ */
+
+void NewFlightDialog::on_doftLineEdit_editingFinished()
+{    
+    auto line_edit = ui->doftLineEdit;
+    auto text = ui->doftLineEdit->text();
+    auto label = ui->doftDisplayLabel;
+    //DEB << line_edit->objectName() << "Editing finished - " << text;
+
+    TODO << "Non-default Date formats not implemented yet.";
+    Opl::Date::ADateFormat date_format = Opl::Date::ADateFormat::ISODate;
+    auto date = ADate::parseInput(text, date_format);
+    if (date.isValid()) {
+        label->setText(date.toString(Qt::TextDate));
+        line_edit->setText(ADate::toString(date, date_format));
+        onGoodInputReceived(line_edit);
+        return;
+    }
+
+    label->setText(tr("Invalid Date."));
+    onBadInputReceived(line_edit);
+}
+
+void NewFlightDialog::onCalendarWidget_clicked(const QDate &date)
+{
+    const auto& le = ui->doftLineEdit;
+    le->blockSignals(false);
+    ui->calendarWidget->hide();
+    ui->placeLabel1->resize(ui->placeLabel2->size());
+    le->setText(date.toString(Qt::ISODate));
+    emit le->editingFinished();
+}
+
+void NewFlightDialog::on_calendarPushButton_clicked()
+{
+    const auto& cw = ui->calendarWidget;
+    const auto& le = ui->doftLineEdit;
+    const auto& anchor = ui->placeLabel1;
+
+    if(cw->isVisible()){
+        le->blockSignals(false);
+        cw->hide();
+        anchor->resize(ui->placeLabel2->size());
+        le->setFocus();
+    } else {
+        le->blockSignals(true);
+        // Determine size based on layout coordinates
+        int c1 = anchor->pos().rx();
+        int c2 = le->pos().rx();
+        int z  = le->size().rwidth();
+        int x = (c2 - c1)+ z;
+        c1 = anchor->pos().ry();
+        c2 = ui->acftLineEdit->pos().ry();
+        z  = ui->acftLineEdit->size().height();
+        int y = (c2 - c1) + z;
+        //Re-size calendar and parent label accordingly
+        anchor->resize(x, y);
+        cw->setParent(ui->placeLabel1);
+        cw->setGeometry(QRect(0, 0, x, y));
+        cw->show();
+        cw->setFocus();
+    }
+}
+
+void NewFlightDialog::validationStatus()
+{
+
+    QString deb_string("Validation State:\tdoft\tdept\tdest\ttofb\ttonb\tpic\tacft\n");
+    deb_string += "\t\t\t\t\t" + QString::number(mandatoryLineEditsValid[0]);
+    deb_string += "\t" + QString::number(mandatoryLineEditsValid[1]);
+    deb_string += "\t" + QString::number(mandatoryLineEditsValid[2]);
+    deb_string += "\t" + QString::number(mandatoryLineEditsValid[3]);
+    deb_string += "\t" + QString::number(mandatoryLineEditsValid[4]);
+    deb_string += "\t" + QString::number(mandatoryLineEditsValid[5]);
+    deb_string += "\t" + QString::number(mandatoryLineEditsValid[6]);
+    qDebug().noquote() << deb_string;
+}
+
+/*
+ * Location Line Edits
+ */
+
+void NewFlightDialog::on_deptLocLineEdit_editingFinished()
+{
+    onLocationEditingFinished(ui->deptLocLineEdit, ui->deptNameLabel);
+}
+
+void NewFlightDialog::on_destLocLineEdit_editingFinished()
+{
+    onLocationEditingFinished(ui->destLocLineEdit, ui->destNameLabel);
+}
+
+void NewFlightDialog::onLocationEditingFinished(QLineEdit *line_edit, QLabel *name_label)
+{
+    const auto &text = line_edit->text();
+    //DEB << line_edit->objectName() << " Editing finished. " << text);
+    int airport_id = 0;
+
+    // try to map iata or icao code to airport id;
+    if (text.length() == 3) {
+        airport_id = completionData.airportIataIdMap.key(text);
+    } else {
+        airport_id = completionData.airportIcaoIdMap.key(text);
+    }
+    // check result
+    if (airport_id == 0) {
+        // to do: prompt user how to handle unknown airport
+        name_label->setText(tr("Unknown airport identifier"));
+        onBadInputReceived(line_edit);
+        return;
+    }
+    line_edit->setText(completionData.airportIcaoIdMap.value(airport_id));
+    name_label->setText(completionData.airportNameIdMap.value(airport_id));
+    onGoodInputReceived(line_edit);
+}
+
+/*
+ * Time Line Edits
+ */
+
+void NewFlightDialog::onTimeLineEdit_editingFinished()
+{
+    auto sender_object = sender();
+    auto line_edit = this->findChild<QLineEdit*>(sender_object->objectName());
+    DEB << line_edit->objectName() << "Editing Finished -" << line_edit->text();
+
+    line_edit->setText(ATime::formatTimeInput(line_edit->text()));
+    const auto time = ATime::fromString(line_edit->text());
+    if(time.isValid()){
+        if(primaryTimeLineEdits.contains(line_edit)) {
+            onGoodInputReceived(line_edit);
+        } else { // is extra time line edit
+            if (!isLessOrEqualThanBlockTime(line_edit->text())) {
+                line_edit->setText(QString());
+                line_edit->setFocus();
+                return;
+            }
+        }
+    } else {
+        if (!line_edit->text().isEmpty())
+            onBadInputReceived(line_edit);
+    }
+}
+
+/*
+ * Aircraft Line Edit
+ */
+
+void NewFlightDialog::on_acftLineEdit_editingFinished()
+{
+    TODO << "Looking up and matching tails is currently broken...";
+    auto line_edit = ui->acftLineEdit;
+    int acft_id = completionData.tailsIdMap.key(line_edit->text());
+    DEB << "acft_id: " << acft_id;
+
+    if (acft_id != 0) { // Success
+        //DEB << "Mapped: " << line_edit->text() << completionData.tailsIdMap.value(line_edit->text());
+        auto acft = aDB->getTailEntry(acft_id);
+        ui->acftTypeLabel->setText(acft.type());
+        ui->picCompanyLabel->setText(acft.getData().value(Opl::Db::TAILS_COMPANY).toString());
+        onGoodInputReceived(line_edit);
+        return;
+    }
+
+    if (!line_edit->completer()->currentCompletion().isEmpty()) {
+        line_edit->setText(line_edit->completer()->currentCompletion().split(QLatin1Char(' ')).first());
+        emit line_edit->editingFinished();
+        return;
+    }
+
+    // If no success mark as bad input
+    onBadInputReceived(line_edit);
+    ui->acftTypeLabel->setText(tr("Unknown Registration."));
+    if (line_edit->text() != QString())
+        addNewTail(line_edit);
+}
+
+/*
+ * Pilot Line Edits
+ */
+
+void NewFlightDialog::onPilotNameLineEdit_editingFinished()
+{
+    auto sender_object = sender();
+    auto line_edit = this->findChild<QLineEdit*>(sender_object->objectName());
+    //DEB << line_edit->objectName() << "Editing Finished -" << line_edit->text());
+
+    if(line_edit->text().contains(SELF, Qt::CaseInsensitive)) {
+        DEB << "self recognized.";
+        line_edit->setText(completionData.pilotsIdMap.value(1));
+        onGoodInputReceived(line_edit);
+        return;
+    }
+
+    if(completionData.pilotsIdMap.key(line_edit->text()) != 0) {
+        DEB << "Mapped: " << line_edit->text() << completionData.pilotsIdMap.key(line_edit->text());
+        onGoodInputReceived(line_edit);
+        return;
+    }
+
+    if (line_edit->text().isEmpty()) {
+        return;
+    }
+
+    if (!line_edit->completer()->currentCompletion().isEmpty()) {
+        DEB << "Trying to fix input...";
+        line_edit->setText(line_edit->completer()->currentCompletion());
+        emit line_edit->editingFinished();
+        return;
+    }
+
+    onBadInputReceived(line_edit);
+    addNewPilot(line_edit);
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+///                               Auto Logging Tab Slots                                        ///
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+void NewFlightDialog::on_setAsDefaultButton_clicked()
+{
+    writeSettings();
+}
+
+void NewFlightDialog::on_restoreDefaultButton_clicked()
+{
+    readSettings();
+}
+
+void NewFlightDialog::on_PilotFlyingCheckBox_stateChanged(int)
+{
+    DEB << "PF checkbox state changed.";
+    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 NewFlightDialog::on_IfrCheckBox_stateChanged(int)
+{
+    if (timeLineEditsValid() && updateEnabled)
+        onMandatoryLineEditsFilled();
+}
+
+void NewFlightDialog::on_manualEditingCheckBox_stateChanged(int arg1)
+{
+    if (!(timeLineEditsValid()) && ui->manualEditingCheckBox->isChecked()) {
+        INFO(tr("Before editing times manually, please fill out the required fields "
+                "in the flight data tab, so that total time can be calculated."));
+        ui->manualEditingCheckBox->setChecked(false);
+        return;
+    }
+    QList<QLineEdit*>   LE = {ui->tSPSETimeLineEdit, ui->tSPMETimeLineEdit, ui->tMPTimeLineEdit,    ui->tIFRTimeLineEdit,
+                              ui->tNIGHTTimeLineEdit,ui->tPICTimeLineEdit,  ui->tPICUSTimeLineEdit, ui->tSICTimeLineEdit,
+                              ui->tDUALTimeLineEdit, ui->tFITimeLineEdit};
+    switch (arg1) {
+    case 0:
+        for(const auto& le : LE){
+            le->setFocusPolicy(Qt::NoFocus);
+            le->setStyleSheet(QString());
+        }
+        updateEnabled = true;
+        if (allMandatoryLineEditsValid() && updateEnabled)
+            onMandatoryLineEditsFilled();
+        break;
+    case 2:
+        for(const auto& le : LE){
+            le->setFocusPolicy(Qt::StrongFocus);
+        }
+        updateEnabled = false;
+        break;
+    default:
+        break;
+    }
+}
+
+void NewFlightDialog::on_ApproachComboBox_currentTextChanged(const QString &arg1)
+{
+    if(arg1 == QLatin1String("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);
+    }
+
+    if (arg1 != QLatin1String("VISUAL"))
+        ui->IfrCheckBox->setChecked(true);
+}
+
+void NewFlightDialog::on_FunctionComboBox_currentIndexChanged(int)
+{
+    if (updateEnabled)
+        fillDeductibleData();
+}
+
+// [F]: Not a priority right now.
+void NewFlightDialog::on_deptTZComboBox_currentIndexChanged(int index)
+{
+    if (index > 0) {
+        INFO(tr("Currently only logging in UTC time is supported."));
+        ui->deptTZComboBox->setCurrentIndex(0);
+    }
+}
+
+void NewFlightDialog::on_destTZComboBox_currentIndexChanged(int index)
+{
+    if (index > 0) {
+        INFO(tr("Currently only logging in UTC time is supported."));
+        ui->destTZComboBox->setCurrentIndex(0);}
+}

+ 216 - 0
src/gui/dialogues/oldnewflightdialog.h

@@ -0,0 +1,216 @@
+/*
+ *openPilotLog - A FOSS Pilot Logbook Application
+ *Copyright (C) 2020-2021 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 <QStringList>
+#include <QButtonGroup>
+#include <QBitArray>
+#include <QLineEdit>
+#include <QCalendarWidget>
+#include <QComboBox>
+#include <QTabWidget>
+#include <QKeyEvent>
+#include "src/functions/atime.h"
+
+#include "src/classes/aflightentry.h"
+#include "src/classes/apilotentry.h"
+#include "src/classes/atailentry.h"
+#include "src/database/adatabase.h"
+#include "src/classes/acompletiondata.h"
+
+namespace Ui {
+
+class NewFlight;
+}
+
+/*!
+ * \brief The NewFlightDialog enables the user to add a new flight or edit an existing one.
+ * \details
+ * - Most line edits have validators and completers.
+ * - Validators are based on regular expressions, serving as raw input validation
+ * - The Completers are based off the database and provide auto-completion
+ * - mandatory line edits only emit editing finished if their content has passed
+ *   raw input validation or focus is lost.
+ * - Editing finished triggers validating inputs by mapping them to Database values
+ *   where required and results in either pass or fail.
+ * - A QBitArray is mainained containing the state of validity of the mandatory line edits
+ * - The deducted entries are automatically filled if the necessary mandatory entries
+ * are valid.
+ * - Comitting an entry to the database is only allowed if all mandatory inputs are valid.
+ */
+class NewFlightDialog : public QDialog
+{
+    Q_OBJECT
+public:
+    /*!
+     * \brief NewFlightDialog create a new flight and add it to the logbook.
+     */
+    explicit NewFlightDialog(ACompletionData &completion_data, QWidget *parent = nullptr);
+    /*!
+     * \brief NewFlightDialog Edit an existing logbook entry.
+     */
+    explicit NewFlightDialog(ACompletionData &completion_data, int row_id, QWidget *parent = nullptr);
+    ~NewFlightDialog();
+
+    /*!
+     * \brief The ValidationSetupData struct encapsulates the items required to initialise
+     * the line edits with QValidators and QCompleters
+     */
+    struct ValidationSetupData
+    {
+        ValidationSetupData(QStringList* completion_data, const QRegularExpression* validation_RegEx)
+            : completionData(completion_data), validationRegEx(validation_RegEx){};
+
+        ValidationSetupData(const QRegularExpression* validation_RegEx)
+            : completionData(nullptr), validationRegEx(validation_RegEx){};
+
+        const QStringList* completionData;
+        const QRegularExpression* validationRegEx;
+    };
+
+private slots:
+
+    void onToUpperTriggered_textChanged(const QString&);
+    void onPilotNameLineEdit_editingFinished();
+    void onLocationEditingFinished(QLineEdit*, QLabel*);
+    void onTimeLineEdit_editingFinished();
+    void onCompleter_highlighted(const QString&);
+    void onCompleter_activated(const QString &);
+    void onCalendarWidget_clicked(const QDate &date);
+    void on_doftLineEdit_editingFinished();
+    void on_cancelButton_clicked();
+    void on_submitButton_clicked();
+    void on_setAsDefaultButton_clicked();
+    void on_restoreDefaultButton_clicked();
+    void on_PilotFlyingCheckBox_stateChanged(int arg1);
+    void on_IfrCheckBox_stateChanged(int);
+    void on_manualEditingCheckBox_stateChanged(int arg1);
+    void on_ApproachComboBox_currentTextChanged(const QString &arg1);
+    void on_FunctionComboBox_currentIndexChanged(int index);
+    void on_deptLocLineEdit_editingFinished();
+    void on_destLocLineEdit_editingFinished();
+    void on_acftLineEdit_editingFinished();
+    void on_deptTZComboBox_currentIndexChanged(int index);
+    void on_destTZComboBox_currentIndexChanged(int index);
+
+    void on_calendarPushButton_clicked();
+
+private:
+    Ui::NewFlight *ui;
+
+    /*!
+     * \brief a AFlightEntry object that is used to store either position data
+     * from an old entry, is used to fill the form for editing an entry, or is
+     * filled with new data for adding a new entry to the logbook.
+     */
+    AFlightEntry flightEntry;
+
+    QVector<QLineEdit*> mandatoryLineEdits;
+    QVector<QLineEdit*> primaryTimeLineEdits;
+    QVector<QLineEdit*> pilotsLineEdits;
+
+    /*!
+     * \brief mandatoryLineEditsValid holds the minimum required information to create a
+     * valid database entries.
+     */
+    QBitArray mandatoryLineEditsValid;
+    enum mandatoryLineEdit {
+        doft = 0,
+        dept = 1,
+        dest = 2,
+        tofb = 3,
+        tonb = 4,
+        pic  = 5,
+        acft = 6
+    };
+    void validateMandatoryLineEdit(mandatoryLineEdit line_edit){mandatoryLineEditsValid.setBit(line_edit, true);}
+    void invalidateMandatoryLineEdit(mandatoryLineEdit line_edit){mandatoryLineEditsValid.setBit(line_edit, false);}
+    bool timeLineEditsValid(){return mandatoryLineEditsValid[mandatoryLineEdit::tofb]
+                                  && mandatoryLineEditsValid[mandatoryLineEdit::tonb];}
+    bool acftLineEditValid(){return mandatoryLineEditsValid[mandatoryLineEdit::acft];}
+    bool locLineEditsValid(){return mandatoryLineEditsValid[mandatoryLineEdit::dept]
+                                 && mandatoryLineEditsValid[mandatoryLineEdit::dest];}
+    bool allMandatoryLineEditsValid(){return mandatoryLineEditsValid.count(true) == 7;}
+
+    //debug
+    void validationStatus();
+    /*!
+     * Contains completion data for QCompleters and mapping user input
+     */
+    ACompletionData completionData;
+
+
+    Opl::Time::FlightTimeFormat flightTimeFormat;
+
+    /*!
+     * \brief If the user elects to manually edit function times, automatic updating
+     * is disabled.
+     */
+    bool updateEnabled;
+
+    void setup();
+    void readSettings();
+    void setupUi();
+    void writeSettings();
+    void setupButtonGroups();
+    void setupRawInputValidation();
+    void setupSignalsAndSlots();
+    void formFiller();
+    void fillDeductibleData();
+
+    void onMandatoryLineEditsFilled();
+    void onGoodInputReceived(QLineEdit*);
+    void onBadInputReceived(QLineEdit *);
+    bool eventFilter(QObject *object, QEvent *event);
+    bool isLessOrEqualThanBlockTime(const QString time_string);
+
+    void addNewTail(QLineEdit*);
+    void addNewPilot(QLineEdit *);
+
+    /*!
+     * \brief Collects user input from the line edits and processes it to be ready
+     * for database submission.
+     */
+    RowData_T collectInput();
+
+    /*!
+     * \brief converts a time string as used in the UI to an integer of minutes for
+     * use in the database based on the format in use in the Dialog
+     */
+    inline int stringToMinutes(const QString &time_string, Opl::Time::FlightTimeFormat format)
+    {
+        return ATime::toMinutes(ATime::fromString(time_string, format));
+    }
+
+    /*!
+     * \brief minutesToString converts an integer of minutes as received from the database
+     * to a String to be displayed in the UI, based on the format in use in the Dialog.
+     */
+    inline QString minutesToString(const int minutes, Opl::Time::FlightTimeFormat format)
+    {
+        return ATime::toString(ATime::qTimefromMinutes(minutes), format);
+    }
+};
+
+#endif // NEWFLIGHT_H

+ 1 - 2
src/gui/widgets/logbookwidget.cpp

@@ -22,7 +22,6 @@
 #include "src/database/adatabase.h"
 #include "src/classes/asettings.h"
 #include "src/gui/dialogues/newflightdialog.h"
-#include "src/gui/dialogues/newnewflightdialog.h"
 #include "src/functions/alog.h"
 #include "src/functions/alog.h"
 
@@ -273,7 +272,7 @@ void LogbookWidget::on_actionEdit_Flight_triggered()
         //ui->stackedWidget->setCurrentWidget(logbookWidget);
         //!
         //! \brief new_state
-        NewNewFlightDialog nff(completionData,selectedFlights.first(), this);
+        NewFlightDialog nff(completionData,selectedFlights.first(), this);
         ui->stackedWidget->addWidget(&nff);
         ui->stackedWidget->setCurrentWidget(&nff);
         nff.setWindowFlag(Qt::Widget);

Some files were not shown because too many files changed in this diff