Переглянути джерело

DbCompletionData replaced with DatabaseCache

Removed the DbCompletionData class and replaced it with the DatabaseCache class, which is a global static and can be accessed from throughout the application instead of passing around a completionData instance and keeping track of updating etc.
Felix Turowsky 2 роки тому
батько
коміт
c9e35280b3

+ 2 - 2
CMakeLists.txt

@@ -85,6 +85,8 @@ set(PROJECT_SOURCES
     src/gui/verification/pilotinput.cpp
     src/gui/verification/completerprovider.h
     src/gui/verification/completerprovider.cpp
+    src/gui/verification/tailinput.h
+    src/gui/verification/tailinput.cpp
 
 
     # Classes
@@ -122,8 +124,6 @@ set(PROJECT_SOURCES
     src/database/database.cpp
     src/database/row.h
     src/database/row.cpp
-    src/database/dbcompletiondata.h
-    src/database/dbcompletiondata.cpp
     src/database/dbsummary.h
     src/database/dbsummary.cpp
     src/database/databasecache.h

+ 0 - 0
src/database/dbcompletiondata.cpp → deprecated/dbcompletiondata.cpp


+ 0 - 0
src/database/dbcompletiondata.h → deprecated/dbcompletiondata.h


+ 4 - 31
mainwindow.cpp

@@ -33,7 +33,7 @@ void MainWindow::doDebugStuff()
     OPL::FlightEntry entry = generator.randomFlight();
     DB->commit(entry);
 
-    auto nfd = NewFlightDialog(completionData, DB->getLastEntry(OPL::DbTable::Flights));
+    auto nfd = NewFlightDialog(DB->getLastEntry(OPL::DbTable::Flights));
     nfd.exec();
 }
 
@@ -54,14 +54,12 @@ MainWindow::MainWindow(QWidget *parent)
              .arg(DB->lastError.text()));
     }
 
-    // retreive completion lists and maps
-    completionData.init();
-    OPL::DBCache.init();
+    DBCache->init();
 
     // Construct Widgets
     homeWidget = new HomeWidget(this);
     ui->stackedWidget->addWidget(homeWidget);
-    logbookWidget = new LogbookWidget(completionData, this);
+    logbookWidget = new LogbookWidget(this);
     ui->stackedWidget->addWidget(logbookWidget);
     aircraftWidget = new AircraftWidget(this);
     ui->stackedWidget->addWidget(aircraftWidget);
@@ -186,30 +184,6 @@ void MainWindow::connectWidgets()
                      pilotsWidget,    &PilotsWidget::repopulateModel);
     QObject::connect(DB,              &OPL::Database::connectionReset,
                      aircraftWidget,  &AircraftWidget::repopulateModel);
-
-    // Catch database updates to lazily update CompletionData
-    QObject::connect(DB,              &OPL::Database::dataBaseUpdated,
-                     this,            &MainWindow::onDatabaseUpdated);
-}
-
-void MainWindow::onDatabaseUpdated(const OPL::DbTable table)
-{
-    switch (table) {
-    case OPL::DbTable::Pilots:
-        DEB << "Pilots table updated...";
-        completionData.updatePilots();
-        break;
-    case OPL::DbTable::Tails:
-        DEB << "Tails table updated...";
-        completionData.updateTails();
-        break;
-    case OPL::DbTable::Airports:
-        DEB << "Airports table updated...";
-        completionData.updateAirports();
-        break;
-    default:
-        break;
-    }
 }
 
 void MainWindow::onDatabaseInvalid()
@@ -264,8 +238,7 @@ void MainWindow::on_actionHome_triggered()
 
 void MainWindow::on_actionNewFlight_triggered()
 {
-    completionData.update();
-    auto* nf = new NewFlightDialog(completionData, this);
+    auto* nf = new NewFlightDialog(this);
     nf->exec();
 }
 

+ 0 - 5
mainwindow.h

@@ -38,7 +38,6 @@
 #include "src/gui/widgets/pilotswidget.h"
 #include "src/gui/widgets/debugwidget.h"
 #include "src/classes/style.h"
-#include "src/database/dbcompletiondata.h"
 
 enum Style {Light, Dark};
 QT_BEGIN_NAMESPACE
@@ -117,8 +116,6 @@ private slots:
 
     void on_actionNewSim_triggered();
 
-    void onDatabaseUpdated(const OPL::DbTable table);
-
 private:
     Ui::MainWindow *ui;
 
@@ -136,8 +133,6 @@ private:
 
     DebugWidget* debugWidget;
 
-    // Completion Data for QCompleters and Mapping
-    OPL::DbCompletionData completionData;
     bool airportDbIsDirty = false;
 
     void setupToolbar();

+ 0 - 2
src/database/database.h

