Prechádzať zdrojové kódy

Merge pull request #68 from fiffty-50/develop-currencies-into-database

Develop currencies into database

-    Created ACurrencyEntry struct to hold data of a currency entry
-    Added Database functions to retreive ACurrencyEntrry
-    Removed QSettings based Dates
-    Updated logic in FirstRunDialog and added a check for database file existance in main.cpp
-    Updated ADatabaseSetup with Currencies table
-    Updated CMakeLists.txt and .pro files
-    Unified and harmonised layout of PilotWidget and Aircraftwidget
-    Cleaned up variable and function naming, slot connections
-    Removed option for logging incomplete tails. Mandatory fields are now enforced.
Felix Turowsky 4 rokov pred
rodič
commit
fb435eba74

+ 2 - 0
CMakeLists.txt

@@ -22,6 +22,7 @@ find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Widgets Sql Network REQUIRED)
 set(PROJECT_SOURCES
     main.cpp
     mainwindow.cpp
+    src/classes/acurrencyentry.cpp
     src/classes/astyle.cpp
     src/classes/astandardpaths.cpp
     src/classes/aaircraftentry.cpp
@@ -51,6 +52,7 @@ set(PROJECT_SOURCES
     src/testing/atimer.cpp
     
     mainwindow.h
+    src/classes/acurrencyentry.h
     src/classes/astyle.h
     src/classes/astandardpaths.h
     src/classes/aaircraftentry.h

+ 1 - 0
assets/database/templates/changelog.csv

@@ -15,3 +15,4 @@ revision,comment,date
 14,Edited tails and aircraft tables - engineClass and weightClass instead of columns for each element,2020-12-19
 15,Renamed some columns to have consistent naming,2020-12-26
 16,Added CASE for views to account for occasions where aircraft variant is NULL,2021-02-03
+17,Added currencies table,2021-02-12

+ 7 - 0
assets/database/templates/currencies.csv

@@ -0,0 +1,7 @@
+currency_id,description,expiryDate
+1,Licence,
+2,Type Rating,
+3,Line Check,
+4,Medical,
+5,Custom1,
+6,Custom2,

+ 8 - 5
assets/icons.qrc

@@ -16,12 +16,15 @@
         <file>opl-icons/appicon_round_transparent.svg</file>
         <file>opl-icons/appicon_round_gradient.svg</file>
         <file>opl-icons/pilot.png</file>
+        <file>opl-icons/pilot_dark.png</file>
         <file>opl-icons/aircraft.png</file>
         <file>opl-icons/new_flight.png</file>
-	<file>opl-icons/icon_main.svg</file>
-	<file>opl-icons/icon_ios.svg</file>
-	<file>opl-icons/icon_linux.svg</file>
-	<file>opl-icons/icon_linux_light.svg</file>
-	<file>opl-icons/icon_about.png</file>
+	    <file>opl-icons/icon_main.svg</file>
+	    <file>opl-icons/icon_ios.svg</file>
+	    <file>opl-icons/icon_linux.svg</file>
+	    <file>opl-icons/icon_linux_light.svg</file>
+	    <file>opl-icons/icon_about.png</file>
+	    <file>opl-icons/icon_backup.svg</file>
+	    <file>opl-icons/icon_home.svg</file>
     </qresource>
 </RCC>

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 0 - 0
assets/opl-icons/icon_backup.svg


+ 1 - 0
assets/opl-icons/icon_home.svg

@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 318 318"><defs><style>.cls-1,.cls-2{fill:none;}.cls-1{stroke:#000;stroke-linecap:round;stroke-linejoin:round;stroke-width:23px;}</style></defs><g id="Layer_2" data-name="Layer 2"><g id="Layer_9" data-name="Layer 9"><path class="cls-1" d="M299.39,174.94h-35.3V261c0,12.63-9.9,22.86-22.12,22.86H197.5V198.64a12,12,0,0,0-12-12h-53a12,12,0,0,0-12,12V283.9H76c-12.22,0-22.12-10.23-22.12-22.86v-86.1H18.61l35.31-35.42,0,0L154,39.12l5-5,5,5L264.06,139.5l0,0Z"/><rect class="cls-2" width="318" height="318"/></g></g></svg>

+ 1 - 0
assets/templates.qrc

@@ -3,5 +3,6 @@
         <file>database/templates/aircraft.csv</file>
         <file>database/templates/airports.csv</file>
         <file>database/templates/changelog.csv</file>
+        <file>database/templates/currencies.csv</file>
     </qresource>
 </RCC>

+ 13 - 6
main.cpp

@@ -52,12 +52,14 @@ int main(int argc, char *argv[])
 
     AStyle::setup();
 
-    if (!aDB->connect()) {
-        LOG << "Error establishing database connection\n";
-        return 2;
-    }
-
-    if (!ASettings::read(ASettings::Main::SetupComplete).toBool()) {
+    if (ASettings::read(ASettings::Main::SetupComplete).toBool()) {
+        QFileInfo database_file(AStandardPaths::directory(AStandardPaths::Database).
+                                     absoluteFilePath(QStringLiteral("logbook.db")));
+        if (!database_file.exists()) {
+            LOG << "Error: Database file not found\n";
+            return 2;
+        }
+    } else {
         if(FirstRunDialog().exec() == QDialog::Rejected){
             LOG << "Initial setup incomplete or unsuccessfull. Exiting.\n";
             return 3;
@@ -66,6 +68,11 @@ int main(int argc, char *argv[])
         DEB << "Wrote setup_commplete";
     }
 
+    if (!aDB->connect()) {
+        LOG << "Error establishing database connection\n";
+        return 4;
+    }
+
     ARunGuard guard(QStringLiteral("opl_single_key"));
     if ( !guard.tryToRun() ){
         LOG << "Another Instance of openPilotLog is already running. Exiting.\n";

+ 17 - 9
mainwindow.cpp

@@ -28,7 +28,7 @@ MainWindow::MainWindow(QWidget *parent)
     ui->setupUi(this);
 
     // Set up Toolbar
-    ui->actionHome->setIcon(QIcon(":/icons/ionicon-icons/home-outline.png"));
+    ui->actionHome->setIcon(QIcon(Opl::Assets::ICON_HOME));
     ui->actionNewFlight->setIcon(QIcon(Opl::Assets::ICON_NEW_FLIGHT));
     ui->actionLogbook->setIcon(QIcon(":/icons/ionicon-icons/book-outline.png"));
     ui->actionAircraft->setIcon(QIcon(Opl::Assets::ICON_AIRCRAFT));
@@ -124,16 +124,24 @@ void MainWindow::on_actionDebug_triggered()
 void MainWindow::connectWidgets()
 {
     QObject::connect(aDB, &ADatabase::dataBaseUpdated,
-                     logbookWidget, &LogbookWidget::onDisplayModel_dataBaseUpdated);
-    QObject::connect(aDB, &ADatabase::dataBaseUpdated,
-                     pilotsWidget, &PilotsWidget::onDisplayModel_dataBaseUpdated);
-    QObject::connect(aDB, &ADatabase::dataBaseUpdated,
-                     aircraftWidget, &AircraftWidget::onDisplayModel_dataBaseUpdated);
+                     logbookWidget, &LogbookWidget::refresh);
+    QObject::connect(settingsWidget, &SettingsWidget::settingChanged,
+                     logbookWidget, &LogbookWidget::onLogbookWidget_viewSelectionChanged);
+
     QObject::connect(aDB, &ADatabase::dataBaseUpdated,
-                     homeWidget, &HomeWidget::onHomeWidget_dataBaseUpdated);
+                     pilotsWidget, &PilotsWidget::onPilotsWidget_databaseUpdated);
+    QObject::connect(settingsWidget, &SettingsWidget::settingChanged,
+                     pilotsWidget, &PilotsWidget::onPilotsWidget_settingChanged);
 
-    QObject::connect(settingsWidget, &SettingsWidget::viewSelectionChanged,
-                     logbookWidget, &LogbookWidget::onLogbookWidget_viewSelectionChanged);
+    QObject::connect(aDB,            &ADatabase::dataBaseUpdated,
+                     aircraftWidget, &AircraftWidget::onAircraftWidget_dataBaseUpdated);
+    QObject::connect(settingsWidget, &SettingsWidget::settingChanged,
+                     aircraftWidget, &AircraftWidget::onAircraftWidget_settingChanged);
+
+    QObject::connect(aDB, &ADatabase::dataBaseUpdated,
+                     homeWidget, &HomeWidget::refresh);
+    QObject::connect(settingsWidget, &SettingsWidget::settingChanged,
+                     homeWidget, &HomeWidget::refresh);
 }
 
 void MainWindow::on_actionSettings_triggered()

+ 2 - 0
openPilotLog.pro

@@ -20,6 +20,7 @@ DEFINES *= QT_USE_QSTRINGBUILDER
 SOURCES += \
     main.cpp \
     mainwindow.cpp \
+    src/classes/acurrencyentry.cpp \
     src/classes/astyle.cpp \
     src/classes/astandardpaths.cpp \
     src/classes/aaircraftentry.cpp \
@@ -50,6 +51,7 @@ SOURCES += \
 
 HEADERS += \
     mainwindow.h \
+    src/classes/acurrencyentry.h \
     src/classes/astyle.h \
     src/classes/astandardpaths.h \
     src/classes/aaircraftentry.h \

+ 39 - 0
src/classes/acurrencyentry.cpp

@@ -0,0 +1,39 @@
+#include "acurrencyentry.h"
+#include "src/oplconstants.h"
+
+//ACurrencyEntry::ACurrencyEntry()
+//{
+//
+//}
+/*!
+ * \brief ACurrencyEntry::ACurrencyEntry Creates an ACurrenyEntry object.
+ *
+ * The Data Position is initalized by using the strongly typed enum
+ * CurrencyName, which maps to the static row id for the currency.
+ */
+ACurrencyEntry::ACurrencyEntry(ACurrencyEntry::CurrencyName currency_name)
+    : AEntry::AEntry(DataPosition(Opl::Db::TABLE_CURRENCIES, static_cast<int>(currency_name)))
+{}
+
+ACurrencyEntry::ACurrencyEntry(ACurrencyEntry::CurrencyName currency_name, QDate expiration_date)
+    : AEntry::AEntry(DataPosition(Opl::Db::TABLE_CURRENCIES, static_cast<int>(currency_name)))
+{
+    if (expiration_date.isValid()) {
+        tableData.insert(Opl::Db::CURRENCIES_EXPIRYDATE, expiration_date.toString(Qt::ISODate));
+    } else {
+        DEB << "Invalid Date.";
+    }
+}
+
+/*!
+ * \brief ACurrencyEntry::isValid returns true if the object holds a valid expiration date.
+ *
+ * Unless a user has previously entered an expiration date, this will return false.
+ * \return
+ */
+bool ACurrencyEntry::isValid() const
+{
+    return QDate::fromString(
+                tableData.value(Opl::Db::CURRENCIES_EXPIRYDATE).toString(), Qt::ISODate
+                ).isValid();
+}

+ 29 - 0
src/classes/acurrencyentry.h

@@ -0,0 +1,29 @@
+#ifndef ACURRENCYENTRY_H
+#define ACURRENCYENTRY_H
+
+#include "src/classes/aentry.h"
+#include "src/database/adatabasetypes.h"
+
+struct ACurrencyEntry : public AEntry
+{
+public:
+    enum class CurrencyName {
+        Licence     = 1,
+        TypeRating  = 2,
+        LineCheck   = 3,
+        Medical     = 4,
+        Custom1     = 5,
+        Custom2     = 6
+    };
+
+    ACurrencyEntry() = delete;
+    ACurrencyEntry(CurrencyName name);
+    ACurrencyEntry(CurrencyName name, QDate expiration_date);
+
+    ACurrencyEntry(const ACurrencyEntry& te) = default;
+    ACurrencyEntry& operator=(const ACurrencyEntry& te) = default;
+
+    bool isValid() const;
+};
+
+#endif // ACURRENCYENTRY_H

+ 0 - 6
src/classes/asettings.cpp

@@ -43,12 +43,6 @@ QMap<ASettings::UserData, QString> ASettings::userDataMap = {
     {UserData::ShowMedCurrency,         QStringLiteral("showMedCurrency")},
     {UserData::ShowCustom1Currency,     QStringLiteral("showCustom1Currency")},
     {UserData::ShowCustom2Currency,     QStringLiteral("showCustom2Currency")},
-    {UserData::LicCurrencyDate,         QStringLiteral("licCurrencyDate")},
-    {UserData::TrCurrencyDate,          QStringLiteral("trCurrencyDate")},
-    {UserData::LckCurrencyDate,         QStringLiteral("lckCurrencyDate")},
-    {UserData::MedCurrencyDate,         QStringLiteral("medCurrencyDate")},
-    {UserData::Custom1CurrencyDate,     QStringLiteral("custom1CurrencyDate")},
-    {UserData::Custom2CurrencyDate,     QStringLiteral("custom2CurrencyDate")},
     {UserData::Custom1CurrencyName,     QStringLiteral("custom1CurrencyName")},
     {UserData::Custom2CurrencyName,     QStringLiteral("custom2CurrencyName")},
 };

+ 0 - 6
src/classes/asettings.h

@@ -50,12 +50,6 @@ public:
         ShowMedCurrency,
         ShowCustom1Currency,
         ShowCustom2Currency,
-        LicCurrencyDate,
-        TrCurrencyDate,
-        LckCurrencyDate,
-        MedCurrencyDate,
-        Custom1CurrencyDate,
-        Custom2CurrencyDate,
         Custom1CurrencyName,
         Custom2CurrencyName,
     };

+ 7 - 0
src/database/adatabase.cpp

@@ -449,6 +449,13 @@ AFlightEntry ADatabase::getFlightEntry(RowId_T row_id)
     return flight_entry;
 }
 
+ACurrencyEntry ADatabase::getCurrencyEntry(ACurrencyEntry::CurrencyName currency_name)
+{
+    ACurrencyEntry currency_entry(currency_name);
+    currency_entry.setData(getEntryData(currency_entry.getPosition()));
+    return currency_entry;
+}
+
 const QStringList ADatabase::getCompletionList(ADatabaseTarget target)
 {
     QString statement;

+ 6 - 0
src/database/adatabase.h

@@ -38,6 +38,7 @@
 #include "src/classes/aaircraftentry.h"
 #include "src/classes/aflightentry.h"
 #include "src/classes/astandardpaths.h"
+#include "src/classes/acurrencyentry.h"
 
 #define SQLITE_DRIVER QStringLiteral("QSQLITE")
 
@@ -216,6 +217,11 @@ public:
      */
     AFlightEntry getFlightEntry(RowId_T row_id);
 
+    /*!
+     * \brief Retreives a currency entry from the database.
+     */
+    ACurrencyEntry getCurrencyEntry(ACurrencyEntry::CurrencyName currency_name);
+
     /*!
      * \brief getCompletionList returns a QStringList of values for a
      * QCompleter based on database values

+ 48 - 35
src/database/adatabasesetup.cpp

@@ -23,8 +23,9 @@
 #include "src/classes/adownload.h"
 #include "src/oplconstants.h"
 #include "src/functions/adatetime.h"
+#include "src/functions/alog.h"
 
-const auto createTablePilots = QStringLiteral("CREATE TABLE pilots ( "
+const auto createTablePilots = QLatin1String("CREATE TABLE pilots ( "
             " pilot_id       INTEGER NOT NULL, "
             " lastname       TEXT    NOT NULL, "
             " firstname      TEXT, "
@@ -36,7 +37,7 @@ const auto createTablePilots = QStringLiteral("CREATE TABLE pilots ( "
             " PRIMARY KEY(pilot_id AUTOINCREMENT)"
             ")");
 
-const auto createTableTails = QStringLiteral("CREATE TABLE tails ("
+const auto createTableTails = QLatin1String("CREATE TABLE tails ("
             " tail_id        INTEGER NOT NULL,"
             " registration   TEXT NOT NULL,"
             " company        TEXT,"
@@ -50,7 +51,7 @@ const auto createTableTails = QStringLiteral("CREATE TABLE tails ("
             " PRIMARY KEY(tail_id AUTOINCREMENT)"
             ")");
 
-const auto createTableFlights = QStringLiteral("CREATE TABLE flights ("
+const auto createTableFlights = QLatin1String("CREATE TABLE flights ("
             " flight_id      INTEGER NOT NULL, "
             " doft           NUMERIC NOT NULL, "
             " dept           TEXT NOT NULL, "
@@ -87,7 +88,7 @@ const auto createTableFlights = QStringLiteral("CREATE TABLE flights ("
             " PRIMARY KEY(flight_id    AUTOINCREMENT) "
         ")");
 
-const auto createTableAirports = QStringLiteral("CREATE TABLE airports ( "
+const auto createTableAirports = QLatin1String("CREATE TABLE airports ( "
             " airport_id     INTEGER NOT NULL, "
             " icao           TEXT NOT NULL, "
             " iata           TEXT, "
@@ -101,7 +102,7 @@ const auto createTableAirports = QStringLiteral("CREATE TABLE airports ( "
             " PRIMARY KEY(airport_id AUTOINCREMENT) "
             ")");
 
-const auto createTableAircraft = QStringLiteral("CREATE TABLE aircraft ("
+const auto createTableAircraft = QLatin1String("CREATE TABLE aircraft ("
             " aircraft_id   INTEGER NOT NULL,"
             " make          TEXT,"
             " model         TEXT,"
@@ -116,15 +117,22 @@ const auto createTableAircraft = QStringLiteral("CREATE TABLE aircraft ("
             " PRIMARY KEY(aircraft_id AUTOINCREMENT)"
             ")");
 
-const auto createTableChangelog = QStringLiteral("CREATE TABLE changelog ( "
+const auto createTableChangelog = QLatin1String("CREATE TABLE changelog ( "
             " revision   INTEGER NOT NULL, "
             " comment    TEXT, "
             " date       NUMERIC, "
             " PRIMARY KEY(revision) "
             ")");
 
+const auto createTableCurrencies = QLatin1String("CREATE TABLE currencies ( "
+            " currency_id	INTEGER PRIMARY KEY AUTOINCREMENT, "
+            " description	TEXT, "
+            " expiryDate     NUMERIC "
+            ")"
+            );
+
 // Statements for creation of views in the database
-const auto createViewDefault = QStringLiteral("CREATE VIEW viewDefault AS "
+const auto createViewDefault = QLatin1String("CREATE VIEW viewDefault AS "
         " SELECT flight_id, doft as 'Date', "
         " dept AS 'Dept', "
         " printf('%02d',(tofb/60))||':'||printf('%02d',(tofb%60)) AS 'Time', "
@@ -148,7 +156,7 @@ const auto createViewDefault = QStringLiteral("CREATE VIEW viewDefault AS "
         " INNER JOIN tails on flights.acft = tails.tail_id "
         " ORDER BY date DESC ");
 
-const auto createViewEASA = QStringLiteral("CREATE VIEW viewEASA AS "
+const auto createViewEASA = QLatin1String("CREATE VIEW viewEASA AS "
         " SELECT "
         " flight_id, doft as 'Date', "
         " dept AS 'Dept', "
@@ -183,7 +191,7 @@ const auto createViewEASA = QStringLiteral("CREATE VIEW viewEASA AS "
         " INNER JOIN tails on flights.acft = tails.tail_id "
         " ORDER BY date DESC");
 
-const auto createViewTails = QStringLiteral("CREATE VIEW viewTails AS "
+const auto createViewTails = QLatin1String("CREATE VIEW viewTails AS "
         " SELECT "
         " tail_id AS 'ID', "
         " registration AS 'Registration', "
@@ -198,7 +206,7 @@ const auto createViewTails = QStringLiteral("CREATE VIEW viewTails AS "
         " company AS 'Company' "
         " FROM tails WHERE variant IS NOT NULL");
 
-const auto createViewPilots = QStringLiteral("CREATE VIEW viewPilots AS "
+const auto createViewPilots = QLatin1String("CREATE VIEW viewPilots AS "
         " SELECT "
         " pilot_id AS 'ID', "
         " lastname AS 'Last Name', "
@@ -206,14 +214,14 @@ const auto createViewPilots = QStringLiteral("CREATE VIEW viewPilots AS "
         " company AS 'Company' "
         " FROM pilots");
 
-const auto createViewQCompleter = QStringLiteral("CREATE VIEW viewQCompleter AS "
+const auto createViewQCompleter = QLatin1String("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 createViewTotals = QStringLiteral("CREATE VIEW viewTotals AS "
+const auto createViewTotals = QLatin1String("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\", "
@@ -237,6 +245,7 @@ const QStringList tables = {
     createTableFlights,
     createTableAircraft,
     createTableAirports,
+    createTableCurrencies,
     createTableChangelog
 };
 const QStringList views = {
@@ -248,14 +257,15 @@ const QStringList views = {
     createViewQCompleter,
 };
 const QStringList userTables = {
-    "flights",
-    "pilots",
-    "tails"
+    QStringLiteral("flights"),
+    QStringLiteral("pilots"),
+    QStringLiteral("tails")
 };
 const QStringList templateTables= {
-    "aircraft",
-    "airports",
-    "changelog"
+    QStringLiteral("aircraft"),
+    QStringLiteral("airports"),
+    QStringLiteral("currencies"),
+    QStringLiteral("changelog")
 };
 
 
@@ -276,7 +286,7 @@ bool ADataBaseSetup::createDatabase()
 
     aDB->updateLayout();
 
-    DEB << "Database successfully created!";
+    LOG << "Database successfully created!\n";
     return true;
 }
 
@@ -288,13 +298,13 @@ bool ADataBaseSetup::downloadTemplates()
         QEventLoop loop;
         ADownload* dl = new ADownload;
         QObject::connect(dl, &ADownload::done, &loop, &QEventLoop::quit );
-        dl->setTarget(QUrl(TEMPLATE_URL % table % QStringLiteral(".csv")));
-        dl->setFileName(template_dir.absoluteFilePath(table % QStringLiteral(".csv")));
+        dl->setTarget(QUrl(TEMPLATE_URL + table + QLatin1String(".csv")));
+        dl->setFileName(template_dir.absoluteFilePath(table + QLatin1String(".csv")));
         dl->download();
         dl->deleteLater();
         loop.exec(); // event loop waits for download done signal before allowing loop to continue
 
-        QFileInfo downloaded_file(template_dir.filePath(table % QStringLiteral(".csv")));
+        QFileInfo downloaded_file(template_dir.filePath(table + QLatin1String(".csv")));
         if (downloaded_file.size() == 0)
             return false; // ssl/network error
     }
@@ -302,8 +312,10 @@ bool ADataBaseSetup::downloadTemplates()
 }
 bool ADataBaseSetup::backupOldData()
 {
-    DEB << "Backing up old database...";
-    auto database_file = aDB->databaseFile;
+    LOG << "Backing up old database...";
+    QFileInfo database_file(AStandardPaths::directory(AStandardPaths::Database).
+                                       absoluteFilePath(QStringLiteral("logbook.db")));
+    DEB << "File Info:" << database_file;
 
     if(!database_file.exists()) {
         DEB << "No Database to backup, returning.";
@@ -314,16 +326,17 @@ bool ADataBaseSetup::backupOldData()
     auto backup_dir = AStandardPaths::directory(AStandardPaths::Backup);
     QString backup_name = database_file.baseName() + QLatin1String("_bak_")
             + date_string + QLatin1String(".db");
-    QFile file(aDB->databaseFile.absoluteFilePath()); 
+    QFile file(database_file.absoluteFilePath());
+    DEB << "File:" << file;
     if (!file.rename(backup_dir.absoluteFilePath(backup_name))) {
-        DEB << "Unable to backup old database.";
+        LOG << "Unable to backup old database.\n";
         return false;
     }
-    DEB << "Backed up old database as: " << backup_name;
+    LOG << "Backed up old database as: " << backup_name << "\n";
     return true;
 }
 
-bool ADataBaseSetup::importDefaultData(bool use_local_data)
+bool ADataBaseSetup::importDefaultData(bool use_ressource_data)
 {
     QSqlQuery query;
     // reset template tables
@@ -338,20 +351,20 @@ bool ADataBaseSetup::importDefaultData(bool use_local_data)
         QVector<QStringList> data_to_commit;
         QString error_message("Error importing data ");
 
-        if (use_local_data) {
+        if (use_ressource_data) {
             data_to_commit = aReadCsv(QStringLiteral(":templates/database/templates/")
-                                      + table_name + QStringLiteral(".csv"));
-            error_message.append(" (local) ");
+                                      + table_name + QLatin1String(".csv"));
+            error_message.append(" (ressource) ");
         } else {
             data_to_commit = aReadCsv(AStandardPaths::directory(
                                           AStandardPaths::Templates).absoluteFilePath(
-                                          table_name + QStringLiteral(".csv")));
-            error_message.append(" (remote) ");
+                                          table_name + QLatin1String(".csv")));
+            error_message.append(" (downloaded) ");
         }
 
         //fill with data from csv
         if (!commitData(data_to_commit, table_name)) {
-            DEB << error_message;
+            LOG << error_message;
             return false;
         }
     }
@@ -425,7 +438,7 @@ bool ADataBaseSetup::createSchemata(const QStringList &statements)
         }
         return false;
     }
-    DEB << "All schemas added successfully";
+    LOG << "All database tables created successfully\n";
     return true;
 }
 /*!

+ 1 - 1
src/database/adatabasesetup.h

@@ -22,7 +22,7 @@
 #include <QStringBuilder>
 #include <QEventLoop>
 
-#define DATABASE_REVISION 16
+#define DATABASE_REVISION 17
 
 const auto TEMPLATE_URL = QStringLiteral("https://raw.githubusercontent.com/fiffty-50/openpilotlog/develop/assets/database/templates/");
 

+ 68 - 45
src/gui/dialogues/firstrundialog.cpp

@@ -50,6 +50,9 @@ FirstRunDialog::FirstRunDialog(QWidget *parent) :
     ui->styleComboBox->addItem(QStringLiteral("Dark-Palette"));
     ui->styleComboBox->model()->sort(0);
     ui->styleComboBox->setCurrentText(AStyle::defaultStyle);
+    // Set Date Edits for currencies
+    for (const auto date_edit : this->findChildren<QDateEdit *>())
+        date_edit->setDate(QDate::currentDate());
 }
 
 FirstRunDialog::~FirstRunDialog()
@@ -106,6 +109,28 @@ bool FirstRunDialog::finishSetup()
 {
     writeSettings();
 
+    QFileInfo database_file(AStandardPaths::directory(AStandardPaths::Database).
+                                 absoluteFilePath(QStringLiteral("logbook.db")));
+    if (database_file.exists()) {
+        QMessageBox message_box(QMessageBox::Critical, tr("Database found"),
+                                tr("Warning."
+                                   "An existing database file has been detected on your system.<br>"
+                                   "A backup copy of the existing database will be created at this location:<br>"
+                                   "%1").arg(
+                                    QDir::cleanPath(AStandardPaths::directory(AStandardPaths::Backup).canonicalPath())));
+        message_box.exec();
+        ADataBaseSetup::backupOldData();
+    }
+    if (!aDB->connect()) {
+        QMessageBox message_box(QMessageBox::Critical, tr("Database setup failed"),
+                                tr("Errors have ocurred creating the database."
+                                   "Without a working database The application will not be usable.<br>"
+                                   "The following error has ocurred:<br>"
+                                   "Database: Unable to connect"));
+        message_box.exec();
+        return false;
+    }
+
     if (!setupDatabase()) {
         QMessageBox message_box(QMessageBox::Critical, tr("Database setup failed"),
                                 tr("Errors have ocurred creating the database."
@@ -124,6 +149,16 @@ bool FirstRunDialog::finishSetup()
         message_box.exec();
         return false;
     }
+
+    if (!writeCurrencies()) {
+        QMessageBox message_box(QMessageBox::Critical, tr("Database setup failed"),
+                                tr("Unable to execute database query<br>"
+                                   "The following error has occured:<br>%1"
+                                   ).arg(aDB->lastError.text()));
+        message_box.exec();
+        return false;
+    }
+    aDB->disconnect(); // connection will be re-established by main()
     return true;
 }
 
@@ -184,28 +219,23 @@ bool FirstRunDialog::setupDatabase()
     confirm.setDefaultButton(QMessageBox::No);
 
     if (confirm.exec() == QMessageBox::Yes) {
-        useLocalTemplates = false;
+        useRessourceData = false;
         if (!ADataBaseSetup::downloadTemplates()) {
             QMessageBox message_box(this);
             message_box.setText(tr("Downloading latest data has failed.<br><br>Using local data instead."));
             message_box.exec();
-            useLocalTemplates = true; // fall back
-        } else {
-            useLocalTemplates = true;
+            useRessourceData = true; // fall back
         }
+    } else {
+        useRessourceData = true;
     }
 
-    aDB->disconnect();
-    ADataBaseSetup::backupOldData();
-    aDB->connect();
-
-    // [F]: todo: handle unsuccessful steps
     if(!ADataBaseSetup::createDatabase())
         return false;
 
     aDB->updateLayout();
 
-    if(!ADataBaseSetup::importDefaultData(useLocalTemplates))
+    if(!ADataBaseSetup::importDefaultData(useRessourceData))
         return false;
     aDB->updateLayout();
     return true;
@@ -214,12 +244,12 @@ bool FirstRunDialog::setupDatabase()
 bool FirstRunDialog::createUserEntry()
 {
     QMap<QString, QVariant> data;
-    data.insert(Opl::Db::PILOTS_LASTNAME, ui->lastnameLineEdit->text());
-    data.insert(Opl::Db::PILOTS_FIRSTNAME, ui->firstnameLineEdit->text());
-    data.insert(Opl::Db::PILOTS_ALIAS, QStringLiteral("self"));
+    data.insert(Opl::Db::PILOTS_LASTNAME,   ui->lastnameLineEdit->text());
+    data.insert(Opl::Db::PILOTS_FIRSTNAME,  ui->firstnameLineEdit->text());
+    data.insert(Opl::Db::PILOTS_ALIAS,      QStringLiteral("self"));
     data.insert(Opl::Db::PILOTS_EMPLOYEEID, ui->employeeidLineEdit->text());
-    data.insert(Opl::Db::PILOTS_PHONE, ui->phoneLineEdit->text());
-    data.insert(Opl::Db::PILOTS_EMAIL, ui->emailLineEdit->text());
+    data.insert(Opl::Db::PILOTS_PHONE,      ui->phoneLineEdit->text());
+    data.insert(Opl::Db::PILOTS_EMAIL,      ui->emailLineEdit->text());
 
     auto pilot = APilotEntry(1);
     pilot.setData(data);
@@ -227,6 +257,29 @@ bool FirstRunDialog::createUserEntry()
     return aDB->commit(pilot);
 }
 
+bool FirstRunDialog::writeCurrencies()
+{
+    const QList<QPair<ACurrencyEntry::CurrencyName, QDateEdit*>> currencies_list = {
+        {ACurrencyEntry::CurrencyName::Licence,     ui->currLicDateEdit},
+        {ACurrencyEntry::CurrencyName::TypeRating,  ui->currTrDateEdit},
+        {ACurrencyEntry::CurrencyName::LineCheck,   ui->currLckDateEdit},
+        {ACurrencyEntry::CurrencyName::Medical,     ui->currMedDateEdit},
+        {ACurrencyEntry::CurrencyName::Custom1,     ui->currCustom1DateEdit},
+        {ACurrencyEntry::CurrencyName::Custom2,     ui->currCustom1DateEdit},
+    };
+
+    QDate today = QDate::currentDate();
+    for (const auto &pair : currencies_list) {
+        // only write dates that have been edited
+        if (pair.second->date() != today) {
+            ACurrencyEntry entry(pair.first, pair.second->date());
+            if (!aDB->commit(entry))
+                return false;
+        }
+    }
+    return true;
+}
+
 void FirstRunDialog::reject()
 {
     QMessageBox confirm(QMessageBox::Critical,
@@ -287,36 +340,6 @@ void FirstRunDialog::on_currWarningThresholdSpinBox_valueChanged(int arg1)
     ASettings::write(ASettings::UserData::CurrWarningThreshold, arg1);
 }
 
-void FirstRunDialog::on_currLicDateEdit_userDateChanged(const QDate &date)
-{
-    ASettings::write(ASettings::UserData::LicCurrencyDate, date);
-}
-
-void FirstRunDialog::on_currTrDateEdit_userDateChanged(const QDate &date)
-{
-    ASettings::write(ASettings::UserData::TrCurrencyDate, date);
-}
-
-void FirstRunDialog::on_currLckDateEdit_userDateChanged(const QDate &date)
-{
-    ASettings::write(ASettings::UserData::LckCurrencyDate, date);
-}
-
-void FirstRunDialog::on_currMedDateEdit_userDateChanged(const QDate &date)
-{
-    ASettings::write(ASettings::UserData::MedCurrencyDate, date);
-}
-
-void FirstRunDialog::on_currCustom1DateEdit_userDateChanged(const QDate &date)
-{
-    ASettings::write(ASettings::UserData::Custom1CurrencyDate, date);
-}
-
-void FirstRunDialog::on_currCustom2DateEdit_userDateChanged(const QDate &date)
-{
-    ASettings::write(ASettings::UserData::Custom2CurrencyDate, date);
-}
-
 void FirstRunDialog::on_currCustom1LineEdit_editingFinished()
 {
     ASettings::write(ASettings::UserData::Custom1CurrencyName, ui->currCustom1LineEdit->text());

+ 2 - 13
src/gui/dialogues/firstrundialog.h

@@ -47,29 +47,18 @@ private slots:
 
     void on_currWarningThresholdSpinBox_valueChanged(int arg1);
 
-    void on_currLicDateEdit_userDateChanged(const QDate &date);
-
-    void on_currTrDateEdit_userDateChanged(const QDate &date);
-
-    void on_currLckDateEdit_userDateChanged(const QDate &date);
-
-    void on_currMedDateEdit_userDateChanged(const QDate &date);
-
-    void on_currCustom1DateEdit_userDateChanged(const QDate &date);
-
-    void on_currCustom2DateEdit_userDateChanged(const QDate &date);
-
     void on_currCustom1LineEdit_editingFinished();
 
     void on_currCustom2LineEdit_editingFinished();
 
 private:
     Ui::FirstRunDialog *ui;
-    bool useLocalTemplates;
+    bool useRessourceData;
 
     void writeSettings();
     bool setupDatabase();
     bool createUserEntry();
+    bool writeCurrencies();
     bool finishSetup();
 
     void reject() override;

+ 12 - 28
src/gui/dialogues/newtaildialog.cpp

@@ -234,25 +234,25 @@ void NewTailDialog::submitForm()
 void NewTailDialog::on_operationComboBox_currentIndexChanged(int index)
 {
     if (index != 0)
-        ui->operationComboBox->setStyleSheet("");
+        ui->operationComboBox->setStyleSheet(QString());
 }
 
 void NewTailDialog::on_ppTypeComboBox_currentIndexChanged(int index)
 {
     if (index != 0)
-        ui->ppTypeComboBox->setStyleSheet("");
+        ui->ppTypeComboBox->setStyleSheet(QString());
 }
 
 void NewTailDialog::on_ppNumberComboBox_currentIndexChanged(int index)
 {
     if (index != 0)
-        ui->ppNumberComboBox->setStyleSheet("");
+        ui->ppNumberComboBox->setStyleSheet(QString());
 }
 
 void NewTailDialog::on_weightComboBox_currentIndexChanged(int index)
 {
     if (index != 0)
-        ui->weightComboBox->setStyleSheet("");
+        ui->weightComboBox->setStyleSheet(QString());
 }
 
 void NewTailDialog::on_buttonBox_accepted()
@@ -266,30 +266,14 @@ void NewTailDialog::on_buttonBox_accepted()
     }
 
     if (!verify()) {
-        if (!ASettings::read(ASettings::UserData::AcftAllowIncomplete).toInt()) {
-            QMessageBox message_box(this);
-            message_box.setIcon(QMessageBox::Warning);
-            message_box.setText(tr("Some or all recommended fields are empty.<br>"
-                                   "Please go back and complete the form.<br><br>"
-                                   "You can allow logging incomplete tail entries "
-                                   "on the settings page."));
-            message_box.exec();
-            return;
-        } else {
-            QMessageBox::StandardButton reply;
-            reply = QMessageBox::question(this, tr("Warning"),
-                                          tr("Some recommended fields are empty.<br><br>"
-                                          "If you do not fill out the aircraft details, "
-                                          "it will be impossible to automatically determine "
-                                          "Single/Multi Pilot Times or Single/Multi Engine Time."
-                                          "This will also impact statistics and auto-logging capabilites.<br><br>"
-                                          "It is highly recommended to fill in all the details.<br><br>"
-                                          "Are you sure you want to proceed?"),
-                                          QMessageBox::Yes | QMessageBox::No);
-            if (reply == QMessageBox::Yes) {
-                submitForm();
-            }
-        }
+        QMessageBox message_box(this);
+        message_box.setIcon(QMessageBox::Warning);
+        message_box.setText(tr("Some or all recommended fields are empty.<br>"
+                               "Please fill out the mandatory fields. You can use "
+                               "the search function to automatically fill out all "
+                               "the required fields for a known aircraft type."));
+        message_box.exec();
+        return;
     }
     DEB << "Form verified";
     submitForm();

+ 99 - 84
src/gui/widgets/aircraftwidget.cpp

@@ -29,8 +29,9 @@ AircraftWidget::AircraftWidget(QWidget *parent) :
     ui(new Ui::AircraftWidget)
 {
     ui->setupUi(this);
-    ui->stackedWidget->addWidget(this->findChild<QWidget*>("welcomePageTails"));
-    ui->stackedWidget->setCurrentWidget(this->findChild<QWidget*>("welcomePageTails"));
+
+    ui->tableView->setMinimumWidth(this->width()/2);
+    ui->stackedWidget->setMinimumWidth(this->width()/2);
 
     setupModelAndView();
 }
@@ -40,46 +41,118 @@ AircraftWidget::~AircraftWidget()
     delete ui;
 }
 
-/*
- * Functions
- */
-
 void AircraftWidget::setupModelAndView()
 {
-    sortColumn = ASettings::read(ASettings::UserData::TailSortColumn).toInt();
-
     model = new QSqlTableModel(this);
-    model->setTable("viewTails");
+    model->setTable(QStringLiteral("viewTails"));
     model->select();
 
     view = ui->tableView;
     view->setModel(model);
 
     view->setSelectionBehavior(QAbstractItemView::SelectRows);
-    view->setSelectionMode(QAbstractItemView::SingleSelection);
+    view->setSelectionMode(QAbstractItemView::SingleSelection); // For now, editing multiple entries is not supported.
     view->setEditTriggers(QAbstractItemView::NoEditTriggers);
     view->horizontalHeader()->setStretchLastSection(QHeaderView::Stretch);
     view->hideColumn(0);
-    view->setColumnWidth(1, 180);
-    view->setColumnWidth(2, 180);
+    view->resizeColumnsToContents();
     view->verticalHeader()->hide();
     view->setAlternatingRowColors(true);
+
+    sortColumn = ASettings::read(ASettings::UserData::TailSortColumn).toInt();
     view->setSortingEnabled(true);
     view->sortByColumn(sortColumn, Qt::DescendingOrder);
 
     view->show();
     selection = view->selectionModel();
 
-    QObject::connect(ui->tableView->selectionModel(), &QItemSelectionModel::selectionChanged,
-                     this, &AircraftWidget::tableView_selectionChanged);
+    QObject::connect(ui->tableView->selectionModel(),   &QItemSelectionModel::selectionChanged,
+                     this,                              &AircraftWidget::tableView_selectionChanged);
     QObject::connect(ui->tableView->horizontalHeader(), &QHeaderView::sectionClicked,
-                     this, &AircraftWidget::tableView_headerClicked);
+                     this,                              &AircraftWidget::tableView_headerClicked);
 }
 
 /*
  * Slots
  */
-void AircraftWidget::on_deleteButton_clicked()
+
+void AircraftWidget::onAircraftWidget_settingChanged(SettingsWidget::SettingSignal signal)
+{
+    if (signal != SettingsWidget::AircraftWidget)
+        return;
+
+    setupModelAndView();
+}
+
+void AircraftWidget::onAircraftWidget_dataBaseUpdated()
+{
+    refreshView();
+}
+
+void AircraftWidget::onNewTailDialog_editingFinished()
+{
+    refreshView();
+}
+
+void AircraftWidget::on_newAircraftButton_clicked()
+{
+    NewTailDialog nt(QString(), this);
+    QObject::connect(&nt,  &QDialog::accepted,
+                     this, &AircraftWidget::onNewTailDialog_editingFinished);
+    QObject::connect(&nt,  &QDialog::rejected,
+                     this, &AircraftWidget::onNewTailDialog_editingFinished);
+    nt.exec();
+}
+
+/*!
+ * \brief Displays a dialog in which the Tail can be edited
+ */
+void AircraftWidget::tableView_selectionChanged()
+{
+    if (this->findChild<NewTailDialog*>() != nullptr)
+        delete this->findChild<NewTailDialog*>();
+
+    selectedTails.clear();
+
+    for (const auto& row : selection->selectedRows()) {
+        selectedTails << row.data().toInt();
+        DEB << "Selected Tails(s) with ID: " << selectedTails;
+    }
+
+    if(selectedTails.length() == 1) {
+        auto* nt = new NewTailDialog(selectedTails.first(), this);
+        QObject::connect(nt,   &QDialog::accepted,
+                         this, &AircraftWidget::onNewTailDialog_editingFinished);
+        QObject::connect(nt,   &QDialog::rejected,
+                         this, &AircraftWidget::onNewTailDialog_editingFinished);
+        ui->stackedWidget->addWidget(nt);
+        ui->stackedWidget->setCurrentWidget(nt);
+        nt->setWindowFlag(Qt::Widget);
+        nt->setAttribute(Qt::WA_DeleteOnClose);
+        nt->exec();
+    }
+}
+
+/*!
+ * \brief Acts as a filter on the display model
+ */
+void AircraftWidget::on_aircraftSearchLineEdit_textChanged(const QString &arg1)
+{
+    if(ui->aircraftSearchComboBox->currentIndex() == 0){
+        ui->aircraftSearchLineEdit->setText(arg1.toUpper());
+    }
+    model->setFilter(ui->aircraftSearchComboBox->currentText()
+                     + QLatin1String(" LIKE \"%")
+                     + arg1 + QLatin1String("%\""));
+}
+
+void AircraftWidget::tableView_headerClicked(int column)
+{
+    sortColumn = column;
+    ASettings::write(ASettings::UserData::TailSortColumn, column);
+}
+
+void AircraftWidget::on_deleteAircraftButton_clicked()
 {
     if (selectedTails.length() == 0) {
         QMessageBox message_box(this);
@@ -116,10 +189,18 @@ void AircraftWidget::on_deleteButton_clicked()
                 onDeleteUnsuccessful();
         }
     }
-
-    model->select();
+    refreshView();
 }
 
