Преглед изворни кода

Added Simulator Logging to Toolbar and viewing/editing to Logbookwidget

- Added a view with Simulators Only to Database
- NewSimDialog now supports editing as well as creating entries
- Logbookwidget can now display Simulator Entries, distinguish between Simulator and Flight Entries, and create the correct Dialog for editing each.
Felix Turo пре 3 година
родитељ
комит
19b54fb77c

+ 1 - 1
mainwindow.cpp

@@ -30,7 +30,7 @@
 // Quick and dirty Debug area
 void MainWindow::doDebugStuff()
 {
-    auto nsd = new NewSimDialog(this);
+    auto nsd = new NewSimDialog(1, this);
     nsd->exec();
 }
 

+ 8 - 8
mainwindow.h

@@ -56,32 +56,32 @@ QT_END_NAMESPACE
  * \details The Tool bar contains shortcuts to the different widgets, which are on selection set active on the stacked main widget.
  * For a detailed description of what each widget does, please refer to the documentation for each widget. This is only a short synopsis:
  *
- * # HomeWidget
+ * ## HomeWidget
  *
  * The home widget displays the total amount of hours for all logged flights, seperated into different categories. It also enables keeping track
  * of currencies and license expiries
  *
- * # New Flight
+ * ## New Flight
  *
  * Opens a NewFlightDialog which can be used to submit a new flight to the database.
  *
- * # Logboook
+ * ## Logboook
  *
  * Shows a view of the logbook table in a QTableView and enables editing the entries by spawning a child NewFlightDialog with the details for a selected flight.
  *
- * # Aircraft
+ * ## Aircraft
  *
  * Shows a view of the tails table in a QTableView and enables editing the entries by spawning a child NewTailDialog with the details for a selected tail.
  *
- * # Pilots
+ * ## Pilots
  *
  * Shows a view of the pilots table in a QTableView and enables editing the entries by spawning a child NewPilotDialog with the details for a selected pilot.
  *
- * # Backup
+ * ## Backup
  *
  * Enables backing up and restoring the database.
  *
- * # Settings
+ * ## Settings
  *
  * Enables changing application settings
 */
