Browse Source

Replaced Table Edit Widgets

PilotsWidget, TailsWidget and AirportWidget are replaced by implementations of TableEditWidgets.
Felix Turowsky 1 year ago
parent
commit
a94b171500

+ 4 - 0
CMakeLists.txt

@@ -88,6 +88,10 @@ set(PROJECT_SOURCES
     src/gui/widgets/tableeditwidget.cpp
     src/gui/widgets/pilottableeditwidget.h
     src/gui/widgets/pilottableeditwidget.cpp
+    src/gui/widgets/tailtableeditwidget.h
+    src/gui/widgets/tailtableeditwidget.cpp
+    src/gui/widgets/airporttableeditwidget.h
+    src/gui/widgets/airporttableeditwidget.cpp
 
     # Verification
     src/gui/verification/validationstate.h

+ 1 - 0
assets/database/database_schema.sql

@@ -22,6 +22,7 @@ CREATE TABLE IF NOT EXISTS 'tails' (
 	'multiengine'	INTEGER,
 	'engineType'	INTEGER,
 	'weightClass'	INTEGER,
+        'typeString'	TEXT,
 	PRIMARY KEY('tail_id' AUTOINCREMENT)
 );
 DROP TABLE IF EXISTS 'flights';

+ 15 - 13
mainwindow.cpp

@@ -17,7 +17,9 @@
  */
 #include <QToolBar>
 #include "mainwindow.h"
+#include "src/gui/widgets/airporttableeditwidget.h"
 #include "src/gui/widgets/pilottableeditwidget.h"
+#include "src/gui/widgets/tailtableeditwidget.h"
 #include "ui_mainwindow.h"
 #include "src/database/database.h"
 #include "src/classes/style.h"
@@ -30,7 +32,7 @@
 // Quick and dirty Debug area
 void MainWindow::doDebugStuff()
 {
-    PilotTableEditWidget *widget = new PilotTableEditWidget(this);
+    AirportTableEditWidget *widget = new AirportTableEditWidget(this);
     widget->init();
     widget->setWindowFlags(Qt::Dialog);
     widget->show();
@@ -89,16 +91,16 @@ void MainWindow::initialiseWidgets()
     logbookWidget = new LogbookWidget(this);
     ui->stackedWidget->addWidget(logbookWidget);
 
-    aircraftWidget = new TailsWidget(this);
-    ui->stackedWidget->addWidget(aircraftWidget);
+    tailsWidget = new TailTableEditWidget(this);
+    tailsWidget->init();
+    ui->stackedWidget->addWidget(tailsWidget);
 
-//    pilotsWidget = new PilotsWidget(this);
-//    ui->stackedWidget->addWidget(pilotsWidget);
     pilotsWidget = new PilotTableEditWidget(this);
     pilotsWidget->init();
     ui->stackedWidget->addWidget(pilotsWidget);
 
-    airportWidget = new AirportWidget(this);
+    airportWidget = new AirportTableEditWidget(this);
+    airportWidget->init();
     ui->stackedWidget->addWidget(airportWidget);
 
     settingsWidget = new SettingsWidget(this);
@@ -176,10 +178,10 @@ void MainWindow::connectWidgets()
     QObject::connect(settingsWidget, &SettingsWidget::settingChanged,
                      logbookWidget,  &LogbookWidget::onLogbookWidget_viewSelectionChanged);
 
-    QObject::connect(DB,             &OPL::Database::dataBaseUpdated,
-                     aircraftWidget, &TailsWidget::onAircraftWidget_dataBaseUpdated);
-    QObject::connect(settingsWidget, &SettingsWidget::settingChanged,
-                     aircraftWidget, &TailsWidget::onAircraftWidget_settingChanged);
+//    QObject::connect(DB,             &OPL::Database::dataBaseUpdated,
+//                     tailsWidget, &TailsWidget::onAircraftWidget_dataBaseUpdated);
+//    QObject::connect(settingsWidget, &SettingsWidget::settingChanged,
+//                     tailsWidget, &TailsWidget::onAircraftWidget_settingChanged);
 
 //    QObject::connect(DB,             &OPL::Database::dataBaseUpdated,
 //                     pilotsWidget,   &PilotsWidget::onPilotsWidget_databaseUpdated);
@@ -192,8 +194,8 @@ void MainWindow::connectWidgets()
                      logbookWidget,   &LogbookWidget::repopulateModel);
 //    QObject::connect(DB,              &OPL::Database::connectionReset,
 //                     pilotsWidget,    &PilotsWidget::repopulateModel);
-    QObject::connect(DB,              &OPL::Database::connectionReset,
-                     aircraftWidget,  &TailsWidget::repopulateModel);
+//    QObject::connect(DB,              &OPL::Database::connectionReset,
+//                     tailsWidget,  &TailsWidget::repopulateModel);
 }
 
 void MainWindow::onDatabaseInvalid()