+/*!
+ * \brief Informs the user that deleting a database entry has been unsuccessful
+ *
+ * \abstract Normally, when one of these entries can not be deleted, it is because of
+ * a [foreign key constraint](https://sqlite.org/foreignkeys.html), meaning that a flight
+ * is associated with the aircraft that was supposed to be deleted.
+ *
+ * This function is used to inform the user and give hints on how to solve the problem.
+ */
 void AircraftWidget::onDeleteUnsuccessful()
 {
     QList<int> foreign_key_constraints = aDB->getForeignKeyConstraints(selectedTails.first(),
@@ -156,69 +237,3 @@ void AircraftWidget::onDeleteUnsuccessful()
         message_box.exec();
     }
 }
-
-void AircraftWidget::on_newAircraftButton_clicked()
-{
-    NewTailDialog nt(QString(), this);
-    connect(&nt, SIGNAL(accepted()), this, SLOT(acft_editing_finished()));
-    connect(&nt, SIGNAL(rejected()), this, SLOT(acft_editing_finished()));
-    nt.exec();
-}
-
-void AircraftWidget::on_aircraftSearchLineEdit_textChanged(const QString &arg1)
-{
-    if(ui->aircraftSearchComboBox->currentIndex() == 0){
-        ui->aircraftSearchLineEdit->setText(arg1.toUpper());
-    }
-    model->setFilter(ui->aircraftSearchComboBox->currentText()
-                     + QStringLiteral(" LIKE \"%")
-                     + arg1 + QStringLiteral("%\""));
-}
-
-void AircraftWidget::onDisplayModel_dataBaseUpdated()
-{
-    //refresh view to reflect changes the user has made via a dialog.
-    model->select();
-}
-
-void AircraftWidget::tableView_selectionChanged()
-{
-    if (this->findChild<NewTailDialog*>() != nullptr) {
-        delete this->findChild<NewTailDialog*>();
-        /// [F] if the user changes the selection without making any changes,
-        /// if(selectedTails.length() == 1) spawns a new dialog without the
-        /// old one being deleted, since neither accept() nor reject() was emitted.
-        /// Is this a reasonable way of avoiding pollution? Creating the widgets on the
-        /// stack does not seem to solve the problem since the Dialog does not get destroyed
-        /// until either accept() or reject() is emitted so I went for this solution.
-    }
-    selectedTails.clear();
-
-    for (const auto& row : selection->selectedRows()) {
-        selectedTails << row.data().toInt();
-        DEB << "Selected Tails(s) with ID: " << selectedTails;
-    }
-    if(selectedTails.length() == 1) {
-        auto* nt = new NewTailDialog(selectedTails.first(), this);
-        QObject::connect(nt,   &QDialog::accepted,
-                         this, &AircraftWidget::acft_editing_finished);
-        QObject::connect(nt,   &QDialog::rejected,
-                         this, &AircraftWidget::acft_editing_finished);
-        ui->stackedWidget->addWidget(nt);
-        ui->stackedWidget->setCurrentWidget(nt);
-        nt->setWindowFlag(Qt::Widget);
-        nt->setAttribute(Qt::WA_DeleteOnClose);
-        nt->exec();
-    }
-}
-
-void AircraftWidget::tableView_headerClicked(int column)
-{
-    sortColumn = column;
-    ASettings::write(ASettings::UserData::TailSortColumn, column);
-}
-
-void AircraftWidget::acft_editing_finished()
-{
-    model->select();
-}