@@ -175,7 +175,7 @@ protected:
      */
     void resizeEvent(QResizeEvent *event) override
     {
-        LOG << "SIZE:" << this->size();
+        //DEB << "SIZE:" << this->size();
         int icon_size;
         if (this->height() < 760)
             icon_size = (this->height() / 16);

+ 2 - 0
src/classes/aentry.h

@@ -47,6 +47,8 @@ public:
     void setPosition(DataPosition position_);
 
     const DataPosition& getPosition() const;
+    const TableName_T &getTableName() const { return position.tableName; }
+    const RowId_T &getRowId() const { return position.rowId; }
     const RowData_T& getData() const;
 
     /*!

+ 1 - 1
src/classes/aflightentry.cpp

@@ -39,7 +39,7 @@ const QString AFlightEntry::summary()
         return QString();
 
     QString flight_summary;
-    auto space = QStringLiteral(" ");
+    auto space = QLatin1Char(' ');
     flight_summary.append(tableData.value(OPL::Db::FLIGHTS_DOFT).toString() + space);
     flight_summary.append(tableData.value(OPL::Db::FLIGHTS_DEPT).toString() + space);
     flight_summary.append(ATime::toString(tableData.value(OPL::Db::FLIGHTS_TOFB).toInt())

+ 7 - 0
src/database/adatabase.cpp

@@ -493,6 +493,13 @@ AFlightEntry ADatabase::getFlightEntry(RowId_T row_id)
     return flight_entry;
 }
 
+ASimulatorEntry ADatabase::getSimEntry(RowId_T row_id)
+{
+    ASimulatorEntry sim_entry(row_id);
+    sim_entry.setData(getEntryData(sim_entry.getPosition()));
+    return sim_entry;
+}
+
 ACurrencyEntry ADatabase::getCurrencyEntry(ACurrencyEntry::CurrencyName currency_name)
 {
     ACurrencyEntry currency_entry(currency_name);

+ 25 - 5
src/database/adatabase.h

@@ -39,6 +39,7 @@
 #include "src/classes/aflightentry.h"
 #include "src/classes/astandardpaths.h"
 #include "src/classes/acurrencyentry.h"
+#include "src/classes/asimulatorentry.h"
 
 #define SQLITE_DRIVER QStringLiteral("QSQLITE")
 
@@ -68,13 +69,22 @@ enum class ADatabaseTarget
     aircraft
 };
 
+/*!
+ * \brief enumarates the tables in the database
+ */
 enum class ADatabaseTable
 {
-    tails,
-    flights,
-    currencies,
-    aircraft,
-    pilots,
+    // user tables
+    tails = 0,
+    pilots = 1,
+    flights = 2,
+    simulators = 3,
+    currencies = 4,
+
+    // template tables
+    aircraft = 4,
+    airports = 5,
+    changelog = 7,
 };
 
 /*!
@@ -306,6 +316,16 @@ public:
      */
     AFlightEntry getFlightEntry(RowId_T row_id);
 
+    /*!
+     * \brief retreives a Simulator entry from the database.
+     *
+     * This function is a wrapper for DataBase::getEntry(DataPosition),
+     * where the table is already set and which returns an ASimEntry
+     * instead of an AEntry. It allows for easy access to a Simulator entry
+     * with only the RowId required as input.
+     */
+    ASimulatorEntry getSimEntry(RowId_T row_id);
+
     /*!
      * \brief Retreives a currency entry from the database.
      */

+ 14 - 2
src/database/adbsetup.cpp

@@ -190,7 +190,7 @@ const static auto CREATE_VIEW_DEFAULT_SIM = QStringLiteral( "CREATE VIEW viewDef
         " FROM flights  "
         " INNER JOIN pilots on flights.pic = pilots.pilot_id  INNER JOIN tails on flights.acft = tails.tail_id  "
         " UNION"
-        " SELECT session_id,"
+        " SELECT (session_id * -1),"
         " date,"
         " null,"
         " null,"
@@ -269,7 +269,7 @@ const static auto CREATE_VIEW_EASA_SIM = QStringLiteral(" CREATE VIEW viewEasaSi
             " INNER JOIN pilots on flights.pic = pilots.pilot_id   "
             " INNER JOIN tails on flights.acft = tails.tail_id   "
             " UNION "
-            " SELECT session_id, "
+            " SELECT (session_id * -1), "
             " date, "
             " null, "
             " null, "
@@ -297,6 +297,17 @@ const static auto CREATE_VIEW_EASA_SIM = QStringLiteral(" CREATE VIEW viewEasaSi
             " ORDER BY date DESC "
             );
 
+const static auto CREATE_VIEW_SIMULATORS = QStringLiteral (" CREATE VIEW viewSimulators AS SELECT (session_id * -1), "
+                                                           " date as 'Date', "
+                                                           " registration AS 'Registration',  "
+                                                           " aircraftType AS 'Aircraft Type',  "
+                                                           " deviceType 'Sim Type', "
+                                                           " printf('%02d',(totalTime/60))||':'||printf('%02d',(totalTime%60)) AS 'Time of Session', "
+                                                           " remarks AS 'Remarks' "
+                                                           " FROM simulators "
+                                                           " ORDER BY date DESC "
+            );
+
 const static auto CREATE_VIEW_TAILS = QStringLiteral("CREATE VIEW viewTails AS "
         " SELECT "
         " tail_id AS 'ID', "
@@ -360,6 +371,7 @@ const static QStringList DATABASE_VIEWS = {
     CREATE_VIEW_DEFAULT_SIM,
     CREATE_VIEW_EASA,
     CREATE_VIEW_EASA_SIM,
+    CREATE_VIEW_SIMULATORS,
     CREATE_VIEW_TAILS,
     CREATE_VIEW_PILOTS,
     CREATE_VIEW_TOTALS,

+ 65 - 21
src/gui/dialogues/newsimdialog.cpp

@@ -4,21 +4,60 @@
 #include "src/functions/atime.h"
 #include "src/functions/adate.h"
 #include <QCompleter>
-
+/*!
+ * \brief create a NewSimDialog to add a new Simulator Entry to the database
+ */
 NewSimDialog::NewSimDialog(QWidget *parent) :
     QDialog(parent),
     ui(new Ui::NewSimDialog)
 {
+    entry = ASimulatorEntry();
     ui->setupUi(this);
     ui->dateLineEdit->setText(ADate::currentDate());
-    OPL::GLOBALS->loadSimulatorTypes(ui->typeComboBox);
+    init();
+}
+/*!
+ * \brief create a NewSimDialog to edit an existing Simulator Entry
+ * \param row_id of the entry to be edited
+ */
+NewSimDialog::NewSimDialog(RowId_T row_id, QWidget *parent) :
+    QDialog(parent),
+    ui(new Ui::NewSimDialog)
+{
+
+    ui->setupUi(this);
+    entry = aDB->getSimEntry(row_id);
+    init();
+    fillEntryData();
+}
+
+/*!
+ * \brief set up the UI with Combo Box entries and QCompleter
+ */
+void NewSimDialog::init()
+{
+    OPL::GLOBALS->loadSimulatorTypes(ui->deviceTypeComboBox);
 
     const QStringList aircraft_list = aDB->getCompletionList(ADatabaseTarget::aircraft);
-    auto completer = new QCompleter(aircraft_list, ui->acftLineEdit);
+    auto completer = new QCompleter(aircraft_list, ui->aircraftTypeLineEdit);
     completer->setCaseSensitivity(Qt::CaseInsensitive);
     completer->setCompletionMode(QCompleter::PopupCompletion);
     completer->setFilterMode(Qt::MatchContains);
-    ui->acftLineEdit->setCompleter(completer);
+    ui->aircraftTypeLineEdit->setCompleter(completer);
+}
+
+/*!
+ * \brief fills the UI with data retreived from an existing entry.
+ */
+void NewSimDialog::fillEntryData()
+{
+    const auto& data = entry.getData();
+    ui->dateLineEdit->setText(data.value(OPL::Db::SIMULATORS_DATE).toString());
+    ui->totalTimeLineEdit->setText(ATime::toString(data.value(OPL::Db::SIMULATORS_TIME).toInt()));
+    ui->deviceTypeComboBox->setCurrentIndex(data.value(OPL::Db::SIMULATORS_TYPE).toInt());
+    ui->aircraftTypeLineEdit->setText(data.value(OPL::Db::SIMULATORS_ACFT).toString());
+    ui->registrationLineEdit->setText(data.value(OPL::Db::SIMULATORS_REG).toString());
+    ui->remarksLineEdit->setText(data.value(OPL::Db::SIMULATORS_REMARKS).toString());
 }
 
 NewSimDialog::~NewSimDialog()
@@ -43,17 +82,17 @@ void NewSimDialog::on_dateLineEdit_editingFinished()
 }
 
 
-void NewSimDialog::on_timeLineEdit_editingFinished()
+void NewSimDialog::on_totalTimeLineEdit_editingFinished()
 {
-    const QString time_string = ATime::formatTimeInput(ui->timeLineEdit->text());
+    const QString time_string = ATime::formatTimeInput(ui->totalTimeLineEdit->text());
     const QTime time = ATime::fromString(time_string);
 
     if (time.isValid()) {
-        ui->timeLineEdit->setText(time_string);
-        ui->timeLineEdit->setStyleSheet(QString());
+        ui->totalTimeLineEdit->setText(time_string);
+        ui->totalTimeLineEdit->setStyleSheet(QString());
     } else {
-        ui->timeLineEdit->setText(QString());
-        ui->timeLineEdit->setStyleSheet(OPL::Styles::RED_BORDER);
+        ui->totalTimeLineEdit->setText(QString());
+        ui->totalTimeLineEdit->setStyleSheet(OPL::Styles::RED_BORDER);
     }
 }
 
@@ -88,19 +127,19 @@ bool NewSimDialog::verifyInput(QString& error_msg)
         return false;
     }
     // Time
-    const QString time_string = ATime::formatTimeInput(ui->timeLineEdit->text());
+    const QString time_string = ATime::formatTimeInput(ui->totalTimeLineEdit->text());
     const QTime time = ATime::fromString(time_string);
 
     if (!time.isValid()) {
-        ui->timeLineEdit->setStyleSheet(OPL::Styles::RED_BORDER);
-        ui->timeLineEdit->setText(QString());
+        ui->totalTimeLineEdit->setStyleSheet(OPL::Styles::RED_BORDER);
+        ui->totalTimeLineEdit->setText(QString());
         error_msg = tr("Invalid time");
         return false;
     }
 
     // Device Type - for FSTD, aircraft info is required
-    if (ui->typeComboBox->currentIndex() == OPL::SimulatorType::FSTD
-            && ui->acftLineEdit->text() == QString()) {
+    if (ui->deviceTypeComboBox->currentIndex() == OPL::SimulatorType::FSTD
+            && ui->aircraftTypeLineEdit->text() == QString()) {
         error_msg = tr("For FSTD, please enter the aircraft type.");
         return false;
     }
@@ -114,11 +153,11 @@ RowData_T NewSimDialog::collectInput()
     // Date
     new_entry.insert(OPL::Db::SIMULATORS_DATE, ui->dateLineEdit->text());
     // Time
-    new_entry.insert(OPL::Db::SIMULATORS_TIME, ATime::toMinutes(ui->timeLineEdit->text()));
+    new_entry.insert(OPL::Db::SIMULATORS_TIME, ATime::toMinutes(ui->totalTimeLineEdit->text()));
     // Device Type
-    new_entry.insert(OPL::Db::SIMULATORS_TYPE, ui->typeComboBox->currentText());
+    new_entry.insert(OPL::Db::SIMULATORS_TYPE, ui->deviceTypeComboBox->currentText());
     // Aircraft Type
-    new_entry.insert(OPL::Db::SIMULATORS_ACFT, ui->acftLineEdit->text());
+    new_entry.insert(OPL::Db::SIMULATORS_ACFT, ui->aircraftTypeLineEdit->text());
     // Registration
     if (!ui->registrationLineEdit->text().isEmpty())
         new_entry.insert(OPL::Db::SIMULATORS_REG, ui->registrationLineEdit->text());
@@ -137,7 +176,12 @@ void NewSimDialog::on_buttonBox_accepted()
         return;
     }
 
-    auto sim_entry = ASimulatorEntry(collectInput());
-    DEB << sim_entry;
-    aDB->commit(sim_entry);
+    entry.setData(collectInput());
+
+    DEB << entry;
+
+    if(aDB->commit(entry))
+        QDialog::accept();
+    else
+        WARN(tr("Unable to commit entry to database. The following error has ocurred <br><br>%1").arg(aDB->lastError.text()));
 }

+ 15 - 2
src/gui/dialogues/newsimdialog.h

@@ -10,12 +10,22 @@ namespace Ui {
 class NewSimDialog;
 }
 
+/*!
+ * \brief The NewSimDialog class enables adding a new Simulator Session to the database or editing an existing one.
+ * \details The NewSimDialog offers two constructors, one is used to create a new Simulator Entry
+ * from scratch, while the other one is used to edit an existing entry. The existing entry
+ * is identified by its ROW ID in the database and is then retreived, its data being used
+ * to pre-fill the UI to enable editing the existing data.
+ *
+ * A QCompleter provides in-line completion for the aircraft type field.
+ */
 class NewSimDialog : public QDialog
 {
     Q_OBJECT
 
 public:
     explicit NewSimDialog(QWidget *parent = nullptr);
+    explicit NewSimDialog(RowId_T row_id, QWidget *parent = nullptr);
     ~NewSimDialog();
 
 private slots:
@@ -23,7 +33,7 @@ private slots:
 
     void on_dateLineEdit_editingFinished();
 
-    void on_timeLineEdit_editingFinished();
+    void on_totalTimeLineEdit_editingFinished();
 
     void on_helpPushButton_clicked();
 
@@ -31,9 +41,12 @@ private slots:
 
 private:
     Ui::NewSimDialog *ui;
-
+    void init();
+    void fillEntryData();
     bool verifyInput(QString &error_msg);
     RowData_T collectInput();
+
+    ASimulatorEntry entry;
 };
 
 #endif // NEWSIMDIALOG_H

+ 6 - 6
src/gui/dialogues/newsimdialog.ui

@@ -43,7 +43,7 @@
     </widget>
    </item>
    <item row="2" column="1">
-    <widget class="QComboBox" name="typeComboBox">
+    <widget class="QComboBox" name="deviceTypeComboBox">
      <property name="minimumSize">
       <size>
        <width>160</width>
@@ -63,7 +63,7 @@
     </widget>
    </item>
    <item row="1" column="1">
-    <widget class="QLineEdit" name="timeLineEdit">
+    <widget class="QLineEdit" name="totalTimeLineEdit">
      <property name="minimumSize">
       <size>
        <width>160</width>
@@ -90,7 +90,7 @@
     </widget>
    </item>
    <item row="3" column="1">
-    <widget class="QLineEdit" name="acftLineEdit">
+    <widget class="QLineEdit" name="aircraftTypeLineEdit">
      <property name="minimumSize">
       <size>
        <width>160</width>
@@ -146,9 +146,9 @@
  </widget>
  <tabstops>
   <tabstop>dateLineEdit</tabstop>
-  <tabstop>timeLineEdit</tabstop>
-  <tabstop>typeComboBox</tabstop>
-  <tabstop>acftLineEdit</tabstop>
+  <tabstop>totalTimeLineEdit</tabstop>
+  <tabstop>deviceTypeComboBox</tabstop>
+  <tabstop>aircraftTypeLineEdit</tabstop>
   <tabstop>registrationLineEdit</tabstop>
   <tabstop>remarksLineEdit</tabstop>
  </tabstops>

+ 54 - 35
src/gui/widgets/logbookwidget.cpp

@@ -22,6 +22,7 @@
 #include "src/database/adatabase.h"
 #include "src/classes/asettings.h"
 #include "src/gui/dialogues/newflightdialog.h"
+#include "src/gui/dialogues/newsimdialog.h"
 #include "src/functions/alog.h"
 #include "src/functions/alog.h"
 
@@ -102,9 +103,6 @@ void LogbookWidget::changeEvent(QEvent *event)
         if(event->type() == QEvent::LanguageChange)
             ui->retranslateUi(this);
 }
-/*
- * Slots
- */
 
 /*!
  * \brief LogbookWidget::flightsTableView_selectionChanged saves the selected row(s)
@@ -112,13 +110,17 @@ void LogbookWidget::changeEvent(QEvent *event)
  */
 void LogbookWidget::flightsTableView_selectionChanged()
 {
-    selectedFlights.clear();
+    selectedEntries.clear();
     for (const auto& row : selectionModel->selectedRows()) {
-        selectedFlights.append(row.data().toInt());
-        DEB << "Selected Flight(s) with ID: " << selectedFlights;
+        selectedEntries.append(row.data().toInt());
+        DEB << "Selected Flight(s) with ID: " << selectedEntries;
+    }
+    if (selectedEntries.length() == 1) {
+        if (isFlight(selectedEntries.first()))
+            on_actionEdit_Flight_triggered();
+        else
+            on_actionEdit_Sim_triggered();
     }
-    if (selectedFlights.length() == 1)
-        on_actionEdit_Flight_triggered();
 }
 
 /*!
@@ -127,14 +129,14 @@ void LogbookWidget::flightsTableView_selectionChanged()
  */
 void LogbookWidget::on_actionDelete_Flight_triggered()
 {
-    DEB << "Flights selected: " << selectedFlights.length();
-    if (selectedFlights.length() == 0) {
+    DEB << "Flights selected: " << selectedEntries.length();
+    if (selectedEntries.length() == 0) {
         WARN(tr("<br>No flight selected.<br>"));
         return;
-    } else if (selectedFlights.length() > 0 && selectedFlights.length() <= 10) {
+    } else if (selectedEntries.length() > 0 && selectedEntries.length() <= 10) {
         QVector<AFlightEntry> flights_list;
 
-        for (const auto &flight_id : qAsConst(selectedFlights)) {
+        for (const auto &flight_id : qAsConst(selectedEntries)) {
             flights_list.append(aDB->getFlightEntry(flight_id));
         }
 
@@ -164,10 +166,10 @@ void LogbookWidget::on_actionDelete_Flight_triggered()
                 }
             }
             INFO(tr("%1 flights have been deleted successfully."
-                                   ).arg(QString::number(selectedFlights.length())));
+                                   ).arg(QString::number(selectedEntries.length())));
             displayModel->select();
         }