@@ -259,7 +261,7 @@ void MainWindow::on_actionLogbook_triggered()
 
 void MainWindow::on_actionAircraft_triggered()
 {
-    ui->stackedWidget->setCurrentWidget(aircraftWidget);
+    ui->stackedWidget->setCurrentWidget(tailsWidget);
 }
 
 void MainWindow::on_actionPilots_triggered()

+ 3 - 3
mainwindow.h

@@ -123,12 +123,12 @@ private:
     HomeWidget* homeWidget;
 
     LogbookWidget* logbookWidget;
-
-    TailsWidget* aircraftWidget;
+    
+    TableEditWidget* tailsWidget;
 
     TableEditWidget* pilotsWidget;
 
-    AirportWidget* airportWidget;
+    TableEditWidget* airportWidget;
 
     SettingsWidget* settingsWidget;
 

+ 23 - 0
src/database/airportentry.cpp

@@ -46,4 +46,27 @@ const QString AirportEntry::getIcaoCode() const
     return getData().value(ICAO).toString();
 }
 
+const QString AirportEntry::getAirportName() const
+{
+    return getData().value(NAME).toString();
+}
+
+const QString AirportEntry::getAirportDescriptor() const
+{
+    if(getIataCode().isEmpty()) {
+        if(getAirportName().isEmpty()) {
+            return getIcaoCode();
+        }
+        return getIcaoCode()
+               + QStringLiteral(" - ")
+               + getAirportName();
+    }
+    return getIcaoCode()
+           + QStringLiteral(" - ")
+           + getAirportName()
+           + QStringLiteral(" (")
+           + getIataCode()
+           + QLatin1Char(')');
+}
+
 } // namespace OPL

+ 12 - 0
src/database/airportentry.h

@@ -43,6 +43,18 @@ public:
      */
     const QString getIcaoCode() const;
 
+    /*!
+     * \brief Returns the airport common given name
+     */
+    const QString getAirportName() const;
+
+    /*!
+     * \brief return a string describing the airport
+     * \details The string consists of the Airport ICAO Code, and if available
+     * IATA Code and Airport Name
+     */
+    const QString getAirportDescriptor() const;
+
     /*!
      * \brief The ICAO code is a 4-letter alphanumeric identifier for airports
      */

+ 16 - 1
src/database/tailentry.cpp

@@ -42,7 +42,22 @@ const QString TailEntry::registration() const
 }
 
 const QString TailEntry::type() const {
-    return getData().value(MAKE).toString();
+    const auto &data = getData();
+
+    if(data.value(VARIANT).toString().isEmpty()) {
+        if(data.value(MODEL).toString().isEmpty()) {
+            return data.value(MAKE).toString();
+        }
+        return data.value(MAKE).toString()
+               + QLatin1Char(' ')
+               + data.value(MODEL).toString();
+    }
+
+    return data.value(MAKE).toString()
+           + QLatin1Char(' ')
+           + data.value(MODEL).toString()
+           + QLatin1Char('-')
+           + data.value(VARIANT).toString();
 }
 
 } // namespace OPL

+ 7 - 2
src/database/tailentry.h