+ 33 - 5
src/gui/widgets/aircraftwidget.h

@@ -21,14 +21,30 @@
 #include <QWidget>
 #include <QItemSelection>
 #include <QSqlTableModel>
-#include <QDebug>
 #include <QTableView>
+#include "src/gui/widgets/settingswidget.h"
 
 
 namespace Ui {
 class AircraftWidget;
 }
-
+/*!
+ * \class AircraftWidget
+ * \brief The AircraftWidget is used to view, edit, delete or add new tails.
+ * \abstract The widget consists of two main parts, a *QTableView* on the left side and a *QStackedWidget* on the right side.
+ *
+ * In the QTableView, a QSqlTableModel is used to access a view from the database, which holds a tails' Registration, Type and
+ * Company.
+ *
+ * The welcome page shown on the QStackedWidget on the right side has a QLineEdit that functions as a search box and a QCombobox
+ * holding the possible columns that can be used to filter what is displayed. The text of the QLineEdit is used as a filter for the
+ * QSqlTableModel, so the view is updated in real time.
+ *
+ * The *NewTailDialog* is used for creating a new entry as well as for editing an existing entry. If the user selects a row
+ * in the QTableView, the NewTailDilog is displayed on the right side of the Widget, inside the QStackedWidget.
+ * In order to avoid leaks from any previously made selections, existing Dialogs are deleted before a new one is created.
+ * The NewTailDialog's `accepted` and `rejected` signals are connected to refresh the view as required.
+ */
 class AircraftWidget : public QWidget
 {
     Q_OBJECT
@@ -42,16 +58,23 @@ private slots:
 
     void tableView_headerClicked(int column);
 
-    void on_deleteButton_clicked();
+    void on_deleteAircraftButton_clicked();
 
     void on_newAircraftButton_clicked();
 
-    void acft_editing_finished();
+    void onNewTailDialog_editingFinished();
 
     void on_aircraftSearchLineEdit_textChanged(const QString &arg1);
 
 public slots:
-    void onDisplayModel_dataBaseUpdated();
+    /*!
+     * \brief invokes setupModelAndView() to account for changes the user has made in the SettingsWidget
+     */
+    void onAircraftWidget_settingChanged(SettingsWidget::SettingSignal signal);
+    /*!
+     * \brief Refreshes the view if the Database has been altered from outside the AircraftWidget
+     */
+    void onAircraftWidget_dataBaseUpdated();
 
 private:
     Ui::AircraftWidget *ui;
@@ -64,11 +87,16 @@ private:
 
     qint32 sortColumn;
 
+    /*!
+     * \brief selectedTails Holds a list of the entries the user has selected
+     */
     QVector<qint32> selectedTails;
 
     void setupModelAndView();
 
     void onDeleteUnsuccessful();
+
+    inline void refreshView(){model->select();}
 };
 
 #endif // AIRCRAFTWIDGET_H

