X-Git-Url: https://gitweb.stoutner.com/?p=PrivacyBrowserPC.git;a=blobdiff_plain;f=src%2Fdialogs%2FCookiesDialog.cpp;fp=src%2Fdialogs%2FCookiesDialog.cpp;h=5763cb9c2ead6d6c68d8939e5b726bbb10cdc825;hp=972bc67d1d49b132a9fb4634f9631ff22804012c;hb=cba9a47f00b59f59f76f1b5195086285ca0cdb59;hpb=9b6cee96126484925bec4f4ab30c2b880df687fe diff --git a/src/dialogs/CookiesDialog.cpp b/src/dialogs/CookiesDialog.cpp index 972bc67..5763cb9 100644 --- a/src/dialogs/CookiesDialog.cpp +++ b/src/dialogs/CookiesDialog.cpp @@ -18,9 +18,8 @@ */ // Application headers. -#include "AddCookieDialog.h" +#include "AddOrEditCookieDialog.h" #include "CookiesDialog.h" -#include "ui_CookieDisplayWidget.h" #include "ui_CookiesDialog.h" // KDE Frameworks headers. @@ -29,9 +28,78 @@ // Qt toolkit headers. #include #include +#include #include -CookiesDialog::CookiesDialog(QList *originalCookieListPointer) : QDialog(nullptr), cookieListPointer(originalCookieListPointer) +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); + } + + } +} + +CookiesDialog::CookiesDialog(std::forward_list *originalCookieListPointer) : QDialog(nullptr), cookieListPointer(originalCookieListPointer) { // Set the dialog window title. setWindowTitle(i18nc("The cookies dialog window title", "Cookies")); @@ -45,39 +113,147 @@ CookiesDialog::CookiesDialog(QList *originalCookieListPointer) : // 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; - // Create the scroll area widget. - QWidget *scrollAreaWidgetPointer = new QWidget(); + // Initialize the standard item model. + standardItemModelPointer = new QStandardItemModel(); - // Set the scroll area widget. - scrollAreaPointer->setWidget(scrollAreaWidgetPointer); + // Set the column count. + standardItemModelPointer->setColumnCount(6); - // Create a scroll area VBox layout. - QVBoxLayout *scrollAreaVBoxLayoutPointer = new QVBoxLayout(); + // Set the header data. + standardItemModelPointer->setHeaderData(0, Qt::Horizontal, i18nc("The cookie Name header.", "Name")); + standardItemModelPointer->setHeaderData(1, Qt::Horizontal, i18nc("The cookie Path header.", "Path")); + standardItemModelPointer->setHeaderData(2, Qt::Horizontal, i18nc("The cookie Expiration Date header.", "Expiration Date")); + standardItemModelPointer->setHeaderData(3, Qt::Horizontal, i18nc("The cookie HTTP Only header.", "HTTP Only")); + standardItemModelPointer->setHeaderData(4, Qt::Horizontal, i18nc("The cookie Secure header.", "Secure")); + standardItemModelPointer->setHeaderData(5, Qt::Horizontal, i18nc("The cookie Value header.", "Value")); - // Set the scroll area widget layout. - scrollAreaWidgetPointer->setLayout(scrollAreaVBoxLayoutPointer); + // Set the header tool tips. + standardItemModelPointer->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.")); + standardItemModelPointer->horizontalHeaderItem(1)->setToolTip(i18nc("The cookie Path tool tip.", "Websites can restrict cookie access to subpath of their URL.")); + standardItemModelPointer->horizontalHeaderItem(2)->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.")); + standardItemModelPointer->horizontalHeaderItem(3)->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.")); + standardItemModelPointer->horizontalHeaderItem(4)->setToolTip(i18nc("The cookie Secure tool tip.", "Only allow the cookie to be transferred across HTTPS (as opposed to HTTP).")); + standardItemModelPointer->horizontalHeaderItem(5)->setToolTip(i18nc("The cookie Value tool tip.", "The value contains the cookie data.")); - // Create the cookies VBox layout. - cookiesVBoxLayoutPointer = new QVBoxLayout(); + // Sort the cookie list. + cookieListPointer->sort(cookieSortPredicate); - // 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(); + // Create the current domain string. + QString currentDomainString = ""; + + // Create the current domain standard item pointer. + QStandardItem *currentDomainStandardItemPointer; // Populate the VBoxLayout. for (QNetworkCookie cookie : *cookieListPointer) { - // Add the cookie to the layout. - addCookieToLayout(cookie); + // Get the cookie domain. + QString cookieDomain = cookie.domain(); + + // Check to see if the cookie is a member of the current domain. + if (cookieDomain != currentDomainString) // Create a new domain in the tree. + { + // Create a list for the domain standard items. + QList domainStandardItemList; + + // Create the new domain standard items. + QStandardItem *domainStandardItemPointer = new QStandardItem(cookieDomain); + QStandardItem *pathStandardItemPointer = new QStandardItem(QStringLiteral("")); + QStandardItem *expirationDateStandardItemPointer = new QStandardItem(QStringLiteral("")); + QStandardItem *isHttpOnlyStandardItemPointer = new QStandardItem(QStringLiteral("")); + QStandardItem *isSecureStandardItemPointer = new QStandardItem(QStringLiteral("")); + QStandardItem *valueStandardItemPointer = new QStandardItem(QStringLiteral("")); + + // Disable editing of the domain. + domainStandardItemPointer->setEditable(false); + pathStandardItemPointer->setEditable(false); + expirationDateStandardItemPointer->setEditable(false); + isHttpOnlyStandardItemPointer->setEditable(false); + isSecureStandardItemPointer->setEditable(false); + valueStandardItemPointer->setEditable(false); + + // Populate the domain standard item list. + domainStandardItemList.append(domainStandardItemPointer); + domainStandardItemList.append(pathStandardItemPointer); + domainStandardItemList.append(expirationDateStandardItemPointer); + domainStandardItemList.append(isHttpOnlyStandardItemPointer); + domainStandardItemList.append(isSecureStandardItemPointer); + domainStandardItemList.append(valueStandardItemPointer); + + // Add the domain to the tree. + standardItemModelPointer->invisibleRootItem()->appendRow(domainStandardItemList); + + // Update the current domain string. + currentDomainString = cookieDomain; + + // Update the current domain standard item pointer. + currentDomainStandardItemPointer = domainStandardItemPointer; + } + + // Create a list for the cookie standard items. + QList cookieStandardItemList; + + // Create the cookie standard items. + QStandardItem *nameStandardItemPointer = new QStandardItem(QString(cookie.name())); + QStandardItem *pathStandardItemPointer = new QStandardItem(QString(cookie.path())); + QStandardItem *expirationDateStandardItemPointer = new QStandardItem(QString(cookie.expirationDate().toString())); + QStandardItem *isHttpOnlyStandardItemPointer = new QStandardItem(QString(cookie.isHttpOnly() ? i18n("yes") : i18n("no"))); + QStandardItem *isSecureStandardItemPointer = new QStandardItem(QString(cookie.isSecure() ? i18n("yes") : i18n("no"))); + QStandardItem *valueStandardItemPointer = new QStandardItem(QString(cookie.value())); + + // Disable editing of the cookie standard items. + nameStandardItemPointer->setEditable(false); + pathStandardItemPointer->setEditable(false); + expirationDateStandardItemPointer->setEditable(false); + isHttpOnlyStandardItemPointer->setEditable(false); + isSecureStandardItemPointer->setEditable(false); + valueStandardItemPointer->setEditable(false); + + // Populate the cookie standard item list. + cookieStandardItemList.append(nameStandardItemPointer); + cookieStandardItemList.append(pathStandardItemPointer); + cookieStandardItemList.append(expirationDateStandardItemPointer); + cookieStandardItemList.append(isHttpOnlyStandardItemPointer); + cookieStandardItemList.append(isSecureStandardItemPointer); + cookieStandardItemList.append(valueStandardItemPointer); + + // Add the cookie to the tree. + currentDomainStandardItemPointer->appendRow(cookieStandardItemList); } + // Auto resize the headers. + treeViewPointer->header()->setSectionResizeMode(QHeaderView::ResizeToContents); + + // 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); + + // Set the tree view model. + treeViewPointer->setModel(standardItemModelPointer); + + // Get a handle for the tree view selection model. + treeViewSelectionModelPointer = treeViewPointer->selectionModel(); + + // Listen for selection changes. + connect(treeViewSelectionModelPointer, SIGNAL(selectionChanged(QItemSelection, QItemSelection)), this, SLOT(updateUi())); + // Get handles for the buttons. addCookieButtonPointer = cookiesDialogUi.addCookieButton; + editCookieButtonPointer = cookiesDialogUi.editCookieButton; + deleteCookieButtonPointer = cookiesDialogUi.deleteCookieButton; 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); @@ -86,12 +262,35 @@ CookiesDialog::CookiesDialog(QList *originalCookieListPointer) : deleteAllButtonPointer->setIcon(QIcon::fromTheme("delete")); // 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(deleteAllButtonPointer, SIGNAL(clicked()), this, SLOT(showDeleteAllMessageBox())); connect(dialogButtonBoxPointer, SIGNAL(rejected()), this, SLOT(reject())); // Set the cancel button to be the default. - cancelButtonPointer->setDefault(true); + 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(); @@ -102,57 +301,218 @@ 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); + // Get the new domain string. + QString newDomain = cookie.domain(); + + // Check to see if the domain already exists in the model. + QList currentDomainStandardItemList = standardItemModelPointer->findItems(newDomain); + + // Create a domain standard item pointer. + QStandardItem *domainStandardItemPointer; + + // Prepare the domain standard item pointer. + if (currentDomainStandardItemList.isEmpty()) // The domain doesn't currently exist in the tree. + { + // Create a list for the domain standard items. + QList domainStandardItemList; + + // Create the new domain standard items. + domainStandardItemPointer = new QStandardItem(newDomain); + QStandardItem *pathStandardItemPointer = new QStandardItem(QStringLiteral("")); + QStandardItem *expirationDateStandardItemPointer = new QStandardItem(QStringLiteral("")); + QStandardItem *isHttpOnlyStandardItemPointer = new QStandardItem(QStringLiteral("")); + QStandardItem *isSecureStandardItemPointer = new QStandardItem(QStringLiteral("")); + QStandardItem *valueStandardItemPointer = new QStandardItem(QStringLiteral("")); + + // Disable editing of the domain. + domainStandardItemPointer->setEditable(false); + pathStandardItemPointer->setEditable(false); + expirationDateStandardItemPointer->setEditable(false); + isHttpOnlyStandardItemPointer->setEditable(false); + isSecureStandardItemPointer->setEditable(false); + valueStandardItemPointer->setEditable(false); + + // Populate the domain standard item list. + domainStandardItemList.append(domainStandardItemPointer); + domainStandardItemList.append(pathStandardItemPointer); + domainStandardItemList.append(expirationDateStandardItemPointer); + domainStandardItemList.append(isHttpOnlyStandardItemPointer); + domainStandardItemList.append(isSecureStandardItemPointer); + domainStandardItemList.append(valueStandardItemPointer); + + // Create the insert domain row number. + int insertDomainRowNumber = 0; + + // Get the number of domains in the tree. + int numberOfDomains = standardItemModelPointer->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 = standardItemModelPointer->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. + standardItemModelPointer->invisibleRootItem()->insertRow(insertDomainRowNumber, domainStandardItemList); + } + else // The domain already exists in the tree. + { + // Use the current domain standard item. + domainStandardItemPointer = currentDomainStandardItemList[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 list for the cookie standard items. + QList cookieStandardItemList; + + // Create the cookie standard items. + QStandardItem *nameStandardItemPointer = new QStandardItem(newCookieName); + QStandardItem *pathStandardItemPointer = new QStandardItem(newCookiePath); + QStandardItem *expirationDateStandardItemPointer = new QStandardItem(QString(cookie.expirationDate().toString())); + QStandardItem *isHttpOnlyStandardItemPointer = new QStandardItem(QString(cookie.isHttpOnly() ? i18n("yes") : i18n("no"))); + QStandardItem *isSecureStandardItemPointer = new QStandardItem(QString(cookie.isSecure() ? i18n("yes") : i18n("no"))); + QStandardItem *valueStandardItemPointer = new QStandardItem(QString(cookie.value())); + + // Disable editing of the cookie standard items. + nameStandardItemPointer->setEditable(false); + pathStandardItemPointer->setEditable(false); + expirationDateStandardItemPointer->setEditable(false); + isHttpOnlyStandardItemPointer->setEditable(false); + isSecureStandardItemPointer->setEditable(false); + valueStandardItemPointer->setEditable(false); + + // Populate the cookie standard item list. + cookieStandardItemList.append(nameStandardItemPointer); + cookieStandardItemList.append(pathStandardItemPointer); + cookieStandardItemList.append(expirationDateStandardItemPointer); + cookieStandardItemList.append(isHttpOnlyStandardItemPointer); + cookieStandardItemList.append(isSecureStandardItemPointer); + cookieStandardItemList.append(valueStandardItemPointer); + + // Create the insert cookie row number. + int insertCookieRowNumber = 0; + + // Get the number of cookies in the domain. + int numberOfCookies = domainStandardItemPointer->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 = domainStandardItemPointer->child(i, 0)->index().data().toString(); + QString currentCookiePath = domainStandardItemPointer->child(i, 1)->index().data().toString(); + + // Check to see if the new cookie should be inserted after the current cookie. + if (newCookieName > currentCookieName) + { + // Insert the new cookie after the current cookie. + insertCookieRowNumber = i + 1; + } + else if ((newCookieName == currentCookieName) && (newCookiePath > currentCookiePath)) + { + // Insert the new cookie after the current cookie. + insertCookieRowNumber = i + 1; + } + } + + // Add the cookie to the tree. + domainStandardItemPointer->insertRow(insertCookieRowNumber, cookieStandardItemList); + + // Get the new cookie model index. + QModelIndex newCookieIndex = nameStandardItemPointer->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 { - // 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(1).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("" + cookie.domain() + ""); - nameLabelPointer->setText("" + cookie.name() + ""); - expirationDateLabelPointer->setText("" + cookie.expirationDate().toString() + ""); - pathLabelPointer->setText("" + cookie.path() + ""); - httpOnlyCheckBoxPointer->setChecked(cookie.isHttpOnly()); - secureCheckBoxPointer->setChecked(cookie.isSecure()); - valueLabelPointer->setText("" + cookie.value() + ""); - - // 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; + + // 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 view. + standardItemModelPointer->removeRow(modelIndex.row(), modelIndex.parent()); + + // Delete the cookie from the cookie list and cookie store. + emit deleteCookie(cookieToDelete); } -void CookiesDialog::showAddCookieMessageBox() const +void CookiesDialog::deleteCookieFromDialog(const QNetworkCookie &cookie) const +{ + // Get the current model index. + QModelIndex currentIndex = treeViewSelectionModelPointer->currentIndex(); + + // Get the parent index. + QModelIndex parentIndex = currentIndex.parent(); + + // Remove the cookie from the tree view. + standardItemModelPointer->removeRow(currentIndex.row(), parentIndex); + + // Remove the domain from the tree view if its only cookie has been deleted. + if (standardItemModelPointer->rowCount(parentIndex) == 0) + standardItemModelPointer->removeRow(parentIndex.row(), parentIndex.parent()); + + // Delete the cookie from the cookie list and cookie store. + emit deleteCookie(cookie); +} + +void CookiesDialog::showAddCookieDialog() const { // Instantiate an add cookie dialog. - QDialog *addCookieDialogPointer = new AddCookieDialog(); + QDialog *addCookieDialogPointer = new AddOrEditCookieDialog(AddOrEditCookieDialog::AddCookie); // Show the dialog. addCookieDialogPointer->show(); @@ -190,29 +550,153 @@ void CookiesDialog::showDeleteAllMessageBox() const // Delete all the cookies. emit deleteAllCookies(); - // Clear the cookie list. - cookieListPointer->clear(); + // Clear the standard item model. + standardItemModelPointer->clear(); + + // Update the UI. + updateUi(); + } +} + +void CookiesDialog::showDeleteCookieMessageBox() const +{ + // Get the current model index. + QModelIndex currentIndex = treeViewSelectionModelPointer->currentIndex(); + + // Get the parent model index. + QModelIndex parentIndex = currentIndex.parent(); + + // Determine if a domain is selected. + bool isDomain = standardItemModelPointer->hasChildren(currentIndex); - // Create a layout item pointer. - QLayoutItem *layoutItemPointer; + // Instantiate a delete cookie message box. + QMessageBox deleteCookieMessageBox; - // Delete each cookie widget. - while ((layoutItemPointer = cookiesVBoxLayoutPointer->takeAt(0)) != nullptr) + // Set the icon. + deleteCookieMessageBox.setIcon(QMessageBox::Warning); + + if (isDomain) + { + // Get the number of cookies. + int numberOfCookiesToDelete = standardItemModelPointer->rowCount(currentIndex); + + // Set the window title. + deleteCookieMessageBox.setWindowTitle(i18nc("Delete cookies dialog title", "Delete %1 Cookies", numberOfCookiesToDelete)); + + // Set the text. + deleteCookieMessageBox.setText(i18nc("Delete cookies dialog text", "Delete %1 cookies?", numberOfCookiesToDelete)); + } + else + { + // 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?")); + } + + // 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. + { + // Get the number of cookies. + int numberOfCookies = standardItemModelPointer->rowCount(currentIndex); + + // Delete each child cookie. + for (int i = 0; i < numberOfCookies; ++i) + { + // Delete the cookie for the first child. Once this is deleted, the second child will become the first child. + deleteCookie(standardItemModelPointer->index(0, 0, currentIndex)); + } + + // Delete the domain from the tree view. + standardItemModelPointer->removeRow(currentIndex.row(), parentIndex); + } + else // A single cookie is selected. { - // Delete the widget. - delete layoutItemPointer->widget(); + // Delete the cookie. + deleteCookie(currentIndex); - // Delete the layout. - delete layoutItemPointer; + // Remove the domain row if its only cookie has been deleted. + if (standardItemModelPointer->rowCount(parentIndex) == 0) + standardItemModelPointer->removeRow(parentIndex.row(), parentIndex.parent()); } + } +} - // Update the UI. - updateUi(); +void CookiesDialog::showEditCookieDialog() const +{ + // Get the current model index. + QModelIndex currentIndex = treeViewSelectionModelPointer->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(1).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); + + // Show the dialog. + editCookieDialogPointer->show(); + + // Process cookie events. + connect(editCookieDialogPointer, SIGNAL(addCookie(QNetworkCookie)), this, SLOT(addCookieFromDialog(QNetworkCookie))); + connect(editCookieDialogPointer, SIGNAL(deleteCookie(QNetworkCookie)), this, SLOT(deleteCookieFromDialog(QNetworkCookie))); } void CookiesDialog::updateUi() const { + // Get the current index of the first column. + QModelIndex currentIndex = treeViewSelectionModelPointer->currentIndex().siblingAtColumn(0); + // Set the status of the buttons. - deleteAllButtonPointer->setEnabled(cookieListPointer->count() > 0); + editCookieButtonPointer->setEnabled(treeViewSelectionModelPointer->hasSelection() && !standardItemModelPointer->hasChildren(currentIndex)); + deleteCookieButtonPointer->setEnabled(treeViewSelectionModelPointer->hasSelection());; + deleteAllButtonPointer->setEnabled(standardItemModelPointer->hasChildren(standardItemModelPointer->invisibleRootItem()->index())); + + // Update the delete cookie button text. + if (deleteCookieButtonPointer->isEnabled()) // The button is enabled. + { + if (standardItemModelPointer->hasChildren(currentIndex)) // A domain is selected. + { + // Update the button text. + deleteCookieButtonPointer->setText(i18nc("Delete cookies button.", "&Delete %1 cookies", standardItemModelPointer->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")); + } }