-    } else if (selectedFlights.length() > 10) {
+    } else if (selectedEntries.length() > 10) {
         QMessageBox confirm;
         confirm.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
         confirm.setDefaultButton(QMessageBox::No);
@@ -176,10 +178,10 @@ void LogbookWidget::on_actionDelete_Flight_triggered()
         confirm.setText(tr("You have selected %1 flights.<br><br>"
                            "Deleting flights is irreversible.<br><br>"
                            "Are you sure you want to proceed?"
-                           ).arg(QString::number(selectedFlights.length())));
+                           ).arg(QString::number(selectedEntries.length())));
         if(confirm.exec() == QMessageBox::Yes) {
             QList<DataPosition> selected_flights;
-            for (const auto& flight_id : qAsConst(selectedFlights)) {
+            for (const auto& flight_id : qAsConst(selectedEntries)) {
                 selected_flights.append({QStringLiteral("flights"), flight_id});
             }
             if (!aDB->removeMany(selected_flights)) {
@@ -187,7 +189,7 @@ void LogbookWidget::on_actionDelete_Flight_triggered()
                 return;
             }
             INFO(tr("%1 flights have been deleted successfully."
-                                   ).arg(QString::number(selectedFlights.length())));
+                                   ).arg(QString::number(selectedEntries.length())));
             displayModel->select();
         }
         displayModel->select();
