]> gitweb.stoutner.com Git - PrivacyBrowserPC.git/commitdiff
Add a durable cookies dialog.
authorSoren Stoutner <soren@stoutner.com>
Tue, 21 Jun 2022 20:43:00 +0000 (13:43 -0700)
committerSoren Stoutner <soren@stoutner.com>
Tue, 21 Jun 2022 20:43:00 +0000 (13:43 -0700)
15 files changed:
src/CMakeLists.txt
src/databases/CookiesDatabase.cpp
src/databases/CookiesDatabase.h
src/delegates/CMakeLists.txt [new file with mode: 0644]
src/delegates/ViewOnlyDelegate.cpp [new file with mode: 0644]
src/delegates/ViewOnlyDelegate.h [new file with mode: 0644]
src/dialogs/CMakeLists.txt
src/dialogs/CookiesDialog.cpp
src/dialogs/CookiesDialog.h
src/dialogs/DomainSettingsDialog.cpp
src/dialogs/DurableCookiesDialog.cpp [new file with mode: 0644]
src/dialogs/DurableCookiesDialog.h [new file with mode: 0644]
src/filters/MouseEventFilter.cpp
src/uis/CookiesDialog.ui
src/uis/DurableCookiesDialog.ui [new file with mode: 0644]

index fd274cef043d381d981fa04f0a3966d8599a2235..335a27d06975e7c32af2ea2db9b05f0e88418285 100644 (file)
@@ -39,6 +39,7 @@ ki18n_wrap_ui(privacy-browser
     uis/BrowserView.ui
     uis/CookiesDialog.ui
     uis/DomainSettingsDialog.ui
+    uis/DurableCookiesDialog.ui
     uis/SettingsGeneral.ui
     uis/SettingsPrivacy.ui
 )
@@ -63,6 +64,7 @@ target_link_libraries(privacy-browser
 
 # Add the subdirectories.
 add_subdirectory(databases)
+add_subdirectory(delegates)
 add_subdirectory(dialogs)
 add_subdirectory(filters)
 add_subdirectory(helpers)
index adc4f1ba2c108362e59bbcda99276a54c0e4f219..a99290985cd7c5f28e971c3e50250f2567aa5aec 100644 (file)
@@ -146,6 +146,33 @@ void CookiesDatabase::addCookie(const QNetworkCookie &cookie)
     }
 }
 
+int CookiesDatabase::cookieCount()
+{
+    // Get a handle for the cookies database.
+    QSqlDatabase cookiesDatabase = QSqlDatabase::database(CONNECTION_NAME);
+
+    // Instantiate a count cookies query.
+    QSqlQuery countCookiesQuery(cookiesDatabase);
+
+    // Set the query to be forward only.
+    countCookiesQuery.setForwardOnly(true);
+
+    // Prepare the query.
+    countCookiesQuery.prepare("SELECT " + _ID + " FROM " + COOKIES_TABLE);
+
+    // Execute the query.
+    countCookiesQuery.exec();
+
+    // Move to the last row.
+    countCookiesQuery.last();
+
+    // Get the number of rows (which is zero based).
+    int numberOfCookies = countCookiesQuery.at() + 1;
+
+    // Return the number of cookies.
+    return numberOfCookies;
+}
+
 void CookiesDatabase::deleteAllCookies()
 {
     // Get a handle for the cookies database.
@@ -224,6 +251,45 @@ QList<QNetworkCookie*>* CookiesDatabase::getCookies()
     return cookieListPointer;
 }
 