+ 169 - 132
src/gui/widgets/aircraftwidget.ui

@@ -6,151 +6,181 @@
    <rect>
     <x>0</x>
     <y>0</y>
-    <width>1920</width>
-    <height>1080</height>
+    <width>1318</width>
+    <height>706</height>
    </rect>
   </property>
   <property name="windowTitle">
    <string>Form</string>
   </property>
-  <layout class="QGridLayout" name="gridLayout">
+  <layout class="QGridLayout" name="gridLayout_2">
    <item row="0" column="0">
     <widget class="QTableView" name="tableView">
-     <property name="sizePolicy">
-      <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
-       <horstretch>0</horstretch>
-       <verstretch>0</verstretch>
-      </sizepolicy>
+     <property name="minimumSize">
+      <size>
+       <width>0</width>
+       <height>0</height>
+      </size>
      </property>
     </widget>
    </item>
-   <item row="2" column="0">
-    <widget class="QPushButton" name="deleteButton">
-     <property name="text">
-      <string>Delete Aircraft</string>
-     </property>
-    </widget>
-   </item>
-   <item row="0" column="1">
-    <layout class="QHBoxLayout" name="horizontalLayout">
-     <item>
-      <spacer name="horizontalSpacer">
-       <property name="orientation">
-        <enum>Qt::Horizontal</enum>
-       </property>
-       <property name="sizeHint" stdset="0">
-        <size>
-         <width>40</width>
-         <height>20</height>
-        </size>
-       </property>
-      </spacer>
-     </item>
-     <item>
-      <widget class="QStackedWidget" name="stackedWidget">
-       <property name="currentIndex">
-        <number>0</number>
-       </property>
-       <widget class="QWidget" name="welcomePageTails">
-        <layout class="QGridLayout" name="gridLayout_2">
-         <item row="0" column="1">
-          <spacer name="verticalSpacer">
-           <property name="orientation">
-            <enum>Qt::Vertical</enum>
-           </property>
-           <property name="sizeHint" stdset="0">
-            <size>
-             <width>20</width>
-             <height>436</height>
-            </size>
-           </property>
-          </spacer>
-         </item>
-         <item row="1" column="0">
-          <layout class="QFormLayout" name="formLayout">
-           <item row="0" column="0">
-            <widget class="QLabel" name="searchLabel">
-             <property name="text">
-              <string>Search:</string>
-             </property>
-            </widget>
-           </item>
-           <item row="0" column="1">
-            <widget class="QLineEdit" name="aircraftSearchLineEdit"/>
-           </item>
-           <item row="1" column="0">
-            <widget class="QLabel" name="label_2">
-             <property name="text">
-              <string>Search in:</string>
-             </property>
-            </widget>
-           </item>
-           <item row="1" column="1">
-            <widget class="QComboBox" name="aircraftSearchComboBox">
-             <item>
-              <property name="text">
-               <string>Registration</string>
-              </property>
-             </item>
-             <item>
-              <property name="text">
-               <string>Type</string>
-              </property>
-             </item>
-             <item>
-              <property name="text">
-               <string>Company</string>
-              </property>
-             </item>
-            </widget>
-           </item>
-          </layout>
-         </item>
-         <item row="2" column="0">
-          <widget class="QLabel" name="spacerLabel">
-           <property name="text">
-            <string/>
-           </property>
-          </widget>
+   <item row="0" column="1" rowspan="3">
+    <widget class="QStackedWidget" name="stackedWidget">
+     <widget class="QWidget" name="welcomePageTails">
+      <layout class="QGridLayout" name="gridLayout">
+       <item row="1" column="1">
+        <widget class="QLabel" name="searchLabel">
+         <property name="minimumSize">
+          <size>
+           <width>0</width>
+           <height>0</height>
+          </size>
+         </property>
+         <property name="text">
+          <string>Search:</string>
+         </property>
+        </widget>
+       </item>
+       <item row="1" column="2">
+        <widget class="QLineEdit" name="aircraftSearchLineEdit">
+         <property name="minimumSize">
+          <size>
+           <width>0</width>
+           <height>0</height>
+          </size>
+         </property>
+        </widget>
+       </item>
+       <item row="2" column="1">
+        <widget class="QLabel" name="label_2">
+         <property name="minimumSize">
+          <size>
+           <width>0</width>
+           <height>0</height>
+          </size>
+         </property>
+         <property name="text">
+          <string>Search in:</string>
+         </property>
+        </widget>
+       </item>
+       <item row="2" column="2">
+        <widget class="QComboBox" name="aircraftSearchComboBox">
+         <property name="minimumSize">
+          <size>
+           <width>0</width>
+           <height>0</height>
+          </size>
+         </property>
+         <item>
+          <property name="text">
+           <string>Registration</string>
+          </property>
          </item>