@@ -39,8 +39,6 @@
 
 namespace OPL {
 
-//using RowData_T = QHash<QString, QVariant>;
-
 /*!
  * \brief Convenience macro that returns instance of DataBase.
  * Instead of this:

+ 30 - 3
src/database/databasecache.cpp

@@ -13,10 +13,12 @@ void DatabaseCache::init()
     updatePilots();
     updateAirports();
     updateSimulators();
+    updateAircraft();
 
     // Listen to database for updates, reload cache if needed
-    QObject::connect(DB,   &OPL::Database::dataBaseUpdated,
-                     this, &DatabaseCache::update);
+    QObject::connect(DB,   		   &OPL::Database::dataBaseUpdated,
+                     this,         &OPL::DatabaseCache::onDatabaseUpdated);
+
 }
 
 const IdMap DatabaseCache::fetchMap(CompleterTarget target)
@@ -131,7 +133,13 @@ void DatabaseCache::updatePilots()
     companiesList  = fetchList(Companies);
 }
 
-void DatabaseCache::update(const DbTable table)
+void DatabaseCache::updateAircraft()
+{
+    aircraftList = fetchList(AircraftTypes);
+    aircraftMap = fetchMap(AircraftTypes);
+}
+
+void DatabaseCache::onDatabaseUpdated(const OPL::DbTable table)
 {
     LOG << "Updating Database Cache...";
     switch (table) {
@@ -147,9 +155,13 @@ void DatabaseCache::update(const DbTable table)
     case DbTable::Airports:
         updateAirports();
         break;
+    case DbTable::Aircraft:
+        updateAircraft();
+        break;
     default:
         break;
     }
+    emit databaseCacheUpdated(table);
 }
 const IdMap &DatabaseCache::getAirportsMapICAO() const
 {
@@ -186,6 +198,21 @@ const QStringList &DatabaseCache::getCompaniesList() const
     return companiesList;
 }
 
+const QStringList &DatabaseCache::getAircraftList() const
+{
+    return aircraftList;
+}
+
+const IdMap &DatabaseCache::getAircraftMap() const
+{
+    return aircraftMap;
+}
+
+const IdMap &DatabaseCache::getTailsMap() const
+{
+    return tailsMap;
+}
+
 
 
 } // namespace OPL

+ 15 - 5
src/database/databasecache.h

@@ -1,13 +1,12 @@
 #ifndef DATABASECACHE_H
 #define DATABASECACHE_H
-#include "QtWidgets/qcompleter.h"
 #include "src/opl.h"
 #include <QtCore>
 
 namespace OPL{
 
 using IdMap = QHash<int, QString>;
-#define DBCache DatabaseCache::getInstance()
+#define DBCache OPL::DatabaseCache::instance()
 
 /*!
  * \brief Caches certain often accessed database content in memory
@@ -20,9 +19,9 @@ using IdMap = QHash<int, QString>;
 class DatabaseCache : public QObject
 {
 public:
-    static DatabaseCache& getInstance() {
+    static DatabaseCache* instance() {
         static DatabaseCache instance;
-        return instance;
+        return &instance;
     }
 
     DatabaseCache(DatabaseCache const&) = delete;
@@ -35,12 +34,18 @@ public:
     const IdMap &getAirportsMapICAO() const;
     const IdMap &getAirportsMapIATA() const;
     const IdMap &getPilotNamesMap() const;
+    const IdMap &getTailsMap() const;
 
     const QStringList &getPilotNamesList() const;
     const QStringList &getTailsList() const;
     const QStringList &getAirportList() const;
     const QStringList &getCompaniesList() const;
 
+
+    const QStringList &getAircraftList() const;
+
+    const IdMap &getAircraftMap() const;
+
 private:
     Q_OBJECT
     DatabaseCache() {};
@@ -50,9 +55,11 @@ private:
     IdMap airportsMapIATA;
     IdMap pilotNamesMap;
     IdMap tailsMap;
+    IdMap aircraftMap;
     // Lists
     QStringList pilotNamesList;
     QStringList tailsList;
+    QStringList aircraftList;
     QStringList airportList;
     QStringList companiesList;
 
@@ -64,9 +71,12 @@ private:
     void updateAirports();
     void updateSimulators();
     void updatePilots();
+    void updateAircraft();
 
 public slots:
-    void update(const OPL::DbTable table);
+    void onDatabaseUpdated(const OPL::DbTable table);
+signals:
+    void databaseCacheUpdated(const OPL::DbTable table);
 
 };
 

+ 72 - 139
src/gui/dialogues/newflightdialog.cpp

@@ -16,6 +16,12 @@
  *along with this program.  If not, see <https://www.gnu.org/licenses/>.
  */
 #include "newflightdialog.h"
+#include "src/database/databasecache.h"
+#include "src/gui/verification/airportinput.h"
+#include "src/gui/verification/completerprovider.h"
+#include "src/gui/verification/pilotinput.h"
+#include "src/gui/verification/tailinput.h"
+#include "src/gui/verification/timeinput.h"
 #include "ui_newflightdialog.h"
 #include "src/opl.h"
 #include "src/functions/datetime.h"
@@ -27,13 +33,10 @@
 #include <QCompleter>
 #include <QKeyEvent>
 
-const auto CAT_3 = QLatin1String(OPL::GLOBALS->getApproachTypes()[3].toLatin1());
 
-NewFlightDialog::NewFlightDialog(OPL::DbCompletionData &completion_data,
-                                       QWidget *parent)
+NewFlightDialog::NewFlightDialog(QWidget *parent)
     : QDialog(parent),
-      ui(new Ui::NewFlightDialog),
-      completionData(completion_data)
+      ui(new Ui::NewFlightDialog)
 {
     init();
     //flightEntry = AFlightEntry();
@@ -53,10 +56,9 @@ NewFlightDialog::NewFlightDialog(OPL::DbCompletionData &completion_data,
     emit ui->doftLineEdit->editingFinished();
 }
 
-NewFlightDialog::NewFlightDialog(OPL::DbCompletionData &completion_data, int row_id, QWidget *parent)
+NewFlightDialog::NewFlightDialog(int row_id, QWidget *parent)
     : QDialog(parent),
-      ui(new Ui::NewFlightDialog),
-      completionData(completion_data)
+      ui(new Ui::NewFlightDialog)
 {
     init();
     flightEntry = DB->getFlightEntry(row_id);
@@ -110,27 +112,14 @@ void NewFlightDialog::setupRawInputValidation()
     for (const auto& line_edit : *locationLineEdits) {
         auto validator = new QRegularExpressionValidator(QRegularExpression("[a-zA-Z0-9]{1,4}"), line_edit);
         line_edit->setValidator(validator);
-
-        auto completer = new QCompleter(completionData.airportList, line_edit);
-        completer->setCaseSensitivity(Qt::CaseInsensitive);
-        completer->setCompletionMode(QCompleter::PopupCompletion);
-        completer->setFilterMode(Qt::MatchContains);
-        line_edit->setCompleter(completer);
+        line_edit->setCompleter(QCompleterProvider.getCompleter(CompleterProvider::Airports));
     }
     // Name Line Edits
     for (const auto& line_edit : *pilotNameLineEdits) {
-        auto completer = new QCompleter(completionData.pilotList, line_edit);
-        completer->setCaseSensitivity(Qt::CaseInsensitive);
-        completer->setCompletionMode(QCompleter::PopupCompletion);
-        completer->setFilterMode(Qt::MatchContains);
-        line_edit->setCompleter(completer);
+        line_edit->setCompleter(QCompleterProvider.getCompleter(CompleterProvider::Pilots));
     }
     // Acft Line Edit
-    auto completer = new QCompleter(completionData.tailsList, ui->acftLineEdit);
-    completer->setCaseSensitivity(Qt::CaseInsensitive);
-    completer->setCompletionMode(QCompleter::PopupCompletion);
-    completer->setFilterMode(Qt::MatchContains);
-    ui->acftLineEdit->setCompleter(completer);
+    ui->acftLineEdit->setCompleter(QCompleterProvider.getCompleter(CompleterProvider::Tails));
 }
 
 void NewFlightDialog::setupSignalsAndSlots()
@@ -204,10 +193,10 @@ void NewFlightDialog::fillWithEntryData()
     // Times
     ui->tofbTimeLineEdit->setText(OPL::Time::toString(flight_data.value(OPL::Db::FLIGHTS_TOFB).toInt()));
     ui->tonbTimeLineEdit->setText(OPL::Time::toString(flight_data.value(OPL::Db::FLIGHTS_TONB).toInt()));
-    ui->acftLineEdit->setText(completionData.tailsIdMap.value(flight_data.value(OPL::Db::FLIGHTS_ACFT).toInt()));
-    ui->picNameLineEdit->setText(completionData.pilotsIdMap.value(flight_data.value(OPL::Db::FLIGHTS_PIC).toInt()));
-    ui->sicNameLineEdit->setText(completionData.pilotsIdMap.value(flight_data.value(OPL::Db::FLIGHTS_SECONDPILOT).toInt()));
-    ui->thirdPilotNameLineEdit->setText(completionData.pilotsIdMap.value(flight_data.value(OPL::Db::FLIGHTS_THIRDPILOT).toInt()));
+    ui->acftLineEdit->setText(DBCache->getTailsMap().value(flight_data.value(OPL::Db::FLIGHTS_ACFT).toInt()));
+    ui->picNameLineEdit->setText(DBCache->getPilotNamesMap().value(flight_data.value(OPL::Db::FLIGHTS_PIC).toInt()));
+    ui->sicNameLineEdit->setText(DBCache->getPilotNamesMap().value(flight_data.value(OPL::Db::FLIGHTS_SECONDPILOT).toInt()));
+    ui->thirdPilotNameLineEdit->setText(DBCache->getPilotNamesMap().value(flight_data.value(OPL::Db::FLIGHTS_THIRDPILOT).toInt()));
 
     //Function
     const QHash<int, QString> functions = {
@@ -248,6 +237,25 @@ void NewFlightDialog::fillWithEntryData()
         emit line_edit->editingFinished();
 }
 
+bool NewFlightDialog::verifyUserInput(QLineEdit *line_edit, const UserInput &input)
+{
+    DEB << "Verifying user input: " << line_edit->text();
+
+    if(!input.isValid()) {
+        QString fixed = input.fixup();
+        if(fixed == QString()) {
+            onBadInputReceived(line_edit);
+            return false;
+        } else {
+            line_edit->setText(fixed);
+            onGoodInputReceived(line_edit);
+            return true;
+        }
+    }
+    onGoodInputReceived(line_edit);
+    return true;
+}
+
 void NewFlightDialog::onGoodInputReceived(QLineEdit *line_edit)
 {
     DEB << line_edit->objectName() << " - Good input received - " << line_edit->text();
@@ -303,13 +311,8 @@ bool NewFlightDialog::addNewTail(QLineEdit& parent_line_edit)
             DEB << "New Tail Entry added:";
             DEB << DB->getTailEntry(DB->getLastEntry(OPL::DbTable::Tails));
 
-            // update completion Data and Completer
-            completionData.updateTails();
-            auto new_model = new QStringListModel(completionData.tailsList, parent_line_edit.completer());
-            parent_line_edit.completer()->setModel(new_model); //setModel deletes old model if it has the completer as parent
-
             // update Line Edit
-            parent_line_edit.setText(completionData.tailsIdMap.value(DB->getLastEntry(OPL::DbTable::Tails)));
+            parent_line_edit.setText(DBCache->getTailsMap().value(DB->getLastEntry(OPL::DbTable::Tails)));
             return true;
         } else {
             return false;
@@ -341,13 +344,9 @@ bool NewFlightDialog::addNewPilot(QLineEdit& parent_line_edit)
         if (ret == QDialog::Accepted) {
             DEB << "New Pilot Entry added:";
             DEB << DB->getPilotEntry(DB->getLastEntry(OPL::DbTable::Pilots));
-            // update completion Data and Completer
-            completionData.updatePilots();
-            auto new_model = new QStringListModel(completionData.pilotList, parent_line_edit.completer());
-            parent_line_edit.completer()->setModel(new_model); //setModel deletes old model if it has the completer as parent
 
             // update Line Edit
-            parent_line_edit.setText(completionData.pilotsIdMap.value(DB->getLastEntry(OPL::DbTable::Pilots)));
+            parent_line_edit.setText(DBCache->getPilotNamesMap().value(DB->getLastEntry(OPL::DbTable::Pilots)));
             return true;
         } else {
             return false;
@@ -382,7 +381,7 @@ OPL::RowData_T NewFlightDialog::prepareFlightEntryData()
     // Night
     new_data.insert(OPL::Db::FLIGHTS_TNIGHT, night_time_data.nightMinutes);
     // Aircraft
-    int acft_id = completionData.tailsIdMap.key(ui->acftLineEdit->text());
+    int acft_id = DBCache->getTailsMap().key(ui->acftLineEdit->text());
     new_data.insert(OPL::Db::FLIGHTS_ACFT, acft_id);
     const OPL::TailEntry acft_data = DB->getTailEntry(acft_id);
     bool multi_pilot = acft_data.getData().value(OPL::Db::TAILS_MULTIPILOT).toBool();
@@ -402,9 +401,9 @@ OPL::RowData_T NewFlightDialog::prepareFlightEntryData()
         new_data.insert(OPL::Db::FLIGHTS_TSPME, block_minutes);
     }
     // Pilots
-    new_data.insert(OPL::Db::FLIGHTS_PIC, completionData.pilotsIdMap.key(ui->picNameLineEdit->text()));
-    new_data.insert(OPL::Db::FLIGHTS_SECONDPILOT, completionData.pilotsIdMap.key(ui->sicNameLineEdit->text()));
-    new_data.insert(OPL::Db::FLIGHTS_THIRDPILOT, completionData.pilotsIdMap.key(ui->thirdPilotNameLineEdit->text()));
+    new_data.insert(OPL::Db::FLIGHTS_PIC, DBCache->getPilotNamesMap().key(ui->picNameLineEdit->text()));
+    new_data.insert(OPL::Db::FLIGHTS_SECONDPILOT, DBCache->getPilotNamesMap().key(ui->sicNameLineEdit->text()));
+    new_data.insert(OPL::Db::FLIGHTS_THIRDPILOT, DBCache->getPilotNamesMap().key(ui->thirdPilotNameLineEdit->text()));
     // IFR time
     if (ui->ifrCheckBox->isChecked()) {
         new_data.insert(OPL::Db::FLIGHTS_TIFR, block_minutes);
@@ -516,17 +515,20 @@ void NewFlightDialog::onTimeLineEdit_editingFinished()
     auto line_edit = this->findChild<QLineEdit*>(sender()->objectName());
     DEB << line_edit->objectName() << "Editing finished -" << line_edit->text();
 
-    const QString time_string = OPL::Time::formatTimeInput(line_edit->text());
-    const QTime time = OPL::Time::fromString(time_string);
-
-    if (time.isValid()) {
-        line_edit->setText(time_string);
-        onGoodInputReceived(line_edit);
-    } else {
-        onBadInputReceived(line_edit);
-        line_edit->setText(QString());
+    TimeInput user_in = TimeInput(line_edit->text());
+    if(!user_in.isValid()) {
+        QString fixed = user_in.fixup();
+        if(fixed == QString()) {
+            onBadInputReceived(line_edit);
+            return;
+        } else {
+            line_edit->setText(fixed);
+            onGoodInputReceived(line_edit);
+            return;
+        }
     }
 
+    onGoodInputReceived(line_edit);
 }
 
 void NewFlightDialog::onPilotNameLineEdit_editingFinshed()
@@ -534,104 +536,35 @@ void NewFlightDialog::onPilotNameLineEdit_editingFinshed()
     auto line_edit = this->findChild<QLineEdit*>(sender()->objectName());
     DEB << line_edit->objectName() << "Editing Finished -" << line_edit->text();
 
-    int pilot_id = 0;
-
-    // Check for self and try mapping to rowid
-    if(line_edit->text().contains(self, Qt::CaseInsensitive)) {
-        DEB << "self recognized.";
-        line_edit->setText(completionData.pilotsIdMap.value(1));
-        pilot_id = 1;
-    } else
-        pilot_id = completionData.pilotsIdMap.key(line_edit->text());
-
-
-    if(pilot_id != 0) {
-        DEB << "Mapped: " << line_edit->text() << pilot_id;
-        onGoodInputReceived(line_edit);
-        return;
-    }
-
-    if (line_edit->text().isEmpty()) {
-        if (line_edit->objectName() == QLatin1String("picNameLineEdit"))
-            validationState.invalidate(mandatoryLineEdits->indexOf(line_edit));
-        return;
-    }
-
-    if (!line_edit->completer()->currentCompletion().isEmpty()) {
-        DEB << "Trying to fix input...";
-        line_edit->setText(line_edit->completer()->currentCompletion());
-        emit line_edit->editingFinished();
-        return;
+    if(!verifyUserInput(line_edit, PilotInput(line_edit->text()))) {
+        if(!addNewPilot(*line_edit))
+            onBadInputReceived(line_edit);
     }
-
-    // Fall through to adding new pilot to database
-    if(!addNewPilot(*line_edit))
-        onBadInputReceived(line_edit);
 }
 
 void NewFlightDialog::onLocationLineEdit_editingFinished()
 {
-    const QString line_edit_name = sender()->objectName();
+    const QString& line_edit_name = sender()->objectName();
     const auto line_edit = this->findChild<QLineEdit*>(line_edit_name);
-    DEB << line_edit->objectName() << "Editing Finished -" << line_edit->text();
-    QLabel* name_label;
-    if (line_edit_name.contains(QLatin1String("dept"))) {
-        name_label = ui->deptNameLabel;
-    } else {
-        name_label = ui->destNameLabel;
-    }
-
-    const auto &text = line_edit->text();
-    int airport_id = 0;
 
-    // try to map iata or icao code to airport id;
-    if (text.length() == 3) {
-        airport_id = completionData.airportIataIdMap.key(text);
-    } else {
-        airport_id = completionData.airportIcaoIdMap.key(text);
-    }
-    // check result
-    if (airport_id == 0) {
-        // to do: prompt user how to handle unknown airport
-        name_label->setText(tr("Unknown airport identifier"));
-        onBadInputReceived(line_edit);
-        return;
+    if( verifyUserInput(line_edit, AirportInput(line_edit->text())) ) {
+        QLabel* name_label;
+        if (line_edit_name.contains(QLatin1String("dept")))
+            name_label = ui->deptNameLabel;
+        else
+            name_label = ui->destNameLabel;
+    name_label->setText("Lookup Airport ID and match");
     }
-    line_edit->setText(completionData.airportIcaoIdMap.value(airport_id));
-    name_label->setText(completionData.airportNameIdMap.value(airport_id));
-    onGoodInputReceived(line_edit);
 }
 
 void NewFlightDialog::on_acftLineEdit_editingFinished()
 {
     const auto line_edit = ui->acftLineEdit;
-    int acft_id = completionData.tailsIdMap.key(line_edit->text());
-    DEB << line_edit->text() << " has acft_id: " << acft_id;
-    DEB << completionData.tailsIdMap;
-
-    if (acft_id != 0) { // Success
-        onGoodInputReceived(line_edit);
-        return;
-    }
-    // check for whitespaces
-    acft_id = completionData.tailsIdMap.key(line_edit->text().split(" ").first());
-    if (acft_id != 0) {
-        line_edit->setText(completionData.tailsIdMap.value(acft_id));
-        onGoodInputReceived(line_edit);
-        return;
-    }
-
 
-    // try to use a completion
-    if (!line_edit->completer()->currentCompletion().isEmpty() && !line_edit->text().isEmpty()) {
-        line_edit->setText(line_edit->completer()->currentCompletion().split(QLatin1Char(' ')).first());
-        emit line_edit->editingFinished();
-        return;
-    }
-
-    if (!(line_edit->text() == QString()))
+    if(!verifyUserInput(line_edit, TailInput(line_edit->text()))) {
         if(!addNewTail(*line_edit))
             onBadInputReceived(line_edit);
+    }
 }
 
 void NewFlightDialog::on_doftLineEdit_editingFinished()
@@ -684,14 +617,14 @@ void NewFlightDialog::on_functionComboBox_currentIndexChanged(int index)
     if (index == static_cast<int>(OPL::PilotFunction::PIC)) {
         ui->picNameLineEdit->setText(self);
         emit ui->picNameLineEdit->editingFinished();
-        if (completionData.pilotsIdMap.key(ui->picNameLineEdit->text())
-         == completionData.pilotsIdMap.key(ui->sicNameLineEdit->text()))
+        if (DBCache->getPilotNamesMap().key(ui->picNameLineEdit->text())
+         == DBCache->getPilotNamesMap().key(ui->sicNameLineEdit->text()))
                 ui->sicNameLineEdit->setText(QString());
     } else if (index == static_cast<int>(OPL::PilotFunction::SIC)) {
         ui->sicNameLineEdit->setText(self);
         emit ui->sicNameLineEdit->editingFinished();
-        if (completionData.pilotsIdMap.key(ui->picNameLineEdit->text())
-         == completionData.pilotsIdMap.key(ui->sicNameLineEdit->text()))
+        if (DBCache->getPilotNamesMap().key(ui->picNameLineEdit->text())
+         == DBCache->getPilotNamesMap().key(ui->sicNameLineEdit->text()))
             ui->picNameLineEdit->setText(QString());
     }
 }
@@ -707,7 +640,7 @@ void NewFlightDialog::on_functionComboBox_currentIndexChanged(int index)
  */
 bool NewFlightDialog::checkPilotFunctionsValid()
 {
-    int pic_id = completionData.pilotsIdMap.key(ui->picNameLineEdit->text());
+    int pic_id = DBCache->getPilotNamesMap().key(ui->picNameLineEdit->text());
     int function_index = ui->functionComboBox->currentIndex();
 
     if (pic_id == 1) {

+ 5 - 8
src/gui/dialogues/newflightdialog.h

@@ -24,9 +24,7 @@
 #include <QList>
 #include <QBitArray>
 
-#include "src/functions/time.h"
-#include "src/database/database.h"
-#include "src/database/dbcompletiondata.h"
+#include "src/gui/verification/userinput.h"
 #include "src/opl.h"
 #include "src/database/row.h"
 
@@ -112,20 +110,17 @@ public:
 
     /*!
      * \brief NewFlightDialog - Creates a NewFlightDialog that can be used to add a new flight entry to the logbook
-     * \param completion_data - contains QStringLists for the QCompleter to autocomplete Airport Codes, Pilot Names and aircraft registrationsn
      */
-    explicit NewFlightDialog(OPL::DbCompletionData& completion_data, QWidget *parent = nullptr);
+    explicit NewFlightDialog(QWidget *parent = nullptr);
     /*!
      * \brief NewFlightDialog - Creates a NewFlightDialog that can be used to edit an existing entry in the logbook
-     * \param completion_data - contains QStringLists for the QCompleter to autocomplete Airport Codes, Pilot Names and aircraft registrationsn
      * \param row_id - The database ROW ID of the entry to be edited
      */
-    explicit NewFlightDialog(OPL::DbCompletionData& completion_data, int row_id, QWidget* parent = nullptr);
+    explicit NewFlightDialog(int row_id, QWidget* parent = nullptr);
     ~NewFlightDialog();
 
 private:
     Ui::NewFlightDialog *ui;
-    OPL::DbCompletionData completionData;
     ValidationState validationState;
 
     /*!
@@ -159,6 +154,7 @@ private:
     void setupSignalsAndSlots();
     void readSettings();
     void fillWithEntryData();
+    bool verifyUserInput(QLineEdit *line_edit, const UserInput &input);
 
     /*!
      * \brief onGoodInputReceived - Sets a verification bit for the line edit that has been edited.
@@ -184,6 +180,7 @@ private:
     bool checkPilotFunctionsValid();
     OPL::RowData_T prepareFlightEntryData();
 
+    const static inline auto CAT_3 = QLatin1String(OPL::GLOBALS->getApproachTypes()[3].toLatin1());
 
 private slots:
     void toUpper(const QString& text);

+ 2 - 7
src/gui/dialogues/newpilotdialog.cpp

@@ -16,13 +16,12 @@
  *along with this program.  If not, see <https://www.gnu.org/licenses/>.
  */
 #include "newpilotdialog.h"
+#include "src/gui/verification/completerprovider.h"
 #include "ui_newpilot.h"
 #include "src/opl.h"
 
 #include "src/database/database.h"
-#include "src/database/dbcompletiondata.h"
 #include "src/database/row.h"
-#include "src/functions/log.h"
 
 /*!
  * \brief NewPilotDialog::NewPilotDialog - creates a new pilot dialog which can be used to add a new entry to the database
@@ -61,11 +60,7 @@ NewPilotDialog::~NewPilotDialog()
 void NewPilotDialog::setup()
 {
     ui->setupUi(this);
-
-    auto completer = new QCompleter(OPL::DbCompletionData::getCompletionList(OPL::CompleterTarget::Companies), ui->companyLineEdit);
-    completer->setCompletionMode(QCompleter::InlineCompletion);
-    completer->setCaseSensitivity(Qt::CaseSensitive);
-    ui->companyLineEdit->setCompleter(completer);
+    ui->companyLineEdit->setCompleter(QCompleterProvider.getCompleter(CompleterProvider::Companies));
 }
 
 void NewPilotDialog::on_buttonBox_accepted()

+ 13 - 11
src/gui/dialogues/newsimdialog.cpp

@@ -1,10 +1,11 @@
 #include "newsimdialog.h"
+#include "src/database/databasecache.h"
+#include "src/gui/verification/timeinput.h"
 #include "ui_newsimdialog.h"
 #include "src/opl.h"
 #include "src/functions/time.h"
 #include "src/functions/datetime.h"
 #include "src/database/database.h"
-#include "src/database/dbcompletiondata.h"
 #include <QCompleter>
 /*!
  * \brief create a NewSimDialog to add a new Simulator Entry to the database
@@ -40,7 +41,7 @@ void NewSimDialog::init()
 {
     OPL::GLOBALS->loadSimulatorTypes(ui->deviceTypeComboBox);
 
-    const QStringList aircraft_list = OPL::DbCompletionData::getCompletionList(OPL::CompleterTarget::AircraftTypes);
+    const QStringList aircraft_list = DBCache->getAircraftList();
     auto completer = new QCompleter(aircraft_list, ui->aircraftTypeLineEdit);
     completer->setCaseSensitivity(Qt::CaseInsensitive);
     completer->setCompletionMode(QCompleter::PopupCompletion);
@@ -86,15 +87,16 @@ void NewSimDialog::on_dateLineEdit_editingFinished()
 
 void NewSimDialog::on_totalTimeLineEdit_editingFinished()
 {
-    const QString time_string = OPL::Time::formatTimeInput(ui->totalTimeLineEdit->text());
-    const QTime time = OPL::Time::fromString(time_string);
-
-    if (time.isValid()) {
-        ui->totalTimeLineEdit->setText(time_string);
-        ui->totalTimeLineEdit->setStyleSheet(QString());
-    } else {
-        ui->totalTimeLineEdit->setText(QString());
-        ui->totalTimeLineEdit->setStyleSheet(OPL::Styles::RED_BORDER);
+    const auto input = TimeInput(ui->totalTimeLineEdit->text());
+    if(input.isValid())
+        return;
+    else {
+        QString fixed = input.fixup();
+        if(fixed == QString()) {
+            ui->totalTimeLineEdit->setText(QString());
+            ui->totalTimeLineEdit->setStyleSheet(OPL::Styles::RED_BORDER);
+        } else
+            ui->totalTimeLineEdit->setText(fixed);
     }
 }
 

+ 3 - 5
src/gui/dialogues/newtaildialog.cpp

@@ -16,9 +16,9 @@
  *along with this program.  If not, see <https://www.gnu.org/licenses/>.
  */
 #include "newtaildialog.h"
+#include "src/database/databasecache.h"
 #include "ui_newtail.h"
 #include "src/opl.h"
-#include "src/database/dbcompletiondata.h"
 
 NewTailDialog::NewTailDialog(const QString &new_registration, QWidget *parent) :
     QDialog(parent),
@@ -65,8 +65,8 @@ NewTailDialog::~NewTailDialog()
  */
 void NewTailDialog::setupCompleter()
 {
-    idMap = OPL::DbCompletionData::getIdMap(OPL::CompleterTarget::AircraftTypes);
-    aircraftList = OPL::DbCompletionData::getCompletionList(OPL::CompleterTarget::AircraftTypes);
+    idMap = DBCache->getAircraftMap();
+    aircraftList = DBCache->getAircraftList();
 
     QCompleter *completer = new QCompleter(aircraftList, ui->searchLineEdit);
     completer->setCaseSensitivity(Qt::CaseInsensitive);
@@ -78,8 +78,6 @@ void NewTailDialog::setupCompleter()
                      this, &NewTailDialog::onSearchCompleterActivated);
     QObject::connect(completer, static_cast<void(QCompleter::*)(const QString &)>(&QCompleter::highlighted),
                      this, &NewTailDialog::onSearchCompleterActivated);
-
-
 }
 
 void NewTailDialog::setupValidators()

+ 4 - 4
src/gui/verification/airportinput.cpp

@@ -2,7 +2,7 @@
 #include "src/database/databasecache.h"
 bool AirportInput::isValid() const
 {
-    return OPL::DBCache.getAirportsMapICAO().key(input) != 0;
+    return DBCache->getAirportsMapICAO().key(input) != 0;
 }
 
 QString AirportInput::fixup() const
@@ -11,12 +11,12 @@ QString AirportInput::fixup() const
 
     if(input.length() == 3) {
         //input could be IATA code, try to look up Airport ID and match to ICAO code
-        int id = OPL::DBCache.getAirportsMapIATA().key(input.toUpper());
+        int id = DBCache->getAirportsMapIATA().key(input.toUpper());
         if (id != 0)
-            fixed = OPL::DBCache.getAirportsMapICAO().value(id);
+            fixed = DBCache->getAirportsMapICAO().value(id);
     } else {
         //input could be lower case
-        int id = OPL::DBCache.getAirportsMapICAO().key(input.toUpper());
+        int id = DBCache->getAirportsMapICAO().key(input.toUpper());
         if (id != 0)
             fixed = input.toUpper();
     }

+ 36 - 28
src/gui/verification/completerprovider.cpp

@@ -5,29 +5,38 @@
 
 CompleterProvider::CompleterProvider()
 {
-    pilotCompleter = new QCompleter(OPL::DBCache.getPilotNamesList());
-    tailsCompleter = new QCompleter(OPL::DBCache.getTailsList());
-    airportCompleter = new QCompleter(OPL::DBCache.getAirportList());
+    pilotCompleter    = new QCompleter(DBCache->getPilotNamesList());
+    tailsCompleter    = new QCompleter(DBCache->getTailsList());
+    airportCompleter  = new QCompleter(DBCache->getAirportList());
+    companyCompleter  = new QCompleter(DBCache->getCompaniesList());
+    aircraftCompleter = new QCompleter(DBCache->getAircraftList());
 
     QList<QCompleter*> completers = {
         pilotCompleter,
         tailsCompleter,
         airportCompleter,
+        companyCompleter,
+        aircraftCompleter,
     };
     for (const auto completer : completers) {
         completer->setCaseSensitivity(Qt::CaseInsensitive);
         completer->setCompletionMode(QCompleter::PopupCompletion);
         completer->setFilterMode(Qt::MatchContains);
     }
+
+    // Listen for changes in Database Cache
+    QObject::connect(DBCache,    	&OPL::DatabaseCache::databaseCacheUpdated,
+                     this,			&CompleterProvider::onDatabaseCacheUpdated);
 }
 
 CompleterProvider::~CompleterProvider()
 {
-    delete pilotCompleter;
-    delete tailsCompleter;
-    delete airportCompleter;
+    pilotCompleter->deleteLater();
+    tailsCompleter->deleteLater();
+    airportCompleter->deleteLater();
 }
 
+
 QCompleter *CompleterProvider::getCompleter(CompleterTarget target) const
 {
     switch (target) {
@@ -39,38 +48,37 @@ QCompleter *CompleterProvider::getCompleter(CompleterTarget target) const
         break;
     case Tails:
         return tailsCompleter;
+    case Aircraft:
+        return aircraftCompleter;
+    case Companies:
+        return companyCompleter;
         break;
     default:
+        return nullptr;
         break;
     }
 }
 
-/*
-QCompleter *ValidatorProvider::newCompleter(CompleterTarget target, QObject *parent)
+void CompleterProvider::onDatabaseCacheUpdated(const OPL::DbTable table)
 {
-    QCompleter* completer = nullptr;
-    switch(target) {
-    case Airports:
-        completer = new QCompleter(OPL::DBCACHE.getAirportList(), parent);
+    switch (table) {
+    case OPL::DbTable::Pilots:
+        DEB << "Pilots completer model updated...";
+        updateModel(CompleterTarget::Pilots);
         break;
-    case Pilots:
-        completer = new QCompleter(OPL::DBCACHE.getPilotNamesList(), parent);
+    case OPL::DbTable::Tails:
+        DEB << "Tails completer model updated...";
+        updateModel(CompleterTarget::Tails);
         break;
-    case Tails: {
-        completer = new QCompleter(OPL::DBCACHE.getTailsList(), parent);
+    case OPL::DbTable::Airports:
+        DEB << "Airports completer model updated...";
+        updateModel(CompleterTarget::Airports);
         break;
-    }
     default:
-        return nullptr;
+        break;
     }
-
-    completer->setCaseSensitivity(Qt::CaseInsensitive);
-    completer->setCompletionMode(QCompleter::PopupCompletion);
-    completer->setFilterMode(Qt::MatchContains);
-
-    return completer;
 }
-*/
+
 void CompleterProvider::updateModel(CompleterTarget target)
 {
     const QStringList *newData = nullptr;
@@ -78,15 +86,15 @@ void CompleterProvider::updateModel(CompleterTarget target)
 
     switch(target) {
     case Airports:
-        newData = &OPL::DBCache.getAirportList();
+        newData = &DBCache->getAirportList();
         model = qobject_cast<QStringListModel*>(airportCompleter->model());
         break;
     case Pilots:
-        newData = &OPL::DBCache.getPilotNamesList();
+        newData = &DBCache->getPilotNamesList();
         model = qobject_cast<QStringListModel*>(pilotCompleter->model());
         break;
     case Tails: {
-        newData = &OPL::DBCache.getTailsList();
+        newData = &DBCache->getTailsList();
         model = qobject_cast<QStringListModel*>(tailsCompleter->model());
         break;
     }

+ 11 - 10
src/gui/verification/completerprovider.h

@@ -1,8 +1,9 @@
 #ifndef VALIDATORFACTORY_H
 #define VALIDATORFACTORY_H
+#include "src/opl.h"
 #include <QCompleter>
 
-//#define OPL::CompleterProvider CompleterProvider::getInstance()
+#define QCompleterProvider CompleterProvider::getInstance()
 /*!
  * \brief The CompleterProvider class provides static QCompleter instances
  * that are set up with application-wide behaviour standards.
@@ -13,15 +14,18 @@
  * set up with application-wide behaviour standards in mind to create
  * a consistent user experience. The QCompleters' models are based on
  * input from the database, so whenever the database content is modified,
- * it is important to call updateModel.
+ * the completion model is updated via the databaseCacheUpdated Signal.
  */
-class CompleterProvider
+class CompleterProvider : public QObject
 {
+    Q_OBJECT
     CompleterProvider();
 
     QCompleter* pilotCompleter;
     QCompleter* airportCompleter;
     QCompleter* tailsCompleter;
+    QCompleter* companyCompleter;
+    QCompleter* aircraftCompleter;
 public:
     static CompleterProvider& getInstance() {
         static CompleterProvider instance;
@@ -32,12 +36,7 @@ public:
     void operator=(CompleterProvider const&) = delete;
     ~CompleterProvider();
 
-    enum CompleterTarget {Pilots, Tails, Airports};
-
-    /*!
-     * \brief Create a new QCompleter for the given CompleterTarget
-     */
-    //static QCompleter *newCompleter(CompleterTarget target, QObject* parent = nullptr);
+    enum CompleterTarget { Pilots, Tails, Aircraft, Airports, Companies };
 
     /*!
      * \brief updates the completion model for a given QCompleter
@@ -45,9 +44,11 @@ public:
     void updateModel(CompleterTarget target);
 
     /*!
-     * \brief return a pointer to the static completer instance
+     * \brief return a pointer to the completer instance
      */
     QCompleter *getCompleter(CompleterTarget target) const;
+public slots:
+    void onDatabaseCacheUpdated(const OPL::DbTable table);
 };
 
 #endif // VALIDATORFACTORY_H

+ 2 - 2
src/gui/verification/pilotinput.cpp

@@ -4,13 +4,13 @@
 
 bool PilotInput::isValid() const
 {
-    return OPL::DBCache.getPilotNamesMap().key(input) != 0;
+    return DBCache->getPilotNamesMap().key(input) != 0;
 }
 
 QString PilotInput::fixup() const
 {
     if (input.contains(self, Qt::CaseInsensitive))
-        return OPL::DBCache.getPilotNamesMap().value(1);
+        return DBCache->getPilotNamesMap().value(1);
 
     QCompleter* completer = CompleterProvider::getInstance().getCompleter(CompleterProvider::Pilots);
     completer->setCompletionPrefix(input);

+ 15 - 0
src/gui/verification/tailinput.cpp

@@ -0,0 +1,15 @@
+#include "tailinput.h"
+#include "src/database/databasecache.h"
+#include "src/gui/verification/completerprovider.h"
+
+bool TailInput::isValid() const
+{
+    return DBCache->getTailsMap().key(input) != 0;
+}
+
+QString TailInput::fixup() const
+{
+    QCompleter *completer = QCompleterProvider.getCompleter(CompleterProvider::Tails);
+    completer->setCompletionPrefix(input);
+    return completer->currentCompletion();
+}

+ 16 - 0
src/gui/verification/tailinput.h

@@ -0,0 +1,16 @@
+#ifndef TAILINPUT_H
+#define TAILINPUT_H
+
+#include "userinput.h"
+
+class TailInput : public UserInput
+{
+public:
+    TailInput() = delete;
+    TailInput(const QString &input) : UserInput(input) {}
+public:
+    bool isValid() const override;
+    QString fixup() const override;
+};
+
+#endif // TAILINPUT_H

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

@@ -16,8 +16,8 @@
  *along with this program.  If not, see <https://www.gnu.org/licenses/>.
  */
 #include "debugwidget.h"
-#include "src/database/dbcompletiondata.h"
 #include "src/gui/verification/airportinput.h"
+#include "src/gui/verification/completerprovider.h"
 #include "src/gui/verification/pilotinput.h"
 #include "src/gui/verification/timeinput.h"
 #include "src/testing/importCrewlounge/processaircraft.h"
@@ -60,6 +60,8 @@ DebugWidget::DebugWidget(QWidget *parent) :
             ui->tableComboBox->addItem(table);
         }
     }
+    ui->debugLineEdit->setCompleter(QCompleterProvider.getCompleter(CompleterProvider::Airports));
+    ui->debug2LineEdit->setCompleter(QCompleterProvider.getCompleter(CompleterProvider::Airports));
 }
 
 DebugWidget::~DebugWidget()
@@ -289,3 +291,9 @@ void DebugWidget::on_debugLineEdit_editingFinished()
     }
 }
 
+
+void DebugWidget::on_debug2LineEdit_editingFinished()
+{
+
+}
+

+ 2 - 0
src/gui/widgets/debugwidget.h

@@ -55,6 +55,8 @@ private slots:
 
     void on_debugLineEdit_editingFinished();
 
+    void on_debug2LineEdit_editingFinished();
+
 private:
     Ui::DebugWidget *ui;
 

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

@@ -23,20 +23,13 @@
 #include "src/classes/settings.h"
 #include "src/gui/dialogues/newflightdialog.h"
 #include "src/gui/dialogues/newsimdialog.h"
+#include "src/functions/time.h"
 
-const QHash<int, QString> FILTER_MAP = {
-    {0, QStringLiteral("Date LIKE \"%")},
-    {1, QStringLiteral("Dept LIKE \"%")},
-    {2, QStringLiteral("Dest LIKE \"%")},
-    {3, QStringLiteral("Registration LIKE \"%")},
-    {4, QStringLiteral("\"Name PIC\" LIKE \"%")}
-};
-const auto NON_WORD_CHAR = QRegularExpression("\\W");
 
-LogbookWidget::LogbookWidget(OPL::DbCompletionData& completion_data, QWidget *parent) :
+
+LogbookWidget::LogbookWidget(QWidget *parent) :
     QWidget(parent),
-    ui(new Ui::LogbookWidget),
-    completionData(completion_data)
+    ui(new Ui::LogbookWidget)
 {
     ui->setupUi(this);
 
@@ -297,9 +290,8 @@ void LogbookWidget::on_viewsComboBox_currentIndexChanged(int index)
 
 void LogbookWidget::on_actionEdit_Flight_triggered()
 {
-    completionData.update();
     if(selectedEntries.length() == 1){
-        NewFlightDialog nff(completionData,selectedEntries.first(), this);
+        NewFlightDialog nff(selectedEntries.first(), this);
         ui->stackedWidget->addWidget(&nff);
         ui->stackedWidget->setCurrentWidget(&nff);
         nff.setWindowFlag(Qt::Widget);

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

@@ -25,8 +25,8 @@
 #include <QDebug>
 #include <QMenu>
 #include <QTableView>
+#include "src/database/row.h"
 #include "src/gui/widgets/settingswidget.h"
-#include "src/database/dbcompletiondata.h"
 #include "src/opl.h"
 
 namespace Ui {
@@ -49,7 +49,7 @@ class LogbookWidget : public QWidget
     Q_OBJECT
 
 public:
-    explicit LogbookWidget(OPL::DbCompletionData &completion_data, QWidget *parent = nullptr);
+    explicit LogbookWidget(QWidget *parent = nullptr);
     ~LogbookWidget();
 
 private slots:
@@ -89,8 +89,6 @@ private:
 
     const QString getFlightSummary(const OPL::FlightEntry &flight) const;
 
-    OPL::DbCompletionData completionData;
-
     /*!
      * \brief isFlight Determines whether an entry shown in a view is a Flight or a Simulator.
      * \param model_row_id the row id in the QSqlTableModel used for displaying
@@ -100,6 +98,15 @@ private:
      */
     inline bool isFlight(int model_row_id) { return model_row_id > 0; }
 
+    const static inline QHash<int, QString> FILTER_MAP = {
+        {0, QStringLiteral("Date LIKE \"%")},
+        {1, QStringLiteral("Dept LIKE \"%")},
+        {2, QStringLiteral("Dest LIKE \"%")},
+        {3, QStringLiteral("Registration LIKE \"%")},
+        {4, QStringLiteral("\"Name PIC\" LIKE \"%")}
+    };
+    const static inline QRegularExpression NON_WORD_CHAR = QRegularExpression("\\W");
+
 protected:
     /*!
      * \brief Handles change events, like updating the UI to new localisation