@@ -44,9 +44,9 @@ public:
      */
     const QString registration() const;
     /*!
-     * \brief Return the aircraft type
+     * \brief Return the aircraft type (Make and  - if available - Model and Variant)
      */
-    const QString type()         const; //TODO - Create String for make-model-variant
+    const QString type() const;
 
     /*!
      * \brief The entries row id in the database
@@ -102,6 +102,11 @@ public:
      * <\ul>
      */
     static const inline QString WEIGHT_CLASS = QStringLiteral("weightClass");
+
+    /*!
+     * \brief The aircraft type string ("Make Model-Variant")
+     */
+    static const inline QString TYPE_STRING = QStringLiteral("typeString");
 };
 
 } // namespace OPL

+ 0 - 6
src/gui/dialogues/entryeditdialog.h

@@ -15,18 +15,12 @@ public:
     EntryEditDialog(QWidget *parent = nullptr);
     EntryEditDialog(int rowID, QWidget *parent = nullptr);
 
-    /*!
-     * \brief reset the Entry Dialog to accept a new entry
-     */
-    virtual void reset() = 0;
-
     /*!
      * \brief load an entry from the database for editing
      * \param rowID - The row ID of the entry
      */
     virtual void loadEntry(int rowID) = 0;
 
-
     /*!
      * \brief delete an entry from the database
      * \param rowID - the row ID to be deleted

+ 18 - 6
src/gui/dialogues/newairportdialog.cpp

@@ -8,19 +8,18 @@
 #include "src/database/row.h"
 
 NewAirportDialog::NewAirportDialog(QWidget *parent) :
-    QDialog(parent), ui(new Ui::NewAirportDialog)
+    EntryEditDialog(parent), ui(new Ui::NewAirportDialog)
 {
-    rowId = 0; // new entry
+    m_rowId = 0; // new entry
     ui->setupUi(this);
     setValidators();
     loadTimeZones();
 }
 
 NewAirportDialog::NewAirportDialog(int row_id, QWidget *parent)
-    : QDialog(parent), ui(new Ui::NewAirportDialog), rowId(row_id)
+    : EntryEditDialog(parent), ui(new Ui::NewAirportDialog), m_rowId(row_id)
 {
     ui->setupUi(this);
-    this->setWindowTitle(tr("Edit Airport"));
     setValidators();
     loadTimeZones();
     loadAirportData(row_id);
@@ -47,8 +46,8 @@ void NewAirportDialog::loadTimeZones()
 
 void NewAirportDialog::loadAirportData(int row_id)
 {
+    this->setWindowTitle(tr("Edit Airport"));
     const auto airport_data = DB->getAirportEntry(row_id).getData();
-    //const auto airport_data = airport.getData();
     DEB << "Filling Airport Data: " << airport_data;
 
     ui->nameLineEdit->setText(airport_data.value(OPL::AirportEntry::NAME).toString());
@@ -118,7 +117,7 @@ void NewAirportDialog::on_buttonBox_accepted()
         {OPL::AirportEntry::COUNTRY,  ui->countryLineEdit->text()},
     };
 
-    OPL::AirportEntry entry(rowId, airport_data);
+    OPL::AirportEntry entry(m_rowId, airport_data);
     if(DB->commit(entry))
         QDialog::accept();
     else {
@@ -142,3 +141,16 @@ void NewAirportDialog::on_buttonBox_rejected()
     QDialog::reject();
 }
 
+// EntryEditDialog interface
+void NewAirportDialog::loadEntry(int rowId)
+{
+    m_rowId = rowId;
+    loadAirportData(rowId);
+}
+
+bool NewAirportDialog::deleteEntry(int rowId)
+{
+    auto entry = DB->getAirportEntry(rowId);
+    return DB->remove(entry);
+}
+

+ 11 - 3
src/gui/dialogues/newairportdialog.h

@@ -1,13 +1,13 @@
 #ifndef NEWAIRPORTDIALOG_H
 #define NEWAIRPORTDIALOG_H
 
-#include <QDialog>
+#include "src/gui/dialogues/entryeditdialog.h"
 
 namespace Ui {
 class NewAirportDialog;
 }
 
-class NewAirportDialog : public QDialog
+class NewAirportDialog : public EntryEditDialog
 {
     Q_OBJECT
 
@@ -17,6 +17,7 @@ public:
     ~NewAirportDialog();
 
 
+
 private slots:
     void on_buttonBox_accepted();
 
@@ -28,12 +29,19 @@ private slots:
 
 private:
     Ui::NewAirportDialog *ui;
+    int m_rowId;
+
     void setValidators();
     void loadTimeZones();
     bool confirmTimezone();
     void loadAirportData(int row_id);
     bool verifyInput();
-    int rowId;
+
+
+    // EntryEditDialog interface
+public:
+    virtual void loadEntry(int rowId) override;
+    virtual bool deleteEntry(int rowId) override;
 };
 
 #endif // NEWAIRPORTDIALOG_H

+ 5 - 16
src/gui/dialogues/newpilotdialog.cpp

@@ -110,27 +110,16 @@ void NewPilotDialog::submitForm()
     }
 }
 
-void NewPilotDialog::reset()
+bool NewPilotDialog::deleteEntry(int rowId)
 {
-    pilotEntry = OPL::PilotEntry();
-    auto line_edits = this->findChildren<QLineEdit *>();
+    auto entry = DB->getPilotEntry(rowId);
+    return DB->remove(entry);
 
-    for (const auto &le : line_edits) {
-        le->setText(QString());
-    }
-    ui->lastnameLineEdit->setFocus();
 }
 
-void NewPilotDialog::loadEntry(int rowID)
+void NewPilotDialog::loadEntry(int rowId)
 {
-    pilotEntry = DB->getPilotEntry(rowID);
+    pilotEntry = DB->getPilotEntry(rowId);
     formFiller();
     ui->lastnameLineEdit->setFocus();
 }
-
-bool NewPilotDialog::deleteEntry(int rowID)
-{
-    auto entry = DB->getPilotEntry(rowID);
-    return DB->remove(entry);
-
-}

+ 3 - 3
src/gui/dialogues/newpilotdialog.h

@@ -74,9 +74,9 @@ private:
 
     // EntryEditDialog interface
 public:
-    virtual void reset() override;
-    virtual void loadEntry(int rowID) override;
-    virtual bool deleteEntry(int rowID) override;
+    virtual bool deleteEntry(int rowId) override;
+    virtual void loadEntry(int rowId) override;
+
 };
 
 

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

@@ -21,8 +21,8 @@
 #include "ui_newtail.h"
 #include "src/opl.h"
 
-NewTailDialog::NewTailDialog(const QString &new_registration, QWidget *parent) :
-    QDialog(parent),
+NewTailDialog::NewTailDialog(QString new_registration, QWidget *parent) :
+    EntryEditDialog(parent),
     ui(new Ui::NewTail)
 {
     ui->setupUi(this);
@@ -38,7 +38,7 @@ NewTailDialog::NewTailDialog(const QString &new_registration, QWidget *parent) :
 }
 
 NewTailDialog::NewTailDialog(int row_id, QWidget *parent) :
-    QDialog(parent),
+    EntryEditDialog(parent),
     ui(new Ui::NewTail)
 {
     ui->setupUi(this);
@@ -202,6 +202,12 @@ void NewTailDialog::submitForm()
     //create db object
 
     entry.setData(new_data);
+
+    // add type string
+    auto data = entry.getData();
+    data.insert(OPL::TailEntry::TYPE_STRING, entry.type());
+    entry.setData(data);
+
     LOG << "Commiting: " << entry;
     if (!DB->commit(entry)) {
         QMessageBox message_box(this);
@@ -271,15 +277,32 @@ void NewTailDialog::onSearchCompleterActivated()
     const auto &text = ui->searchLineEdit->text();
     if (aircraftList.contains(text)) {
 
-            DEB << "Template Selected. aircraft_id is: " << idMap.key(text);
-            //call autofiller for dialog
-            fillForm(DB->getAircraftEntry(idMap.key(text)), true);
-            ui->searchLineEdit->setStyleSheet(QStringLiteral("border: 1px solid green"));
-            ui->searchLabel->setText(text);
-        } else {
-            //for example, editing finished without selecting a result from Qcompleter
-            ui->searchLineEdit->setStyleSheet(QStringLiteral("border: 1px solid orange"));
-        }
+        DEB << "Template Selected. aircraft_id is: " << idMap.key(text);
+        //call autofiller for dialog
+        fillForm(DB->getAircraftEntry(idMap.key(text)), true);
+        ui->searchLineEdit->setStyleSheet(QStringLiteral("border: 1px solid green"));
+        ui->searchLabel->setText(text);
+    } else {
+        //for example, editing finished without selecting a result from Qcompleter
+        ui->searchLineEdit->setStyleSheet(QStringLiteral("border: 1px solid orange"));
+    }
+}
+
+bool NewTailDialog::deleteEntry(int rowID)
+{
+    auto entry = DB->getTailEntry(rowID);
+    return DB->remove(entry);
+}
+
+void NewTailDialog::loadEntry(int rowId)
+{
+    ui->searchLabel->hide();
+    ui->searchLineEdit->hide();
+    ui->line->hide();
+
+    setupValidators();
+    entry = DB->getTailEntry(rowId);
+    fillForm(entry, false);
 }
 
 void NewTailDialog::on_registrationLineEdit_textChanged(const QString &arg1)

+ 10 - 2
src/gui/dialogues/newtaildialog.h

@@ -26,6 +26,7 @@
 
 #include "src/database/row.h"
 #include "src/database/tailentry.h"
+#include "src/gui/dialogues/entryeditdialog.h"
 
 namespace Ui {
 class NewTail;
@@ -55,7 +56,7 @@ class NewTail;
  *
  *
  */
