Browse Source

Started incorporating Simulator Session Logging

New database table 'simulators' in which simulator sessions are logged.
NewSimDialog for logging the sessions
ASimulatorEntry class
Literals in opl.h

Included the new table in ADatabaseSetup and adjusted some SQL statements

Some QStringLiterals iso QLatin1Strings where no string comparisons are made
Felix Turo 3 years ago
parent
commit
7d20d7e554

+ 13 - 0
CMakeLists.txt

@@ -38,6 +38,7 @@ set(PROJECT_SOURCES
     src/classes/atranslator.cpp
     src/classes/ajson.cpp
     src/classes/ahash.cpp
+    src/classes/asimulatorentry.cpp
     src/database/adatabase.cpp
     src/database/adbsetup.cpp
     src/functions/acalc.cpp
@@ -49,6 +50,7 @@ set(PROJECT_SOURCES
     src/gui/dialogues/newflightdialog.cpp
     src/gui/dialogues/newpilotdialog.cpp
     src/gui/dialogues/newtaildialog.cpp
+    src/gui/dialogues/newsimdialog.cpp
     src/gui/widgets/aircraftwidget.cpp
     src/gui/widgets/backupwidget.cpp
     src/gui/widgets/debugwidget.cpp
@@ -75,6 +77,7 @@ set(PROJECT_SOURCES
     src/classes/atranslator.h
     src/classes/ajson.h
     src/classes/ahash.h
+    src/classes/asimulatorentry.h
     src/database/adatabase.h
     src/database/adbsetup.h
     src/database/adatabasetypes.h
@@ -89,6 +92,7 @@ set(PROJECT_SOURCES
     src/gui/dialogues/newflightdialog.h
     src/gui/dialogues/newpilotdialog.h
     src/gui/dialogues/newtaildialog.h
+    src/gui/dialogues/newsimdialog.h
     src/gui/widgets/aircraftwidget.h
     src/gui/widgets/backupwidget.h
     src/gui/widgets/debugwidget.h
@@ -110,6 +114,7 @@ set(PROJECT_SOURCES
     src/gui/widgets/logbookwidget.ui
     src/gui/widgets/pilotswidget.ui
     src/gui/widgets/settingswidget.ui
+    src/gui/dialogues/newsimdialog.ui
 
     assets/icons.qrc
     assets/themes/stylesheets/breeze/breeze.qrc
@@ -146,6 +151,14 @@ set(PROJECT_SOURCES
 #    endif(Qt5Widgets_VERSION VERSION_LESS 5.15.0)
 #endif(Qt5Widgets_FOUND)
 
+if(CMAKE_BUILD_TYPE STREQUAL "Debug")
+    message("Build type: Debug")
+elseif(CMAKE_BUILD_TYPE STREQUAL "Release")
+    message("Build type: Release")
+    add_definitions(-DQT_NO_DEBUG_OUTPUT)
+endif()
+
+
 if(${QT_VERSION_MAJOR} GREATER_EQUAL 6)
     qt_add_executable(openPilotLog
         ${PROJECT_SOURCES}

+ 3 - 2
mainwindow.cpp

@@ -26,11 +26,12 @@
 #include "src/functions/adatetime.h"
 #include "src/classes/aentry.h"
 
-
+#include "src/gui/dialogues/newsimdialog.h"
 // Quick and dirty Debug area
 void MainWindow::doDebugStuff()
 {
-
+    auto nsd = new NewSimDialog(this);
+    nsd->exec();
 }
 
 MainWindow::MainWindow(QWidget *parent)

+ 18 - 0
src/classes/asimulatorentry.cpp

@@ -0,0 +1,18 @@
+/*
+ *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 "asimulatorentry.h"

+ 38 - 0
src/classes/asimulatorentry.h

@@ -0,0 +1,38 @@
+/*
+ *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 ASIMULATORENTRY_H
+#define ASIMULATORENTRY_H
+
+#include "aentry.h"
+#include "src/opl.h"
+
+class ASimulatorEntry : public AEntry
+{
+public:
+    ASimulatorEntry()
+        : AEntry::AEntry(DataPosition(Opl::Db::TABLE_SIMULATORS, 0)){};
+    ASimulatorEntry(RowId_T row_id)
+        : AEntry::AEntry(DataPosition(Opl::Db::TABLE_SIMULATORS, row_id)){};
+    ASimulatorEntry(RowData_T table_data)
+        : AEntry::AEntry(DataPosition(Opl::Db::TABLE_SIMULATORS, 0), table_data){};
+
+    ASimulatorEntry(const ASimulatorEntry& pe) = default;
+    ASimulatorEntry& operator=(const ASimulatorEntry& pe) = default;
+};
+
+#endif // ASIMULATORENTRY_H

+ 70 - 52
src/database/adbsetup.cpp

@@ -24,23 +24,24 @@
 namespace aDbSetup {
 
 // const auto TEMPLATE_URL = QStringLiteral("https://raw.githubusercontent.com/fiffty-50/openpilotlog/tree/main/assets/database/templates/");
-const auto TEMPLATE_URL = QStringLiteral("https://raw.githubusercontent.com/fiffty-50/openpilotlog/develop/assets/database/templates/");
+const static auto TEMPLATE_URL = QStringLiteral("https://raw.githubusercontent.com/fiffty-50/openpilotlog/develop/assets/database/templates/");
 
 
-const auto CREATE_TABLE_PILOTS = QLatin1String("CREATE TABLE pilots ( "
-            " pilot_id       INTEGER NOT NULL, "
+const static auto CREATE_TABLE_PILOTS = QStringLiteral("CREATE TABLE pilots ( "
+            " pilot_id       INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, "
             " lastname       TEXT    NOT NULL, "
             " firstname      TEXT, "
             " alias          TEXT, "
             " company        TEXT, "
             " employeeid     TEXT, "
             " phone          TEXT, "
-            " email          TEXT, "
-            " PRIMARY KEY(pilot_id AUTOINCREMENT)"
-            ")");
+            " email          TEXT "
+//            " PRIMARY KEY(pilot_id AUTOINCREMENT)"
+            ")"
+                                                       );
 
-const auto CREATE_TABLE_TAILS = QLatin1String("CREATE TABLE tails ("
-            " tail_id        INTEGER NOT NULL,"
+const static auto CREATE_TABLE_TAILS = QStringLiteral("CREATE TABLE tails ("
+            " tail_id        INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,"
             " registration   TEXT NOT NULL,"
             " company        TEXT,"
             " make           TEXT,"
@@ -49,12 +50,13 @@ const auto CREATE_TABLE_TAILS = QLatin1String("CREATE TABLE tails ("
             " multipilot     INTEGER,"
             " multiengine    INTEGER,"
             " engineType     INTEGER,"
-            " weightClass    INTEGER,"
-            " PRIMARY KEY(tail_id AUTOINCREMENT)"
-            ")");
+            " weightClass    INTEGER"
+//            " PRIMARY KEY(tail_id AUTOINCREMENT)"
+            ")"
+                                                      );
 
-const auto CREATE_TABLE_FLIGHTS = QLatin1String("CREATE TABLE flights ("
-            " flight_id      INTEGER NOT NULL, "
+const static auto CREATE_TABLE_FLIGHTS = QStringLiteral("CREATE TABLE flights ("
+            " flight_id      INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, "
             " doft           NUMERIC NOT NULL, "
             " dept           TEXT NOT NULL, "
             " dest           TEXT NOT NULL, "
@@ -86,12 +88,13 @@ const auto CREATE_TABLE_FLIGHTS = QLatin1String("CREATE TABLE flights ("
             " flightNumber   TEXT, "
             " remarks        TEXT, "
             " FOREIGN KEY(pic)  REFERENCES pilots(pilot_id) ON DELETE RESTRICT, "
-            " FOREIGN KEY(acft) REFERENCES tails(tail_id)   ON DELETE RESTRICT, "
-            " PRIMARY KEY(flight_id    AUTOINCREMENT) "
-        ")");
+            " FOREIGN KEY(acft) REFERENCES tails(tail_id)   ON DELETE RESTRICT "
+//            " PRIMARY KEY(flight_id    AUTOINCREMENT) "
+        ")"
+                                                        );
 
-const auto CREATE_TABLE_AIRPORTS = QLatin1String("CREATE TABLE airports ( "
-            " airport_id     INTEGER NOT NULL, "
+const static auto CREATE_TABLE_AIRPORTS = QStringLiteral("CREATE TABLE airports ( "
+            " airport_id     INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, "
             " icao           TEXT NOT NULL, "
             " iata           TEXT, "
             " name           TEXT, "
@@ -100,12 +103,13 @@ const auto CREATE_TABLE_AIRPORTS = QLatin1String("CREATE TABLE airports ( "
             " country        TEXT, "
             " alt            INTEGER, "
             " utcoffset      INTEGER, "
-            " tzolson        TEXT, "
-            " PRIMARY KEY(airport_id AUTOINCREMENT) "
-            ")");
+            " tzolson        TEXT "
+ //           " PRIMARY KEY(airport_id AUTOINCREMENT) "
+            ")"
+                                                         );
 
-const auto CREATE_TABLE_AIRCRAFT = QLatin1String("CREATE TABLE aircraft ("
-            " aircraft_id   INTEGER NOT NULL,"
+const static auto CREATE_TABLE_AIRCRAFT = QStringLiteral("CREATE TABLE aircraft ("
+            " aircraft_id   INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,"
             " make          TEXT,"
             " model         TEXT,"
             " variant       TEXT,"
@@ -115,26 +119,39 @@ const auto CREATE_TABLE_AIRCRAFT = QLatin1String("CREATE TABLE aircraft ("
             " multipilot    INTEGER,"
             " multiengine   INTEGER,"
             " engineType    INTEGER,"
-            " weightClass   INTEGER,"
-            " PRIMARY KEY(aircraft_id AUTOINCREMENT)"
-            ")");
+            " weightClass   INTEGER"
+//            " PRIMARY KEY(aircraft_id AUTOINCREMENT)"
+            ")"
+                                                         );
 
-const auto CREATE_TABLE_CHANGELOG = QLatin1String("CREATE TABLE changelog ( "
-            " revision   INTEGER NOT NULL, "
+const static auto CREATE_TABLE_CHANGELOG = QStringLiteral("CREATE TABLE changelog ( "
+            " revision   INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, "
             " comment    TEXT, "
-            " date       NUMERIC, "
-            " PRIMARY KEY(revision) "
-            ")");
+            " date       NUMERIC "
+//            " PRIMARY KEY(revision) "
+            ")"
+                                                          );
 
-const auto CREATE_TABLE_CURRENCIES = QLatin1String("CREATE TABLE currencies ( "
-            " currency_id	INTEGER PRIMARY KEY AUTOINCREMENT, "
+const static auto CREATE_TABLE_CURRENCIES = QStringLiteral("CREATE TABLE currencies ( "
+            " currency_id	INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, "
             " description	TEXT, "
             " expiryDate     NUMERIC "
             ")"
-            );
+                                                           );
+
+const static auto CREATE_TABLE_SIMULATORS = QStringLiteral("CREATE TABLE simulators ( "
+                                                       " session_id	INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, "
+                                                       " date	NUMERIC NOT NULL, "
+                                                       " totalTime	INTEGER NOT NULL, "
+                                                       " deviceType	TEXT NOT NULL, "
+                                                       " aircraftType	TEXT, "
+                                                       " registration	TEXT, "
+                                                       " remarks	TEXT "
+                                                       ")"
+                                                   );
 
 // Statements for creation of views in the database
-const auto CREATE_VIEW_DEFAULT = QLatin1String("CREATE VIEW viewDefault AS "
+const static auto CREATE_VIEW_DEFAULT = QStringLiteral("CREATE VIEW viewDefault AS "
         " SELECT flight_id, doft as 'Date', "
         " dept AS 'Dept', "
         " printf('%02d',(tofb/60))||':'||printf('%02d',(tofb%60)) AS 'Time', "
@@ -158,7 +175,7 @@ const auto CREATE_VIEW_DEFAULT = QLatin1String("CREATE VIEW viewDefault AS "
         " INNER JOIN tails on flights.acft = tails.tail_id "
         " ORDER BY date DESC ");
 
-const auto CREATE_VIEW_EASA = QLatin1String("CREATE VIEW viewEASA AS "
+const static auto CREATE_VIEW_EASA = QStringLiteral("CREATE VIEW viewEASA AS "
         " SELECT "
         " flight_id, doft as 'Date', "
         " dept AS 'Dept', "
@@ -193,7 +210,7 @@ const auto CREATE_VIEW_EASA = QLatin1String("CREATE VIEW viewEASA AS "
         " INNER JOIN tails on flights.acft = tails.tail_id "
         " ORDER BY date DESC");
 
-const auto CREATE_VIEW_TAILS = QLatin1String("CREATE VIEW viewTails AS "
+const static auto CREATE_VIEW_TAILS = QStringLiteral("CREATE VIEW viewTails AS "
         " SELECT "
         " tail_id AS 'ID', "
         " registration AS 'Registration', "
@@ -208,7 +225,7 @@ const auto CREATE_VIEW_TAILS = QLatin1String("CREATE VIEW viewTails AS "
         " company AS 'Company' "
         " FROM tails WHERE variant IS NOT NULL");
 
-const auto CREATE_VIEW_PILOTS = QLatin1String("CREATE VIEW viewPilots AS "
+const static auto CREATE_VIEW_PILOTS = QStringLiteral("CREATE VIEW viewPilots AS "
         " SELECT "
         " pilot_id AS 'ID', "
         " lastname AS 'Last Name', "
@@ -216,14 +233,14 @@ const auto CREATE_VIEW_PILOTS = QLatin1String("CREATE VIEW viewPilots AS "
         " company AS 'Company' "
         " FROM pilots");
 
-const auto CREATE_VIEW_QCOMPLETER = QLatin1String("CREATE VIEW viewQCompleter AS "
+const static auto CREATE_VIEW_QCOMPLETER = QStringLiteral("CREATE VIEW viewQCompleter AS "
         " SELECT airport_id, icao, iata, tail_id, registration, pilot_id, "
         " lastname||', '||firstname AS 'pilot_name', alias "
         " FROM airports "
         " LEFT JOIN tails ON airports.airport_id = tails.tail_id "
         " LEFT JOIN pilots ON airports.airport_id = pilots.pilot_id");
 
-const auto CREATE_VIEW_TOTALS = QLatin1String("CREATE VIEW viewTotals AS "
+const static auto CREATE_VIEW_TOTALS = QStringLiteral("CREATE VIEW viewTotals AS "
         " SELECT "
         " printf(\"%02d\",CAST(SUM(tblk) AS INT)/60)||\":\"||printf(\"%02d\",CAST(SUM(tblk) AS INT)%60) AS \"TOTAL\", "
         " printf(\"%02d\",CAST(SUM(tSPSE) AS INT)/60)||\":\"||printf(\"%02d\",CAST(SUM(tSPSE) AS INT)%60) AS \"SP SE\", "
@@ -241,16 +258,17 @@ const auto CREATE_VIEW_TOTALS = QLatin1String("CREATE VIEW viewTotals AS "
         " CAST(SUM(ldgDay) AS INT) AS \"LDG Day\", CAST(SUM(ldgNight) AS INT) AS \"LDG Night\" "
         " FROM flights");
 
-const QList<QLatin1String> DATABASE_TABLES = {
+const static QStringList DATABASE_TABLES = {
     CREATE_TABLE_PILOTS,
     CREATE_TABLE_TAILS,
     CREATE_TABLE_FLIGHTS,
     CREATE_TABLE_AIRCRAFT,
     CREATE_TABLE_AIRPORTS,
     CREATE_TABLE_CURRENCIES,
-    CREATE_TABLE_CHANGELOG
+    CREATE_TABLE_CHANGELOG,
+    CREATE_TABLE_SIMULATORS,
 };
-const QList<QLatin1String> DATABASE_VIEWS = {
+const static QStringList DATABASE_VIEWS = {
     CREATE_VIEW_DEFAULT,
     CREATE_VIEW_EASA,
     CREATE_VIEW_TAILS,
@@ -259,16 +277,16 @@ const QList<QLatin1String> DATABASE_VIEWS = {
     CREATE_VIEW_QCOMPLETER,
 };
 
-const QList<QLatin1String> USER_TABLES = {
-    QLatin1String("flights"),
-    QLatin1String("pilots"),
-    QLatin1String("tails")
+const static QStringList USER_TABLES = {
+    QStringLiteral("flights"),
+    QStringLiteral("pilots"),
+    QStringLiteral("tails")
 };
-const QList<QLatin1String> TEMPLATE_TABLES= {
-    QLatin1String("aircraft"),
-    QLatin1String("airports"),
-    QLatin1String("currencies"),
-    QLatin1String("changelog")
+const static QStringList TEMPLATE_TABLES= {
+    QStringLiteral("aircraft"),
+    QStringLiteral("airports"),
+    QStringLiteral("currencies"),
+    QStringLiteral("changelog")
 };
 
 bool createDatabase()

+ 5 - 0
src/functions/adate.cpp

@@ -132,3 +132,8 @@ const QString ADate::getFormatString(Opl::Date::ADateFormat format)
     return ADATEFORMATSMAP.value(format);
 }
 
+const QString ADate::currentDate()
+{
+    return QDate::currentDate().toString(Qt::ISODate);
+}
+

+ 6 - 0
src/functions/adate.h

@@ -60,6 +60,12 @@ public:
 
     static const QString getFormatString(Opl::Date::ADateFormat format);
 
+    /*!
+     * \brief today Returns a string containing the current date in ISO format
+     * \return
+     */
+    static const QString currentDate();
+
 };
 
 #endif // ADATE_H

+ 2 - 2
src/gui/dialogues/newflightdialog.cpp

@@ -50,7 +50,7 @@ NewFlightDialog::NewFlightDialog(ACompletionData &completion_data,
         emit ui->sicNameLineEdit->editingFinished();
     }
 
-    ui->doftLineEdit->setText(QDate::currentDate().toString(Qt::ISODate));
+    ui->doftLineEdit->setText(ADate::currentDate());
     emit ui->doftLineEdit->editingFinished();
 }
 
@@ -270,7 +270,7 @@ void NewFlightDialog::onGoodInputReceived(QLineEdit *line_edit)
 void NewFlightDialog::onBadInputReceived(QLineEdit *line_edit)
 {
     DEB << line_edit->objectName() << " - Bad input received - " << line_edit->text();
-    line_edit->setStyleSheet(QStringLiteral("border: 1px solid red"));
+    line_edit->setStyleSheet(Opl::Styles::RED_BORDER);
     line_edit->setText(QString());
 
     if (mandatoryLineEdits->contains(line_edit))

+ 143 - 0
src/gui/dialogues/newsimdialog.cpp

@@ -0,0 +1,143 @@
+#include "newsimdialog.h"
+#include "ui_newsimdialog.h"
+#include "src/opl.h"
+#include "src/functions/atime.h"
+#include "src/functions/adate.h"
+#include <QCompleter>
+
+NewSimDialog::NewSimDialog(QWidget *parent) :
+    QDialog(parent),
+    ui(new Ui::NewSimDialog)
+{
+    ui->setupUi(this);
+    ui->dateLineEdit->setText(ADate::currentDate());
+    Opl::loadSimulatorTypes(ui->typeComboBox);
+
+    const QStringList aircraft_list = aDB->getCompletionList(ADatabaseTarget::aircraft);
+    auto completer = new QCompleter(aircraft_list, ui->acftLineEdit);
+    completer->setCaseSensitivity(Qt::CaseInsensitive);
+    completer->setCompletionMode(QCompleter::PopupCompletion);
+    completer->setFilterMode(Qt::MatchContains);
+    ui->acftLineEdit->setCompleter(completer);
+}
+
+NewSimDialog::~NewSimDialog()
+{
+    delete ui;
+}
+
+void NewSimDialog::on_dateLineEdit_editingFinished()
+{
+    auto text = ui->dateLineEdit->text();
+
+    Opl::Date::ADateFormat date_format = Opl::Date::ADateFormat::ISODate;
+    auto date = ADate::parseInput(text, date_format);
+    if (date.isValid()) {
+        ui->dateLineEdit->setText(ADate::toString(date, date_format));
+        ui->dateLineEdit->setStyleSheet(QString());
+        return;
+    } else {
+        ui->dateLineEdit->setText(QString());
+        ui->dateLineEdit->setStyleSheet(Opl::Styles::RED_BORDER);
+    }
+}
+
+
+void NewSimDialog::on_timeLineEdit_editingFinished()
+{
+    const QString time_string = ATime::formatTimeInput(ui->timeLineEdit->text());
+    const QTime time = ATime::fromString(time_string);
+
+    if (time.isValid()) {
+        ui->timeLineEdit->setText(time_string);
+        ui->timeLineEdit->setStyleSheet(QString());
+    } else {
+        ui->timeLineEdit->setText(QString());
+        ui->timeLineEdit->setStyleSheet(Opl::Styles::RED_BORDER);
+    }
+}
+
+void NewSimDialog::on_registrationLineEdit_textChanged(const QString &arg1)
+{
+    ui->registrationLineEdit->setText(arg1.toUpper());
+}
+
+void NewSimDialog::on_helpPushButton_clicked()
+{
+    INFO(tr("<br>"
+         "For  any  FSTD  enter  the  type  of  aircraft  and  qualification "
+         "number  of  the  device.  For  other  flight  training  devices  enter "
+         "either FNPT I or FNPT II as appropriate<br><br>"
+         "Total time of session includes all exercises carried out in the "
+         "device, including pre- and after-flight checks<br><br>"
+         "Enter the type of exercise performed in the ‘remarks’ field "
+            "for example operator proficiency check, revalidation."));
+}
+
+bool NewSimDialog::verifyInput(QString& error_msg)
+{
+    // Date
+    auto text = ui->dateLineEdit->text();
+    Opl::Date::ADateFormat date_format = Opl::Date::ADateFormat::ISODate;
+    const auto date = ADate::parseInput(text, date_format);
+
+    if (!date.isValid()) {
+        ui->dateLineEdit->setStyleSheet(Opl::Styles::RED_BORDER);
+        ui->dateLineEdit->setText(QString());
+        error_msg = tr("Invalid Date");
+        return false;
+    }
+    // Time
+    const QString time_string = ATime::formatTimeInput(ui->timeLineEdit->text());
+    const QTime time = ATime::fromString(time_string);
+
+    if (!time.isValid()) {
+        ui->timeLineEdit->setStyleSheet(Opl::Styles::RED_BORDER);
+        ui->timeLineEdit->setText(QString());
+        error_msg = tr("Invalid time");
+        return false;
+    }
+
+    // Device Type - for FSTD, aircraft info is required
+    if (ui->typeComboBox->currentIndex() == Opl::SimulatorTypes::FSTD
+            && ui->acftLineEdit->text() == QString()) {
+        error_msg = tr("For FSTD, please enter the aircraft type.");
+        return false;
+    }
+
+    return true;
+}
+
+RowData_T NewSimDialog::collectInput()
+{
+    RowData_T new_entry;
+    // Date
+    new_entry.insert(Opl::Db::SIMULATORS_DATE, ui->dateLineEdit->text());
+    // Time
+    new_entry.insert(Opl::Db::SIMULATORS_TIME, ATime::toMinutes(ui->timeLineEdit->text()));
+    // Device Type
+    new_entry.insert(Opl::Db::SIMULATORS_TYPE, ui->typeComboBox->currentText());
+    // Aircraft Type
+    new_entry.insert(Opl::Db::SIMULATORS_ACFT, ui->acftLineEdit->text());
+    // Registration
+    if (!ui->registrationLineEdit->text().isEmpty())
+        new_entry.insert(Opl::Db::SIMULATORS_REG, ui->registrationLineEdit->text());
+    // Remarks
+    if (!ui->remarksLineEdit->text().isEmpty())
+        new_entry.insert(Opl::Db::FLIGHTS_REMARKS, ui->remarksLineEdit->text());
+
+    return new_entry;
+}
+
+void NewSimDialog::on_buttonBox_accepted()
+{
+    QString error_msg;
+    if (!verifyInput(error_msg)) {
+        INFO(error_msg);
+        return;
+    }
+
+    auto sim_entry = ASimulatorEntry(collectInput());
+    DEB << sim_entry;
+    aDB->commit(sim_entry);
+}

+ 39 - 0
src/gui/dialogues/newsimdialog.h

@@ -0,0 +1,39 @@
+#ifndef NEWSIMDIALOG_H
+#define NEWSIMDIALOG_H
+
+#include <QDialog>
+#include "src/classes/asimulatorentry.h"
+#include "src/database/adatabase.h"
+#include "src/classes/acompletiondata.h"
+
+namespace Ui {
+class NewSimDialog;
+}
+
+class NewSimDialog : public QDialog
+{
+    Q_OBJECT
+
+public:
+    explicit NewSimDialog(QWidget *parent = nullptr);
+    ~NewSimDialog();
+
+private slots:
+    void on_buttonBox_accepted();
+
+    void on_dateLineEdit_editingFinished();
+
+    void on_timeLineEdit_editingFinished();
+
+    void on_helpPushButton_clicked();
+
+    void on_registrationLineEdit_textChanged(const QString &arg1);
+
+private:
+    Ui::NewSimDialog *ui;
+
+    bool verifyInput(QString &error_msg);
+    RowData_T collectInput();
+};
+
+#endif // NEWSIMDIALOG_H

+ 174 - 0
src/gui/dialogues/newsimdialog.ui

@@ -0,0 +1,174 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>NewSimDialog</class>
+ <widget class="QDialog" name="NewSimDialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>400</width>
+    <height>300</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Dialog</string>
+  </property>
+  <layout class="QGridLayout" name="gridLayout">
+   <item row="2" column="0">
+    <widget class="QLabel" name="typeLabel">
+     <property name="text">
+      <string>Simulator Type</string>
+     </property>
+    </widget>
+   </item>
+   <item row="5" column="0">
+    <widget class="QLabel" name="remarksLabel">
+     <property name="text">
+      <string>Remarks</string>
+     </property>
+    </widget>
+   </item>
+   <item row="3" column="0">
+    <widget class="QLabel" name="acftLabel">
+     <property name="text">
+      <string>Aircraft Type</string>
+     </property>
+    </widget>
+   </item>
+   <item row="4" column="0">
+    <widget class="QLabel" name="registrationLabel">
+     <property name="text">
+      <string>Registration</string>
+     </property>
+    </widget>
+   </item>
+   <item row="2" column="1">
+    <widget class="QComboBox" name="typeComboBox">
+     <property name="minimumSize">
+      <size>
+       <width>160</width>
+       <height>0</height>
+      </size>
+     </property>
+    </widget>
+   </item>
+   <item row="4" column="1">
+    <widget class="QLineEdit" name="registrationLineEdit">
+     <property name="minimumSize">
+      <size>
+       <width>160</width>
+       <height>0</height>
+      </size>
+     </property>
+    </widget>
+   </item>
+   <item row="1" column="1">
+    <widget class="QLineEdit" name="timeLineEdit">
+     <property name="minimumSize">
+      <size>
+       <width>160</width>
+       <height>0</height>
+      </size>
+     </property>
+    </widget>
+   </item>
+   <item row="1" column="0">
+    <widget class="QLabel" name="timeLabel">
+     <property name="text">
+      <string>Total Time of Session</string>
+     </property>
+    </widget>
+   </item>
+   <item row="0" column="1">
+    <widget class="QLineEdit" name="dateLineEdit">
+     <property name="minimumSize">
+      <size>
+       <width>160</width>
+       <height>0</height>
+      </size>
+     </property>
+    </widget>
+   </item>
+   <item row="3" column="1">
+    <widget class="QLineEdit" name="acftLineEdit">
+     <property name="minimumSize">
+      <size>
+       <width>160</width>
+       <height>0</height>
+      </size>
+     </property>
+    </widget>
+   </item>
+   <item row="0" column="0">
+    <widget class="QLabel" name="dateLabel">
+     <property name="text">
+      <string>Date</string>
+     </property>
+    </widget>
+   </item>
+   <item row="5" column="1">
+    <widget class="QLineEdit" name="remarksLineEdit">
+     <property name="minimumSize">
+      <size>
+       <width>160</width>
+       <height>0</height>
+      </size>
+     </property>
+    </widget>
+   </item>
+   <item row="6" column="0">
+    <widget class="QPushButton" name="helpPushButton">
+     <property name="maximumSize">
+      <size>
+       <width>20</width>
+       <height>16777215</height>
+      </size>
+     </property>
+     <property name="text">
+      <string>?</string>
+     </property>
+    </widget>
+   </item>
+   <item row="6" column="1">
+    <widget class="QDialogButtonBox" name="buttonBox">
+     <property name="layoutDirection">
+      <enum>Qt::LeftToRight</enum>
+     </property>
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+     <property name="standardButtons">
+      <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <tabstops>
+  <tabstop>dateLineEdit</tabstop>
+  <tabstop>timeLineEdit</tabstop>
+  <tabstop>typeComboBox</tabstop>
+  <tabstop>acftLineEdit</tabstop>
+  <tabstop>registrationLineEdit</tabstop>
+  <tabstop>remarksLineEdit</tabstop>
+ </tabstops>
+ <resources/>
+ <connections>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>rejected()</signal>
+   <receiver>NewSimDialog</receiver>
+   <slot>reject()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>316</x>
+     <y>260</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>286</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+</ui>

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

@@ -160,6 +160,8 @@ void HomeWidget::fillSelectedCurrencies()
 void HomeWidget::fillCurrencyTakeOffLanding()
 {
     const auto takeoff_landings = AStat::countTakeOffLanding();
+    if(takeoff_landings.isEmpty())
+        return;
 
     ui->TakeOffDisplayLabel->setText(takeoff_landings[0].toString());
     if (takeoff_landings[0].toUInt() < 3)

+ 59 - 27
src/opl.h

@@ -109,38 +109,55 @@ static const QMap<PilotFunction, QLatin1String> PILOT_FUNCTIONS = {
 
 inline void loadPilotFunctios(QComboBox *combo_box)
 {
-    for (int i = 0; i < Opl::PILOT_FUNCTIONS.size(); i++)
-        combo_box->addItem(Opl::PILOT_FUNCTIONS.value(Opl::PilotFunction(i)));
+    for (int i = PilotFunction::PIC; i < PILOT_FUNCTIONS.size(); i++)
+        combo_box->addItem(PILOT_FUNCTIONS.value(PilotFunction(i)));
 };
 
-static const QList<QLatin1String> APPROACH_TYPES = {
-        QLatin1String("VISUAL"),
-        QLatin1String("ILS CAT I"),
-        QLatin1String("ILS CAT II"),
-        QLatin1String("ILS CAT III"),
-        QLatin1String("GLS"),
-        QLatin1String("MLS"),
-        QLatin1String("LOC"),
-        QLatin1String("LOC/DME"),
-        QLatin1String("RNAV"),
-        QLatin1String("RNAV (LNAV)"),
-        QLatin1String("RNAV (LNAV/VNAV)"),
-        QLatin1String("RNAV (LPV)"),
-        QLatin1String("RNAV (RNP)"),
-        QLatin1String("RNAV (RNP-AR)"),
-        QLatin1String("VOR"),
-        QLatin1String("VOR/DME"),
-        QLatin1String("NDB"),
-        QLatin1String("NDB/DME"),
-        QLatin1String("TACAN"),
-        QLatin1String("SRA"),
-        QLatin1String("PAR"),
-        QLatin1String("OTHER")
+/*!
+ * \brief Flight and Navigation Procedures Trainer 1/2, Flight Simulation Training Device
+ */
+enum SimulatorTypes {FNPTI = 0, FNPTII = 1, FSTD = 2};
+
+static const QMap<SimulatorTypes, QString> SIMULATOR_TYPES = {
+    {FNPTI,  QStringLiteral("FNPT I")},
+    {FNPTII, QStringLiteral("FNPT II")},
+    {FSTD,   QStringLiteral("FSTD")},
+};
+
+inline void loadSimulatorTypes(QComboBox *combo_box)
+{
+    for (int i = 0; i < SIMULATOR_TYPES.size(); i++)
+        combo_box->addItem(SIMULATOR_TYPES.value(SimulatorTypes(i)));
+}
+
+static const QStringList APPROACH_TYPES = {
+        QStringLiteral("VISUAL"),
+        QStringLiteral("ILS CAT I"),
+        QStringLiteral("ILS CAT II"),
+        QStringLiteral("ILS CAT III"),
+        QStringLiteral("GLS"),
+        QStringLiteral("MLS"),
+        QStringLiteral("LOC"),
+        QStringLiteral("LOC/DME"),
+        QStringLiteral("RNAV"),
+        QStringLiteral("RNAV (LNAV)"),
+        QStringLiteral("RNAV (LNAV/VNAV)"),
+        QStringLiteral("RNAV (LPV)"),
+        QStringLiteral("RNAV (RNP)"),
+        QStringLiteral("RNAV (RNP-AR)"),
+        QStringLiteral("VOR"),
+        QStringLiteral("VOR/DME"),
+        QStringLiteral("NDB"),
+        QStringLiteral("NDB/DME"),
+        QStringLiteral("TACAN"),
+        QStringLiteral("SRA"),
+        QStringLiteral("PAR"),
+        QStringLiteral("OTHER")
 };
 
 inline void loadApproachTypes(QComboBox *combo_box)
 {
-    for (const auto & approach : Opl::APPROACH_TYPES)
+    for (const auto & approach : APPROACH_TYPES)
         combo_box->addItem(approach);
 };
 
@@ -191,6 +208,7 @@ static const auto TABLE_TAILS            = QStringLiteral("tails");
 static const auto TABLE_AIRCRAFT         = QStringLiteral("aircraft");
 static const auto TABLE_AIRPORTS         = QStringLiteral("airports");
 static const auto TABLE_CURRENCIES       = QStringLiteral("currencies");
+static const auto TABLE_SIMULATORS       = QStringLiteral("simulators");
 
 // Flights table columns
 static const auto FLIGHTS_ROWID          = QStringLiteral("flight_id");
@@ -253,8 +271,17 @@ static const auto PILOTS_EMAIL           = QStringLiteral("email");
 static const auto CURRENCIES_EXPIRYDATE  = QStringLiteral("expiryDate");
 static const auto CURRENCIES_DESCRIPTION = QStringLiteral("description");
 
+// Simulators table
+static const auto SIMULATORS_ROWID       = QStringLiteral("session_id");
+static const auto SIMULATORS_DATE        = QStringLiteral("date");
+static const auto SIMULATORS_TIME        = QStringLiteral("totalTime");
+static const auto SIMULATORS_TYPE        = QStringLiteral("deviceType");
+static const auto SIMULATORS_ACFT        = QStringLiteral("aircraftType");
+static const auto SIMULATORS_REG         = QStringLiteral("registration");
+static const auto SIMULATORS_REMARKS     = QStringLiteral("remarks");
+
 // all tables
-static const auto ROWID                  = QStringLiteral("ROWID");
+static const auto ROWID                  = QStringLiteral("rowid");
 static const auto NULL_TIME_hhmm         = QStringLiteral("00:00");
 
 static const auto DEFAULT_FLIGHT_POSITION   = DataPosition(TABLE_FLIGHTS, 0);
@@ -294,6 +321,11 @@ static const auto ICON_TOOLBAR_BACKUP_DARK      = QStringLiteral(":/icons/opl-ic
 
 }
 
+namespace Styles {
+
+static const auto RED_BORDER = QStringLiteral("border: 1px solid red");
+} // namespace ui
+
 } // namespace opl
 
 #endif // OPLCONSTANTS_H