-         <item row="3" column="0" colspan="2">
-          <widget class="QLabel" name="welcomeLabel">
-           <property name="text">
-            <string>Select an Aircraft from the List to show or edit details.</string>
-           </property>
-          </widget>
+         <item>
+          <property name="text">
+           <string>Type</string>
+          </property>
          </item>
-         <item row="4" column="1">
-          <spacer name="verticalSpacer_2">
-           <property name="orientation">
-            <enum>Qt::Vertical</enum>
-           </property>
-           <property name="sizeHint" stdset="0">
-            <size>
-             <width>20</width>
-             <height>410</height>
-            </size>
-           </property>
-          </spacer>
+         <item>
+          <property name="text">
+           <string>Company</string>
+          </property>
          </item>
-        </layout>
-       </widget>
-      </widget>
-     </item>
-     <item>
-      <spacer name="horizontalSpacer_2">
-       <property name="orientation">
-        <enum>Qt::Horizontal</enum>
-       </property>
-       <property name="sizeHint" stdset="0">
-        <size>
-         <width>40</width>
-         <height>20</height>
-        </size>
-       </property>
-      </spacer>
-     </item>
-    </layout>
+        </widget>
+       </item>
+       <item row="3" column="0">
+        <spacer name="horizontalSpacer">
+         <property name="minimumSize">
+          <size>
+           <width>0</width>
+           <height>0</height>
+          </size>
+         </property>
+         <property name="orientation">
+          <enum>Qt::Horizontal</enum>
+         </property>
+         <property name="sizeHint" stdset="0">
+          <size>
+           <width>130</width>
+           <height>20</height>
+          </size>
+         </property>
+        </spacer>
+       </item>
+       <item row="3" column="1" colspan="2">
+        <widget class="QLabel" name="welcomeLabel">
+         <property name="minimumSize">
+          <size>
+           <width>0</width>
+           <height>0</height>
+          </size>
+         </property>
+         <property name="text">
+          <string>Select an Aircraft from the List to show or edit details.</string>
+         </property>
+        </widget>
+       </item>
+       <item row="3" column="3">
+        <spacer name="horizontalSpacer_2">
+         <property name="minimumSize">
+          <size>
+           <width>0</width>
+           <height>0</height>
+          </size>
+         </property>
+         <property name="orientation">
+          <enum>Qt::Horizontal</enum>
+         </property>
+         <property name="sizeHint" stdset="0">
+          <size>
+           <width>129</width>
+           <height>20</height>
+          </size>
+         </property>
+        </spacer>
+       </item>
+       <item row="4" column="3">
+        <spacer name="verticalSpacer_2">
+         <property name="minimumSize">
+          <size>
+           <width>0</width>
+           <height>0</height>
+          </size>
+         </property>
+         <property name="orientation">
+          <enum>Qt::Vertical</enum>
+         </property>
+         <property name="sizeHint" stdset="0">
+          <size>
+           <width>20</width>
+           <height>286</height>
+          </size>
+         </property>
+        </spacer>
+       </item>
+       <item row="0" column="3">
+        <spacer name="verticalSpacer">
+         <property name="minimumSize">
+          <size>
+           <width>0</width>
+           <height>0</height>
+          </size>
+         </property>
+         <property name="orientation">
+          <enum>Qt::Vertical</enum>
+         </property>
+         <property name="sizeHint" stdset="0">
+          <size>
+           <width>20</width>
+           <height>287</height>
+          </size>
+         </property>
+        </spacer>
+       </item>
+      </layout>
+     </widget>
+    </widget>
    </item>
    <item row="1" column="0">
     <widget class="QPushButton" name="newAircraftButton">
@@ -159,6 +189,13 @@
      </property>
     </widget>
    </item>
+   <item row="2" column="0">
+    <widget class="QPushButton" name="deleteAircraftButton">
+     <property name="text">
+      <string>Delete Aircraft</string>
+     </property>
+    </widget>
+   </item>
   </layout>
  </widget>
  <resources/>

+ 3 - 1
src/gui/widgets/debugwidget.cpp

@@ -25,6 +25,7 @@
 #include <QtGlobal>
 #include "src/functions/atime.h"
 #include "src/functions/astat.h"
+#include "src/classes/acurrencyentry.h"
 
 DebugWidget::DebugWidget(QWidget *parent) :
     QWidget(parent),
@@ -185,7 +186,8 @@ void DebugWidget::on_importCsvPushButton_clicked()
 
 void DebugWidget::on_debugPushButton_clicked()
 {
-    DEB << "Expiration Date:" << AStat::currencyTakeOffLandingExpiry();
+
+    DEB << ASettings::read(ASettings::UserData::CurrWarningThreshold).toInt();
     // debug space
     //ASettings::write(ASettings::Setup::SetupComplete, false);
 }

+ 33 - 26
src/gui/widgets/homewidget.cpp

@@ -37,6 +37,7 @@ HomeWidget::HomeWidget(QWidget *parent) :
     ui->setupUi(this);
     today = QDate::currentDate();
     currWarningThreshold = ASettings::read(ASettings::UserData::CurrWarningThreshold).toInt();
+    DEB << "Current Warning Threshold:"<< currWarningThreshold;
     ftlWarningThreshold = ASettings::read(ASettings::UserData::FtlWarningThreshold).toDouble();
     auto logo = QPixmap(Opl::Assets::LOGO);
     ui->logoLabel->setPixmap(logo);
@@ -51,7 +52,7 @@ HomeWidget::HomeWidget(QWidget *parent) :
 
     DEB << "Filling Home Widget...";
     fillTotals();
-    fillCurrencies();
+    fillAllCurrencies();
     fillLimitations();
 }
 
@@ -60,13 +61,17 @@ HomeWidget::~HomeWidget()
     delete ui;
 }
 
-void HomeWidget::onHomeWidget_dataBaseUpdated()
+void HomeWidget::refresh()
 {
+    DEB << "Updating HomeWidget...";
+    for (const auto label : this->findChildren<QLabel *>())
+        label->setVisible(true);
+    currWarningThreshold = ASettings::read(ASettings::UserData::CurrWarningThreshold).toInt();
     for (const auto &label : limitationDisplayLabels)
         label->setStyleSheet(QString());
 
     fillTotals();
-    fillCurrencyTakeOffLanding();
+    fillAllCurrencies();
     fillLimitations();
 }
 
@@ -79,51 +84,53 @@ void HomeWidget::fillTotals()
     }
 }
 
