From 9b6cee96126484925bec4f4ab30c2b880df687fe Mon Sep 17 00:00:00 2001
From: Soren Stoutner <soren@stoutner.com>
Date: Thu, 21 Apr 2022 17:02:34 -0700
Subject: [PATCH] Implement manual adding of cookies.

---
 src/CMakeLists.txt                            |   3 +-
 src/dialogs/AddCookieDialog.cpp               | 121 ++++++++
 src/dialogs/AddCookieDialog.h                 |  60 ++++
 src/dialogs/CMakeLists.txt                    |   1 +
 src/dialogs/CookiesDialog.cpp                 | 144 +++++----
 src/dialogs/CookiesDialog.h                   |   8 +-
 src/dialogs/DomainSettingsDialog.cpp          |  10 +-
 src/ui/AddCookieDialog.ui                     | 292 ++++++++++++++++++
 ...CookieWidget.ui => CookieDisplayWidget.ui} |   8 +-
 src/ui/CookiesDialog.ui                       |   6 +-
 src/views/BrowserView.cpp                     |  21 ++
 src/views/BrowserView.h                       |   1 +
 src/windows/BrowserWindow.cpp                 |   6 +-
 src/windows/BrowserWindow.h                   |   2 +-
 14 files changed, 614 insertions(+), 69 deletions(-)
 create mode 100644 src/dialogs/AddCookieDialog.cpp
 create mode 100644 src/dialogs/AddCookieDialog.h
 create mode 100644 src/ui/AddCookieDialog.ui
 rename src/ui/{CookieWidget.ui => CookieDisplayWidget.ui} (97%)

diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index ea4fecb..a7ee578 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -35,9 +35,10 @@ kconfig_add_kcfg_files(privacy-browser settings/Settings.kcfgc)
 
 # Use KDE Frameworks to handle internationalization of the following UI files.
 ki18n_wrap_ui(privacy-browser
+    ui/AddCookieDialog.ui
     ui/BrowserView.ui
+    ui/CookieDisplayWidget.ui
     ui/CookiesDialog.ui
-    ui/CookieWidget.ui
     ui/DomainSettingsDialog.ui
     ui/SettingsGeneral.ui
     ui/SettingsPrivacy.ui
diff --git a/src/dialogs/AddCookieDialog.cpp b/src/dialogs/AddCookieDialog.cpp
new file mode 100644
index 0000000..a81d433
--- /dev/null
+++ b/src/dialogs/AddCookieDialog.cpp
@@ -0,0 +1,121 @@
+/*
+ * 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 "AddCookieDialog.h"
+#include "ui_AddCookieDialog.h"
+
+// KDE Framework headers.
+#include <KLocalizedString>
+
+// Qt toolkit header.
+#include <QPushButton>
+#include <QUrl>
+
+AddCookieDialog::AddCookieDialog() : QDialog(nullptr)
+{
+   // Set the dialog window title.
+    setWindowTitle(i18nc("The add cookie dialog window title", "Add Cookie"));
+
+    // Set the window modality.
+    setWindowModality(Qt::WindowModality::ApplicationModal);
+
+    // Instantiate the cookie settings dialog UI.
+    Ui::AddCookieDialog addCookieDialogUi;
+
+    // Setup the UI.
+    addCookieDialogUi.setupUi(this);
+
+    // Get handles for the views.
+    domainLineEditPointer = addCookieDialogUi.domainLineEdit;
+    nameLineEditPointer = addCookieDialogUi.nameLineEdit;
+    expirationCheckBoxPointer = addCookieDialogUi.expirationCheckBox;
+    expirationDateTimeEditPointer = addCookieDialogUi.expirationDateTimeEdit;
+    pathLineEditPointer = addCookieDialogUi.pathLineEdit;
+    httpOnlyCheckBoxPointer = addCookieDialogUi.httpOnlyCheckBox;
+    secureCheckBoxPointer = addCookieDialogUi.secureCheckBox;
+    valueLineEditPointer = addCookieDialogUi.valueLineEdit;
+    QDialogButtonBox *dialogButtonBoxPointer = addCookieDialogUi.dialogButtonBox;
+    saveButtonPointer = dialogButtonBoxPointer->button(QDialogButtonBox::Save);
+
+    // Connect the line edits.
+    connect(domainLineEditPointer, SIGNAL(textEdited(QString)), this, SLOT(updateUi()));
+    connect(nameLineEditPointer, SIGNAL(textEdited(QString)), this, SLOT(updateUi()));
+    connect(pathLineEditPointer, SIGNAL(textEdited(QString)), this, SLOT(updateUi()));
+    connect(valueLineEditPointer, SIGNAL(textEdited(QString)), this, SLOT(updateUi()));
+
+    // Connect the check boxes.
+    connect(expirationCheckBoxPointer, SIGNAL(stateChanged(int)), this, SLOT(updateExpirationDateTimeState(int)));
+
+    // Connect the buttons.
+    connect(dialogButtonBoxPointer, SIGNAL(accepted()), this, SLOT(saveCookie()));
+    connect(dialogButtonBoxPointer, SIGNAL(rejected()), this, SLOT(reject()));
+
+    // Update the UI.
+    updateUi();
+}
+
+void AddCookieDialog::saveCookie()
+{
+    // Create the variables.
+    QNetworkCookie cookie;
+
+    // Populate the cookie.
+    cookie.setDomain(domainLineEditPointer->text());
+    cookie.setName(nameLineEditPointer->text().toUtf8());
+    cookie.setPath(pathLineEditPointer->text());
+    cookie.setHttpOnly(httpOnlyCheckBoxPointer->isChecked());
+    cookie.setSecure(secureCheckBoxPointer->isChecked());
+    cookie.setValue(valueLineEditPointer->text().toUtf8());
+
+    // Populate the expiration date if it is specified.
+    if (expirationCheckBoxPointer->isChecked()) cookie.setExpirationDate(expirationDateTimeEditPointer->dateTime());
+
+    // Add the cookie.
+    emit addCookie(cookie);
+
+    // Close the dialog.
+    reject();
+}
+
+void AddCookieDialog::updateExpirationDateTimeState(const int &newState) const
+{
+    // Update the state of the of the expiration date time edit.
+    switch (newState)
+    {
+        case Qt::Unchecked:
+            // Disable the expiration date time.
+            expirationDateTimeEditPointer->setEnabled(false);
+
+            break;
+
+        case Qt::Checked:
+            // Enable the expiration date time edit.
+            expirationDateTimeEditPointer->setEnabled(true);
+
+            break;
+    }
+}
+
+void AddCookieDialog::updateUi() const
+{
+    // Update the state of the save button based on all the required fields containing text.
+    saveButtonPointer->setDisabled(domainLineEditPointer->text().isEmpty() || nameLineEditPointer->text().isEmpty() || pathLineEditPointer->text().isEmpty() ||
+                                    valueLineEditPointer->text().isEmpty());
+}
diff --git a/src/dialogs/AddCookieDialog.h b/src/dialogs/AddCookieDialog.h
new file mode 100644
index 0000000..f7354ce
--- /dev/null
+++ b/src/dialogs/AddCookieDialog.h
@@ -0,0 +1,60 @@
+/*
+ * 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 ADDCOOKIEDIALOG_H
+#define ADDCOOKIEDIALOG_H
+
+// Qt toolkit headers.
+#include <QCheckBox>
+#include <QDateTimeEdit>
+#include <QDialog>
+#include <QNetworkCookie>
+
+class AddCookieDialog : public QDialog
+{
+    // Include the Q_OBJECT macro.
+    Q_OBJECT
+
+public:
+    // The default constructor.
+    explicit AddCookieDialog();
+
+signals:
+    // The signals.
+    void addCookie(const QNetworkCookie &cookie) const;
+
+private Q_SLOTS:
+    // The private slots.
+    void saveCookie();
+    void updateExpirationDateTimeState(const int &newState) const;
+    void updateUi() const;
+
+private:
+    // The private variables.
+    QLineEdit *domainLineEditPointer;
+    QCheckBox *expirationCheckBoxPointer;
+    QDateTimeEdit *expirationDateTimeEditPointer;
+    QCheckBox *httpOnlyCheckBoxPointer;
+    QLineEdit *nameLineEditPointer;
+    QLineEdit *pathLineEditPointer;
+    QPushButton *saveButtonPointer;
+    QCheckBox *secureCheckBoxPointer;
+    QLineEdit *valueLineEditPointer;
+};
+#endif
diff --git a/src/dialogs/CMakeLists.txt b/src/dialogs/CMakeLists.txt
index ee3d9ff..5eaf0f4 100644
--- a/src/dialogs/CMakeLists.txt
+++ b/src/dialogs/CMakeLists.txt
@@ -18,6 +18,7 @@
 
 # List the sources to include in the executable.
 target_sources(privacy-browser PRIVATE
+    AddCookieDialog.cpp
     CookiesDialog.cpp
     DomainSettingsDialog.cpp
 )
diff --git a/src/dialogs/CookiesDialog.cpp b/src/dialogs/CookiesDialog.cpp
index 3321c65..972bc67 100644
--- a/src/dialogs/CookiesDialog.cpp
+++ b/src/dialogs/CookiesDialog.cpp
@@ -18,16 +18,18 @@
  */
 
 // Application headers.
+#include "AddCookieDialog.h"
 #include "CookiesDialog.h"
+#include "ui_CookieDisplayWidget.h"
 #include "ui_CookiesDialog.h"
-#include "ui_CookieWidget.h"
 
-// The KDE Frameworks headers.
+// KDE Frameworks headers.
 #include <KLocalizedString>
 
-// The Qt toolkit headers.
+// Qt toolkit headers.
 #include <QDateTime>
 #include <QMessageBox>
+#include <QUrl>
 
 CookiesDialog::CookiesDialog(QList<QNetworkCookie> *originalCookieListPointer) : QDialog(nullptr), cookieListPointer(originalCookieListPointer)
 {
@@ -35,7 +37,7 @@ CookiesDialog::CookiesDialog(QList<QNetworkCookie> *originalCookieListPointer) :
     setWindowTitle(i18nc("The cookies dialog window title", "Cookies"));
 
     // Set the window modality.
-    setWindowModality(Qt::WindowModality::WindowModal);
+    setWindowModality(Qt::WindowModality::ApplicationModal);
 
     // Instantiate the cookie settings dialog UI.
     Ui::CookiesDialog cookiesDialogUi;
@@ -43,66 +45,37 @@ CookiesDialog::CookiesDialog(QList<QNetworkCookie> *originalCookieListPointer) :
     // Setup the UI.
     cookiesDialogUi.setupUi(this);
 
+    // Get a handle for the scroll area.
+    QScrollArea *scrollAreaPointer = cookiesDialogUi.scrollArea;
+
     // Create the scroll area widget.
     QWidget *scrollAreaWidgetPointer = new QWidget();
 
+    // Set the scroll area widget.
+    scrollAreaPointer->setWidget(scrollAreaWidgetPointer);
+
+    // Create a scroll area VBox layout.
+    QVBoxLayout *scrollAreaVBoxLayoutPointer = new QVBoxLayout();
+
+    // Set the scroll area widget layout.
+    scrollAreaWidgetPointer->setLayout(scrollAreaVBoxLayoutPointer);
+
     // Create the cookies VBox layout.
     cookiesVBoxLayoutPointer = new QVBoxLayout();
 
+    // Populate the scroll area VBox layout.  The stretch prevents the cookies from expanding vertically if they are smaller than the dialog.
+    scrollAreaVBoxLayoutPointer->addLayout(cookiesVBoxLayoutPointer);
+    scrollAreaVBoxLayoutPointer->addStretch();
+
     // Populate the VBoxLayout.
     for (QNetworkCookie cookie : *cookieListPointer)
     {
-        // Create a cookie display widget.
-        QWidget *cookieDisplayWidgetPointer = new QWidget();
-
-        // Instantiate the cookie widget dialog UI.
-        Ui::CookieWidget cookieWidgetUi;
-
-        // Setup the UI.
-        cookieWidgetUi.setupUi(cookieDisplayWidgetPointer);
-
-        // Get handles for the views.
-        QLabel *domainLabelPointer = cookieWidgetUi.domainLabel;
-        QLabel *nameLabelPointer = cookieWidgetUi.nameLabel;
-        QLabel *expirationDateLabelPointer = cookieWidgetUi.expirationDateLabel;
-        QLabel *pathLabelPointer = cookieWidgetUi.pathLabel;
-        QCheckBox *httpOnlyCheckBoxPointer = cookieWidgetUi.httpOnlyCheckBox;
-        QCheckBox *secureCheckBoxPointer = cookieWidgetUi.secureCheckBox;
-        QLabel *valueLabelPointer = cookieWidgetUi.valueLabel;
-
-        // Populate the views.
-        domainLabelPointer->setText("<font size=\"+1\"><b>" + cookie.domain() + "</b></font>");
-        nameLabelPointer->setText("<font size=\"+1\"><b>" + cookie.name() + "</b></font>");
-        expirationDateLabelPointer->setText("<b>" + cookie.expirationDate().toString() + "</b>");
-        pathLabelPointer->setText("<b>" + cookie.path() + "</b>");
-        httpOnlyCheckBoxPointer->setChecked(cookie.isHttpOnly());
-        secureCheckBoxPointer->setChecked(cookie.isSecure());
-        valueLabelPointer->setText("<b>" + cookie.value() + "</b>");
-
-        // Add the widget to the cookies VBox layout.
-        cookiesVBoxLayoutPointer->addWidget(cookieDisplayWidgetPointer);
-
-        // Create a line.
-        QFrame *lineFrame = new QFrame();
-
-        // Format the line.
-        lineFrame->setFrameShape(QFrame::HLine);
-        lineFrame->setFrameShadow(QFrame::Sunken);
-
-        // Add the line to the cookies VBox layout.
-        cookiesVBoxLayoutPointer->addWidget(lineFrame);
+        // Add the cookie to the layout.
+        addCookieToLayout(cookie);
     }
 
-    // Set the scroll area widget layout.
-    scrollAreaWidgetPointer->setLayout(cookiesVBoxLayoutPointer);
-
-    // Get a handle for the scroll area.
-    QScrollArea *scrollAreaPointer = cookiesDialogUi.scrollArea;
-
-    // Set the scroll area widget.
-    scrollAreaPointer->setWidget(scrollAreaWidgetPointer);
-
     // Get handles for the buttons.
+    addCookieButtonPointer = cookiesDialogUi.addCookieButton;
     QDialogButtonBox *dialogButtonBoxPointer = cookiesDialogUi.dialogButtonBox;
     QPushButton *cancelButtonPointer = dialogButtonBoxPointer->button(QDialogButtonBox::Close);
 
@@ -113,7 +86,8 @@ CookiesDialog::CookiesDialog(QList<QNetworkCookie> *originalCookieListPointer) :
     deleteAllButtonPointer->setIcon(QIcon::fromTheme("delete"));
 
     // Connect the buttons.
-    connect(deleteAllButtonPointer, SIGNAL(released()), this, SLOT(showDeleteAllMessageBox()));
+    connect(addCookieButtonPointer, SIGNAL(clicked()), this, SLOT(showAddCookieMessageBox()));
+    connect(deleteAllButtonPointer, SIGNAL(clicked()), this, SLOT(showDeleteAllMessageBox()));
     connect(dialogButtonBoxPointer, SIGNAL(rejected()), this, SLOT(reject()));
 
     // Set the cancel button to be the default.
@@ -123,6 +97,70 @@ CookiesDialog::CookiesDialog(QList<QNetworkCookie> *originalCookieListPointer) :
     updateUi();
 };
 
+void CookiesDialog::addCookieFromDialog(const QNetworkCookie &cookie) const
+{
+    // Add the cookie to the cookie list and the cookie store.
+    emit addCookie(cookie);
+
+    // Add the cookie to the VBox layout.
+    addCookieToLayout(cookie);
+}
+
+void CookiesDialog::addCookieToLayout(const QNetworkCookie &cookie) const
+{
+    // Create a cookie display widget.
+    QWidget *cookieDisplayWidgetPointer = new QWidget();
+
+    // Instantiate the cookie widget dialog UI.
+    Ui::CookieDisplayWidget cookieDisplayWidgetUi;
+
+    // Setup the UI.
+    cookieDisplayWidgetUi.setupUi(cookieDisplayWidgetPointer);
+
+    // Get handles for the views.
+    QLabel *domainLabelPointer = cookieDisplayWidgetUi.domainLabel;
+    QLabel *nameLabelPointer = cookieDisplayWidgetUi.nameLabel;
+    QLabel *expirationDateLabelPointer = cookieDisplayWidgetUi.expirationDateLabel;
+    QLabel *pathLabelPointer = cookieDisplayWidgetUi.pathLabel;
+    QCheckBox *httpOnlyCheckBoxPointer = cookieDisplayWidgetUi.httpOnlyCheckBox;
+    QCheckBox *secureCheckBoxPointer = cookieDisplayWidgetUi.secureCheckBox;
+    QLabel *valueLabelPointer = cookieDisplayWidgetUi.valueLabel;
+
+    // Populate the views.
+    domainLabelPointer->setText("<font size=\"+1\"><b>" + cookie.domain() + "</b></font>");
+    nameLabelPointer->setText("<font size=\"+1\"><b>" + cookie.name() + "</b></font>");
+    expirationDateLabelPointer->setText("<b>" + cookie.expirationDate().toString() + "</b>");
+    pathLabelPointer->setText("<b>" + cookie.path() + "</b>");
+    httpOnlyCheckBoxPointer->setChecked(cookie.isHttpOnly());
+    secureCheckBoxPointer->setChecked(cookie.isSecure());
+    valueLabelPointer->setText("<b>" + cookie.value() + "</b>");
+
+    // Add the cookie display widget to the cookies VBox layout.
+    cookiesVBoxLayoutPointer->addWidget(cookieDisplayWidgetPointer);
+
+    // Create a line.
+    QFrame *lineFrame = new QFrame();
+
+    // Format the line.
+    lineFrame->setFrameShape(QFrame::HLine);
+    lineFrame->setFrameShadow(QFrame::Sunken);
+
+    // Add the line to the cookies VBox layout.
+    cookiesVBoxLayoutPointer->addWidget(lineFrame);
+}
+
+void CookiesDialog::showAddCookieMessageBox() const
+{
+    // Instantiate an add cookie dialog.
+    QDialog *addCookieDialogPointer = new AddCookieDialog();
+
+    // Show the dialog.
+    addCookieDialogPointer->show();
+
+    // Add the cookie if directed.
+    connect(addCookieDialogPointer, SIGNAL(addCookie(QNetworkCookie)), this, SLOT(addCookieFromDialog(QNetworkCookie)));
+}
+
 void CookiesDialog::showDeleteAllMessageBox() const
 {
     // Instantiate a delete all message box.
diff --git a/src/dialogs/CookiesDialog.h b/src/dialogs/CookiesDialog.h
index 17498ca..89f9c62 100644
--- a/src/dialogs/CookiesDialog.h
+++ b/src/dialogs/CookiesDialog.h
@@ -31,23 +31,29 @@ class CookiesDialog : public QDialog
     Q_OBJECT
 
 public:
-    // The default constructor.
+    // The primary constructor.
     explicit CookiesDialog(QList<QNetworkCookie> *cookieListPointer);
 
 signals:
+    // The signals.
+    void addCookie(const QNetworkCookie &cookie) const;
     void deleteAllCookies() const;
 
 private Q_SLOTS:
     // The private slots.
+    void addCookieFromDialog(const QNetworkCookie &cookie) const;
+    void showAddCookieMessageBox() const;
     void showDeleteAllMessageBox() const;
 
 private:
     // The private variables.
+    QPushButton *addCookieButtonPointer;
     QList<QNetworkCookie> *cookieListPointer;
     QVBoxLayout *cookiesVBoxLayoutPointer;
     QPushButton *deleteAllButtonPointer;
 
     // The private functions.
+    void addCookieToLayout(const QNetworkCookie &cookie) const;
     void updateUi() const;
 };
 #endif
diff --git a/src/dialogs/DomainSettingsDialog.cpp b/src/dialogs/DomainSettingsDialog.cpp
index 42c713a..32d61d0 100644
--- a/src/dialogs/DomainSettingsDialog.cpp
+++ b/src/dialogs/DomainSettingsDialog.cpp
@@ -40,7 +40,7 @@ DomainSettingsDialog::DomainSettingsDialog(const int &startType, const QString &
     setWindowTitle(i18nc("The domain settings dialog window title", "Domain Settings"));
 
     // Set the window modality.
-    setWindowModality(Qt::WindowModality::WindowModal);;
+    setWindowModality(Qt::WindowModality::ApplicationModal);;
 
     // Instantiate the domain settings dialog UI.
     Ui::DomainSettingsDialog domainSettingsDialogUi;
@@ -138,11 +138,11 @@ DomainSettingsDialog::DomainSettingsDialog(const int &startType, const QString &
     connect(customZoomFactorSpinBoxPointer, SIGNAL(valueChanged(double)), this, SLOT(customZoomFactorChanged(double)));
 
     // Connect the buttons.
-    connect(addDomainButtonPointer, SIGNAL(released()), this, SLOT(showAddMessageBox()));
-    connect(deleteDomainButtonPointer, SIGNAL(released()), this, SLOT(showDeleteMessageBox()));
-    connect(resetButtonPointer, SIGNAL(released()), this, SLOT(reset()));
+    connect(addDomainButtonPointer, SIGNAL(clicked()), this, SLOT(showAddMessageBox()));
+    connect(deleteDomainButtonPointer, SIGNAL(clicked()), this, SLOT(showDeleteMessageBox()));
+    connect(resetButtonPointer, SIGNAL(clicked()), this, SLOT(reset()));
     connect(dialogButtonBoxPointer, SIGNAL(accepted()), this, SLOT(ok()));
-    connect(applyButtonPointer, SIGNAL(released()), this, SLOT(apply()));
+    connect(applyButtonPointer, SIGNAL(clicked()), this, SLOT(apply()));
     connect(dialogButtonBoxPointer, SIGNAL(rejected()), this, SLOT(cancel()));
 
     // Update the UI.
diff --git a/src/ui/AddCookieDialog.ui b/src/ui/AddCookieDialog.ui
new file mode 100644
index 0000000..413224a
--- /dev/null
+++ b/src/ui/AddCookieDialog.ui
@@ -0,0 +1,292 @@
+<?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>AddCookieDialog</class>
+
+    <widget class="QWidget">
+        <layout class="QVBoxLayout">
+            <item>
+                <layout class="QHBoxLayout">
+                    <property name="alignment">
+                        <enum>Qt::AlignLeft</enum>
+                    </property>
+
+                    <!-- Domain. -->
+                    <item>
+                        <widget class="QLabel">
+                            <property name="toolTip">
+                                <string>Cookies prepended by a period are accessible to all subdomains.</string>
+                            </property>
+
+                            <property name="textFormat">
+                                <enum>Qt::RichText</enum>
+                            </property>
+
+                            <property name="text">
+                                <string>Domain&amp;nbsp;</string>
+                            </property>
+                        </widget>
+                    </item>
+
+                    <item>
+                        <widget class="QLineEdit" name="domainLineEdit">
+                            <property name="toolTip">
+                                <string>Cookies prepended by a period are accessible to all subdomains.</string>
+                            </property>
+                        </widget>
+                    </item>
+
+                    <!-- Name. -->
+                    <item>
+                        <widget class="QLabel">
+                            <property name="toolTip">
+                                <string>The identifier of the cookie, which is unique when combined with the domain and the path.</string>
+                            </property>
+
+                            <property name="textFormat">
+                                <enum>Qt::RichText</enum>
+                            </property>
+
+                            <property name="text">
+                                <string>&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Name&amp;nbsp;</string>
+                            </property>
+                        </widget>
+                    </item>
+
+                    <item>
+                        <widget class="QLineEdit" name="nameLineEdit">
+                            <property name="toolTip">
+                                <string>The identifier of the cookie, which is unique when combined with the domain and the path.</string>
+                            </property>
+                        </widget>
+                    </item>
+                </layout>
+            </item>
+
+            <item>
+                <layout class="QHBoxLayout">
+                    <property name="alignment">
+                        <enum>Qt::AlignLeft</enum>
+                    </property>
+
+                    <!-- Expiration date. -->
+                    <item>
+                        <widget class="QCheckBox" name="expirationCheckBox">
+                            <property name="toolTip">
+                                <string>Cookies without an expiration date are known as session cookies and are expected to be deleted every time the browser closes.</string>
+                            </property>
+                        </widget>
+                    </item>
+
+                    <item>
+                        <widget class="QLabel">
+                            <property name="toolTip">
+                                <string>Cookies without an expiration date are known as session cookies and are expected to be deleted every time the browser closes.</string>
+                            </property>
+
+                            <property name="textFormat">
+                                <enum>Qt::RichText</enum>
+                            </property>
+
+                            <property name="text">
+                                <string>Expiration date&amp;nbsp;</string>
+                            </property>
+                        </widget>
+                    </item>
+
+                    <item>
+                        <widget class="QDateTimeEdit" name="expirationDateTimeEdit">
+                            <property name="toolTip">
+                                <string>Cookies without an expiration date are known as session cookies and are expected to be deleted every time the browser closes.</string>
+                            </property>
+
+                            <property name="dateTime">
+                                <datetime>
+                                    <year>2030</year>
+                                    <month>1</month>
+                                    <day>1</day>
+                                    <hour>0</hour>
+                                    <minute>0</minute>
+                                    <second>0</second>
+                                </datetime>
+                            </property>
+
+                            <property name="calendarPopup">
+                                <bool>true</bool>
+                            </property>
+
+                            <property name="enabled">
+                                <bool>false</bool>
+                            </property>
+                        </widget>
+                    </item>
+
+                    <!-- Path. -->
+                    <item>
+                        <widget class="QLabel">
+                            <property name="toolTip">
+                                <string>Websites can restrict cookie access to subpath of their URL.</string>
+                            </property>
+
+                            <property name="textFormat">
+                                <enum>Qt::RichText</enum>
+                            </property>
+
+                            <property name="text">
+                                <string>&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Path&amp;nbsp;</string>
+                            </property>
+                        </widget>
+                    </item>
+
+                    <item>
+                        <widget class="QLineEdit" name="pathLineEdit">
+                            <property name="toolTip">
+                                <string>Websites can restrict cookie access to subpath of their URL.</string>
+                            </property>
+
+                            <property name="text">
+                                <string>/</string>
+                            </property>
+                        </widget>
+                    </item>
+
+                    <!-- A spacer label.  Necessary to add space before the check box. -->
+                    <item>
+                        <widget class="QLabel">
+                            <property name="textFormat">
+                                <enum>Qt::RichText</enum>
+                            </property>
+
+                            <property name="text">
+                                <string>&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;</string>
+                            </property>
+                        </widget>
+                    </item>
+
+                    <!-- HTTP only. -->
+                    <item>
+                        <widget class="QCheckBox" name="httpOnlyCheckBox">
+                            <property name="toolTip">
+                                <string>Restrict cookie access to HTTP (and HTTPS). This prevents JavaScript from accessing the cookie, which hardens it against cross-site scripting attacks.</string>
+                            </property>
+
+                            <property name="checked">
+                                <bool>true</bool>
+                            </property>
+                        </widget>
+                    </item>
+
+                    <item>
+                        <widget class="QLabel">
+                            <property name="toolTip">
+                                <string>Restrict cookie access to HTTP (and HTTPS). This prevents JavaScript from accessing the cookie, which hardens it against cross-site scripting attacks.</string>
+                            </property>
+
+                            <property name="textFormat">
+                                <enum>Qt::RichText</enum>
+                            </property>
+
+                            <property name="text">
+                                <string>HTTP only&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;</string>
+                            </property>
+                        </widget>
+                    </item>
+
+                    <!-- Secure. -->
+                    <item>
+                        <widget class="QCheckBox" name="secureCheckBox">
+                            <property name="toolTip">
+                                <string>Only allow the cookie to be transferred across HTTPS (as opposed to HTTP).</string>
+                            </property>
+
+                            <property name="checked">
+                                <bool>true</bool>
+                            </property>
+                        </widget>
+                    </item>
+
+                    <item>
+                        <widget class="QLabel">
+                            <property name="toolTip">
+                                <string>Only allow the cookie to be transferred across HTTPS (as opposed to HTTP).</string>
+                            </property>
+
+                            <property name="text">
+                                <string>Secure</string>
+                            </property>
+                        </widget>
+                    </item>
+                </layout>
+            </item>
+
+            <item>
+                <layout class="QHBoxLayout">
+                    <property name="alignment">
+                        <enum>Qt::AlignLeft</enum>
+                    </property>
+
+                    <!-- Value. -->
+                    <item>
+                        <widget class="QLabel">
+                            <property name="toolTip">
+                                <string>The value contains the cookie data.</string>
+                            </property>
+
+                            <property name="textFormat">
+                                <enum>Qt::RichText</enum>
+                            </property>
+
+                            <property name="text">
+                                <string>Value&amp;nbsp;</string>
+                            </property>
+                        </widget>
+                    </item>
+
+                    <item>
+                        <widget class="QLineEdit" name="valueLineEdit">
+                            <property name="toolTip">
+                                <string>The value contains the cookie data.</string>
+                            </property>
+                        </widget>
+                    </item>
+                </layout>
+            </item>
+
+            <!-- Spacer. -->
+            <item>
+                <spacer>
+                    <property name="orientation">
+                        <enum>Qt::Vertical</enum>
+                    </property>
+                </spacer>
+            </item>
+
+            <!-- Dialog buttons. -->
+            <item>
+                <widget class="QDialogButtonBox" name="dialogButtonBox">
+                    <property name="standardButtons">
+                        <set>QDialogButtonBox::Save | QDialogButtonBox::Cancel</set>
+                    </property>
+                </widget>
+            </item>
+        </layout>
+    </widget>
+</ui>
diff --git a/src/ui/CookieWidget.ui b/src/ui/CookieDisplayWidget.ui
similarity index 97%
rename from src/ui/CookieWidget.ui
rename to src/ui/CookieDisplayWidget.ui
index efad03a..21665ff 100644
--- a/src/ui/CookieWidget.ui
+++ b/src/ui/CookieDisplayWidget.ui
@@ -19,7 +19,7 @@
   along with Privacy Browser PC.  If not, see <http://www.gnu.org/licenses/>. -->
 
 <ui version="4.0">
-    <class>CookieWidget</class>
+    <class>CookieDisplayWidget</class>
 
     <widget class="QWidget">
         <layout class="QVBoxLayout">
@@ -140,7 +140,7 @@
                     <item>
                         <widget class="QLabel">
                             <property name="toolTip">
-                                <string>Websites can restrict access to only a subpath of their URL.</string>
+                                <string>Websites can restrict cookie access to a subpath of their URL.</string>
                             </property>
 
                             <property name="textFormat">
@@ -156,7 +156,7 @@
                     <item>
                         <widget class="QLabel" name="pathLabel">
                             <property name="toolTip">
-                                <string>Websites can restrict access to only a subpath of their URL.</string>
+                                <string>Websites can restrict cookie access to a subpath of their URL.</string>
                             </property>
 
                             <property name="textFormat">
@@ -169,7 +169,7 @@
                         </widget>
                     </item>
 
-                    <!-- A spacer labe.  Necessary to add space before the check box. -->
+                    <!-- A spacer label.  Necessary to add space before the check box. -->
                     <item>
                         <widget class="QLabel">
                             <property name="textFormat">
diff --git a/src/ui/CookiesDialog.ui b/src/ui/CookiesDialog.ui
index 69773c1..6816c50 100644
--- a/src/ui/CookiesDialog.ui
+++ b/src/ui/CookiesDialog.ui
@@ -35,7 +35,11 @@
         <layout class="QVBoxLayout">
             <item>
                 <!-- Scroll area. -->
-                <widget class="QScrollArea" name="scrollArea" />
+                <widget class="QScrollArea" name="scrollArea">
+                    <property name="widgetResizable">
+                        <bool>true</bool>
+                    </property>
+                </widget>
             </item>
 
             <item>
diff --git a/src/views/BrowserView.cpp b/src/views/BrowserView.cpp
index 07ce5f5..b5c915b 100644
--- a/src/views/BrowserView.cpp
+++ b/src/views/BrowserView.cpp
@@ -120,6 +120,27 @@ BrowserView::~BrowserView()
     webEnginePagePointer->deleteLater();
 }
 
+// The cookie is copied instead of referenced so that changes made to the cookie do not create a race condition with the display of the cookie in the dialog.
+void BrowserView::addCookieToStore(QNetworkCookie cookie) const
+{
+    // Create a url.
+    QUrl url;
+
+    // Check to see if the domain does not start with a `.` because Qt makes this harder than it should be.  <https://doc.qt.io/qt-5/qwebenginecookiestore.html#setCookie>
+    if (!cookie.domain().startsWith(QStringLiteral(".")))
+    {
+        // Populate the URL.
+        url.setHost(cookie.domain());
+        url.setScheme(QStringLiteral("https"));
+
+        // Clear the domain from the cookie.
+        cookie.setDomain(QStringLiteral(""));
+    }
+
+    // Add the cookie to the store.
+    webEngineCookieStorePointer->setCookie(cookie, url);
+}
+
 void BrowserView::applyApplicationSettings()
 {
     // Set the search engine URL.
diff --git a/src/views/BrowserView.h b/src/views/BrowserView.h
index 0a88a2c..fb60f03 100644
--- a/src/views/BrowserView.h
+++ b/src/views/BrowserView.h
@@ -70,6 +70,7 @@ signals:
 
 public Q_SLOTS:
     // The public slots.
+    void addCookieToStore(QNetworkCookie cookie) const;
     void applyApplicationSettings();
     void applyDomainSettingsAndReload();
     void applyDomainSettingsWithoutReloading(const QString &hostname);
diff --git a/src/windows/BrowserWindow.cpp b/src/windows/BrowserWindow.cpp
index 3293f02..c70bab1 100644
--- a/src/windows/BrowserWindow.cpp
+++ b/src/windows/BrowserWindow.cpp
@@ -241,13 +241,13 @@ BrowserWindow::BrowserWindow() : KXmlGuiWindow()
     cookieListPointer = new QList<QNetworkCookie>;
 
     // Add new cookies to the list.
-    connect(browserViewPointer, SIGNAL(addCookie(QNetworkCookie)), this, SLOT(addCookie(QNetworkCookie)));
+    connect(browserViewPointer, SIGNAL(addCookie(QNetworkCookie)), this, SLOT(addCookieToList(QNetworkCookie)));
 
     // Load the initial website.
     browserViewPointer->loadInitialWebsite();
 }
 
-void BrowserWindow::addCookie(const QNetworkCookie &newCookie) const
+void BrowserWindow::addCookieToList(const QNetworkCookie &newCookie) const
 {
     // Check to see if the list already contains a cookie with this ID.
     for (QNetworkCookie existingCookie : *cookieListPointer)
@@ -377,10 +377,10 @@ void BrowserWindow::openCookiesDialog()
     cookiesDialogPointer->show();
 
     // Connect the dialog signals.
+    connect(cookiesDialogPointer, SIGNAL(addCookie(QNetworkCookie)), browserViewPointer, SLOT(addCookieToStore(QNetworkCookie)));
     connect(cookiesDialogPointer, SIGNAL(deleteAllCookies()), browserViewPointer, SLOT(deleteAllCookies()));
 }
 
-
 void BrowserWindow::openDomainSettings() const
 {
     // Remove the focus from the URL line edit.
diff --git a/src/windows/BrowserWindow.h b/src/windows/BrowserWindow.h
index 6995efc..016879b 100644
--- a/src/windows/BrowserWindow.h
+++ b/src/windows/BrowserWindow.h
@@ -45,7 +45,7 @@ public:
 
 private Q_SLOTS:
     // The private slots.
-    void addCookie(const QNetworkCookie &newCookie) const;
+    void addCookieToList(const QNetworkCookie &newCookie) const;
     void addOrEditDomainSettings() const;
     void back() const;
     void clearUrlLineEditFocus() const;
-- 
2.47.2