Explorar o código

Migrated deleting to new DB architecture

Deleting flights in the logbookwidget is now done using the new DB architecture. Implemented signals and slots, did some preliminary testing.
Added a function for batch-deleting flights, optimised for larger selections. Used when deleting more than 10 flights at once.
Felix Turo %!s(int64=4) %!d(string=hai) anos
pai
achega
b38fe82260

+ 69 - 1
src/experimental/adatabase.cpp

@@ -108,6 +108,46 @@ bool ADataBase::remove(AEntry entry)
     }
 }
 
+bool ADataBase::removeMany(QList<DataPosition> data_position_list)
+{
+    int errorCount = 0;
+    QSqlQuery query;
+    query.prepare("BEGIN EXCLUSIVE TRANSACTION");
+    query.exec();
+
+    for (const auto data_position : data_position_list) {
+        if (!exists(data_position)) {
+            DEB("Error: Entry does not exist.");
+            errorCount++;
+        }
+        QString statement = "DELETE FROM " + data_position.first +
+                " WHERE ROWID=" + QString::number(data_position.second);
+
+        query.prepare(statement);
+        query.exec();
+
+        if (!(query.lastError().type() == QSqlError::NoError))
+            errorCount++;
+    }
+
+    if (errorCount == 0) {
+        query.prepare("COMMIT");
+        query.exec();
+        if(query.lastError().type() == QSqlError::NoError) {
+            emit sqlSuccessful();
+            return true;
+        } else {
+            emit sqlError(query.lastError(), "Transaction unsuccessful. Error count: " + QString::number(errorCount));
+            return false;
+        }
+    } else {
+        query.prepare("ROLLBACK");
+        query.exec();
+        emit sqlError(query.lastError(), "Transaction unsuccessful(rolled back). Error count: " + QString::number(errorCount));
+        return false;
+    }
+}
+
 bool ADataBase::exists(AEntry entry)
 {
     if(entry.getPosition().second == 0)
@@ -116,11 +156,11 @@ bool ADataBase::exists(AEntry entry)
     //Check database for row id
     QString statement = "SELECT COUNT(*) FROM " + entry.getPosition().tableName +
             " WHERE ROWID=" + QString::number(entry.getPosition().rowId);
-    //this returns either 1 or 0 since row ids are unique
     QSqlQuery query;
     query.prepare(statement);
     query.setForwardOnly(true);
     query.exec();
+    //this returns either 1 or 0 since row ids are unique
     if (!query.isActive()) {
         emit sqlError(query.lastError(), statement);
         DEB("Query Error: " << query.lastError().text() << statement);
@@ -136,6 +176,34 @@ bool ADataBase::exists(AEntry entry)
     }
 }
 
+bool ADataBase::exists(DataPosition data_position)
+{
+    if(data_position.second == 0)
+        return false;
+
+    //Check database for row id
+    QString statement = "SELECT COUNT(*) FROM " + data_position.first +
+            " WHERE ROWID=" + QString::number(data_position.second);
+    QSqlQuery query;
+    query.prepare(statement);
+    query.setForwardOnly(true);
+    query.exec();
+    //this returns either 1 or 0 since row ids are unique
+    if (!query.isActive()) {
+        emit sqlError(query.lastError(), statement);
+        DEB("Query Error: " << query.lastError().text() << statement);
+    }
+    query.next();
+    int rowId = query.value(0).toInt();
+    if (rowId) {
+        DEB("Entry exists at DataPosition: " << data_position);
+        return true;
+    } else {
+        DEB("No entry exists at DataPosition: " << data_position);
+        return false;
+    }
+}
+
 
 bool ADataBase::update(AEntry updated_entry)
 {

+ 7 - 0
src/experimental/adatabase.h

@@ -85,6 +85,7 @@ public:
      * \brief Checks if an entry exists in the database, based on position data
      */
     bool exists(AEntry entry);
+    bool exists(DataPosition data_position);
 
     /*!
      * \brief commits an entry to the database, calls either insert or update,
@@ -107,6 +108,12 @@ public:
      */
     bool remove(AEntry entry);
 
+    /*!
+     * \brief deletes a list of entries from the database. Optimised for speed when
+     * deleting many entries.
+     */
+    bool removeMany(QList<DataPosition>);
+
     /*!
      * \brief retreive entry data from the database to create an entry object
      */

+ 3 - 3
src/experimental/aflightentry.cpp

@@ -15,7 +15,7 @@ AFlightEntry::AFlightEntry(TableData table_data)
     : AEntry::AEntry(DEFAULT_FLIGHT_POSITION, table_data)
 {}
 
-QString AFlightEntry::summary()
+const QString AFlightEntry::summary()
 {
     if(tableData.isEmpty())
         return QString();
@@ -30,7 +30,7 @@ QString AFlightEntry::summary()
     return flight_summary;
 }
 
-QString AFlightEntry::registration()
+const QString AFlightEntry::registration()
 {
     QString tail_id = tableData.value("acft");
     if(tail_id.isEmpty())
@@ -49,7 +49,7 @@ QString AFlightEntry::registration()
     }
 }
 