-void HomeWidget::fillCurrency(ASettings::UserData date, QLabel* display_label)
+void HomeWidget::fillCurrency(ACurrencyEntry::CurrencyName currency_name, QLabel* display_label)
 {
-    auto currency_date = ASettings::read(date).toDate();
-
-    if (!currency_date.isValid())
-        return;
-
-    display_label->setText(currency_date.toString(Qt::TextDate));
-    if (today.addDays(currWarningThreshold) >= currency_date) { // expires less than 30 days from today
-        setLabelColour(display_label, Colour::Orange);
-    }
-    if (today >= currency_date) { // is expired
-        setLabelColour(display_label, Colour::Red);
+    auto currency_entry = aDB->getCurrencyEntry(currency_name);
+    if (currency_entry.isValid()) {
+        auto currency_date = QDate::fromString(currency_entry.tableData.value(
+                                               Opl::Db::CURRENCIES_EXPIRYDATE).toString(),
+                                               Qt::ISODate);
+        display_label->setText(currency_date.toString(Qt::TextDate));
+        setLabelColour(display_label, Colour::None);
+
+        if (today.addDays(currWarningThreshold) >= currency_date) { // expires less than 30 days from today
+            setLabelColour(display_label, Colour::Orange);
+        }
+        if (today >= currency_date) { // is expired
+            setLabelColour(display_label, Colour::Red);
+        }
+    } else {
+        display_label->setText(tr("Invalid Date"));
     }
 }
 
-void HomeWidget::fillCurrencies()
+void HomeWidget::fillAllCurrencies()
 {
     fillCurrencyTakeOffLanding();
+    DEB << "Show med currency?" << ASettings::read(ASettings::UserData::ShowMedCurrency).toBool();
 
     ASettings::read(ASettings::UserData::ShowLicCurrency).toBool() ?
-                fillCurrency(ASettings::UserData::ShowLicCurrency, ui->currLicDisplayLabel)
+                fillCurrency(ACurrencyEntry::CurrencyName::Licence, ui->currLicDisplayLabel)
               : hideLabels(ui->currLicLabel, ui->currLicDisplayLabel);
-
     ASettings::read(ASettings::UserData::ShowTrCurrency).toBool() ?
-                fillCurrency(ASettings::UserData::TrCurrencyDate, ui->currTrDisplayLabel)
+                fillCurrency(ACurrencyEntry::CurrencyName::TypeRating, ui->currTrDisplayLabel)
               : hideLabels(ui->currTrLabel, ui->currTrDisplayLabel);
-
     ASettings::read(ASettings::UserData::ShowLckCurrency).toBool() ?
-                fillCurrency(ASettings::UserData::LckCurrencyDate, ui->currLckDisplayLabel)
+                fillCurrency(ACurrencyEntry::CurrencyName::LineCheck, ui->currLckDisplayLabel)
               : hideLabels(ui->currLckLabel, ui->currLckDisplayLabel);
-
     ASettings::read(ASettings::UserData::ShowMedCurrency).toBool() ?
-                fillCurrency(ASettings::UserData::MedCurrencyDate, ui->currMedDisplayLabel)
+                fillCurrency(ACurrencyEntry::CurrencyName::Medical, ui->currMedDisplayLabel)
               : hideLabels(ui->currMedLabel, ui->currMedDisplayLabel);
 
     ASettings::read(ASettings::UserData::ShowCustom1Currency).toBool() ?
-                fillCurrency(ASettings::UserData::Custom1CurrencyDate, ui->currCustom1DisplayLabel)
+                fillCurrency(ACurrencyEntry::CurrencyName::Custom1, ui->currCustom1DisplayLabel)
               : hideLabels(ui->currCustom1Label, ui->currCustom1DisplayLabel);
     const QString custom1_text = ASettings::read(ASettings::UserData::Custom1CurrencyName).toString();
     if (!custom1_text.isEmpty())
         ui->currCustom1Label->setText(custom1_text);
-
     ASettings::read(ASettings::UserData::ShowCustom2Currency).toBool() ?
-                fillCurrency(ASettings::UserData::Custom2CurrencyDate, ui->currCustom2DisplayLabel)
+                fillCurrency(ACurrencyEntry::CurrencyName::Custom2, ui->currCustom2DisplayLabel)
               : hideLabels(ui->currCustom2Label, ui->currCustom2DisplayLabel);
     const QString custom2_text = ASettings::read(ASettings::UserData::Custom2CurrencyName).toString();
     if (!custom2_text.isEmpty())

+ 17 - 16
src/gui/widgets/homewidget.h

@@ -26,6 +26,7 @@
 #include "src/functions/astat.h"
 #include "src/database/adatabase.h"
 #include "src/classes/asettings.h"
+#include "src/classes/acurrencyentry.h"
 
 namespace Ui {
 class HomeWidget;
@@ -42,28 +43,24 @@ public:
 private:
     Ui::HomeWidget *ui;
 
-    QDate today;
-    int currWarningThreshold;
-    double ftlWarningThreshold;
+    QList<QLabel*> limitationDisplayLabels;
+    QDate          today;
+    int            currWarningThreshold;
+    double         ftlWarningThreshold;
 
     void fillTotals();
-    void fillCurrencies();
+    void fillAllCurrencies();
     void fillCurrencyTakeOffLanding();
+    void fillCurrency(ACurrencyEntry::CurrencyName currency_name, QLabel *display_label);
     void fillLimitations();
 
-
-
-    QList<QLabel*> limitationDisplayLabels;
-    /*!
-     * \brief Retreives the users first name from the database.
-     */
-    const QString userName();
-
-    enum class Colour {Red, Orange};
-
+    enum class Colour {Red, Orange, None};
     inline void setLabelColour(QLabel* label, Colour colour)
     {
         switch (colour) {
+        case Colour::None:
+            label->setStyleSheet(QString());
+            break;
         case Colour::Red:
             label->setStyleSheet(QStringLiteral("color: red"));
             break;
@@ -80,9 +77,13 @@ private:
         label1->hide();
         label2->hide();
     }
-    void fillCurrency(ASettings::UserData date, QLabel *display_label);
+
+    /*!
+     * \brief Retreives the users first name from the database.
+     */
+    const QString userName();
 public slots:
-    void onHomeWidget_dataBaseUpdated();
+    void refresh();
 };
 
 #endif // HOMEWIDGET_H

+ 7 - 6
src/gui/widgets/logbookwidget.cpp

@@ -52,7 +52,7 @@ LogbookWidget::LogbookWidget(QWidget *parent) :
     displayModel = new QSqlTableModel(this);
     view = ui->tableView;
 
-    prepareModelAndView(ASettings::read(ASettings::Main::LogbookView).toInt());
+    setupModelAndView(ASettings::read(ASettings::Main::LogbookView).toInt());
     connectSignalsAndSlots();
 
 }
@@ -66,7 +66,7 @@ LogbookWidget::~LogbookWidget()
  * Functions
  */
 
-void LogbookWidget::prepareModelAndView(int view_id)
+void LogbookWidget::setupModelAndView(int view_id)
 {
     switch (view_id) {
     case 0:
@@ -75,7 +75,7 @@ void LogbookWidget::prepareModelAndView(int view_id)
         displayModel->select();
         break;
     case 1:
-        LOG << "Loading Default View...\n";
+        LOG << "Loading EASA View...\n";
         displayModel->setTable(QStringLiteral("viewEASA"));
         displayModel->select();
         break;
@@ -243,16 +243,17 @@ void LogbookWidget::on_flightSearchComboBox_currentIndexChanged(int)
     emit ui->showAllButton->clicked();
 }
 
-void LogbookWidget::onDisplayModel_dataBaseUpdated()
+void LogbookWidget::refresh()
 {
     //refresh view to reflect changes the user has made via a dialog.
     displayModel->select();
     view->resizeColumnsToContents();
 }
 
-void LogbookWidget::onLogbookWidget_viewSelectionChanged(int view_id)
+void LogbookWidget::onLogbookWidget_viewSelectionChanged(SettingsWidget::SettingSignal signal)
 {
-    prepareModelAndView(view_id);
+    if (signal == SettingsWidget::SettingSignal::LogbookWidget)
+        setupModelAndView(ASettings::read(ASettings::Main::LogbookView).toInt());
 }
 
 void LogbookWidget::on_showAllButton_clicked()

+ 4 - 3
src/gui/widgets/logbookwidget.h

@@ -25,6 +25,7 @@
 #include <QDebug>
 #include <QMenu>
 #include <QTableView>
+#include "src/gui/widgets/settingswidget.h"
 
 namespace Ui {
 class LogbookWidget;
@@ -52,8 +53,8 @@ private slots:
     void on_flightSearchComboBox_currentIndexChanged(int);
 
 public slots:
-    void onDisplayModel_dataBaseUpdated();
-    void onLogbookWidget_viewSelectionChanged(int);
+    void refresh();
+    void onLogbookWidget_viewSelectionChanged(SettingsWidget::SettingSignal signal);
 
 private:
     Ui::LogbookWidget *ui;
@@ -70,7 +71,7 @@ private:
 
     QVector<qint32> selectedFlights;
 
-    void prepareModelAndView(int view_id);
+    void setupModelAndView(int view_id);
     void connectSignalsAndSlots();
 };
 

+ 46 - 36
src/gui/widgets/pilotswidget.cpp

@@ -27,6 +27,9 @@ PilotsWidget::PilotsWidget(QWidget *parent) :
 {
     ui->setupUi(this);
 
+    ui->tableView->setMinimumWidth(this->width()/2);
+    ui->stackedWidget->setMinimumWidth(this->width()/2);
+
     setupModelAndView();
 }
 
@@ -37,59 +40,64 @@ PilotsWidget::~PilotsWidget()
 
 void PilotsWidget::setupModelAndView()
 {
-    sortColumn = ASettings::read(ASettings::UserData::PilotSortColumn).toInt();
-
     model = new QSqlTableModel(this);
     model->setTable(QStringLiteral("viewPilots"));
     model->setFilter(QStringLiteral("ID > 1")); // Don't show self
     model->select();
 
-    view = ui->pilotsTableView;
+    view = ui->tableView;
     view->setModel(model);
     view->setSelectionBehavior(QAbstractItemView::SelectRows);
     view->setSelectionMode(QAbstractItemView::SingleSelection);
     view->setEditTriggers(QAbstractItemView::NoEditTriggers);
     view->horizontalHeader()->setStretchLastSection(QHeaderView::Stretch);
     view->hideColumn(0);
-    view->setColumnWidth(1, 180);
-    view->setColumnWidth(2, 180);
+    view->resizeColumnsToContents();
     view->verticalHeader()->hide();
     view->setAlternatingRowColors(true);
     view->setSortingEnabled(true);
+    sortColumn = ASettings::read(ASettings::UserData::PilotSortColumn).toInt();
     view->sortByColumn(sortColumn, Qt::AscendingOrder);
 
     view->show();
     selectionModel = view->selectionModel();
 
-    QObject::connect(ui->pilotsTableView->selectionModel(), &QItemSelectionModel::selectionChanged,
-                     this, &PilotsWidget::tableView_selectionChanged);
-    QObject::connect(ui->pilotsTableView->horizontalHeader(), &QHeaderView::sectionClicked,
-                     this, &PilotsWidget::tableView_headerClicked);
+    QObject::connect(ui->tableView->selectionModel(),   &QItemSelectionModel::selectionChanged,
+                     this,                                    &PilotsWidget::tableView_selectionChanged);
+    QObject::connect(ui->tableView->horizontalHeader(), &QHeaderView::sectionClicked,
+                     this,                                    &PilotsWidget::tableView_headerClicked);
 }
 
-void PilotsWidget::on_pilotSearchLineEdit_textChanged(const QString &arg1)
+void PilotsWidget::onPilotsWidget_settingChanged(SettingsWidget::SettingSignal signal)
 {
-    model->setFilter("\"" + ui->pilotsSearchComboBox->currentText() + "\" LIKE \"%" + arg1 + "%\" AND ID > 1");
+    if (signal == SettingsWidget::PilotsWidget)
+        setupModelAndView();
 }
 
-void PilotsWidget::onDisplayModel_dataBaseUpdated()
+void PilotsWidget::onPilotsWidget_databaseUpdated()
 {
-    //refresh view to reflect changes the user has made via a dialog.
-    model->select();
+    refreshView();
+}
+
+void PilotsWidget::onNewPilotDialog_editingFinished()
+{
+    refreshView();
+}
+
+void PilotsWidget::on_pilotSearchLineEdit_textChanged(const QString &arg1)
+{
+    model->setFilter(QLatin1Char('\"') + ui->pilotsSearchComboBox->currentText()
+                     + QLatin1String("\" LIKE '%") + arg1
+                     + QLatin1String("%' AND ID > 1"));
 }
 
-void PilotsWidget::tableView_selectionChanged()//const QItemSelection &index, const QItemSelection &
+void PilotsWidget::tableView_selectionChanged()
 {
     if (this->findChild<NewPilotDialog*>() != nullptr) {
         delete this->findChild<NewPilotDialog*>();
-        /// [F] if the user changes the selection without making any changes,
-        /// if(selectedPilots.length() == 1) spawns a new dialog without the
-        /// old one being deleted, since neither accept() nor reject() was emitted.
-        /// Is this a reasonable way of avoiding pollution? Creating the widgets on the
-        /// stack does not seem to solve the problem since the Dialog does not get deleted
-        /// until either accept() or reject() is emitted so I went for this solution.
     }
-    auto *selection = ui->pilotsTableView->selectionModel();
+
+    auto *selection = ui->tableView->selectionModel();
     selectedPilots.clear();
 
     for (const auto& row : selection->selectedRows()) {
@@ -99,10 +107,10 @@ void PilotsWidget::tableView_selectionChanged()//const QItemSelection &index, co
     if(selectedPilots.length() == 1) {
 
         NewPilotDialog* np = new NewPilotDialog(selectedPilots.first(), this);
-        QObject::connect(np, &QDialog::accepted,
-                         this, &PilotsWidget::pilot_editing_finished);
-        QObject::connect(np, &QDialog::rejected,
-                         this, &PilotsWidget::pilot_editing_finished);
+        QObject::connect(np,   &QDialog::accepted,
+                         this, &PilotsWidget::onNewPilotDialog_editingFinished);
+        QObject::connect(np,   &QDialog::rejected,
+                         this, &PilotsWidget::onNewPilotDialog_editingFinished);
         np->setWindowFlag(Qt::Widget);
         np->setAttribute(Qt::WA_DeleteOnClose);
         ui->stackedWidget->addWidget(np);
@@ -121,9 +129,9 @@ void PilotsWidget::on_newPilotButton_clicked()
 {
     NewPilotDialog* np = new NewPilotDialog(this);
     QObject::connect(np,   &QDialog::accepted,
-                     this, &PilotsWidget::pilot_editing_finished);
+                     this, &PilotsWidget::onNewPilotDialog_editingFinished);
     QObject::connect(np,   &QDialog::rejected,
-                     this, &PilotsWidget::pilot_editing_finished);
+                     this, &PilotsWidget::onNewPilotDialog_editingFinished);
     np->setAttribute(Qt::WA_DeleteOnClose);
     np->exec();
 }
@@ -163,13 +171,20 @@ void PilotsWidget::on_deletePilotButton_clicked()
                 onDeleteUnsuccessful();
         }
     }
-    model->select();
+    refreshView();
 }
 
+/*!
+ * \brief Informs the user that deleting a database entry has been unsuccessful
+ *
+ * \abstract Normally, when one of these entries can not be deleted, it is because of
+ * a [foreign key constraint](https://sqlite.org/foreignkeys.html), meaning that a flight
+ * is associated with the Pilot that was supposed to be deleted as Pilot-in-command.
+ *
+ * This function is used to inform the user and give hints on how to solve the problem.
+ */
 void PilotsWidget::onDeleteUnsuccessful()
 {
-    /// [F]: To do: Some logic to display a warning if too many entries exists, so that
-    /// the messagebox doesn't grow too tall.
     QList<int> foreign_key_constraints = aDB->getForeignKeyConstraints(selectedPilots.first(),
                                                                        ADatabaseTarget::pilots);
     QList<AFlightEntry> constrained_flights;
@@ -205,8 +220,3 @@ void PilotsWidget::onDeleteUnsuccessful()
         message_box.exec();
     }
 }
-
-void PilotsWidget::pilot_editing_finished()
-{
-    model->select();
-}

+ 33 - 4
src/gui/widgets/pilotswidget.h

@@ -21,15 +21,35 @@
 #include <QWidget>
 #include <QItemSelection>
 #include <QSqlTableModel>
-#include <QDebug>
 #include <QTableView>
 #include "src/classes/asettings.h"
 #include "src/gui/dialogues/newpilotdialog.h"
+#include "src/gui/widgets/settingswidget.h"
 
 namespace Ui {
 class PilotsWidget;
 }
-
+/*!
+ * \class PilotsWidget
+ * \brief The PilotsWidget is used to view, edit, delete or add new pilots.
+ * \abstract The widget consists of two main parts, a *QTableView* on the left side and a *QStackedWidget* on the right side.
+ *
+ * In the QTableView, a QSqlTableModel is used to access a view from the database, which holds a Pilots' Last Name,
+ * First name and Company.
+ *
+ * The welcome page shown on the QStackedWidget on the right side has a QLineEdit that functions as a search box and a QCombobox
+ * holding the possible columns that can be used to filter what is displayed. The text of the QLineEdit is used as a filter for the
+ * QSqlTableModel, so the view is updated in real time.
+ *
+ * The *NewPilotDialog* is used for creating a new entry as well as for editing an existing entry. If the user selects a row
+ * in the QTableView, the NewPilotDialog is displayed on the right side of the Widget, inside the QStackedWidget.
+ * In order to avoid leaks from any previously made selections, existing Dialogs are deleted before a new one is created.
+ * The NewPilotDialog's `accepted` and `rejected` signals are connected to refresh the view as required.
+ *
+ * The logbook owner is not shown in the QTableView as an editable Pilot since `self` is a special reserved alias for the
+ * pilot with ROWID #1 as a way to identify and adequately display the logbook owner in the logbook. Editing personal details
+ * is done via the *SettingsWidget*
+ */
 class PilotsWidget : public QWidget
 {
     Q_OBJECT
@@ -44,11 +64,18 @@ private slots:
     void on_newPilotButton_clicked();
     void on_deletePilotButton_clicked();
     void onDeleteUnsuccessful();
-    void pilot_editing_finished();
+    void onNewPilotDialog_editingFinished();
     void on_pilotSearchLineEdit_textChanged(const QString &arg1);
 
 public slots:
-    void onDisplayModel_dataBaseUpdated();
+    /*!
+     * \brief invokes setupModelAndView() to account for changes the user has made in the SettingsWidget
+     */
+    void onPilotsWidget_settingChanged(SettingsWidget::SettingSignal signal);
+    /*!
+     * \brief Refreshes the view if the Database has been altered from outside the AircraftWidget
+     */
+    void onPilotsWidget_databaseUpdated();
 
 private:
     Ui::PilotsWidget *ui;
@@ -64,6 +91,8 @@ private:
     QVector<qint32> selectedPilots;
 
     void setupModelAndView();
+
+    inline void refreshView(){model->select();}
 };
 
 #endif // PILOTSWIDGET_H

