2 * Copyright © 2022 Soren Stoutner <soren@stoutner.com>.
4 * This file is part of Privacy Browser PC <https://www.stoutner.com/privacy-browser-pc>.
6 * Privacy Browser PC is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * Privacy Browser PC is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with Privacy Browser PC. If not, see <http://www.gnu.org/licenses/>.
20 // Application headers.
21 #include "AddOrEditCookieDialog.h"
22 #include "CookiesDialog.h"
23 #include "DurableCookiesDialog.h"
24 #include "ui_CookiesDialog.h"
25 #include "databases/CookiesDatabase.h"
27 // KDE Frameworks headers.
28 #include <KLocalizedString>
30 // Qt toolkit headers.
32 #include <QMessageBox>
36 // Define the cookie sort predicate.
37 bool cookieSortPredicate(const QNetworkCookie &leftHandCookie, const QNetworkCookie &rightHandCookie)
39 // Check to see if the domains are identical.
40 if (leftHandCookie.domain() == rightHandCookie.domain())
42 // Check to see if the names are identical.
43 if (leftHandCookie.name() == rightHandCookie.name())
45 // Sort the cookies by the path.
46 return (leftHandCookie.path() < rightHandCookie.path());
48 else // The name are not identical.
50 // Sort the cookies by the name.
51 return (leftHandCookie.name() < rightHandCookie.name());
54 else // The domains are not identical.
56 // Get copies of the domains.
57 QString leftHandDomain = leftHandCookie.domain();
58 QString rightHandDomain = rightHandCookie.domain();
60 // Get the top level domains.
61 QString leftHandTopLevelDomain = leftHandDomain.section('.', -1);
62 QString rightHandTopLevelDomain = rightHandDomain.section('.', -1);
64 // Get the second level domains.
65 QString leftHandSecondLevelDomain = leftHandDomain.section('.', -2);
66 QString rightHandSecondLevelDomain = rightHandDomain.section('.', -2);
68 // Get the third level domains.
69 QString leftHandThirdLevelDomain = leftHandDomain.section('.', -3);
70 QString rightHandThirdLevelDomain = rightHandDomain.section('.', -3);
72 // Check to see if the top level domains are the same.
73 if (leftHandTopLevelDomain == rightHandTopLevelDomain)
75 // Check to see if the second level domains are the same.
76 if (leftHandSecondLevelDomain == rightHandSecondLevelDomain)
78 // Check to see if the third level domains are the same.
79 if (leftHandThirdLevelDomain == rightHandThirdLevelDomain)
81 // Sort the cookies by the full domain because they share the same third level domain.
82 return (leftHandDomain < rightHandDomain);
84 else // The second level domains are the same, but the third level domains are different.
86 // Sort the cookies by the third level domains.
87 return (leftHandThirdLevelDomain < rightHandThirdLevelDomain);
90 else // The top level domains are the same, but the second level domains are diferent.
92 // Sort the cookies by the second level domain.
93 return (leftHandSecondLevelDomain < rightHandSecondLevelDomain);
96 else // The top level domains are different.
98 // Sort the cookies by the top level domain.
99 return (leftHandTopLevelDomain < rightHandTopLevelDomain);
104 // Construct the class.
105 CookiesDialog::CookiesDialog(std::list<QNetworkCookie> *originalCookieListPointer) : QDialog(nullptr), cookieListPointer(originalCookieListPointer)
107 // Set the dialog window title.
108 setWindowTitle(i18nc("The cookies dialog window title", "Cookies"));
110 // Set the window modality.
111 setWindowModality(Qt::WindowModality::ApplicationModal);
113 // Instantiate the cookie settings dialog UI.
114 Ui::CookiesDialog cookiesDialogUi;
117 cookiesDialogUi.setupUi(this);
119 // Get a handle for the tree view.
120 treeViewPointer = cookiesDialogUi.treeView;
122 // Initialize the tree model.
123 treeModelPointer = new QStandardItemModel();
125 // Set the column count.
126 treeModelPointer->setColumnCount(7);
128 // Set the tree header data.
129 treeModelPointer->setHeaderData(0, Qt::Horizontal, i18nc("The cookie Name header.", "Name"));
130 treeModelPointer->setHeaderData(1, Qt::Horizontal, i18nc("The cookie Durable header.", "Durable"));
131 treeModelPointer->setHeaderData(2, Qt::Horizontal, i18nc("The cookie Path header.", "Path"));
132 treeModelPointer->setHeaderData(3, Qt::Horizontal, i18nc("The cookie Expiration Date header.", "Expiration Date"));
133 treeModelPointer->setHeaderData(4, Qt::Horizontal, i18nc("The cookie HTTP Only header.", "HTTP Only"));
134 treeModelPointer->setHeaderData(5, Qt::Horizontal, i18nc("The cookie Secure header.", "Secure"));
135 treeModelPointer->setHeaderData(6, Qt::Horizontal, i18nc("The cookie Value header.", "Value"));
137 // Set the tree header tool tips.
138 treeModelPointer->horizontalHeaderItem(0)->setToolTip(i18nc("The cookie Name tool tip.",
139 "The name identifies the cookie. Each cookie has a unique combination of domain, name, and path."));
140 treeModelPointer->horizontalHeaderItem(1)->setToolTip(i18nc("The cookie Durable tool tip",
141 "Durable cookies pursist across restarts, irrespective of the expiration date. All other cookies are deleted when Privacy Browser closes, irrespective of the expiration date."));
142 treeModelPointer->horizontalHeaderItem(2)->setToolTip(i18nc("The cookie Path tool tip.", "Websites can restrict cookie access to subpath of their URL."));
143 treeModelPointer->horizontalHeaderItem(3)->setToolTip(i18nc("The cookie Expiration Date tool tip.",
144 "Cookies without an expiration date are known as session cookies and are expected to be deleted every time the browser closes."));
145 treeModelPointer->horizontalHeaderItem(4)->setToolTip(i18nc("The cookie HTTP Only tool tip.",
146 "Restrict cookie access to HTTP (and HTTPS). This prevents JavaScript from accessing the cookie, which hardens it against cross-site scripting attacks."));
147 treeModelPointer->horizontalHeaderItem(5)->setToolTip(i18nc("The cookie Secure tool tip.", "Only allow the cookie to be transferred across HTTPS (as opposed to HTTP)."));
148 treeModelPointer->horizontalHeaderItem(6)->setToolTip(i18nc("The cookie Value tool tip.", "The value contains the cookie data."));
150 // Sort the cookie list.
151 cookieListPointer->sort(cookieSortPredicate);
153 // Create the current domain string.
154 QString currentDomainString = "";
156 // Create the current domain item pointer.
157 QStandardItem *currentDomainItemPointer;
159 // Populate the cookie tree view.
160 for (QNetworkCookie cookie : *cookieListPointer)
162 // Get the cookie domain.
163 QString cookieDomain = cookie.domain();
165 // Check to see if the cookie is a member of the current domain.
166 if (cookieDomain != currentDomainString) // Create a new domain in the tree.
168 // Create the domain name item.
169 QStandardItem *domainNameItemPointer = new QStandardItem(cookieDomain);
171 // Add the domain to the tree.
172 treeModelPointer->invisibleRootItem()->appendRow(domainNameItemPointer);
174 // Update the current domain string.
175 currentDomainString = cookieDomain;
177 // Update the current domain item pointer.
178 currentDomainItemPointer = domainNameItemPointer;
181 // Check to see if the cookie is durable.
182 bool isDurable = CookiesDatabase::isDurable(cookie);
184 // Create a list for the cookie items.
185 QList<QStandardItem*> cookieItemList;
187 // Create the cookie items.
188 QStandardItem *nameItemPointer = new QStandardItem(QString(cookie.name()));
189 QStandardItem *durableItemPointer = new QStandardItem(QString(isDurable ? i18n("yes") : i18n("no")));
190 QStandardItem *pathItemPointer = new QStandardItem(QString(cookie.path()));
191 QStandardItem *expirationDateItemPointer = new QStandardItem(QString(cookie.expirationDate().toString()));
192 QStandardItem *isHttpOnlyItemPointer = new QStandardItem(QString(cookie.isHttpOnly() ? i18n("yes") : i18n("no")));
193 QStandardItem *isSecureItemPointer = new QStandardItem(QString(cookie.isSecure() ? i18n("yes") : i18n("no")));
194 QStandardItem *valueItemPointer = new QStandardItem(QString(cookie.value()));
196 // Populate the cookie standard item list.
197 cookieItemList.append(nameItemPointer);
198 cookieItemList.append(durableItemPointer);
199 cookieItemList.append(pathItemPointer);
200 cookieItemList.append(expirationDateItemPointer);
201 cookieItemList.append(isHttpOnlyItemPointer);
202 cookieItemList.append(isSecureItemPointer);
203 cookieItemList.append(valueItemPointer);
205 // Add the cookie to the tree.
206 currentDomainItemPointer->appendRow(cookieItemList);
209 // Auto resize the headers.
210 treeViewPointer->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
212 // Disable stretching the last section. Otherwise, the Value field will be truncated to the width of the window when a row is expanded.
213 treeViewPointer->header()->setStretchLastSection(false);
215 // Don't elide the Value field (or any other field).
216 treeViewPointer->setTextElideMode(Qt::ElideNone);
218 // Indicate that all the rows are the same height, wich improves performance.
219 treeViewPointer->setUniformRowHeights(true);
221 // Disable editing in the tree view.
222 treeViewPointer->setEditTriggers(QAbstractItemView::NoEditTriggers);
224 // Set the tree model.
225 treeViewPointer->setModel(treeModelPointer);
227 // Get a handle for the tree selection model.
228 treeSelectionModelPointer = treeViewPointer->selectionModel();
230 // Listen for selection changes.
231 connect(treeSelectionModelPointer, SIGNAL(selectionChanged(QItemSelection, QItemSelection)), this, SLOT(updateUi()));
233 // Get handles for the buttons.
234 addCookieButtonPointer = cookiesDialogUi.addCookieButton;
235 editCookieButtonPointer = cookiesDialogUi.editCookieButton;
236 deleteCookieButtonPointer = cookiesDialogUi.deleteCookieButton;
237 deleteAllButtonPointer = cookiesDialogUi.deleteAllCookiesButton;
238 QDialogButtonBox *dialogButtonBoxPointer = cookiesDialogUi.dialogButtonBox;
239 QPushButton *closeButtonPointer = dialogButtonBoxPointer->button(QDialogButtonBox::Close);
241 // Add buttons to the dialog button box.
242 durableCookiesButtonPointer = dialogButtonBoxPointer->addButton(i18nc("View the durable cookies button", "Durable cookies - %1", CookiesDatabase::cookieCount()),
243 QDialogButtonBox::ActionRole);
245 // Set the button icons.
246 durableCookiesButtonPointer->setIcon(QIcon::fromTheme("view-visible"));
248 // Connect the buttons.
249 connect(addCookieButtonPointer, SIGNAL(clicked()), this, SLOT(showAddCookieDialog()));
250 connect(editCookieButtonPointer, SIGNAL(clicked()), this, SLOT(showEditCookieDialog()));
251 connect(deleteCookieButtonPointer, SIGNAL(clicked()), this, SLOT(showDeleteCookieMessageBox()));
252 connect(durableCookiesButtonPointer, SIGNAL(clicked()), this, SLOT(showDurableCookiesDialog()));
253 connect(deleteAllButtonPointer, SIGNAL(clicked()), this, SLOT(showDeleteAllMessageBox()));
254 connect(dialogButtonBoxPointer, SIGNAL(rejected()), this, SLOT(reject()));
256 // Set the close button to be the default.
257 closeButtonPointer->setDefault(true);
259 // Create the keyboard shortcuts.
260 QShortcut *aShortcutPointer = new QShortcut(QKeySequence(i18nc("The add cookie key shortcut.", "a")), this);
261 QShortcut *eShortcutPointer = new QShortcut(QKeySequence(i18nc("The edit cookie key shorcut.", "e")), this);
262 QShortcut *dShortcutPointer = new QShortcut(QKeySequence(i18nc("The delete cookie key shortcut.", "d")), this);
263 QShortcut *deleteShortcutPointer = new QShortcut(QKeySequence::Delete, this);
264 QShortcut *lShortcutPointer = new QShortcut(QKeySequence(i18nc("The delete all key shortcut.", "l")), this);
265 QShortcut *cShortcutPointer = new QShortcut(QKeySequence(i18nc("The close key shortcut.", "c")), this);
266 QShortcut *quitShortcutPointer = new QShortcut(QKeySequence::Quit, this);
268 // Connect the keyboard shortcuts to the buttons.
269 connect(aShortcutPointer, SIGNAL(activated()), addCookieButtonPointer, SLOT(click()));
270 connect(eShortcutPointer, SIGNAL(activated()), editCookieButtonPointer, SLOT(click()));
271 connect(dShortcutPointer, SIGNAL(activated()), deleteCookieButtonPointer, SLOT(click()));
272 connect(deleteShortcutPointer, SIGNAL(activated()), deleteCookieButtonPointer, SLOT(click()));
273 connect(lShortcutPointer, SIGNAL(activated()), deleteAllButtonPointer, SLOT(click()));
274 connect(cShortcutPointer, SIGNAL(activated()), closeButtonPointer, SLOT(click()));
275 connect(quitShortcutPointer, SIGNAL(activated()), closeButtonPointer, SLOT(click()));
277 // Edit a cookie when it is double clicked.
278 connect(treeViewPointer, SIGNAL(doubleClicked(QModelIndex)), editCookieButtonPointer, SLOT(click()));
284 void CookiesDialog::addCookieFromDialog(const QNetworkCookie &cookie, const bool &isDurable) const
286 // Add the cookie to the cookie list and the cookie store.
287 emit addCookie(cookie);
289 // Get the new domain string.
290 QString newDomain = cookie.domain();
292 // Check to see if the domain already exists in the model.
293 QList<QStandardItem*> currentDomainItemList = treeModelPointer->findItems(newDomain);
295 // Create a domain item pointer.
296 QStandardItem *domainNameItemPointer;
298 // Prepare the domain item pointer.
299 if (currentDomainItemList.isEmpty()) // The domain doesn't currently exist in the tree.
301 // Create the domain name item.
302 domainNameItemPointer = new QStandardItem(newDomain);
304 // Create the insert domain row number.
305 int insertDomainRowNumber = 0;
307 // Get the number of domains in the tree.
308 int numberOfDomains = treeModelPointer->invisibleRootItem()->rowCount();
310 // Get the new domain strings.
311 QString newDomainTopLevelDomain = newDomain.section('.', -1);
312 QString newDomainSecondLevelDomain = newDomain.section('.', -2);
313 QString newDomainThirdLevelDomain = newDomain.section('.', -3);
315 // Iterate through all the domains.
316 for (int i = 0; i < numberOfDomains; ++i)
318 // Get the current domain strings.
319 QString currentDomain = treeModelPointer->invisibleRootItem()->child(i, 0)->index().data().toString();
320 QString currentDomainTopLevelDomain = currentDomain.section('.', -1);
321 QString currentDomainSecondLevelDomain = currentDomain.section('.', -2);
322 QString currentDomainThirdLevelDomain = currentDomain.section('.', -3);
324 // Check to see if the new domain should be inserted after the current domain.
325 if (newDomainTopLevelDomain > currentDomainTopLevelDomain)
327 // Insert the new domain after the current domain.
328 insertDomainRowNumber = i + 1;
330 else if ((newDomainTopLevelDomain == currentDomainTopLevelDomain) && (newDomainSecondLevelDomain > currentDomainSecondLevelDomain))
332 // Insert the new domain after the current domain.
333 insertDomainRowNumber = i + 1;
335 else if ((newDomainSecondLevelDomain == currentDomainSecondLevelDomain) && (newDomainThirdLevelDomain > currentDomainThirdLevelDomain))
337 // Insert the new domain after the current domain.
338 insertDomainRowNumber = i + 1;
340 else if ((newDomainThirdLevelDomain == currentDomainThirdLevelDomain) && (newDomain > currentDomain))
342 // Insert the new domain after the current domain.
343 insertDomainRowNumber = i + 1;
347 // Add the domain to the tree.
348 treeModelPointer->invisibleRootItem()->insertRow(insertDomainRowNumber, domainNameItemPointer);
350 else // The domain already exists in the tree.
352 // Use the current domain standard item.
353 domainNameItemPointer = currentDomainItemList[0];
356 // Get strings for the new cookie name and path (used later in the placement of the row).
357 QString newCookieName = QString(cookie.name());
358 QString newCookiePath = QString(cookie.path());
360 // Create a cookie item list.
361 QList<QStandardItem*> cookieItemList;
363 // Create the cookie items.
364 QStandardItem *nameItemPointer = new QStandardItem(newCookieName);
365 QStandardItem *durableItemPointer = new QStandardItem(QString(isDurable ? i18n("yes") : i18n("no")));
366 QStandardItem *pathItemPointer = new QStandardItem(newCookiePath);
367 QStandardItem *expirationDateItemPointer = new QStandardItem(QString(cookie.expirationDate().toString()));
368 QStandardItem *isHttpOnlyItemPointer = new QStandardItem(QString(cookie.isHttpOnly() ? i18n("yes") : i18n("no")));
369 QStandardItem *isSecureItemPointer = new QStandardItem(QString(cookie.isSecure() ? i18n("yes") : i18n("no")));
370 QStandardItem *valueItemPointer = new QStandardItem(QString(cookie.value()));
372 // Populate the cookie item list.
373 cookieItemList.append(nameItemPointer);
374 cookieItemList.append(durableItemPointer);
375 cookieItemList.append(pathItemPointer);
376 cookieItemList.append(expirationDateItemPointer);
377 cookieItemList.append(isHttpOnlyItemPointer);
378 cookieItemList.append(isSecureItemPointer);
379 cookieItemList.append(valueItemPointer);
381 // Create the insert cookie row number.
382 int insertCookieRowNumber = 0;
384 // Create the remove existing row tracker.
385 bool removeExistingRow = false;
387 // Get the number of cookies in the domain.
388 int numberOfCookies = domainNameItemPointer->rowCount();
390 // Iterate through the cookies for this domain.
391 for (int i = 0; i < numberOfCookies; ++i)
393 // Get the current cookie name and path at the indicated row.
394 QString currentCookieName = domainNameItemPointer->child(i, 0)->index().data().toString();
395 QString currentCookiePath = domainNameItemPointer->child(i, 2)->index().data().toString();
397 // Check to see if the new cookie should be inserted after the current cookie.
398 if (newCookieName > currentCookieName) // The new cookie name comes after the current cookie name.
400 // Insert the new cookie after the current cookie.
401 insertCookieRowNumber = i + 1;
403 else if ((newCookieName == currentCookieName) && (newCookiePath > currentCookiePath)) // The names are the same, but the new cookie path comes after the current cookie path.
405 // Insert the new cookie after the current cookie.
406 insertCookieRowNumber = i + 1;
408 else if ((newCookieName == currentCookieName) && (newCookiePath == currentCookiePath)) // The cookies are the same.
410 // Remove the existing cookie in this row.
411 removeExistingRow = true;
413 // Insert the cookie in it's place.
414 insertCookieRowNumber = i;
418 // Remove the existing row if it is being edited.
419 if (removeExistingRow)
420 domainNameItemPointer->removeRow(insertCookieRowNumber);
422 // Add the cookie to the tree model.
423 domainNameItemPointer->insertRow(insertCookieRowNumber, cookieItemList);
425 // Get the new cookie model index.
426 QModelIndex newCookieIndex = nameItemPointer->index();
428 // Set the new cookie to be the current index.
429 treeViewPointer->setCurrentIndex(newCookieIndex);
431 // Expand the parent of the new cookie.
432 treeViewPointer->expand(newCookieIndex.parent());
435 void CookiesDialog::deleteCookie(const QModelIndex &modelIndex, const bool &deleteDurableCookies) const
437 // Create a partial cookie.
438 QNetworkCookie partialCookie;
440 // Populate the partial cookie from the current model index.
441 partialCookie.setDomain(modelIndex.parent().siblingAtColumn(0).data().toString());
442 partialCookie.setName(modelIndex.siblingAtColumn(0).data().toString().toUtf8());
443 partialCookie.setPath(modelIndex.siblingAtColumn(2).data().toString());
445 // Create a cookie to delete.
446 QNetworkCookie cookieToDelete;
448 // Check if the cookie is durable.
449 bool isDurable = CookiesDatabase::isDurable(partialCookie);
451 // Only delete durable cookies if directed.
452 if (deleteDurableCookies || !isDurable)
454 // Search for the partial cookie in the cookie list.
455 for (QNetworkCookie cookie : *cookieListPointer)
457 // Store the cookie to delete if it has the same identifier as the partial cookie.
458 if (cookie.hasSameIdentifier(partialCookie))
459 cookieToDelete = cookie;
462 // Remove the cookie from the tree model.
463 treeModelPointer->removeRow(modelIndex.row(), modelIndex.parent());
465 // Delete the cookie from the cookie list and cookie store.
466 emit deleteCookie(cookieToDelete);
468 // Delete the cookie from the durable cookies database.
470 CookiesDatabase::deleteCookie(cookieToDelete);
474 void CookiesDialog::deleteDomain(const QModelIndex &modelIndex, const bool &deleteDurableCookies) const
476 // Get the parent index.
477 QModelIndex parentIndex = modelIndex.parent();
479 // Get the number of cookies in the domain.
480 int numberOfCookies = treeModelPointer->rowCount(modelIndex);
482 // Delete each child cookie, starting from the bottom.
483 for (int i = numberOfCookies; i > 0; --i)
484 deleteCookie(treeModelPointer->index(i-1, 0, modelIndex), deleteDurableCookies);
486 // Remove the domain if all the cookies have been deleted.
487 if (treeModelPointer->rowCount(modelIndex) == 0)
488 treeModelPointer->removeRow(modelIndex.row(), parentIndex);
491 void CookiesDialog::deleteCookieFromDatabase(const QNetworkCookie &cookie) const
493 // Get a list of the matching domains. There should only be one item in this list
494 QList<QStandardItem *> domainList = treeModelPointer->findItems(cookie.domain());
496 // Find any matching cookies.
497 for (QStandardItem *domainItemPointer : domainList)
499 // Get the number of cookies in the domain.
500 int numberOfCookies = domainItemPointer->rowCount();
502 // Initialize the tracking variables.
503 bool cookieFound = false;
506 // Find the cookie in the tree model.
507 while (!cookieFound && (currentRow < numberOfCookies))
509 // Get the name item.
510 QStandardItem *nameItemPointer = domainItemPointer->child(currentRow);
512 // Get the name model index.
513 QModelIndex nameModelIndex = nameItemPointer->index();
515 // Check to see if the name and the path match.
516 if ((nameModelIndex.data().toString() == cookie.name()) && (nameModelIndex.siblingAtColumn(2).data().toString() == cookie.path()))
518 // Set the current index.
519 treeSelectionModelPointer->setCurrentIndex(nameModelIndex, QItemSelectionModel::ClearAndSelect);
521 // Delete the cookie.
522 deleteCookieFromDialog(cookie);
524 // Mark the cookie as found.
528 // Move to the next row.
534 void CookiesDialog::deleteCookieFromDialog(const QNetworkCookie &cookie) const
536 // Get the current model index.
537 QModelIndex currentIndex = treeSelectionModelPointer->currentIndex();
539 // Get the parent index.
540 QModelIndex parentIndex = currentIndex.parent();
542 // Remove the cookie from the tree model.
543 treeModelPointer->removeRow(currentIndex.row(), parentIndex);
545 // Remove the domain from the tree model if its only cookie has been deleted.
546 if (treeModelPointer->rowCount(parentIndex) == 0)
547 treeModelPointer->removeRow(parentIndex.row(), parentIndex.parent());
549 // Delete the cookie from the cookie list and cookie store.
550 emit deleteCookie(cookie);
553 void CookiesDialog::showAddCookieDialog() const
555 // Instantiate an add cookie dialog.
556 QDialog *addCookieDialogPointer = new AddOrEditCookieDialog(AddOrEditCookieDialog::AddCookie);
559 addCookieDialogPointer->show();
561 // Add the cookie if directed.
562 connect(addCookieDialogPointer, SIGNAL(addCookie(QNetworkCookie, bool)), this, SLOT(addCookieFromDialog(QNetworkCookie, bool)));
565 void CookiesDialog::showDeleteAllMessageBox() const
567 // Instantiate a delete all message box.
568 QMessageBox deleteAllCookiesMessageBox;
571 deleteAllCookiesMessageBox.setIcon(QMessageBox::Warning);
573 // Set the window title.
574 deleteAllCookiesMessageBox.setWindowTitle(i18nc("Delete all cookies dialog title", "Delete All Cookies"));
577 deleteAllCookiesMessageBox.setText(i18nc("Delete all cookies dialog text", "Delete all cookies?"));
579 // Create a delete durable cookies check box.
580 QCheckBox deleteDurableCookiesCheckBox(i18nc("Delete durable cookies check box", "Delete even if durable"));
582 // Add the check box to the dialog.
583 deleteAllCookiesMessageBox.setCheckBox(&deleteDurableCookiesCheckBox);
585 // Set the standard buttons.
586 deleteAllCookiesMessageBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
588 // Set the default button.
589 deleteAllCookiesMessageBox.setDefaultButton(QMessageBox::No);
591 // Display the dialog and capture the return value.
592 int returnValue = deleteAllCookiesMessageBox.exec();
594 // Delete all cookies if instructed.
595 if (returnValue == QMessageBox::Yes)
597 // Only delete durable cookies if requested.
598 if (deleteDurableCookiesCheckBox.isChecked()) // Delete everything.
600 // Delete all the cookies.
601 emit deleteAllCookies();
603 // Clear the tree model.
604 treeModelPointer->clear();
606 // Delete the durable cookies from the database.
607 CookiesDatabase::deleteAllCookies();
612 else // Only delete cookies that are not durable.
614 // Get the root model index.
615 QModelIndex rootIndex = treeModelPointer->invisibleRootItem()->index();
617 // Get the number of domains.
618 int numberOfDomains = treeModelPointer->rowCount(rootIndex);
620 // Delete each domain, starting from the bottom.
621 for (int i = numberOfDomains; i > 0; --i)
622 deleteDomain(treeModelPointer->index(i - 1, 0, rootIndex), deleteDurableCookiesCheckBox.isChecked());
627 void CookiesDialog::showDeleteCookieMessageBox() const
629 // Get the current model index.
630 QModelIndex currentIndex = treeSelectionModelPointer->currentIndex();
632 // Determine if a domain is selected.
633 bool isDomain = treeModelPointer->hasChildren(currentIndex);
635 // Instantiate a delete cookie message box.
636 QMessageBox deleteCookieMessageBox;
639 deleteCookieMessageBox.setIcon(QMessageBox::Warning);
641 // Create a delete durable cookies check box.
642 QCheckBox deleteDurableCookiesCheckBox(i18nc("Delete durable cookies check box", "Delete even if durable"));
644 if (isDomain) // A domain is selected.
646 // Get the number of cookies.
647 int numberOfCookiesToDelete = treeModelPointer->rowCount(currentIndex);
649 // Set the window title.
650 deleteCookieMessageBox.setWindowTitle(i18ncp("Delete cookies dialog title", "Delete %1 Cookie", "Delete 1% Cookies", numberOfCookiesToDelete));
653 deleteCookieMessageBox.setText(i18ncp("Delete cookies dialog text", "Delete %1 cookie?", "Delete %1 cookies?", numberOfCookiesToDelete));
655 else // A single cookie is selected.
657 // Set the window title.
658 deleteCookieMessageBox.setWindowTitle(i18nc("Delete cookie dialog title", "Delete 1 Cookie"));
661 deleteCookieMessageBox.setText(i18nc("Delete cookie dialog text", "Delete 1 cookie?"));
664 deleteDurableCookiesCheckBox.setChecked(true);
667 // Add the check box to the dialog.
668 deleteCookieMessageBox.setCheckBox(&deleteDurableCookiesCheckBox);
670 // Set the standard buttons.
671 deleteCookieMessageBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
673 // Set the default button.
674 deleteCookieMessageBox.setDefaultButton(QMessageBox::No);
676 // Display the dialog and capture the return value.
677 int returnValue = deleteCookieMessageBox.exec();
679 // Delete the cookie if instructed.
680 if (returnValue == QMessageBox::Yes)
682 // Delete the cookies according to the selection.
683 if (isDomain) // A domain is selected.
685 // Delete the domain.
686 deleteDomain(currentIndex, deleteDurableCookiesCheckBox.isChecked());
688 else // A single cookie is selected.
690 // Get the parent model index.
691 QModelIndex parentIndex = currentIndex.parent();
693 // Delete the cookie.
694 deleteCookie(currentIndex, deleteDurableCookiesCheckBox.isChecked());
696 // Remove the domain row if its only cookie has been deleted.
697 if (treeModelPointer->rowCount(parentIndex) == 0)
698 treeModelPointer->removeRow(parentIndex.row(), parentIndex.parent());
703 void CookiesDialog::showDurableCookiesDialog() const
705 // Instantiate a durable cookies dialog.
706 QDialog *durableCookiesDialogPointer = new DurableCookiesDialog();
709 durableCookiesDialogPointer->show();
711 // Process cookie changes.
712 connect(durableCookiesDialogPointer, SIGNAL(addingCookie(QNetworkCookie, bool)), this, SLOT(addCookieFromDialog(QNetworkCookie, bool)));
713 connect(durableCookiesDialogPointer, SIGNAL(deletingCookie(QNetworkCookie)), this, SLOT(deleteCookieFromDatabase(QNetworkCookie)));
714 connect(durableCookiesDialogPointer, SIGNAL(updateParentUi()), this, SLOT(updateUi()));
717 void CookiesDialog::showEditCookieDialog() const
719 // Get the current model index.
720 QModelIndex currentIndex = treeSelectionModelPointer->currentIndex();
722 // Create a partial cookie.
723 QNetworkCookie partialCookie;
725 // Populate the partial cookie from the current model index.
726 partialCookie.setDomain(currentIndex.parent().siblingAtColumn(0).data().toString());
727 partialCookie.setName(currentIndex.siblingAtColumn(0).data().toString().toUtf8());
728 partialCookie.setPath(currentIndex.siblingAtColumn(2).data().toString());
730 // Create a cookie to edit.
731 QNetworkCookie cookieToEdit;
733 // Search for the partial cookie in the cookie list.
734 for (QNetworkCookie cookie : *cookieListPointer)
736 // Store the cookie to edit if it has the same identifier as the partial cookie.
737 if (cookie.hasSameIdentifier(partialCookie))
738 cookieToEdit = cookie;
741 // Instantiate an edit cookie dialog.
742 QDialog *editCookieDialogPointer = new AddOrEditCookieDialog(AddOrEditCookieDialog::EditCookie, &cookieToEdit, currentIndex.siblingAtColumn(1).data().toString() == i18n("yes"));
745 editCookieDialogPointer->show();
747 // Process cookie events.
748 connect(editCookieDialogPointer, SIGNAL(addCookie(QNetworkCookie, bool)), this, SLOT(addCookieFromDialog(QNetworkCookie, bool)));
749 connect(editCookieDialogPointer, SIGNAL(deleteCookie(QNetworkCookie)), this, SLOT(deleteCookieFromDialog(QNetworkCookie)));
752 void CookiesDialog::updateUi() const
754 // Get the current index of the first column.
755 QModelIndex currentIndex = treeSelectionModelPointer->currentIndex().siblingAtColumn(0);
757 // Set the status of the buttons.
758 editCookieButtonPointer->setEnabled(treeSelectionModelPointer->hasSelection() && !treeModelPointer->hasChildren(currentIndex));
759 deleteCookieButtonPointer->setEnabled(treeSelectionModelPointer->hasSelection());;
760 deleteAllButtonPointer->setEnabled(treeModelPointer->hasChildren(treeModelPointer->invisibleRootItem()->index()));
762 // Update the delete cookie button text.
763 if (deleteCookieButtonPointer->isEnabled()) // The button is enabled.
765 if (treeModelPointer->hasChildren(currentIndex)) // A domain is selected.
767 // Update the button text.
768 deleteCookieButtonPointer->setText(i18ncp("Delete cookies button.", "&Delete %1 cookie", "&Delete %1 cookies", treeModelPointer->rowCount(currentIndex)));
770 else // A single cookie is selected.
772 // Update the button text.
773 deleteCookieButtonPointer->setText(i18nc("Delete cookies button.", "&Delete 1 cookie"));
776 else // The button is disabled.
778 // Reset the button text.
779 deleteCookieButtonPointer->setText(i18nc("Delete cookie button.", "&Delete cookie"));
782 // Update the text of the durable cookies button.
783 durableCookiesButtonPointer->setText(i18nc("View the durable cookies button", "Durable cookies - %1", CookiesDatabase::cookieCount()));