-class NewTailDialog : public QDialog
+class NewTailDialog : public EntryEditDialog
 {
     Q_OBJECT
 
@@ -64,7 +65,7 @@ public:
      * \brief NewTailDialog - create a new ATailEntry and submit it to the database
      * \param new_registration - when called from the NewFlightDialog, pre-fills the registration already entered.
      */
-    explicit NewTailDialog(const QString& new_registration, QWidget *parent = nullptr);
+    explicit NewTailDialog(QString new_registration, QWidget *parent = nullptr);
     /*!
      * \brief NewTailDialog - edit an existing Tail Entry
      * \param row_id - the ROW_ID of the entry to be edited in the database
@@ -73,6 +74,8 @@ public:
 
     ~NewTailDialog();
 
+
+
 signals:
     void tailDataChanged();
 private:
@@ -102,6 +105,11 @@ private slots:
     void on_buttonBox_accepted();
     void onSearchCompleterActivated();
 
+
+    // EntryEditDialog interface
+public:
+    virtual bool deleteEntry(int rowID) override;
+    virtual void loadEntry(int rowId) override;
 };
 
 #endif // NEWTAIL_H

+ 78 - 0
src/gui/widgets/airporttableeditwidget.cpp

@@ -0,0 +1,78 @@
+#include "airporttableeditwidget.h"
+#include "src/database/database.h"
+#include "src/gui/dialogues/newairportdialog.h"
+
+AirportTableEditWidget::AirportTableEditWidget(QWidget *parent)
+    : TableEditWidget{parent}
+{}
+
+void AirportTableEditWidget::setupModelAndView()
+{
+    model = new QSqlTableModel(this, DB->database());
+    model->setTable(OPL::GLOBALS->getDbTableName(OPL::DbTable::Airports));
+    model->select();
+
+    for(int i = 0; i < HEADER_NAMES.size(); i++) {
+        model->setHeaderData(i + 1, Qt::Horizontal, HEADER_NAMES.at(i));
+    }
+
+    view->setModel(model);
+    view->setSelectionMode(QAbstractItemView::SingleSelection);
+    view->setSelectionBehavior(QAbstractItemView::SelectRows);
+    view->setEditTriggers(QAbstractItemView::NoEditTriggers);
+    view->horizontalHeader()->setStretchLastSection(QHeaderView::Stretch);
+    view->resizeColumnsToContents();
+    view->verticalHeader()->hide();
+    view->setAlternatingRowColors(true);
+    view->hideColumn(COL_ROWID);
+
+}
+
+void AirportTableEditWidget::setupUI()
+{
+    // the base class does most of the setup
+    TableEditWidget::setupUI();
+
+    // only need to set the table specific labels and combo box items
+    addNewEntryPushButton->setText(tr("Add New Airport"));
+    deleteEntryPushButton->setText(tr("Delete Selected Airport"));
+    for(const int i : FILTER_COLUMNS) {
+        filterSelectionComboBox->addItem(HEADER_NAMES.at(i));
+    }
+}
+
+QString AirportTableEditWidget::deleteErrorString(int rowId)
+{
+    return tr("<br>Unable to delete.<br><br>The following error has ocurred: %1"
+              ).arg(DB->lastError.text());
+}
+
+QString AirportTableEditWidget::confirmDeleteString(int rowId)
+{
+    const auto entry = DB->getAirportEntry(rowId);
+    return tr("The following airport will be deleted:<br><br><b><tt>"
+              "%1<br></b></tt>"
+              "Deleting airports is irreversible.<br>Do you want to proceed?"
+              ).arg(entry.getAirportDescriptor());
+}
+
+EntryEditDialog *AirportTableEditWidget::getEntryEditDialog(QWidget *parent)
+{
+    return new NewAirportDialog(parent);
+}
+
+void AirportTableEditWidget::filterTextChanged(const QString &filterString)
+{
+    if(filterString.isEmpty()) {
+        return;
+    }
+
+    int i = filterSelectionComboBox->currentIndex();
+    const QString filter =
+        QLatin1Char('\"')
+        + HEADER_NAMES.at(FILTER_COLUMNS[i])
+        + QLatin1String("\" LIKE '%")
+        + filterString
+        + QLatin1String("%'");
+    model->setFilter(filter);
+}

+ 52 - 0
src/gui/widgets/airporttableeditwidget.h

@@ -0,0 +1,52 @@
+#ifndef AIRPORTTABLEEDITWIDGET_H
+#define AIRPORTTABLEEDITWIDGET_H
+
+#include "tableeditwidget.h"
+#include <QObject>
+#include "src/database/airportentry.h"
+
+class AirportTableEditWidget : public TableEditWidget
+{
+    Q_OBJECT
+public:
+    AirportTableEditWidget() = delete;
+    AirportTableEditWidget(QWidget *parent = nullptr);
+
+    // TableEditWidget interface
+    virtual void setupModelAndView() override;
+    virtual void setupUI() override;
+    virtual QString deleteErrorString(int rowId) override;
+    virtual QString confirmDeleteString(int rowId) override;
+    virtual EntryEditDialog *getEntryEditDialog(QWidget *parent) override;
+
+    // table columns and header names
+
+    const int COL_ROWID = 0;
+
+    // used to display the Header Views and Fill the FilterComboBox
+    const QStringList HEADER_NAMES = {
+                                      tr("ICAO"),
+                                      tr("IATA"),
+                                      tr("Name"),
+                                      tr("Latitude"),
+                                      tr("Longitude"),
+                                      tr("Country"),
+                                      tr("Time Zone"),
+    };
+
+    // These are indexes into HEADER_NAMES
+    const int FILTER_COLUMNS[4] = {0, 1, 2, 5};
+
+    // The sql column names corresponding to the entries of the FilterComboBox index
+    const static inline QStringList FILTER_COLUMN_NAMES = {
+        OPL::AirportEntry::ICAO,
+        OPL::AirportEntry::IATA,
+        OPL::AirportEntry::NAME,
+        OPL::AirportEntry::TZ_OLSON,
+    };
+
+private slots:
+    virtual void filterTextChanged(const QString &filterString) override;
+};
+
+#endif // AIRPORTTABLEEDITWIDGET_H

+ 6 - 1
src/gui/widgets/pilottableeditwidget.h

@@ -6,6 +6,7 @@
 
 class PilotTableEditWidget : public TableEditWidget
 {
+    Q_OBJECT
 public:
     PilotTableEditWidget(QWidget *parent = nullptr);
 
@@ -21,7 +22,11 @@ private:
     const int COL_COMPANY = 4;
     const int COLS_TO_HIDE[5] = {0, 3, 5, 6, 7};
 
-    const static inline QStringList FILTER_COLUMNS = { tr("First Name"), tr("Last Name"), tr("Company") };
+    const QString COLUMN_1_NAME = tr("First Name");
+    const QString COLUMN_2_NAME = tr("Last Name");
+    const QString COLUMN_3_NAME = tr("Company");
+
+    const QStringList FILTER_COLUMNS = { COLUMN_1_NAME, COLUMN_2_NAME, COLUMN_3_NAME };
     const static inline QStringList FILTER_COLUMN_NAMES = {
                                                             OPL::PilotEntry::FIRSTNAME,
                                                             OPL::PilotEntry::LASTNAME,

+ 0 - 7
src/gui/widgets/tableeditwidget.cpp

@@ -80,15 +80,8 @@ void TableEditWidget::setupSignalsAndSlots()
 
 void TableEditWidget::addEntryRequested()
 {
-    clearStackedWidget();
-
-    // create a Dialog for adding a new entry and put it on the stackedWidget
     auto editDialog = getEntryEditDialog(this);
-    stackedWidget->addWidget(editDialog);
-    stackedWidget->show();
     editDialog->exec();
-
-    stackedWidget->hide();
 }
 
 

+ 99 - 0
src/gui/widgets/tailtableeditwidget.cpp

@@ -0,0 +1,99 @@
+#include "tailtableeditwidget.h"
+#include "src/database/database.h"
+#include "src/gui/dialogues/newtaildialog.h"
+
+TailTableEditWidget::TailTableEditWidget(QWidget *parent)
+    : TableEditWidget{parent}
+{}
+
+void TailTableEditWidget::setupModelAndView()
+{
+    model = new QSqlTableModel(this, DB->database());
+    model->setTable(OPL::GLOBALS->getDbTableName(OPL::DbTable::Tails));
+    model->select();
+    model->setHeaderData(COL_REGISTRATION, Qt::Horizontal, COLUMN_NAME_REGISTRATION);
+    model->setHeaderData(COL_TYPE, Qt::Horizontal, COLUMN_NAME_TYPE);
+    model->setHeaderData(COL_COMPANY, Qt::Horizontal, COLUMN_NAME_COMPANY);
+
+    view->setModel(model);
+    view->setSelectionMode(QAbstractItemView::SingleSelection);
+    view->setSelectionBehavior(QAbstractItemView::SelectRows);
+    view->setEditTriggers(QAbstractItemView::NoEditTriggers);
+    view->horizontalHeader()->setStretchLastSection(QHeaderView::Stretch);
+    view->resizeColumnsToContents();
+    view->verticalHeader()->hide();
+    view->setAlternatingRowColors(true);
+    for(const int i : COLS_TO_HIDE)
+        view->hideColumn(i);
+}
+
+void TailTableEditWidget::setupUI()
+{
+    // the base class does most of the setup
+    TableEditWidget::setupUI();
+
+    // only need to set the table specific labels and combo box items
+    addNewEntryPushButton->setText(tr("Add New Tail"));
+    deleteEntryPushButton->setText(tr("Delete Selected Tail"));
+    filterSelectionComboBox->addItems(FILTER_COLUMNS);
+}
+
+QString TailTableEditWidget::deleteErrorString(int rowId)
+{
+    QList<int> foreign_key_constraints = DB->getForeignKeyConstraints(rowId,
+                                                                      OPL::DbTable::Tails);
+    QList<OPL::FlightEntry> constrained_flights;
+    for (const auto &row_id : qAsConst(foreign_key_constraints)) {
+        constrained_flights.append(DB->getFlightEntry(row_id));
+    }
+
+    QMessageBox message_box(this);
+    if (constrained_flights.isEmpty()) {
+        // error is a database error
+        return tr("<br>Unable to delete.<br><br>The following error has ocurred: %1"
+                  ).arg(DB->lastError.text());
+    } else {
+        QString constrained_flights_string;
+        for (int i=0; i<constrained_flights.length(); i++) {
+            constrained_flights_string.append(constrained_flights[i].getFlightSummary()
+                                              + QLatin1String("&nbsp;&nbsp;&nbsp;&nbsp;<br>"));
+            if (i>10) {
+                constrained_flights_string.append(QLatin1String("<br>[...]<br>"));
+                break;
+            }
+        }
+        return (tr("Unable to delete.<br><br>"
+                   "This is most likely the case because a flight exists with the aircraft "
+                   "you are trying to delete.<br><br>"
+                   "%1 flight(s) with this aircraft have been found:<br><br><br><b><tt>"
+                   "%2"
+                   "</b></tt><br><br>You have to change or remove the conflicting flight(s) "
+                   "before removing this aircraft from the database.<br><br>"
+                   ).arg(
+                        QString::number(constrained_flights.length()),
+                        constrained_flights_string)
+                );
+    }
+}
+
+QString TailTableEditWidget::confirmDeleteString(int rowId)
+{
+    const auto entry = DB->getTailEntry(rowId);
+    return tr("You are deleting the following aircraft:<br><br><b><tt>"
+              "%1 (%2)</b></tt><br><br>Are you sure?"
+              ).arg(
+              entry.getData().value(OPL::TailEntry::REGISTRATION).toString(),
+              entry.type()
+              );
+}
+
+EntryEditDialog *TailTableEditWidget::getEntryEditDialog(QWidget *parent)
+{
+    QString empty;
+    return new NewTailDialog(empty, parent);
+}
+
+void TailTableEditWidget::filterTextChanged(const QString &filterString)
+{
+    TODO << "not implemented.";
+}

+ 43 - 0
src/gui/widgets/tailtableeditwidget.h

@@ -0,0 +1,43 @@
+#ifndef TAILTABLEEDITWIDGET_H
+#define TAILTABLEEDITWIDGET_H
+
+#include "tableeditwidget.h"
+
+class TailTableEditWidget : public TableEditWidget
+{
+    Q_OBJECT
+public:
+    TailTableEditWidget() = delete;
+    explicit TailTableEditWidget(QWidget *parent = nullptr);
+
+
+    virtual void setupModelAndView() override;
+    virtual void setupUI() override;
+    virtual QString deleteErrorString(int rowId) override;
+    virtual QString confirmDeleteString(int rowId) override;
+    virtual EntryEditDialog *getEntryEditDialog(QWidget *parent) override;
+
+private:
+    const int COL_ROWID = 0;
+    const int COL_REGISTRATION = 1;
+    const int COL_TYPE = 10;
+    const int COL_COMPANY = 3;
+
+    const int COLS_TO_HIDE[8] = {0, 2, 4, 5, 6, 7, 8, 9};
+
+    const QString COLUMN_NAME_REGISTRATION = tr("Registration");
+    const QString COLUMN_NAME_TYPE = tr("Type");
+    const QString COLUMN_NAME_COMPANY = tr("Company");
+
+    const QStringList FILTER_COLUMNS = {
+        COLUMN_NAME_REGISTRATION,
+        COLUMN_NAME_TYPE,
+        COLUMN_NAME_COMPANY,
+    };
+
+private slots:
+
+    virtual void filterTextChanged(const QString &filterString) override;
+};
+
+#endif // TAILTABLEEDITWIDGET_H