+ 184 - 118
src/gui/widgets/pilotswidget.ui

@@ -13,130 +13,196 @@
   <property name="windowTitle">
    <string>Form</string>
   </property>
-  <layout class="QGridLayout" name="gridLayout">
+  <layout class="QGridLayout" name="gridLayout_2">
    <item row="0" column="0">
-    <widget class="QTableView" name="pilotsTableView"/>
+    <widget class="QTableView" name="tableView">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
+     <property name="minimumSize">
+      <size>
+       <width>0</width>
+       <height>0</height>
+      </size>
+     </property>
+    </widget>
    </item>
    <item row="0" column="1" rowspan="3">
-    <layout class="QHBoxLayout" name="horizontalLayout">
-     <item>
-      <spacer name="horizontalSpacer">
-       <property name="orientation">
-        <enum>Qt::Horizontal</enum>
-       </property>
-       <property name="sizeHint" stdset="0">
-        <size>
-         <width>40</width>
-         <height>20</height>
-        </size>
-       </property>
-      </spacer>
-     </item>
-     <item>
-      <widget class="QStackedWidget" name="stackedWidget">
-       <property name="currentIndex">
-        <number>0</number>
-       </property>
-       <widget class="QWidget" name="welcomePage">
-        <layout class="QGridLayout" name="gridLayout_3">
-         <item row="0" column="0">
-          <spacer name="verticalSpacer">
-           <property name="orientation">
-            <enum>Qt::Vertical</enum>
-           </property>
-           <property name="sizeHint" stdset="0">
-            <size>
-             <width>20</width>
-             <height>424</height>
-            </size>
-           </property>
-          </spacer>
+    <widget class="QStackedWidget" name="stackedWidget">
+     <property name="currentIndex">
+      <number>0</number>
+     </property>
+     <widget class="QWidget" name="welcomePage">
+      <layout class="QGridLayout" name="gridLayout">
+       <item row="0" column="3">
+        <spacer name="verticalSpacer">
+         <property name="minimumSize">
+          <size>
+           <width>0</width>
+           <height>0</height>
+          </size>
+         </property>
+         <property name="orientation">
+          <enum>Qt::Vertical</enum>
+         </property>
+         <property name="sizeHint" stdset="0">
+          <size>
+           <width>20</width>
+           <height>292</height>
+          </size>
+         </property>
+        </spacer>
+       </item>
+       <item row="1" column="1">
+        <widget class="QLabel" name="searchLabel">
+         <property name="minimumSize">
+          <size>
+           <width>0</width>
+           <height>0</height>
+          </size>
+         </property>
+         <property name="text">
+          <string>Search:</string>
+         </property>
+        </widget>
+       </item>
+       <item row="1" column="2">
+        <widget class="QLineEdit" name="pilotSearchLineEdit">
+         <property name="minimumSize">
+          <size>
+           <width>0</width>
+           <height>0</height>
+          </size>
+         </property>
+        </widget>
+       </item>
+       <item row="2" column="0">
+        <widget class="QLabel" name="spacerLabel">
+         <property name="minimumSize">
+          <size>
+           <width>0</width>
+           <height>0</height>
+          </size>
+         </property>
+         <property name="text">
+          <string/>
+         </property>
+        </widget>
+       </item>
+       <item row="2" column="1">
+        <widget class="QLabel" name="searchInLabel">
+         <property name="minimumSize">
+          <size>
+           <width>0</width>
+           <height>0</height>
+          </size>
+         </property>
+         <property name="text">
+          <string>Search in:</string>
+         </property>
+        </widget>
+       </item>
+       <item row="2" column="2">
+        <widget class="QComboBox" name="pilotsSearchComboBox">
+         <property name="minimumSize">
+          <size>
+           <width>0</width>
+           <height>0</height>
+          </size>
+         </property>
+         <item>
+          <property name="text">
+           <string>Last Name</string>
+          </property>
          </item>
-         <item row="1" column="0">
-          <layout class="QGridLayout" name="pilotsDiasogGridLayout">
-           <item row="0" column="0">
-            <widget class="QLabel" name="searchLabel">
-             <property name="text">
-              <string>Search:</string>
-             </property>
-            </widget>
-           </item>
-           <item row="0" column="1">
-            <widget class="QLineEdit" name="pilotSearchLineEdit"/>
-           </item>
-           <item row="1" column="0">
-            <widget class="QLabel" name="searchInLabel">
-             <property name="text">
-              <string>Search in:</string>
-             </property>
-            </widget>
-           </item>
-           <item row="1" column="1">
-            <widget class="QComboBox" name="pilotsSearchComboBox">
-             <item>
-              <property name="text">
-               <string>Last Name</string>
-              </property>
-             </item>
-             <item>
-              <property name="text">
-               <string>First Name</string>
-              </property>
-             </item>
-             <item>
-              <property name="text">
-               <string>Company</string>
-              </property>
-             </item>
-            </widget>
-           </item>
-           <item row="2" column="0" colspan="2">
-            <widget class="QLabel" name="spacerLabel">
-             <property name="text">
-              <string/>
-             </property>
-            </widget>
-           </item>
-           <item row="3" column="0" colspan="2">
-            <widget class="QLabel" name="welcomeLabel">
-             <property name="text">
-              <string>Select a Pilot from the List to show or edit details.</string>
-             </property>
-            </widget>
-           </item>
-          </layout>
+         <item>
+          <property name="text">
+           <string>First Name</string>
+          </property>
          </item>
-         <item row="2" column="0">
-          <spacer name="verticalSpacer_2">
-           <property name="orientation">
-            <enum>Qt::Vertical</enum>
-           </property>
-           <property name="sizeHint" stdset="0">
-            <size>
-             <width>20</width>
-             <height>423</height>
-            </size>
-           </property>
-          </spacer>
+         <item>
+          <property name="text">
+           <string>Company</string>
+          </property>
          </item>
-        </layout>
-       </widget>
-      </widget>
-     </item>
-     <item>
-      <spacer name="horizontalSpacer_2">
-       <property name="orientation">
-        <enum>Qt::Horizontal</enum>
-       </property>
-       <property name="sizeHint" stdset="0">
-        <size>
-         <width>40</width>
-         <height>20</height>
-        </size>
-       </property>
-      </spacer>
-     </item>
-    </layout>
+        </widget>
+       </item>
+       <item row="3" column="0">
+        <spacer name="horizontalSpacer">
+         <property name="minimumSize">
+          <size>
+           <width>0</width>
+           <height>0</height>
+          </size>
+         </property>
+         <property name="orientation">
+          <enum>Qt::Horizontal</enum>
+         </property>
+         <property name="sizeHint" stdset="0">
+          <size>
+           <width>134</width>
+           <height>20</height>
+          </size>
+         </property>
+        </spacer>
+       </item>
+       <item row="4" column="3">
+        <spacer name="verticalSpacer_2">
+         <property name="minimumSize">
+          <size>
+           <width>0</width>
+           <height>0</height>
+          </size>
+         </property>
+         <property name="orientation">
+          <enum>Qt::Vertical</enum>
+         </property>
+         <property name="sizeHint" stdset="0">
+          <size>
+           <width>20</width>
+           <height>292</height>
+          </size>
+         </property>
+        </spacer>
+       </item>
+       <item row="3" column="1" colspan="2">
+        <widget class="QLabel" name="welcomeLabel">
+         <property name="minimumSize">
+          <size>
+           <width>0</width>
+           <height>0</height>
+          </size>
+         </property>
+         <property name="text">
+          <string>Select a Pilot from the List to show or edit details.</string>
+         </property>
+        </widget>
+       </item>
+       <item row="3" column="3" colspan="2">
+        <spacer name="horizontalSpacer_2">
+         <property name="minimumSize">
+          <size>
+           <width>0</width>
+           <height>0</height>
+          </size>
+         </property>
+         <property name="orientation">
+          <enum>Qt::Horizontal</enum>
+         </property>
+         <property name="sizeHint" stdset="0">
+          <size>
+           <width>134</width>
+           <height>20</height>
+          </size>
+         </property>
+        </spacer>
+       </item>
+      </layout>
+     </widget>
+    </widget>
    </item>
    <item row="1" column="0">
     <widget class="QPushButton" name="newPilotButton">

+ 65 - 31
src/gui/widgets/settingswidget.cpp

@@ -51,7 +51,11 @@ SettingsWidget::SettingsWidget(QWidget *parent) :
     ui->setupUi(this);
     ui->tabWidget->setCurrentIndex(0);
 
+    ui->acAllowIncompleteComboBox->hide(); // [F]: Hidden for now, thinking of removing that option
+    ui->acAllowIncompleteLabel->hide();
+
     setupComboBoxes();
+    setupDateEdits();
     setupValidators();
     readSettings();
 }
@@ -81,6 +85,30 @@ void SettingsWidget::setupComboBoxes(){
     }
 }
 