-QString AFlightEntry::pilotName(pilot pilot_)
+const QString AFlightEntry::pilotName(pilot pilot_)
 {
     QString row_id;
     switch (pilot_) {

+ 3 - 3
src/experimental/aflightentry.h

@@ -20,18 +20,18 @@ public:
      * \brief Returs a summary of the flight data
      * \return "doft, dept, tofb, dest, tonb"
      */
-    QString summary();
+    const QString summary();
     /*!
      * \brief Returns the tails' registration from the database.
      */
-    QString registration();
+    const QString registration();
     /*!
      * \brief Returns the pilots name from the Database
      *
      * \param pilot_number - 1=pic, 2=second Pilot, 3 = third Pilot
      * \return "Lastname, Firstname"
      */
-    QString pilotName(pilot);
+    const QString pilotName(pilot);
 };
 
 } // namespace experimental

+ 74 - 59
src/gui/widgets/logbookwidget.cpp

@@ -19,9 +19,12 @@
 #include "ui_logbookwidget.h"
 #include "src/testing/adebug.h"
 
-const QMap<int, QString> filterMap = {
-    {0, "Date LIKE \"%"}, {1, "Dept LIKE \"%"}, {2, "Dest LIKE \"%"},
-    {3, "Registration LIKE \"%"}, {4, "\"Name PIC\" LIKE \"%"}
+const QMap<int, QString> FILTER_MAP = {
+    {0, "Date LIKE \"%"},
+    {1, "Dept LIKE \"%"},
+    {2, "Dest LIKE \"%"},
+    {3, "Registration LIKE \"%"},
+    {4, "\"Name PIC\" LIKE \"%"}
 };
 const auto NON_WORD_CHAR = QRegularExpression("\\W");
 
@@ -38,7 +41,7 @@ LogbookWidget::LogbookWidget(QWidget *parent) :
     menu->addAction(ui->actionDelete_Flight);
 
     //Initialise message Box
-    nope = new QMessageBox(this);
+    messageBox = new QMessageBox(this);
 
     prepareModelAndView(ASettings::read("logbook/view").toInt());
     connectSignalsAndSlots();
@@ -72,6 +75,11 @@ void LogbookWidget::connectSignalsAndSlots()
     selection = view->selectionModel();
     QObject::connect(view->selectionModel(), &QItemSelectionModel::selectionChanged,
                      this, &LogbookWidget::flightsTableView_selectionChanged);
+    using namespace experimental;
+    QObject::connect(aDB(), &ADataBase::sqlSuccessful,
+                     this, &LogbookWidget::onDeletedSuccessfully);
+    QObject::connect(aDB(), &ADataBase::sqlError,
+                     this, &LogbookWidget::onDeleteUnsuccessful);
 }
 
 void LogbookWidget::setupDefaultView()