+QNetworkCookie* CookiesDatabase::getCookieById(const int &id)
+{
+    // Get a handle for the cookies database.
+    QSqlDatabase cookiesDatabase = QSqlDatabase::database(CONNECTION_NAME);
+
+    // Instantiate a cookie query.
+    QSqlQuery cookieQuery(cookiesDatabase);
+
+    // Set the query to be forward only.
+    cookieQuery.setForwardOnly(true);
+
+    // Prepare the cookies query.
+    cookieQuery.prepare("SELECT * FROM " + COOKIES_TABLE + " WHERE " + _ID + " = :id");
+
+    // Bind the values.
+    cookieQuery.bindValue(":id", id);
+
+    // Execute the query.
+    cookieQuery.exec();
+
+    // Move to the first entry.
+    cookieQuery.first();
+
+    // Create a cookie.
+    QNetworkCookie *cookiePointer = new QNetworkCookie();
+
+    // Populate the cookie.
+    cookiePointer->setDomain(cookieQuery.value(DOMAIN).toString());
+    cookiePointer->setName(cookieQuery.value(NAME).toString().toUtf8());
+    cookiePointer->setPath(cookieQuery.value(PATH).toString());
+    cookiePointer->setExpirationDate(QDateTime::fromString(cookieQuery.value(EXPIRATION_DATE).toString(), Qt::ISODate));
+    cookiePointer->setHttpOnly(cookieQuery.value(HTTP_ONLY).toBool());
+    cookiePointer->setSecure(cookieQuery.value(SECURE).toBool());
+    cookiePointer->setValue(cookieQuery.value(VALUE).toString().toUtf8());
+
+    // Return the cookie.
+    return cookiePointer;
+}
+
 bool CookiesDatabase::isDurable(const QNetworkCookie &cookie)
 {
     // Get a handle for the cookies database.
index 6fcae894242a2433b7d4c520748891ab891cedb2..76e788ca63572bc8dadb721ba12826666b46b944 100644 (file)
@@ -33,9 +33,11 @@ public:
     // The public functions.
     static void addDatabase();
     static void addCookie(const QNetworkCookie &cookie);
+    static int cookieCount();
     static void deleteAllCookies();
     static void deleteCookie(const QNetworkCookie &cookie);
     static QList<QNetworkCookie*>* getCookies();
+    static QNetworkCookie* getCookieById(const int &id);
     static bool isDurable(const QNetworkCookie &cookie);
     static bool isUpdate(const QNetworkCookie &cookie);
     static void updateCookie(const QNetworkCookie &cookie);
diff --git a/src/delegates/CMakeLists.txt b/src/delegates/CMakeLists.txt
new file mode 100644 (file)
index 0000000..d56c050
--- /dev/null
@@ -0,0 +1,22 @@
+# Copyright © 2022 Soren Stoutner <soren@stoutner.com>.
+#
+# This file is part of Privacy Browser PC <https://www.stoutner.com/privacy-browser-pc>.
+#
+# Privacy Browser PC is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Privacy Browser PC is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Privacy Browser PC.  If not, see <http://www.gnu.org/licenses/>.
+
+
+# List the sources to include in the executable.
+target_sources(privacy-browser PRIVATE
+    ViewOnlyDelegate.cpp
+)
diff --git a/src/delegates/ViewOnlyDelegate.cpp b/src/delegates/ViewOnlyDelegate.cpp
new file mode 100644 (file)
index 0000000..ab7f873
--- /dev/null
@@ -0,0 +1,34 @@
+ /*
+ * Copyright © 2022 Soren Stoutner <soren@stoutner.com>.
+ *
+ * This file is part of Privacy Browser PC <https://www.stoutner.com/privacy-browser-pc>.
+ *
+ * Privacy Browser PC is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Privacy Browser PC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Privacy Browser PC.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+// Application headers.
+#include "ViewOnlyDelegate.h"
+
+ViewOnlyDelegate::ViewOnlyDelegate(QObject *parentPointer) : QStyledItemDelegate(parentPointer) {}
+
+QWidget* ViewOnlyDelegate::createEditor(QWidget *parentWidgetPointer, const QStyleOptionViewItem &styleOptionsViewItem, const QModelIndex &modelIndex) const
+{
+    // Instruct the compiler to ignore the unused variables.
+    (void) parentWidgetPointer;
+    (void) styleOptionsViewItem;
+    (void) modelIndex;
+
+    // Disable editing.
+    return nullptr;
+}
diff --git a/src/delegates/ViewOnlyDelegate.h b/src/delegates/ViewOnlyDelegate.h
new file mode 100644 (file)
index 0000000..774335c
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright © 2022 Soren Stoutner <soren@stoutner.com>.
+ *
+ * This file is part of Privacy Browser PC <https://www.stoutner.com/privacy-browser-pc>.
+ *
+ * Privacy Browser PC is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Privacy Browser PC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Privacy Browser PC.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef VIEWONLYDELEGATE_H
+#define VIEWONLYDELEGATE_H
+
+// Qt toolkit headers.
+#include <QStyledItemDelegate>
+
+class ViewOnlyDelegate : public QStyledItemDelegate
+{
+    // Include the Q_OBJECT macro.
+    Q_OBJECT
+
+public:
+    // The default constructor.
+    explicit ViewOnlyDelegate(QObject *parentPointer = nullptr);
+
+    // The public functions.
+    QWidget* createEditor(QWidget *parentWidgetPointer, const QStyleOptionViewItem &styleOptionsViewItem, const QModelIndex &modelIndex) const override;
+};
+#endif
index 55f66fdf226a8463dd4621ea2123cfe6dcf46cd2..2b722cca588fa4c4333dff1faad664c01d76d878 100644 (file)
@@ -21,4 +21,5 @@ target_sources(privacy-browser PRIVATE
     AddOrEditCookieDialog.cpp
     CookiesDialog.cpp
     DomainSettingsDialog.cpp
+    DurableCookiesDialog.cpp
 )
index fa9679c457a4b4e58e906457cd367ca2ed577c30..612888d2e15fcc42e37ba765be9e6193dc1191ef 100644 (file)
@@ -20,6 +20,7 @@
 // Application headers.
 #include "AddOrEditCookieDialog.h"
 #include "CookiesDialog.h"
+#include "DurableCookiesDialog.h"
 #include "ui_CookiesDialog.h"
 #include "databases/CookiesDatabase.h"
 
@@ -32,7 +33,7 @@
 #include <QShortcut>
 #include <QUrl>
 
-// Construct the class.
+// Define the cookie sort predicate.
 bool cookieSortPredicate(const QNetworkCookie &leftHandCookie, const QNetworkCookie &rightHandCookie)
 {
     // Check to see if the domains are identical.
@@ -97,10 +98,10 @@ bool cookieSortPredicate(const QNetworkCookie &leftHandCookie, const QNetworkCoo
             // Sort the cookies by the top level domain.
             return (leftHandTopLevelDomain < rightHandTopLevelDomain);
         }
-
     }
 }
 
+// Construct the class.
 CookiesDialog::CookiesDialog(std::list<QNetworkCookie> *originalCookieListPointer) : QDialog(nullptr), cookieListPointer(originalCookieListPointer)
 {
     // Set the dialog window title.
@@ -217,7 +218,7 @@ CookiesDialog::CookiesDialog(std::list<QNetworkCookie> *originalCookieListPointe
     // Indicate that all the rows are the same height, wich improves performance.
     treeViewPointer->setUniformRowHeights(true);
 
-    // Disable editing.
+    // Disable editing in the tree view.
     treeViewPointer->setEditTriggers(QAbstractItemView::NoEditTriggers);
 
     // Set the tree model.
@@ -233,23 +234,26 @@ CookiesDialog::CookiesDialog(std::list<QNetworkCookie> *originalCookieListPointe
     addCookieButtonPointer = cookiesDialogUi.addCookieButton;
     editCookieButtonPointer = cookiesDialogUi.editCookieButton;
     deleteCookieButtonPointer = cookiesDialogUi.deleteCookieButton;
+    deleteAllButtonPointer = cookiesDialogUi.deleteAllCookiesButton;
     QDialogButtonBox *dialogButtonBoxPointer = cookiesDialogUi.dialogButtonBox;
     QPushButton *closeButtonPointer = dialogButtonBoxPointer->button(QDialogButtonBox::Close);
 
-    // Add a delete all button to the dialog button box.
-    deleteAllButtonPointer = dialogButtonBoxPointer->addButton(i18nc("Delete all cookies button", "Delete all"), QDialogButtonBox::ActionRole);
+    // Add buttons to the dialog button box.
+    durableCookiesButtonPointer = dialogButtonBoxPointer->addButton(i18nc("View the durable cookies button", "Durable cookies - %1", CookiesDatabase::cookieCount()),
+                                                                    QDialogButtonBox::ActionRole);
 
-    // Set the delete all button icon.
-    deleteAllButtonPointer->setIcon(QIcon::fromTheme("delete"));
+    // Set the button icons.
+    durableCookiesButtonPointer->setIcon(QIcon::fromTheme("view-visible"));
 
     // Connect the buttons.
     connect(addCookieButtonPointer, SIGNAL(clicked()), this, SLOT(showAddCookieDialog()));
     connect(editCookieButtonPointer, SIGNAL(clicked()), this, SLOT(showEditCookieDialog()));
     connect(deleteCookieButtonPointer, SIGNAL(clicked()), this, SLOT(showDeleteCookieMessageBox()));
+    connect(durableCookiesButtonPointer, SIGNAL(clicked()), this, SLOT(showDurableCookiesDialog()));
     connect(deleteAllButtonPointer, SIGNAL(clicked()), this, SLOT(showDeleteAllMessageBox()));
     connect(dialogButtonBoxPointer, SIGNAL(rejected()), this, SLOT(reject()));
 
-    // Set the cancel button to be the default.
+    // Set the close button to be the default.
     closeButtonPointer->setDefault(true);
 
     // Create the keyboard shortcuts.
@@ -484,6 +488,48 @@ void CookiesDialog::deleteDomain(const QModelIndex &modelIndex, const bool &dele
         treeModelPointer->removeRow(modelIndex.row(), parentIndex);
 }
 
+void CookiesDialog::deleteCookieFromDatabase(const QNetworkCookie &cookie) const
+{
+    // Get a list of the matching domains.  There should only be one item in this list
+    QList<QStandardItem *> domainList = treeModelPointer->findItems(cookie.domain());
+
+    // Find any matching cookies.
+    for (QStandardItem *domainItemPointer : domainList)
+    {
+        // Get the number of cookies in the domain.
+        int numberOfCookies = domainItemPointer->rowCount();
+
+        // Initialize the tracking variables.
+        bool cookieFound = false;
+        int currentRow = 0;
+
+        // Find the cookie in the tree model.
+        while (!cookieFound && (currentRow < numberOfCookies))
+        {
+            // Get the name item.
+            QStandardItem *nameItemPointer = domainItemPointer->child(currentRow);
+
+            // Get the name model index.
+            QModelIndex nameModelIndex = nameItemPointer->index();
+
+            // Check to see if the name and the path match.
+            if ((nameModelIndex.data().toString() == cookie.name()) && (nameModelIndex.siblingAtColumn(2).data().toString() == cookie.path()))
+            {
+                // Set the current index.
+                treeSelectionModelPointer->setCurrentIndex(nameModelIndex, QItemSelectionModel::ClearAndSelect);
+
+                // Delete the cookie.
+                deleteCookieFromDialog(cookie);
+
+                // Mark the cookie as found.
+                cookieFound = true;
+            }
+
+            // Move to the next row.
+            ++currentRow;
+        }
+    }
+}
 
 void CookiesDialog::deleteCookieFromDialog(const QNetworkCookie &cookie) const
 {
@@ -654,6 +700,20 @@ void CookiesDialog::showDeleteCookieMessageBox() const
     }
 }
 
+void CookiesDialog::showDurableCookiesDialog() const
+{
+    // Instantiate a durable cookies dialog.
+    QDialog *durableCookiesDialogPointer = new DurableCookiesDialog();
+
+    // Show the dialog.
+    durableCookiesDialogPointer->show();
+
+    // Process cookie changes.
+    connect(durableCookiesDialogPointer, SIGNAL(addingCookie(QNetworkCookie, bool)), this, SLOT(addCookieFromDialog(QNetworkCookie, bool)));
+    connect(durableCookiesDialogPointer, SIGNAL(deletingCookie(QNetworkCookie)), this, SLOT(deleteCookieFromDatabase(QNetworkCookie)));
+    connect(durableCookiesDialogPointer, SIGNAL(updateParentUi()), this, SLOT(updateUi()));
+}
+
 void CookiesDialog::showEditCookieDialog() const
 {
     // Get the current model index.
@@ -718,4 +778,7 @@ void CookiesDialog::updateUi() const
         // Reset the button text.
         deleteCookieButtonPointer->setText(i18nc("Delete cookie button.", "&Delete cookie"));
     }
+
+    // Update the text of the durable cookies button.
+    durableCookiesButtonPointer->setText(i18nc("View the durable cookies button", "Durable cookies - %1", CookiesDatabase::cookieCount()));
 }
index 89c2be4e1998432c40faf8536960cf99d032c50b..36a7d722fc722cc6a25bbd50eaf981d4d2e67eb6 100644 (file)
@@ -48,10 +48,12 @@ signals:
 private Q_SLOTS:
     // The private slots.
     void addCookieFromDialog(const QNetworkCookie &cookie, const bool &isDurable) const;
+    void deleteCookieFromDatabase(const QNetworkCookie &cookie) const;
     void deleteCookieFromDialog(const QNetworkCookie &cookie) const;
     void showAddCookieDialog() const;
     void showDeleteAllMessageBox() const;
     void showDeleteCookieMessageBox() const;
+    void showDurableCookiesDialog() const;
     void showEditCookieDialog() const;
     void updateUi() const;
 
@@ -61,6 +63,7 @@ private:
     std::list<QNetworkCookie> *cookieListPointer;
     QPushButton *deleteAllButtonPointer;
     QPushButton *deleteCookieButtonPointer;
+    QPushButton *durableCookiesButtonPointer;
     QPushButton *editCookieButtonPointer;
     QStandardItemModel *treeModelPointer;
     QItemSelectionModel *treeSelectionModelPointer;
index 76477ecf8ccceab21f23aad2005282f5d064ada2..c8dc3ea8bdd2b7486c2914843620424ef142b3c1 100644 (file)
@@ -561,12 +561,12 @@ void DomainSettingsDialog::updateUi() const
     // Update the delete button status.
     deleteDomainButtonPointer->setEnabled(domainsSelectionModelPointer->hasSelection());
 
-    // Update the apply button status.
-    applyButtonPointer->setEnabled(domainsTableModelPointer->isDirty());
-
     // Update the reset button status.
     resetButtonPointer->setEnabled(domainsTableModelPointer->isDirty());
 
+    // Update the apply button status.
+    applyButtonPointer->setEnabled(domainsTableModelPointer->isDirty());
+
     // Display the domain settings if there is at least one domain.
     domainSettingsWidgetPointer->setVisible(domainsTableModelPointer->rowCount() > 0);
 }
diff --git a/src/dialogs/DurableCookiesDialog.cpp b/src/dialogs/DurableCookiesDialog.cpp
new file mode 100644 (file)
index 0000000..d998c20
--- /dev/null
@@ -0,0 +1,239 @@
+/*
+ * Copyright © 2022 Soren Stoutner <soren@stoutner.com>.
+ *
+ * This file is part of Privacy Browser PC <https://www.stoutner.com/privacy-browser-pc>.
+ *
+ * Privacy Browser PC is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Privacy Browser PC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Privacy Browser PC.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+// Application headers.
+#include "DurableCookiesDialog.h"
+#include "ui_DurableCookiesDialog.h"
+#include "databases/CookiesDatabase.h"
+#include "delegates/ViewOnlyDelegate.h"
+
+// KDE Frameworks headers.
+#include <KLocalizedString>
+
+DurableCookiesDialog::DurableCookiesDialog() : QDialog(nullptr)
+{
+    // Set the dialog window title.
+    setWindowTitle(i18nc("The durable cookies dialog window title", "Durable Cookies"));
+
+    // Set the window modality.
+    setWindowModality(Qt::WindowModality::ApplicationModal);
+
+    // Instantiate the durable cookies dialog UI.
+    Ui::DurableCookiesDialog durableCookiesDialogUi;
+
+    // Setup the UI.
+    durableCookiesDialogUi.setupUi(this);
+
+    // Get a handle for the table view.
+    QTableView *tableViewPointer = durableCookiesDialogUi.tableView;
+
+    // Create the durable cookies table model.
+    durableCookiesTableModelPointer = new QSqlTableModel(nullptr, QSqlDatabase::database(CookiesDatabase::CONNECTION_NAME));
+
+    // Set the table.
+    durableCookiesTableModelPointer->setTable(CookiesDatabase::COOKIES_TABLE);
+
+    // Set the edit strategy.
+    durableCookiesTableModelPointer->setEditStrategy(QSqlTableModel::OnManualSubmit);
+
+    // Populate the model.
+    durableCookiesTableModelPointer->select();
+
+    // Set the model.
+    tableViewPointer->setModel(durableCookiesTableModelPointer);
+
+    // Instantiate the view only delegate.
+    ViewOnlyDelegate *viewOnlyDelegatePointer = new ViewOnlyDelegate();
+
+    // Disable editing the first column.
+    tableViewPointer->setItemDelegateForColumn(0, viewOnlyDelegatePointer);
+
+    // Optimize the width of the columns.
+    tableViewPointer->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
+
+    // Get the seleciton model.
+    tableSelectionModelPointer = tableViewPointer->selectionModel();
+
+    // Update the UI when the selection changes.
+    connect(tableSelectionModelPointer, SIGNAL(selectionChanged(QItemSelection, QItemSelection)), this, SLOT(updateUi()));
+
+    // Update the UI when the table model data changes.
+    connect(durableCookiesTableModelPointer, SIGNAL(dataChanged(QModelIndex, QModelIndex)), this, SLOT(updateUi()));
+
+    // Get handles for the buttons.
+    QPushButton *addCookieButtonPointer = durableCookiesDialogUi.addCookieButton;
+    deleteCookieButtonPointer = durableCookiesDialogUi.deleteCookieButton;
+    deleteAllCookiesButtonPointer = durableCookiesDialogUi.deleteAllCookiesButton;
+    QDialogButtonBox *dialogButtonBoxPointer = durableCookiesDialogUi.dialogButtonBox;
+    resetButtonPointer = dialogButtonBoxPointer->button(QDialogButtonBox::Reset);
+    applyButtonPointer = dialogButtonBoxPointer->button(QDialogButtonBox::Apply);
+    QPushButton *okButtonPointer = dialogButtonBoxPointer->button(QDialogButtonBox::Ok);
+
+    // Set the OK button to be the default.
+    okButtonPointer->setDefault(true);
+
+    // Connect the buttons.
+    connect(addCookieButtonPointer, SIGNAL(clicked()), this, SLOT(addCookie()));
+    connect(deleteCookieButtonPointer, SIGNAL(clicked()), this, SLOT(deleteCookie()));
+    connect(deleteAllCookiesButtonPointer, SIGNAL(clicked()), this, SLOT(deleteAllCookies()));
+    connect(resetButtonPointer, SIGNAL(clicked()), this, SLOT(reset()));
+    connect(dialogButtonBoxPointer, SIGNAL(accepted()), this, SLOT(ok()));
+    connect(applyButtonPointer, SIGNAL(clicked()), this, SLOT(apply()));
+    connect(dialogButtonBoxPointer, SIGNAL(rejected()), this, SLOT(reject()));
+
+    // Connect the table model signals.
+    connect(durableCookiesTableModelPointer, SIGNAL(beforeDelete(int)), this, SLOT(beforeDelete(int)));
+    connect(durableCookiesTableModelPointer, SIGNAL(beforeUpdate(int, QSqlRecord &)), this, SLOT(beforeUpdate(int, QSqlRecord &)));
+    connect(durableCookiesTableModelPointer, SIGNAL(beforeInsert(QSqlRecord &)), this, SLOT(newCookie(QSqlRecord &)));
+
+    // Update the UI.
+    updateUi();
+}
+
+void DurableCookiesDialog::addCookie() const
+{
+    // Add a new row to the bottom of the table.
+    durableCookiesTableModelPointer->insertRow(durableCookiesTableModelPointer->rowCount());
+
+    // Update the UI.
+    updateUi();
+}
+
+void DurableCookiesDialog::apply() const
+{
+    // Submit all pending changes.
+    durableCookiesTableModelPointer->submitAll();
+
+    // Update the UI.
+    updateUi();
+}
+
+void DurableCookiesDialog::beforeDelete(int row) const
+{
+    // Get the SQL record for the row to be deleted.
+    QSqlRecord sqlRecord = durableCookiesTableModelPointer->record(row);
+
+    // Create a network cookie.
+    QNetworkCookie cookie;
+
+    // Populate the network cookie.
+    cookie.setDomain(sqlRecord.value(CookiesDatabase::DOMAIN).toString());
+    cookie.setName(sqlRecord.value(CookiesDatabase::NAME).toByteArray());
+    cookie.setPath(sqlRecord.value(CookiesDatabase::PATH).toString());
+
+    // Delete the cookie.
+    emit deletingCookie(cookie);
+}
+
+void DurableCookiesDialog::beforeUpdate(int row, QSqlRecord &sqlRecord) const
+{
+    // Tell the compiler to ignore the unused row parameter.
+    (void) row;
+
+    // Delete the old cookie if the core attributes are changing.
+    if (sqlRecord.isGenerated(CookiesDatabase::DOMAIN) || sqlRecord.isGenerated(CookiesDatabase::NAME) || sqlRecord.isGenerated(CookiesDatabase::PATH))
+    {
+        // Get the ID of the cookie
+        int id = sqlRecord.value(CookiesDatabase::_ID).toInt();
+
+        // Get the cookie.
+        QNetworkCookie *cookiePointer = CookiesDatabase::getCookieById(id);
+
+        // Delete the cookie.
+        emit deletingCookie(*cookiePointer);
+    }
+
+    // Add the new cookie, which modifies any existing cookies with the same core attributes.
+    newCookie(sqlRecord);
+}
+
+void DurableCookiesDialog::deleteAllCookies() const
+{
+    // Mark all the cookies for deletion.
+    durableCookiesTableModelPointer->removeRows(0, durableCookiesTableModelPointer->rowCount());
+
+    // Update the UI.
+    updateUi();
+}
+
+void DurableCookiesDialog::deleteCookie() const
+{
+    // Delete the currently selected row.
+    durableCookiesTableModelPointer->removeRow(tableSelectionModelPointer->selectedRows()[0].row());
+
+    // Update the UI.
+    updateUi();
+}
+
+void DurableCookiesDialog::newCookie(QSqlRecord &sqlRecord) const
+{
+    // Create a network cookie.
+    QNetworkCookie cookie;
+
+    // Populate the network cookie from the SQL record.
+    cookie.setDomain(sqlRecord.value(CookiesDatabase::DOMAIN).toString());
+    cookie.setName(sqlRecord.value(CookiesDatabase::NAME).toByteArray());
+    cookie.setPath(sqlRecord.value(CookiesDatabase::PATH).toString());
+    cookie.setExpirationDate(QDateTime::fromString(sqlRecord.value(CookiesDatabase::EXPIRATION_DATE).toString(), Qt::ISODate));
+    cookie.setHttpOnly(sqlRecord.value(CookiesDatabase::HTTP_ONLY).toBool());
+    cookie.setSecure(sqlRecord.value(CookiesDatabase::SECURE).toBool());
+    cookie.setValue(sqlRecord.value(CookiesDatabase::VALUE).toByteArray());
+
+    // Update the cookie in the cookies dialog tree, cookies list, and cookie store.
+    emit addingCookie(cookie, false);
+}
+
+void DurableCookiesDialog::ok()
+{
+    // Submit all pending changes.
+    durableCookiesTableModelPointer->submitAll();
+
+    // Update the parent UI.
+    updateParentUi();
+
+    // Close the dialog.
+    accept();
+}
+
+void DurableCookiesDialog::reset() const
+{
+    // Cancel all pending changes.
+    durableCookiesTableModelPointer->revertAll();
+
+    // Update the UI.
+    updateUi();
+}
+
+void DurableCookiesDialog::updateUi() const
+{
+    // Update the delete button status.
+    deleteCookieButtonPointer->setEnabled(tableSelectionModelPointer->hasSelection());
+
+    // Update the delete all button status.
+    deleteAllCookiesButtonPointer->setEnabled(durableCookiesTableModelPointer->rowCount() > 0);
+
+    // Update the reset button status.
+    resetButtonPointer->setEnabled(durableCookiesTableModelPointer->isDirty());
+
+    // Update the apply button status.
+    applyButtonPointer->setEnabled(durableCookiesTableModelPointer->isDirty());
+
+    // Update the parent UI.
+    emit updateParentUi();
+}
diff --git a/src/dialogs/DurableCookiesDialog.h b/src/dialogs/DurableCookiesDialog.h
new file mode 100644 (file)
index 0000000..61ffe5f
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * Copyright © 2022 Soren Stoutner <soren@stoutner.com>.
+ *
+ * This file is part of Privacy Browser PC <https://www.stoutner.com/privacy-browser-pc>.
+ *
+ * Privacy Browser PC is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Privacy Browser PC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Privacy Browser PC.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef DURABLECOOKIESDIALOG_H
+#define DURABLECOOKIESDIALOG_H
+
+// Qt toolkit headers.
+#include <QDialog>
+#include <QItemSelectionModel>
+#include <QNetworkCookie>
+#include <QSqlTableModel>
+
+class DurableCookiesDialog : public QDialog
+{
+    // Include the Q_OBJECT macro.
+    Q_OBJECT
+
+public:
+    // The default constructor.
+    explicit DurableCookiesDialog();
+
+signals:
+    // The signals.
+    void addingCookie(const QNetworkCookie &cookie, const bool &addToDatabase) const;
+    void deletingCookie(const QNetworkCookie &cookie) const;
+    void updateParentUi() const;
+
+private Q_SLOTS:
+    // The private slots.
+    void addCookie() const;
+    void apply() const;
+    void beforeDelete(int row) const;
+    void beforeUpdate(int row, QSqlRecord &sqlRecord) const;
+    void deleteAllCookies() const;
+    void deleteCookie() const;
+    void newCookie(QSqlRecord &sqlRecord) const;
+    void ok();
+    void reset() const;
+    void updateUi() const;
+
+private:
+    // The private variables.
+    QPushButton *applyButtonPointer;
+    QPushButton *deleteAllCookiesButtonPointer;
+    QPushButton *deleteCookieButtonPointer;
+    QSqlTableModel *durableCookiesTableModelPointer;
+    QItemSelectionModel *tableSelectionModelPointer;
+    QPushButton *resetButtonPointer;
+};
+#endif
index b6cb81f3f7a2bf50db90ae656a4aceea6b4e5395..1d08396cf3ea95bcce6e4c13ad3d064b65c50d3a 100644 (file)
@@ -34,7 +34,7 @@ bool MouseEventFilter::eventFilter(QObject *objectPointer, QEvent *eventPointer)
     if (eventPointer->type() == QEvent::MouseButtonPress)
     {
         // Tell the compiler to ignore the unused object pointer.
-        (void)objectPointer;
+        (void) objectPointer;
 
         // Cast the event to a mouse event.
         QMouseEvent *mouseEventPointer = static_cast<QMouseEvent *>(eventPointer);
index 9c3c2dcda9c0092d5366ff8ea506f26a43183e23..d182c03e28a3622e27c4d0662638f4c932d933f9 100644 (file)
         </property>
 
         <layout class="QVBoxLayout">
+            <!-- Tree view. -->
             <item>
-                <!-- Scroll area. -->
                 <widget class="QTreeView" name="treeView" />
             </item>
 
+            <!-- Buttons. -->
             <item>
                 <layout class="QHBoxLayout">
                     <!-- Add cookie button. -->
                         </widget>
                     </item>
 
-                    <!-- Delete domain button. -->
+                    <!-- Delete cookie button. -->
                     <item>
                         <widget class="QPushButton" name="deleteCookieButton">
                             <property name="text">
-                                <string>De&amp;lete cookie</string>
+                                <string>&amp;Delete cookie</string>
                             </property>
 
                             <property name="icon">
                         </widget>
                     </item>
 
-                    <!-- Close button. -->
+                    <!-- Delete all cookies button. -->
+                    <item>
+                        <widget class="QPushButton" name="deleteAllCookiesButton">
+                            <property name="text">
+                                <string>Delete &amp;all</string>
+                            </property>
+
+                            <property name="icon">
+                                <iconset theme="delete" />
+                            </property>
+                        </widget>
+                    </item>
+
+                    <!-- Close button - dialog button box. -->
                     <item>
                         <widget class="QDialogButtonBox" name="dialogButtonBox">
                             <property name="standardButtons">
diff --git a/src/uis/DurableCookiesDialog.ui b/src/uis/DurableCookiesDialog.ui
new file mode 100644 (file)
index 0000000..d1ee522
--- /dev/null
@@ -0,0 +1,111 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+  Copyright © 2022 Soren Stoutner <soren@stoutner.com>.
+
+  This file is part of Privacy Browser PC <https://www.stoutner.com/privacy-browser-android>.
+
+  Privacy Browser PC is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  Privacy Browser PC is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with Privacy Browser PC.  If not, see <http://www.gnu.org/licenses/>. -->
+
+<ui version="4.0">
+    <class>DurableCookiesDialog</class>
+
+    <widget class="QWidget">
+        <property name="geometry">
+            <rect>
+                <x>0</x>
+                <y>0</y>
+                <height>900</height>
+                <width>1400</width>
+            </rect>
+        </property>
+
+        <layout class="QVBoxLayout">
+            <!-- Table view. -->
+            <item>
+                <widget class="QTableView" name="tableView">
+                    <property name="selectionMode">
+                        <enum>QAbstractItemView::SingleSelection</enum>
+                    </property>
+
+                    <property name="selectionBehavior">
+                        <enum>QAbstractItemView::SelectRows</enum>
+                    </property>
+                </widget>
+            </item>
+
+            <!-- Buttons. -->
+            <item>
+                <layout class="QHBoxLayout">
+                    <!-- Add cookie button.-->
+                    <item>
+                        <widget class="QPushButton" name="addCookieButton">
+                            <property name="text">
+                                <string>&amp;Add cookie</string>
+                            </property>
+
+                            <property name="icon">
+                                <iconset theme="list-add" />
+                            </property>
+                        </widget>
+                    </item>
+
+                    <!-- Delete cookie button. -->
+                    <item>
+                        <widget class="QPushButton" name="deleteCookieButton">
+                            <property name="text">
+                                <string>&amp;Delete cookie</string>
+                            </property>
+
+                            <property name="icon">
+                                <iconset theme="list-remove" />
+                            </property>
+                        </widget>
+                    </item>
+
+                    <!-- Delete all cookies button. -->
+                    <item>
+                        <widget class="QPushButton" name="deleteAllCookiesButton">
+                            <property name="text">
+                                <string>Delete &amp;all</string>
+                            </property>
+
+                            <property name="icon">
+                                <iconset theme="delete" />
+                            </property>
+                        </widget>
+                    </item>
+
+                    <!-- Spacer. -->
+                    <item>
+                        <spacer>
+                            <property name="orientation">
+                                <enum>Qt::Horizontal</enum>
+                            </property>
+                        </spacer>
+                    </item>
+
+                    <!-- Dialog button box - reset, OK, apply and close. -->
+                    <item>
+                        <widget class="QDialogButtonBox" name="dialogButtonBox">
+                            <property name="standardButtons">
+                                <set>QDialogButtonBox::Reset | QDialogButtonBox::Ok | QDialogButtonBox::Apply | QDialogButtonBox::Cancel</set>
+                            </property>
+                        </widget>
+                    </item>
+                </layout>
+            </item>
+        </layout>
+    </widget>
+</ui>