+void SettingsWidget::setupDateEdits()
+{
+    const QList<QPair<ACurrencyEntry::CurrencyName, QDateEdit* >> currencies = {
+        {ACurrencyEntry::CurrencyName::Licence,     ui->currLicDateEdit},
+        {ACurrencyEntry::CurrencyName::TypeRating,  ui->currTrDateEdit},
+        {ACurrencyEntry::CurrencyName::LineCheck,   ui->currLckDateEdit},
+        {ACurrencyEntry::CurrencyName::Medical,     ui->currMedDateEdit},
+        {ACurrencyEntry::CurrencyName::Custom1,     ui->currCustom1DateEdit},
+        {ACurrencyEntry::CurrencyName::Custom2,     ui->currCustom2DateEdit}
+    };
+    for (const auto &pair : currencies) {
+        const QSignalBlocker signal_blocker(pair.second);
+        const auto entry = aDB->getCurrencyEntry(pair.first);
+        if (entry.isValid()) { // set date
+            const auto date = QDate::fromString(
+                        entry.tableData.value(Opl::Db::CURRENCIES_EXPIRYDATE).toString(),
+                        Qt::ISODate);
+            pair.second->setDate(date);
+        } else { // set current date
+            pair.second->setDate(QDate::currentDate());
+        }
+    }
+}
+
 void SettingsWidget::readSettings()
 {
     /*
@@ -112,35 +140,24 @@ void SettingsWidget::readSettings()
      * Currencies Tab
      */
     ui->currToLdgCheckBox->setChecked(ASettings::read(ASettings::UserData::ShowToLgdCurrency).toBool());
-
-    ui->currLicDateEdit->setDate(ASettings::read(ASettings::UserData::LicCurrencyDate).toDate());
     ui->currLicCheckBox->setChecked(ASettings::read(ASettings::UserData::ShowLicCurrency).toBool());
-
-    ui->currTrDateEdit->setDate(ASettings::read(ASettings::UserData::TrCurrencyDate).toDate());
     ui->currTrCheckBox->setChecked(ASettings::read(ASettings::UserData::ShowTrCurrency).toBool());
-
-    ui->currLckDateEdit->setDate(ASettings::read(ASettings::UserData::LckCurrencyDate).toDate());
     ui->currLckCheckBox->setChecked(ASettings::read(ASettings::UserData::ShowLckCurrency).toBool());
-
-    ui->currMedDateEdit->setDate(ASettings::read(ASettings::UserData::MedCurrencyDate).toDate());
     ui->currMedCheckBox->setChecked(ASettings::read(ASettings::UserData::ShowMedCurrency).toBool());
-
-    ui->currCustom1DateEdit->setDate(ASettings::read(ASettings::UserData::Custom1CurrencyDate).toDate());
     ui->currCustom1CheckBox->setChecked(ASettings::read(ASettings::UserData::ShowCustom1Currency).toBool());
-
-    ui->currCustom2DateEdit->setDate(ASettings::read(ASettings::UserData::Custom2CurrencyDate).toDate());
     ui->currCustom2CheckBox->setChecked(ASettings::read(ASettings::UserData::ShowCustom2Currency).toBool());
-
-    ui->currWarningCheckBox->setChecked(ASettings::read(ASettings::UserData::CurrWarningEnabled).toBool());
     ui->currWarningThresholdSpinBox->setValue(ASettings::read(ASettings::UserData::CurrWarningThreshold).toInt());
+    ui->currWarningCheckBox->setChecked(ASettings::read(ASettings::UserData::CurrWarningEnabled).toBool());
+    ui->currCustom1LineEdit->setText(ASettings::read(ASettings::UserData::Custom1CurrencyName).toString());
+    ui->currCustom2LineEdit->setText(ASettings::read(ASettings::UserData::Custom2CurrencyName).toString());
 
 
     /*
      * Misc Tab
      */
-    ui->acSortComboBox->setCurrentIndex(ASettings::read(ASettings::UserData::TailSortColumn).toInt());
+    ui->acftSortComboBox->setCurrentIndex(ASettings::read(ASettings::UserData::TailSortColumn).toInt());
     ui->pilotSortComboBox->setCurrentIndex(ASettings::read(ASettings::UserData::PilotSortColumn).toInt());
-    ui->acAllowIncompleteComboBox->setCurrentIndex(ASettings::read(ASettings::UserData::AcftAllowIncomplete).toInt());
+    //ui->acAllowIncompleteComboBox->setCurrentIndex(ASettings::read(ASettings::UserData::AcftAllowIncomplete).toInt());
     {
         // Block style widgets signals to not trigger style changes during UI setup
         const QSignalBlocker style_blocker(ui->styleComboBox);
@@ -300,18 +317,21 @@ void SettingsWidget::on_prefixLineEdit_textChanged(const QString &arg1)
 void SettingsWidget::on_logbookViewComboBox_currentIndexChanged(int index)
 {
     ASettings::write(ASettings::Main::LogbookView, index);
-    emit viewSelectionChanged(index);
+    emit settingChanged(SettingSignal::LogbookWidget);
 }
 void SettingsWidget::on_pilotSortComboBox_currentIndexChanged(int index)
 {
     ASettings::write(ASettings::UserData::PilotSortColumn, index);
+    emit settingChanged(PilotsWidget);
 }
 
-void SettingsWidget::on_acSortComboBox_currentIndexChanged(int index)
+void SettingsWidget::on_acftSortComboBox_currentIndexChanged(int index)
 {
     ASettings::write(ASettings::UserData::TailSortColumn, index);
+    emit settingChanged(AircraftWidget);
 }
 
+QT_DEPRECATED
 void SettingsWidget::on_acAllowIncompleteComboBox_currentIndexChanged(int index)
 {
     ASettings::write(ASettings::UserData::AcftAllowIncomplete, index);
@@ -480,32 +500,44 @@ void SettingsWidget::on_resetStylePushButton_clicked()
 
 void SettingsWidget::on_currLicDateEdit_userDateChanged(const QDate &date)
 {
-    ASettings::write(ASettings::UserData::LicCurrencyDate, date);
+    ACurrencyEntry entry(ACurrencyEntry::CurrencyName::Licence, date);
+    aDB->commit(entry);
+    emit settingChanged(HomeWidget);
 }
 
 void SettingsWidget::on_currTrDateEdit_userDateChanged(const QDate &date)
 {
-    ASettings::write(ASettings::UserData::TrCurrencyDate, date);
+    ACurrencyEntry entry(ACurrencyEntry::CurrencyName::TypeRating, date);
+    aDB->commit(entry);
+    emit settingChanged(HomeWidget);
 }
 
 void SettingsWidget::on_currLckDateEdit_userDateChanged(const QDate &date)
 {
-    ASettings::write(ASettings::UserData::LckCurrencyDate, date);
+    ACurrencyEntry entry(ACurrencyEntry::CurrencyName::LineCheck, date);
+    aDB->commit(entry);
+    emit settingChanged(HomeWidget);
 }
 
 void SettingsWidget::on_currMedDateEdit_userDateChanged(const QDate &date)
 {
-    ASettings::write(ASettings::UserData::MedCurrencyDate, date);
+    ACurrencyEntry entry(ACurrencyEntry::CurrencyName::Medical, date);
+    aDB->commit(entry);
+    emit settingChanged(HomeWidget);
 }
 
 void SettingsWidget::on_currCustom1DateEdit_userDateChanged(const QDate &date)
 {
-    ASettings::write(ASettings::UserData::Custom1CurrencyDate, date);
+    ACurrencyEntry entry(ACurrencyEntry::CurrencyName::Custom1, date);
+    aDB->commit(entry);
+    emit settingChanged(HomeWidget);
 }
 
 void SettingsWidget::on_currCustom2DateEdit_userDateChanged(const QDate &date)
 {
-    ASettings::write(ASettings::UserData::Custom2CurrencyDate, date);
+    ACurrencyEntry entry(ACurrencyEntry::CurrencyName::Custom2, date);
+    aDB->commit(entry);
+    emit settingChanged(HomeWidget);
 }
 
 void SettingsWidget::on_currToLdgCheckBox_stateChanged(int arg1)
@@ -520,6 +552,7 @@ void SettingsWidget::on_currToLdgCheckBox_stateChanged(int arg1)
     default:
         break;
     }
+    emit settingChanged(HomeWidget);
 }
 
 void SettingsWidget::on_currLicCheckBox_stateChanged(int arg1)
@@ -534,7 +567,7 @@ void SettingsWidget::on_currLicCheckBox_stateChanged(int arg1)
     default:
         break;
     }
-    ASettings::write(ASettings::UserData::LicCurrencyDate, ui->currLicDateEdit->date());
+    emit settingChanged(HomeWidget);
 }
 
 void SettingsWidget::on_currTrCheckBox_stateChanged(int arg1)
@@ -549,7 +582,7 @@ void SettingsWidget::on_currTrCheckBox_stateChanged(int arg1)
     default:
         break;
     }
-    ASettings::write(ASettings::UserData::TrCurrencyDate, ui->currTrDateEdit->date());
+    emit settingChanged(HomeWidget);
 }
 
 void SettingsWidget::on_currLckCheckBox_stateChanged(int arg1)
@@ -564,7 +597,7 @@ void SettingsWidget::on_currLckCheckBox_stateChanged(int arg1)
     default:
         break;
     }
-    ASettings::write(ASettings::UserData::LckCurrencyDate, ui->currLckDateEdit->date());
+    emit settingChanged(HomeWidget);
 }
 
 void SettingsWidget::on_currMedCheckBox_stateChanged(int arg1)
@@ -579,7 +612,7 @@ void SettingsWidget::on_currMedCheckBox_stateChanged(int arg1)
     default:
         break;
     }
-    ASettings::write(ASettings::UserData::MedCurrencyDate, ui->currMedDateEdit->date());
+    emit settingChanged(HomeWidget);
 }
 
 void SettingsWidget::on_currCustom1CheckBox_stateChanged(int arg1)
@@ -594,7 +627,7 @@ void SettingsWidget::on_currCustom1CheckBox_stateChanged(int arg1)
     default:
         break;
     }
-    ASettings::write(ASettings::UserData::Custom1CurrencyDate, ui->currCustom1DateEdit->date());
+    emit settingChanged(HomeWidget);
 }
 
 void SettingsWidget::on_currCustom2CheckBox_stateChanged(int arg1)
@@ -609,7 +642,7 @@ void SettingsWidget::on_currCustom2CheckBox_stateChanged(int arg1)
     default:
         break;
     }
-    ASettings::write(ASettings::UserData::Custom2CurrencyDate, ui->currCustom2DateEdit->date());
+    emit settingChanged(HomeWidget);
 }
 
 void SettingsWidget::on_currWarningCheckBox_stateChanged(int arg1)
@@ -624,12 +657,13 @@ void SettingsWidget::on_currWarningCheckBox_stateChanged(int arg1)
     default:
         break;
     }
-    ASettings::write(ASettings::UserData::CurrWarningThreshold, arg1);
+    emit settingChanged(HomeWidget);
 }
 
 void SettingsWidget::on_currWarningThresholdSpinBox_valueChanged(int arg1)
 {
     ASettings::write(ASettings::UserData::CurrWarningThreshold, arg1);
+    emit settingChanged(SettingSignal::HomeWidget);
 }
 
 void SettingsWidget::on_currCustom1LineEdit_editingFinished()

+ 14 - 2
src/gui/widgets/settingswidget.h

@@ -38,11 +38,16 @@ public:
     explicit SettingsWidget(QWidget *parent = nullptr);
     ~SettingsWidget();
 
+    /*!
+     * \brief Widgets that need to receive a signal when a setting is updated.
+     */
+    enum SettingSignal {LogbookWidget, HomeWidget, AircraftWidget, PilotsWidget};
+
 private slots:
 
 //    void onThemeGroup_buttonClicked(int theme_id);
     void on_aboutPushButton_clicked();
-    void on_acSortComboBox_currentIndexChanged(int index);
+    void on_acftSortComboBox_currentIndexChanged(int index);
     void on_acAllowIncompleteComboBox_currentIndexChanged(int index);
     void on_prefixLineEdit_textChanged(const QString &arg1);
     void on_lastnameLineEdit_editingFinished();
@@ -113,12 +118,19 @@ private:
 
     void setupComboBoxes();
 
+    void setupDateEdits();
+
     void updatePersonalDetails();
 
     bool usingStylesheet();
 
 signals:
-    void viewSelectionChanged(int view_id);
+
+    /*!
+     * \brief settingChanged is emitted when a setting change shall trigger
+     * an update to another widget.
+     */
+    void settingChanged(SettingSignal widget);
 };
 
 #endif // SETTINGSWIDGET_H

+ 3 - 3
src/gui/widgets/settingswidget.ui

@@ -17,7 +17,7 @@
    <item row="0" column="0">
     <widget class="QTabWidget" name="tabWidget">
      <property name="currentIndex">
-      <number>2</number>
+      <number>3</number>
      </property>
      <widget class="QWidget" name="personalTab">
       <attribute name="title">
@@ -998,7 +998,7 @@
         </widget>
        </item>
        <item row="3" column="0">
-        <widget class="QLabel" name="acSortLabel">
+        <widget class="QLabel" name="acftSortLabel">
          <property name="sizePolicy">
           <sizepolicy hsizetype="Minimum" vsizetype="Minimum">
            <horstretch>0</horstretch>
@@ -1017,7 +1017,7 @@
         </widget>
        </item>
        <item row="3" column="2">
-        <widget class="QComboBox" name="acSortComboBox">
+        <widget class="QComboBox" name="acftSortComboBox">
          <property name="toolTip">
           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Determines by which column to sort the display of Aircaft in the Aircraft Tab.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
          </property>

+ 13 - 7
src/oplconstants.h

@@ -104,6 +104,7 @@ static const auto TABLE_PILOTS           = QLatin1String("pilots");
 static const auto TABLE_TAILS            = QLatin1String("tails");
 static const auto TABLE_AIRCRAFT         = QLatin1String("aircraft");
 static const auto TABLE_AIRPORTS         = QLatin1String("airports");
+static const auto TABLE_CURRENCIES       = QLatin1String("currencies");
 
 // Flights table columns
 static const auto FLIGHTS_DOFT           = QLatin1String("doft");
@@ -159,6 +160,9 @@ static const auto PILOTS_EMPLOYEEID      = QLatin1String("employeeid");
 static const auto PILOTS_PHONE           = QLatin1String("phone");
 static const auto PILOTS_EMAIL           = QLatin1String("email");
 
+// Currencies table
+static const auto CURRENCIES_EXPIRYDATE  = QLatin1String("expiryDate");
+
 // all tables
 static const auto ROWID                  = QLatin1String("ROWID");
 static const auto NULL_TIME_hhmm         = QLatin1String("00:00");
@@ -172,13 +176,15 @@ static const auto DEFAULT_AIRCRAFT_POSITION = DataPosition(TABLE_AIRCRAFT, 0);
 
 namespace Assets {
 
-static const auto LOGO = QLatin1String(":/icons/opl-icons/opl_logo.svg");
-static const auto ICON_APPICON = QLatin1String(":/icons/opl-icons/icon_main.svg");
-static const auto ICON_ABOUT = QLatin1String(":/icons/opl-icons/icon_about.png");
-static const auto ICON_PILOT = QLatin1String(":/icons/opl-icons/pilot.png");
-static const auto ICON_NEW_FLIGHT = QLatin1String(":/icons/opl-icons/new_flight.png");
-static const auto ICON_AIRCRAFT = QLatin1String(":/icons/opl-icons/aircraft.png");
-
+static const auto LOGO                  = QLatin1String(":/icons/opl-icons/opl_logo.svg");
+static const auto ICON_APPICON          = QLatin1String(":/icons/opl-icons/icon_main.svg");
+static const auto ICON_HOME             = QLatin1String(":/icons/opl-icons/icon_home.svg");
+static const auto ICON_ABOUT            = QLatin1String(":/icons/opl-icons/icon_about.png");
+static const auto ICON_PILOT            = QLatin1String(":/icons/opl-icons/pilot.png");
+static const auto ICON_PILOT_DARK       = QLatin1String(":/icons/opl-icons/pilot_dark.png");
+static const auto ICON_NEW_FLIGHT       = QLatin1String(":/icons/opl-icons/new_flight.png");
+static const auto ICON_AIRCRAFT         = QLatin1String(":/icons/opl-icons/aircraft.png");
+static const auto ICON_BACKUP           = QLatin1String(":/icons/opl-icons/icon_backup.svg");
 }
 
 } // namespace opl

Niektoré súbory nie sú zobrazené, pretože je v týchto rozdielových dátach zmenené mnoho súborov