@@ -180,31 +188,34 @@ void LogbookWidget::on_editFlightButton_clicked()
         ef->exec();
         displayModel->select();
     } else if (selectedFlights.isEmpty()) {
-        nope->setText("No flight selected.\n");
-        nope->exec();
+        messageBox->setText("No flight selected.\n");
+        messageBox->exec();
     } else {
-        nope->setText("More than one flight selected.\n\nEditing multiple entries is not yet supported.");
-        nope->exec();
+        messageBox->setText("More than one flight selected.\n\nEditing multiple entries is not yet supported.");
+        messageBox->exec();
     }
 }
 
 void LogbookWidget::on_deleteFlightPushButton_clicked()
 {
     DEB("Flights selected: " << selectedFlights.length());
-    if (selectedFlights.length() > 0 && selectedFlights.length() < 11) {
-        QVector<QString> columns = {
-            "doft", "dept", "dest"
-        };
-        QVector<QString> details;
+    if (selectedFlights.length() == 0) {
+        messageBox->setIcon(QMessageBox::Information);
+        messageBox->setText("No Flight Selected.");
+        messageBox->exec();
+        return;
+    } else if (selectedFlights.length() > 0 && selectedFlights.length() < 11) {
+        QList<experimental::AFlightEntry> flights_list;
+
+        for (const auto &flight_id : selectedFlights) {
+            flights_list.append(experimental::aDB()->getFlightEntry(flight_id));
+        }
+
         QString warningMsg = "The following flight(s) will be deleted:<br><br><b><tt>";
-        for(const auto& selectedFlight : selectedFlights){
-            details = Db::multiSelect(columns, "flights", "flight_id",
-                                       QString::number(selectedFlight), Db::exactMatch);
-            for (const auto &item : details) {
-                warningMsg.append(item);
-                warningMsg.append(' ');
-            }
-            warningMsg.append("<br>");
+
+        for (auto &flight : flights_list) {
+            warningMsg.append(flight.summary());
+            warningMsg.append(QLatin1String("&nbsp;&nbsp;&nbsp;&nbsp;<br>"));
         }
         warningMsg.append("</b></tt><br>Deleting Flights is irreversible."
                           "<br>Do you want to proceed?");
@@ -217,21 +228,16 @@ void LogbookWidget::on_deleteFlightPushButton_clicked()
         confirm.setText(warningMsg);
         int reply = confirm.exec();
         if (reply == QMessageBox::Yes) {
-            for (const auto& selectedFlight : selectedFlights) {
-                DEB("Deleting flight with ID# " << selectedFlight);
-                auto entry = Flight(selectedFlight);
-                entry.remove();
+            for (auto& flight : flights_list) {
+                DEB("Deleting flight: " << flight.summary());
+                experimental::aDB()->remove(flight);
             }
-            prepareModelAndView(ASettings::read("logbook/view").toInt());
+            displayModel->select();
         }
-    } else if (selectedFlights.length() == 0) {
-        nope->setIcon(QMessageBox::Information);
-        nope->setText("No Flight Selected.");
-        nope->exec();
     } else if (selectedFlights.length() > 10) {
         auto& warningMsg = "You have selected " + QString::number(selectedFlights.length())
-                         + " flights.\n\n Deleting these flights is irreversible.\n\n"
-                           "Are you sure you want to proceed?";
+                + " flights.\n\n Deleting flights is irreversible.\n\n"
+                  "Are you sure you want to proceed?";
         QMessageBox confirm;
         confirm.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
         confirm.setDefaultButton(QMessageBox::No);
@@ -240,23 +246,16 @@ void LogbookWidget::on_deleteFlightPushButton_clicked()
         confirm.setText(warningMsg);
         int reply = confirm.exec();
         if(reply == QMessageBox::Yes) {
-            for (const auto& selectedFlight : selectedFlights) {
-                DEB("Deleting flight with ID# " << selectedFlight);
-                auto entry = Flight(selectedFlight);
-                entry.remove();
+            QList<experimental::DataPosition> selected_flights;
+            for (const auto& flight_id : selectedFlights) {
+                selected_flights.append({"flights", flight_id});
             }
-            prepareModelAndView(ASettings::read("logbook/view").toInt());
+            experimental::aDB()->removeMany(selected_flights);
+            displayModel->select();
         }
     }
 }
 
-void LogbookWidget::on_showAllButton_clicked()
-{
-    ui->flightSearchLlineEdit->setText(QString());
-    displayModel->setFilter(QString());
-    displayModel->select();
-}
-
 void LogbookWidget::on_tableView_customContextMenuRequested(const QPoint &pos)
 {
     menu->popup(ui->tableView->viewport()->mapToGlobal(pos));
@@ -267,6 +266,19 @@ void LogbookWidget::on_actionDelete_Flight_triggered()
     emit ui->deleteFlightPushButton->clicked();
 }
 
+void LogbookWidget::onDeletedSuccessfully()
+{
+    messageBox->setText(QString::number(selectedFlights.length()) + " flights have been deleted.");
+    messageBox->exec();
+}
+
+void LogbookWidget::onDeleteUnsuccessful(const QSqlError error)
+{
+    messageBox->setText("Error deleting " + QString::number(selectedFlights.length())
+                        + " flights.\n\nThe following error has ocurred:\n\n" + error.text());
+    messageBox->exec();
+}
+
 void LogbookWidget::on_actionEdit_Flight_triggered()
 {
     emit ui->editFlightButton->clicked();
@@ -277,34 +289,37 @@ void LogbookWidget::on_tableView_doubleClicked()
     emit ui->editFlightButton->clicked();
 }
 
+void LogbookWidget::on_flightSearchComboBox_currentIndexChanged()
+{
+    emit ui->showAllButton->clicked();
+}
+
+void LogbookWidget::on_showAllButton_clicked()
+{
+    ui->flightSearchLlineEdit->setText(QString());
+    displayModel->setFilter(QString());
+    displayModel->select();
+}
+
 void LogbookWidget::on_flightSearchLlineEdit_textChanged(const QString &arg1)
 {
     if(arg1.length() == 0) {
-        DEB("Resetting filter...");
         displayModel->setFilter("");
         displayModel->select();
         return;
     }
 
     if (ui->flightSearchComboBox->currentIndex() < 3) {
-        displayModel->setFilter(filterMap.value(ui->flightSearchComboBox->currentIndex())
-                         + arg1 + "%\"");
-        //DEB("display model filter:" << displayModel->filter());
+        displayModel->setFilter(FILTER_MAP.value(ui->flightSearchComboBox->currentIndex())
+                                + arg1 + "%\"");
         return;
     } else if (ui->flightSearchComboBox->currentIndex() == 3) { // registration
-        displayModel->setFilter(filterMap.value(ui->flightSearchComboBox->currentIndex())
-                         + arg1 + "%\"");
-        //DEB("display model filter:" << displayModel->filter());
+        displayModel->setFilter(FILTER_MAP.value(ui->flightSearchComboBox->currentIndex())
+                                + arg1 + "%\"");
         return;
     } else if (ui->flightSearchComboBox->currentIndex() == 4) { // Name Pic
-        displayModel->setFilter(filterMap.value(ui->flightSearchComboBox->currentIndex())
-                         + arg1 + "%\"");
-        //DEB("display model filter:" << displayModel->filter());
+        displayModel->setFilter(FILTER_MAP.value(ui->flightSearchComboBox->currentIndex())
+                                + arg1 + "%\"");
         return;
     }
 }
-
-void LogbookWidget::on_flightSearchComboBox_currentIndexChanged()
-{
-    ui->flightSearchLlineEdit->setText(QString());
-}

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

@@ -60,6 +60,9 @@ private slots:
 
     void on_actionDelete_Flight_triggered();
 
+    void onDeletedSuccessfully();
+    void onDeleteUnsuccessful(const QSqlError);
+
     void on_actionEdit_Flight_triggered();
 
     void on_tableView_doubleClicked();
@@ -79,7 +82,7 @@ private:
 
     QMenu* menu;
 
-    QMessageBox* nope;
+    QMessageBox* messageBox;
 
     QVector<qint32> selectedFlights;
 

+ 4 - 1
src/gui/widgets/logbookwidget.ui

@@ -63,9 +63,12 @@
    </item>
    <item row="1" column="2">
     <widget class="QLineEdit" name="flightSearchLlineEdit">
-     <property name="whatsThis">
+     <property name="toolTip">
       <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Enter the searchterm you want to filter your flights by.&lt;/p&gt;&lt;p&gt;For dates, make sure to use the format YYYY-MM-DD&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
      </property>
+     <property name="whatsThis">
+      <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+     </property>
     </widget>
    </item>
    <item row="2" column="2" rowspan="2">