@@ -200,24 +202,6 @@ void LogbookWidget::on_tableView_customContextMenuRequested(const QPoint &pos)
     menu->popup(ui->tableView->viewport()->mapToGlobal(pos));
 }
 
-void LogbookWidget::on_actionEdit_Flight_triggered()
-{
-    completionData.update();
-    if(selectedFlights.length() == 1){
-        NewFlightDialog nff(completionData,selectedFlights.first(), this);
-        ui->stackedWidget->addWidget(&nff);
-        ui->stackedWidget->setCurrentWidget(&nff);
-        nff.setWindowFlag(Qt::Widget);
-        nff.exec();
-        displayModel->select();
-    } else if (selectedFlights.isEmpty()) {
-        WARN(tr("<br>No flight selected.<br>"));
-    } else {
-        WARN(tr("<br>More than one flight selected."
-                               "<br><br>Editing multiple entries is not yet supported."));
-    }
-}
-
 void LogbookWidget::on_tableView_doubleClicked()
 {
     on_actionEdit_Flight_triggered();
@@ -298,3 +282,38 @@ void LogbookWidget::on_viewsComboBox_currentIndexChanged(int index)
     setupModelAndView(index);
 }
 
+void LogbookWidget::on_actionEdit_Flight_triggered()
+{
+    completionData.update();
+    if(selectedEntries.length() == 1){
+        NewFlightDialog nff(completionData,selectedEntries.first(), this);
+        ui->stackedWidget->addWidget(&nff);
+        ui->stackedWidget->setCurrentWidget(&nff);
+        nff.setWindowFlag(Qt::Widget);
+        nff.exec();
+        displayModel->select();
+    } else if (selectedEntries.isEmpty()) {
+        WARN(tr("<br>No flight selected.<br>"));
+    } else {
+        WARN(tr("<br>More than one flight selected."
+                               "<br><br>Editing multiple entries is not yet supported."));
+    }
+}
+
+void LogbookWidget::on_actionEdit_Sim_triggered()
+{
+    if (selectedEntries.length() == 1) {
+        NewSimDialog nsd((selectedEntries.first() * -1), this);
+        ui->stackedWidget->addWidget(&nsd);
+        ui->stackedWidget->setCurrentWidget(&nsd);
+        nsd.setWindowFlag(Qt::Widget);
+        nsd.exec();
+        displayModel->select();
+    } else if (selectedEntries.isEmpty()) {
+        WARN(tr("<br>No flight selected.<br>"));
+    } else {
+        WARN(tr("<br>More than one flight selected."
+                               "<br><br>Editing multiple entries is not yet supported."));
+    }
+}
+

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

