*/
// Application headers.
-#include "AddCookieDialog.h"
+#include "AddOrEditCookieDialog.h"
#include "CookiesDialog.h"
-#include "ui_CookieDisplayWidget.h"
+#include "DurableCookiesDialog.h"
#include "ui_CookiesDialog.h"
+#include "databases/CookiesDatabase.h"
// KDE Frameworks headers.
#include <KLocalizedString>
// Qt toolkit headers.
#include <QDateTime>
#include <QMessageBox>
+#include <QShortcut>
#include <QUrl>
-CookiesDialog::CookiesDialog(QList<QNetworkCookie> *originalCookieListPointer) : QDialog(nullptr), cookieListPointer(originalCookieListPointer)
+// Define the cookie sort predicate.
+bool cookieSortPredicate(const QNetworkCookie &leftHandCookie, const QNetworkCookie &rightHandCookie)
+{
+ // Check to see if the domains are identical.
+ if (leftHandCookie.domain() == rightHandCookie.domain())
+ {
+ // Check to see if the names are identical.
+ if (leftHandCookie.name() == rightHandCookie.name())
+ {
+ // Sort the cookies by the path.
+ return (leftHandCookie.path() < rightHandCookie.path());
+ }
+ else // The name are not identical.
+ {
+ // Sort the cookies by the name.
+ return (leftHandCookie.name() < rightHandCookie.name());
+ }
+ }
+ else // The domains are not identical.
+ {
+ // Get copies of the domains.
+ QString leftHandDomain = leftHandCookie.domain();
+ QString rightHandDomain = rightHandCookie.domain();
+
+ // Get the top level domains.
+ QString leftHandTopLevelDomain = leftHandDomain.section('.', -1);
+ QString rightHandTopLevelDomain = rightHandDomain.section('.', -1);
+
+ // Get the second level domains.
+ QString leftHandSecondLevelDomain = leftHandDomain.section('.', -2);
+ QString rightHandSecondLevelDomain = rightHandDomain.section('.', -2);
+
+ // Get the third level domains.
+ QString leftHandThirdLevelDomain = leftHandDomain.section('.', -3);
+ QString rightHandThirdLevelDomain = rightHandDomain.section('.', -3);
+
+ // Check to see if the top level domains are the same.
+ if (leftHandTopLevelDomain == rightHandTopLevelDomain)
+ {
+ // Check to see if the second level domains are the same.
+ if (leftHandSecondLevelDomain == rightHandSecondLevelDomain)
+ {
+ // Check to see if the third level domains are the same.
+ if (leftHandThirdLevelDomain == rightHandThirdLevelDomain)
+ {
+ // Sort the cookies by the full domain because they share the same third level domain.
+ return (leftHandDomain < rightHandDomain);
+ }
+ else // The second level domains are the same, but the third level domains are different.
+ {
+ // Sort the cookies by the third level domains.
+ return (leftHandThirdLevelDomain < rightHandThirdLevelDomain);
+ }
+ }
+ else // The top level domains are the same, but the second level domains are diferent.
+ {
+ // Sort the cookies by the second level domain.
+ return (leftHandSecondLevelDomain < rightHandSecondLevelDomain);
+ }
+ }
+ else // The top level domains are different.
+ {
+ // 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.
setWindowTitle(i18nc("The cookies dialog window title", "Cookies"));
// Setup the UI.
cookiesDialogUi.setupUi(this);
- // Get a handle for the scroll area.
- QScrollArea *scrollAreaPointer = cookiesDialogUi.scrollArea;
+ // Get a handle for the tree view.
+ treeViewPointer = cookiesDialogUi.treeView;
+
+ // Initialize the tree model.
+ treeModelPointer = new QStandardItemModel();
+
+ // Set the column count.
+ treeModelPointer->setColumnCount(7);
+
+ // Set the tree header data.
+ treeModelPointer->setHeaderData(0, Qt::Horizontal, i18nc("The cookie Name header.", "Name"));
+ treeModelPointer->setHeaderData(1, Qt::Horizontal, i18nc("The cookie Durable header.", "Durable"));
+ treeModelPointer->setHeaderData(2, Qt::Horizontal, i18nc("The cookie Path header.", "Path"));
+ treeModelPointer->setHeaderData(3, Qt::Horizontal, i18nc("The cookie Expiration Date header.", "Expiration Date"));
+ treeModelPointer->setHeaderData(4, Qt::Horizontal, i18nc("The cookie HTTP Only header.", "HTTP Only"));
+ treeModelPointer->setHeaderData(5, Qt::Horizontal, i18nc("The cookie Secure header.", "Secure"));
+ treeModelPointer->setHeaderData(6, Qt::Horizontal, i18nc("The cookie Value header.", "Value"));
+
+ // Set the tree header tool tips.
+ treeModelPointer->horizontalHeaderItem(0)->setToolTip(i18nc("The cookie Name tool tip.",
+ "The name identifies the cookie. Each cookie has a unique combination of domain, name, and path."));
+ treeModelPointer->horizontalHeaderItem(1)->setToolTip(i18nc("The cookie Durable tool tip",
+ "Durable cookies pursist across restarts, irrespective of the expiration date. All other cookies are deleted when Privacy Browser closes, irrespective of the expiration date."));
+ treeModelPointer->horizontalHeaderItem(2)->setToolTip(i18nc("The cookie Path tool tip.", "Websites can restrict cookie access to subpath of their URL."));
+ treeModelPointer->horizontalHeaderItem(3)->setToolTip(i18nc("The cookie Expiration Date tool tip.",
+ "Cookies without an expiration date are known as session cookies and are expected to be deleted every time the browser closes."));
+ treeModelPointer->horizontalHeaderItem(4)->setToolTip(i18nc("The cookie HTTP Only tool tip.",
+ "Restrict cookie access to HTTP (and HTTPS). This prevents JavaScript from accessing the cookie, which hardens it against cross-site scripting attacks."));
+ treeModelPointer->horizontalHeaderItem(5)->setToolTip(i18nc("The cookie Secure tool tip.", "Only allow the cookie to be transferred across HTTPS (as opposed to HTTP)."));
+ treeModelPointer->horizontalHeaderItem(6)->setToolTip(i18nc("The cookie Value tool tip.", "The value contains the cookie data."));
+
+ // Sort the cookie list.
+ cookieListPointer->sort(cookieSortPredicate);
+
+ // Create the current domain string.
+ QString currentDomainString = "";
+
+ // Create the current domain item pointer.
+ QStandardItem *currentDomainItemPointer;
+
+ // Populate the cookie tree view.
+ for (QNetworkCookie cookie : *cookieListPointer)
+ {
+ // Get the cookie domain.
+ QString cookieDomain = cookie.domain();
- // Create the scroll area widget.
- QWidget *scrollAreaWidgetPointer = new QWidget();
+ // Check to see if the cookie is a member of the current domain.
+ if (cookieDomain != currentDomainString) // Create a new domain in the tree.
+ {
+ // Create the domain name item.
+ QStandardItem *domainNameItemPointer = new QStandardItem(cookieDomain);
- // Set the scroll area widget.
- scrollAreaPointer->setWidget(scrollAreaWidgetPointer);
+ // Add the domain to the tree.
+ treeModelPointer->invisibleRootItem()->appendRow(domainNameItemPointer);
- // Create a scroll area VBox layout.
- QVBoxLayout *scrollAreaVBoxLayoutPointer = new QVBoxLayout();
+ // Update the current domain string.
+ currentDomainString = cookieDomain;
- // Set the scroll area widget layout.
- scrollAreaWidgetPointer->setLayout(scrollAreaVBoxLayoutPointer);
+ // Update the current domain item pointer.
+ currentDomainItemPointer = domainNameItemPointer;
+ }
- // Create the cookies VBox layout.
- cookiesVBoxLayoutPointer = new QVBoxLayout();
+ // Check to see if the cookie is durable.
+ bool isDurable = CookiesDatabase::isDurable(cookie);
+
+ // Create a list for the cookie items.
+ QList<QStandardItem*> cookieItemList;
+
+ // Create the cookie items.
+ QStandardItem *nameItemPointer = new QStandardItem(QString(cookie.name()));
+ QStandardItem *durableItemPointer = new QStandardItem(QString(isDurable ? i18n("yes") : i18n("no")));
+ QStandardItem *pathItemPointer = new QStandardItem(QString(cookie.path()));
+ QStandardItem *expirationDateItemPointer = new QStandardItem(QString(cookie.expirationDate().toString()));
+ QStandardItem *isHttpOnlyItemPointer = new QStandardItem(QString(cookie.isHttpOnly() ? i18n("yes") : i18n("no")));
+ QStandardItem *isSecureItemPointer = new QStandardItem(QString(cookie.isSecure() ? i18n("yes") : i18n("no")));
+ QStandardItem *valueItemPointer = new QStandardItem(QString(cookie.value()));
+
+ // Populate the cookie standard item list.
+ cookieItemList.append(nameItemPointer);
+ cookieItemList.append(durableItemPointer);
+ cookieItemList.append(pathItemPointer);
+ cookieItemList.append(expirationDateItemPointer);
+ cookieItemList.append(isHttpOnlyItemPointer);
+ cookieItemList.append(isSecureItemPointer);
+ cookieItemList.append(valueItemPointer);
+
+ // Add the cookie to the tree.
+ currentDomainItemPointer->appendRow(cookieItemList);
+ }
- // 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();
+ // Auto resize the headers.
+ treeViewPointer->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
- // Populate the VBoxLayout.
- for (QNetworkCookie cookie : *cookieListPointer)
- {
- // Add the cookie to the layout.
- addCookieToLayout(cookie);
- }
+ // Disable stretching the last section. Otherwise, the Value field will be truncated to the width of the window when a row is expanded.
+ treeViewPointer->header()->setStretchLastSection(false);
+
+ // Don't elide the Value field (or any other field).
+ treeViewPointer->setTextElideMode(Qt::ElideNone);
+
+ // Indicate that all the rows are the same height, wich improves performance.
+ treeViewPointer->setUniformRowHeights(true);
+
+ // Disable editing in the tree view.
+ treeViewPointer->setEditTriggers(QAbstractItemView::NoEditTriggers);
+
+ // Set the tree model.
+ treeViewPointer->setModel(treeModelPointer);
+
+ // Get a handle for the tree selection model.
+ treeSelectionModelPointer = treeViewPointer->selectionModel();
+
+ // Listen for selection changes.
+ connect(treeSelectionModelPointer, SIGNAL(selectionChanged(QItemSelection, QItemSelection)), this, SLOT(updateUi()));
// Get handles for the buttons.
addCookieButtonPointer = cookiesDialogUi.addCookieButton;
+ editCookieButtonPointer = cookiesDialogUi.editCookieButton;
+ deleteCookieButtonPointer = cookiesDialogUi.deleteCookieButton;
+ deleteAllButtonPointer = cookiesDialogUi.deleteAllCookiesButton;
QDialogButtonBox *dialogButtonBoxPointer = cookiesDialogUi.dialogButtonBox;
- QPushButton *cancelButtonPointer = dialogButtonBoxPointer->button(QDialogButtonBox::Close);
+ 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(showAddCookieMessageBox()));
+ 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.
- cancelButtonPointer->setDefault(true);
+ // Set the close button to be the default.
+ closeButtonPointer->setDefault(true);
+
+ // Create the keyboard shortcuts.
+ QShortcut *aShortcutPointer = new QShortcut(QKeySequence(i18nc("The add cookie key shortcut.", "a")), this);
+ QShortcut *eShortcutPointer = new QShortcut(QKeySequence(i18nc("The edit cookie key shorcut.", "e")), this);
+ QShortcut *dShortcutPointer = new QShortcut(QKeySequence(i18nc("The delete cookie key shortcut.", "d")), this);
+ QShortcut *deleteShortcutPointer = new QShortcut(QKeySequence::Delete, this);
+ QShortcut *lShortcutPointer = new QShortcut(QKeySequence(i18nc("The delete all key shortcut.", "l")), this);
+ QShortcut *cShortcutPointer = new QShortcut(QKeySequence(i18nc("The close key shortcut.", "c")), this);
+ QShortcut *quitShortcutPointer = new QShortcut(QKeySequence::Quit, this);
+
+ // Connect the keyboard shortcuts to the buttons.
+ connect(aShortcutPointer, SIGNAL(activated()), addCookieButtonPointer, SLOT(click()));
+ connect(eShortcutPointer, SIGNAL(activated()), editCookieButtonPointer, SLOT(click()));
+ connect(dShortcutPointer, SIGNAL(activated()), deleteCookieButtonPointer, SLOT(click()));
+ connect(deleteShortcutPointer, SIGNAL(activated()), deleteCookieButtonPointer, SLOT(click()));
+ connect(lShortcutPointer, SIGNAL(activated()), deleteAllButtonPointer, SLOT(click()));
+ connect(cShortcutPointer, SIGNAL(activated()), closeButtonPointer, SLOT(click()));
+ connect(quitShortcutPointer, SIGNAL(activated()), closeButtonPointer, SLOT(click()));
+
+ // Edit a cookie when it is double clicked.
+ connect(treeViewPointer, SIGNAL(doubleClicked(QModelIndex)), editCookieButtonPointer, SLOT(click()));
// Update the UI.
updateUi();
};
-void CookiesDialog::addCookieFromDialog(const QNetworkCookie &cookie) const
+void CookiesDialog::addCookieFromDialog(const QNetworkCookie &cookie, const bool &isDurable) const
{
// Add the cookie to the cookie list and the cookie store.
emit addCookie(cookie);
- // Add the cookie to the VBox layout.
- addCookieToLayout(cookie);
+ // Get the new domain string.
+ QString newDomain = cookie.domain();
+
+ // Check to see if the domain already exists in the model.
+ QList<QStandardItem*> currentDomainItemList = treeModelPointer->findItems(newDomain);
+
+ // Create a domain item pointer.
+ QStandardItem *domainNameItemPointer;
+
+ // Prepare the domain item pointer.
+ if (currentDomainItemList.isEmpty()) // The domain doesn't currently exist in the tree.
+ {
+ // Create the domain name item.
+ domainNameItemPointer = new QStandardItem(newDomain);
+
+ // Create the insert domain row number.
+ int insertDomainRowNumber = 0;
+
+ // Get the number of domains in the tree.
+ int numberOfDomains = treeModelPointer->invisibleRootItem()->rowCount();
+
+ // Get the new domain strings.
+ QString newDomainTopLevelDomain = newDomain.section('.', -1);
+ QString newDomainSecondLevelDomain = newDomain.section('.', -2);
+ QString newDomainThirdLevelDomain = newDomain.section('.', -3);
+
+ // Iterate through all the domains.
+ for (int i = 0; i < numberOfDomains; ++i)
+ {
+ // Get the current domain strings.
+ QString currentDomain = treeModelPointer->invisibleRootItem()->child(i, 0)->index().data().toString();
+ QString currentDomainTopLevelDomain = currentDomain.section('.', -1);
+ QString currentDomainSecondLevelDomain = currentDomain.section('.', -2);
+ QString currentDomainThirdLevelDomain = currentDomain.section('.', -3);
+
+ // Check to see if the new domain should be inserted after the current domain.
+ if (newDomainTopLevelDomain > currentDomainTopLevelDomain)
+ {
+ // Insert the new domain after the current domain.
+ insertDomainRowNumber = i + 1;
+ }
+ else if ((newDomainTopLevelDomain == currentDomainTopLevelDomain) && (newDomainSecondLevelDomain > currentDomainSecondLevelDomain))
+ {
+ // Insert the new domain after the current domain.
+ insertDomainRowNumber = i + 1;
+ }
+ else if ((newDomainSecondLevelDomain == currentDomainSecondLevelDomain) && (newDomainThirdLevelDomain > currentDomainThirdLevelDomain))
+ {
+ // Insert the new domain after the current domain.
+ insertDomainRowNumber = i + 1;
+ }
+ else if ((newDomainThirdLevelDomain == currentDomainThirdLevelDomain) && (newDomain > currentDomain))
+ {
+ // Insert the new domain after the current domain.
+ insertDomainRowNumber = i + 1;
+ }
+ }
+
+ // Add the domain to the tree.
+ treeModelPointer->invisibleRootItem()->insertRow(insertDomainRowNumber, domainNameItemPointer);
+ }
+ else // The domain already exists in the tree.
+ {
+ // Use the current domain standard item.
+ domainNameItemPointer = currentDomainItemList[0];
+ }
+
+ // Get strings for the new cookie name and path (used later in the placement of the row).
+ QString newCookieName = QString(cookie.name());
+ QString newCookiePath = QString(cookie.path());
+
+ // Create a cookie item list.
+ QList<QStandardItem*> cookieItemList;
+
+ // Create the cookie items.
+ QStandardItem *nameItemPointer = new QStandardItem(newCookieName);
+ QStandardItem *durableItemPointer = new QStandardItem(QString(isDurable ? i18n("yes") : i18n("no")));
+ QStandardItem *pathItemPointer = new QStandardItem(newCookiePath);
+ QStandardItem *expirationDateItemPointer = new QStandardItem(QString(cookie.expirationDate().toString()));
+ QStandardItem *isHttpOnlyItemPointer = new QStandardItem(QString(cookie.isHttpOnly() ? i18n("yes") : i18n("no")));
+ QStandardItem *isSecureItemPointer = new QStandardItem(QString(cookie.isSecure() ? i18n("yes") : i18n("no")));
+ QStandardItem *valueItemPointer = new QStandardItem(QString(cookie.value()));
+
+ // Populate the cookie item list.
+ cookieItemList.append(nameItemPointer);
+ cookieItemList.append(durableItemPointer);
+ cookieItemList.append(pathItemPointer);
+ cookieItemList.append(expirationDateItemPointer);
+ cookieItemList.append(isHttpOnlyItemPointer);
+ cookieItemList.append(isSecureItemPointer);
+ cookieItemList.append(valueItemPointer);
+
+ // Create the insert cookie row number.
+ int insertCookieRowNumber = 0;
+
+ // Create the remove existing row tracker.
+ bool removeExistingRow = false;
+
+ // Get the number of cookies in the domain.
+ int numberOfCookies = domainNameItemPointer->rowCount();
+
+ // Iterate through the cookies for this domain.
+ for (int i = 0; i < numberOfCookies; ++i)
+ {
+ // Get the current cookie name and path at the indicated row.
+ QString currentCookieName = domainNameItemPointer->child(i, 0)->index().data().toString();
+ QString currentCookiePath = domainNameItemPointer->child(i, 2)->index().data().toString();
+
+ // Check to see if the new cookie should be inserted after the current cookie.
+ if (newCookieName > currentCookieName) // The new cookie name comes after the current cookie name.
+ {
+ // Insert the new cookie after the current cookie.
+ insertCookieRowNumber = i + 1;
+ }
+ else if ((newCookieName == currentCookieName) && (newCookiePath > currentCookiePath)) // The names are the same, but the new cookie path comes after the current cookie path.
+ {
+ // Insert the new cookie after the current cookie.
+ insertCookieRowNumber = i + 1;
+ }
+ else if ((newCookieName == currentCookieName) && (newCookiePath == currentCookiePath)) // The cookies are the same.
+ {
+ // Remove the existing cookie in this row.
+ removeExistingRow = true;
+
+ // Insert the cookie in it's place.
+ insertCookieRowNumber = i;
+ }
+ }
+
+ // Remove the existing row if it is being edited.
+ if (removeExistingRow)
+ domainNameItemPointer->removeRow(insertCookieRowNumber);
+
+ // Add the cookie to the tree model.
+ domainNameItemPointer->insertRow(insertCookieRowNumber, cookieItemList);
+
+ // Get the new cookie model index.
+ QModelIndex newCookieIndex = nameItemPointer->index();
+
+ // Set the new cookie to be the current index.
+ treeViewPointer->setCurrentIndex(newCookieIndex);
+
+ // Expand the parent of the new cookie.
+ treeViewPointer->expand(newCookieIndex.parent());
}
-void CookiesDialog::addCookieToLayout(const QNetworkCookie &cookie) const
+void CookiesDialog::deleteCookie(const QModelIndex &modelIndex, const bool &deleteDurableCookies) const
{
- // Create a cookie display widget.
- QWidget *cookieDisplayWidgetPointer = new QWidget();
+ // Create a partial cookie.
+ QNetworkCookie partialCookie;
- // Instantiate the cookie widget dialog UI.
- Ui::CookieDisplayWidget cookieDisplayWidgetUi;
+ // Populate the partial cookie from the current model index.
+ partialCookie.setDomain(modelIndex.parent().siblingAtColumn(0).data().toString());
+ partialCookie.setName(modelIndex.siblingAtColumn(0).data().toString().toUtf8());
+ partialCookie.setPath(modelIndex.siblingAtColumn(2).data().toString());
- // 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);
+ // Create a cookie to delete.
+ QNetworkCookie cookieToDelete;
+
+ // Check if the cookie is durable.
+ bool isDurable = CookiesDatabase::isDurable(partialCookie);
+
+ // Only delete durable cookies if directed.
+ if (deleteDurableCookies || !isDurable)
+ {
+ // Search for the partial cookie in the cookie list.
+ for (QNetworkCookie cookie : *cookieListPointer)
+ {
+ // Store the cookie to delete if it has the same identifier as the partial cookie.
+ if (cookie.hasSameIdentifier(partialCookie))
+ cookieToDelete = cookie;
+ }
+
+ // Remove the cookie from the tree model.
+ treeModelPointer->removeRow(modelIndex.row(), modelIndex.parent());
+
+ // Delete the cookie from the cookie list and cookie store.
+ emit deleteCookie(cookieToDelete);
+
+ // Delete the cookie from the durable cookies database.
+ if (isDurable)
+ CookiesDatabase::deleteCookie(cookieToDelete);
+ }
+}
+
+void CookiesDialog::deleteDomain(const QModelIndex &modelIndex, const bool &deleteDurableCookies) const
+{
+ // Get the parent index.
+ QModelIndex parentIndex = modelIndex.parent();
+
+ // Get the number of cookies in the domain.
+ int numberOfCookies = treeModelPointer->rowCount(modelIndex);
+
+ // Delete each child cookie, starting from the bottom.
+ for (int i = numberOfCookies; i > 0; --i)
+ deleteCookie(treeModelPointer->index(i-1, 0, modelIndex), deleteDurableCookies);
+
+ // Remove the domain if all the cookies have been deleted.
+ if (treeModelPointer->rowCount(modelIndex) == 0)
+ 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
+{
+ // Get the current model index.
+ QModelIndex currentIndex = treeSelectionModelPointer->currentIndex();
+
+ // Get the parent index.
+ QModelIndex parentIndex = currentIndex.parent();
+
+ // Remove the cookie from the tree model.
+ treeModelPointer->removeRow(currentIndex.row(), parentIndex);
+
+ // Remove the domain from the tree model if its only cookie has been deleted.
+ if (treeModelPointer->rowCount(parentIndex) == 0)
+ treeModelPointer->removeRow(parentIndex.row(), parentIndex.parent());
+
+ // Delete the cookie from the cookie list and cookie store.
+ emit deleteCookie(cookie);
}
-void CookiesDialog::showAddCookieMessageBox() const
+void CookiesDialog::showAddCookieDialog() const
{
// Instantiate an add cookie dialog.
- QDialog *addCookieDialogPointer = new AddCookieDialog();
+ QDialog *addCookieDialogPointer = new AddOrEditCookieDialog(AddOrEditCookieDialog::AddCookie);
// Show the dialog.
addCookieDialogPointer->show();
// Add the cookie if directed.
- connect(addCookieDialogPointer, SIGNAL(addCookie(QNetworkCookie)), this, SLOT(addCookieFromDialog(QNetworkCookie)));
+ connect(addCookieDialogPointer, SIGNAL(addCookie(QNetworkCookie, bool)), this, SLOT(addCookieFromDialog(QNetworkCookie, bool)));
}
void CookiesDialog::showDeleteAllMessageBox() const
// Set the text.
deleteAllCookiesMessageBox.setText(i18nc("Delete all cookies dialog text", "Delete all cookies?"));
+ // Create a delete durable cookies check box.
+ QCheckBox deleteDurableCookiesCheckBox(i18nc("Delete durable cookies check box", "Delete even if durable"));
+
+ // Add the check box to the dialog.
+ deleteAllCookiesMessageBox.setCheckBox(&deleteDurableCookiesCheckBox);
+
// Set the standard buttons.
deleteAllCookiesMessageBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
// Delete all cookies if instructed.
if (returnValue == QMessageBox::Yes)
{
- // Delete all the cookies.
- emit deleteAllCookies();
+ // Only delete durable cookies if requested.
+ if (deleteDurableCookiesCheckBox.isChecked()) // Delete everything.
+ {
+ // Delete all the cookies.
+ emit deleteAllCookies();
- // Clear the cookie list.
- cookieListPointer->clear();
+ // Clear the tree model.
+ treeModelPointer->clear();
- // Create a layout item pointer.
- QLayoutItem *layoutItemPointer;
+ // Delete the durable cookies from the database.
+ CookiesDatabase::deleteAllCookies();
- // Delete each cookie widget.
- while ((layoutItemPointer = cookiesVBoxLayoutPointer->takeAt(0)) != nullptr)
+ // Update the UI.
+ updateUi();
+ }
+ else // Only delete cookies that are not durable.
{
- // Delete the widget.
- delete layoutItemPointer->widget();
+ // Get the root model index.
+ QModelIndex rootIndex = treeModelPointer->invisibleRootItem()->index();
- // Delete the layout.
- delete layoutItemPointer;
+ // Get the number of domains.
+ int numberOfDomains = treeModelPointer->rowCount(rootIndex);
+
+ // Delete each domain, starting from the bottom.
+ for (int i = numberOfDomains; i > 0; --i)
+ deleteDomain(treeModelPointer->index(i - 1, 0, rootIndex), deleteDurableCookiesCheckBox.isChecked());
}
+ }
+}
+
+void CookiesDialog::showDeleteCookieMessageBox() const
+{
+ // Get the current model index.
+ QModelIndex currentIndex = treeSelectionModelPointer->currentIndex();
+
+ // Determine if a domain is selected.
+ bool isDomain = treeModelPointer->hasChildren(currentIndex);
+
+ // Instantiate a delete cookie message box.
+ QMessageBox deleteCookieMessageBox;
+
+ // Set the icon.
+ deleteCookieMessageBox.setIcon(QMessageBox::Warning);
+
+ // Create a delete durable cookies check box.
+ QCheckBox deleteDurableCookiesCheckBox(i18nc("Delete durable cookies check box", "Delete even if durable"));
+
+ if (isDomain) // A domain is selected.
+ {
+ // Get the number of cookies.
+ int numberOfCookiesToDelete = treeModelPointer->rowCount(currentIndex);
+
+ // Set the window title.
+ deleteCookieMessageBox.setWindowTitle(i18ncp("Delete cookies dialog title", "Delete %1 Cookie", "Delete 1% Cookies", numberOfCookiesToDelete));
- // Update the UI.
- updateUi();
+ // Set the text.
+ deleteCookieMessageBox.setText(i18ncp("Delete cookies dialog text", "Delete %1 cookie?", "Delete %1 cookies?", numberOfCookiesToDelete));
}
+ else // A single cookie is selected.
+ {
+ // Set the window title.
+ deleteCookieMessageBox.setWindowTitle(i18nc("Delete cookie dialog title", "Delete 1 Cookie"));
+
+ // Set the text.
+ deleteCookieMessageBox.setText(i18nc("Delete cookie dialog text", "Delete 1 cookie?"));
+
+ // Check the box.
+ deleteDurableCookiesCheckBox.setChecked(true);
+ }
+
+ // Add the check box to the dialog.
+ deleteCookieMessageBox.setCheckBox(&deleteDurableCookiesCheckBox);
+
+ // Set the standard buttons.
+ deleteCookieMessageBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
+
+ // Set the default button.
+ deleteCookieMessageBox.setDefaultButton(QMessageBox::No);
+
+ // Display the dialog and capture the return value.
+ int returnValue = deleteCookieMessageBox.exec();
+
+ // Delete the cookie if instructed.
+ if (returnValue == QMessageBox::Yes)
+ {
+ // Delete the cookies according to the selection.
+ if (isDomain) // A domain is selected.
+ {
+ // Delete the domain.
+ deleteDomain(currentIndex, deleteDurableCookiesCheckBox.isChecked());
+ }
+ else // A single cookie is selected.
+ {
+ // Get the parent model index.
+ QModelIndex parentIndex = currentIndex.parent();
+
+ // Delete the cookie.
+ deleteCookie(currentIndex, deleteDurableCookiesCheckBox.isChecked());
+
+ // Remove the domain row if its only cookie has been deleted.
+ if (treeModelPointer->rowCount(parentIndex) == 0)
+ treeModelPointer->removeRow(parentIndex.row(), parentIndex.parent());
+ }
+ }
+}
+
+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.
+ QModelIndex currentIndex = treeSelectionModelPointer->currentIndex();
+
+ // Create a partial cookie.
+ QNetworkCookie partialCookie;
+
+ // Populate the partial cookie from the current model index.
+ partialCookie.setDomain(currentIndex.parent().siblingAtColumn(0).data().toString());
+ partialCookie.setName(currentIndex.siblingAtColumn(0).data().toString().toUtf8());
+ partialCookie.setPath(currentIndex.siblingAtColumn(2).data().toString());
+
+ // Create a cookie to edit.
+ QNetworkCookie cookieToEdit;
+
+ // Search for the partial cookie in the cookie list.
+ for (QNetworkCookie cookie : *cookieListPointer)
+ {
+ // Store the cookie to edit if it has the same identifier as the partial cookie.
+ if (cookie.hasSameIdentifier(partialCookie))
+ cookieToEdit = cookie;
+ }
+
+ // Instantiate an edit cookie dialog.
+ QDialog *editCookieDialogPointer = new AddOrEditCookieDialog(AddOrEditCookieDialog::EditCookie, &cookieToEdit, currentIndex.siblingAtColumn(1).data().toString() == i18n("yes"));
+
+ // Show the dialog.
+ editCookieDialogPointer->show();
+
+ // Process cookie events.
+ connect(editCookieDialogPointer, SIGNAL(addCookie(QNetworkCookie, bool)), this, SLOT(addCookieFromDialog(QNetworkCookie, bool)));
+ connect(editCookieDialogPointer, SIGNAL(deleteCookie(QNetworkCookie)), this, SLOT(deleteCookieFromDialog(QNetworkCookie)));
}
void CookiesDialog::updateUi() const
{
+ // Get the current index of the first column.
+ QModelIndex currentIndex = treeSelectionModelPointer->currentIndex().siblingAtColumn(0);
+
// Set the status of the buttons.
- deleteAllButtonPointer->setEnabled(cookieListPointer->count() > 0);
+ editCookieButtonPointer->setEnabled(treeSelectionModelPointer->hasSelection() && !treeModelPointer->hasChildren(currentIndex));
+ deleteCookieButtonPointer->setEnabled(treeSelectionModelPointer->hasSelection());;
+ deleteAllButtonPointer->setEnabled(treeModelPointer->hasChildren(treeModelPointer->invisibleRootItem()->index()));
+
+ // Update the delete cookie button text.
+ if (deleteCookieButtonPointer->isEnabled()) // The button is enabled.
+ {
+ if (treeModelPointer->hasChildren(currentIndex)) // A domain is selected.
+ {
+ // Update the button text.
+ deleteCookieButtonPointer->setText(i18ncp("Delete cookies button.", "&Delete %1 cookie", "&Delete %1 cookies", treeModelPointer->rowCount(currentIndex)));
+ }
+ else // A single cookie is selected.
+ {
+ // Update the button text.
+ deleteCookieButtonPointer->setText(i18nc("Delete cookies button.", "&Delete 1 cookie"));
+ }
+ }
+ else // The button is disabled.
+ {
+ // 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()));
}