@@ -56,13 +56,16 @@ private slots:
     void flightsTableView_selectionChanged();
     void on_tableView_customContextMenuRequested(const QPoint &pos);
     void on_actionDelete_Flight_triggered();
-    void on_actionEdit_Flight_triggered();
+
     void on_tableView_doubleClicked();
     void on_flightSearchLlineEdit_textChanged(const QString &arg1);
     void on_flightSearchComboBox_currentIndexChanged(int);
 
     void on_viewsComboBox_currentIndexChanged(int index);
 
+    void on_actionEdit_Flight_triggered();
+    void on_actionEdit_Sim_triggered();
+
 public slots:
     void refresh();
     void onLogbookWidget_viewSelectionChanged(SettingsWidget::SettingSignal signal);
@@ -79,13 +82,22 @@ private:
 
     QMenu* menu;
 
-    QVector<qint32> selectedFlights;
+    QVector<qint32> selectedEntries;
 
     void setupModelAndView(int view_id);
     void connectSignalsAndSlots();
 
     ACompletionData 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
+     * \details In the composite views (SQL UNION) with Simulators included, the row_id of the
+     * simulator entries is inverted to a negative value. A positive row id is thus a row id from
+     * the flights table, whereas a negative rowid is a row id from the simulators table.
+     */
+    inline bool isFlight(int model_row_id) { return model_row_id > 0; }
+
 protected:
     /*!
      * \brief Handles change events, like updating the UI to new localisation

+ 8 - 0
src/gui/widgets/logbookwidget.ui

@@ -155,6 +155,14 @@
     <string>Delete Flight</string>
    </property>
   </action>
+  <action name="actionEdit_Sim">
+   <property name="text">
+    <string>Edit_Sim</string>
+   </property>
+   <property name="toolTip">
+    <string>Edit an existing Simulator Entry</string>
+   </property>
+  </action>
  </widget>
  <resources/>
  <connections/>

+ 3 - 1
src/opl.h

@@ -108,7 +108,7 @@ enum Translation {English, German, Spanish};
 /*!
  * \brief Enumerates the available SQL views in the database
  */
-enum DbViewName {Default, DefaultWithSim, Easa, EasaWithSim};
+enum DbViewName {Default, DefaultWithSim, Easa, EasaWithSim, SimulatorOnly};
 
 /*!
  * \brief Enumerates the Simulator Types: Flight and Navigation Procedures Trainer 1/2, Flight Simulation Training Device
@@ -152,12 +152,14 @@ private:
         {DefaultWithSim, QStringLiteral("viewDefaultSim")},
         {Easa,           QStringLiteral("viewEasa")},
         {EasaWithSim,    QStringLiteral("viewEasaSim")},
+        {SimulatorOnly,  QStringLiteral("viewSimulators")},
     };
     const QMap<DbViewName, QString> DATABASE_VIEW_DISPLAY_NAMES = {
         {Default,        tr("Default")},
         {DefaultWithSim, tr("Default with Simulator")},
         {Easa,           tr("EASA-FCL")},
         {EasaWithSim,    tr("EASA-FCL with Simulator")},
+        {SimulatorOnly,  tr("Simulator Sessions Only")},
     };
     const QMap<PilotFunction, QLatin1String> PILOT_FUNCTIONS = {
         {PilotFunction::PIC,   QLatin1String("PIC")},