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 "ui_CookiesDialog.h"
24 #include "databases/CookiesDatabase.h"
26 // KDE Frameworks headers.
27 #include <KLocalizedString>
29 // Qt toolkit headers.
31 #include <QMessageBox>
35 // Construct the class.
36 bool cookieSortPredicate(const QNetworkCookie &leftHandCookie, const QNetworkCookie &rightHandCookie)
38 // Check to see if the domains are identical.
39 if (leftHandCookie.domain() == rightHandCookie.domain())
41 // Check to see if the names are identical.
42 if (leftHandCookie.name() == rightHandCookie.name())
44 // Sort the cookies by the path.
45 return (leftHandCookie.path() < rightHandCookie.path());
47 else // The name are not identical.
49 // Sort the cookies by the name.
50 return (leftHandCookie.name() < rightHandCookie.name());
53 else // The domains are not identical.
55 // Get copies of the domains.
56 QString leftHandDomain = leftHandCookie.domain();
57 QString rightHandDomain = rightHandCookie.domain();
59 // Get the top level domains.
60 QString leftHandTopLevelDomain = leftHandDomain.section('.', -1);
61 QString rightHandTopLevelDomain = rightHandDomain.section('.', -1);
63 // Get the second level domains.
64 QString leftHandSecondLevelDomain = leftHandDomain.section('.', -2);
65 QString rightHandSecondLevelDomain = rightHandDomain.section('.', -2);
67 // Get the third level domains.
68 QString leftHandThirdLevelDomain = leftHandDomain.section('.', -3);
69 QString rightHandThirdLevelDomain = rightHandDomain.section('.', -3);
71 // Check to see if the top level domains are the same.
72 if (leftHandTopLevelDomain == rightHandTopLevelDomain)
74 // Check to see if the second level domains are the same.
75 if (leftHandSecondLevelDomain == rightHandSecondLevelDomain)
77 // Check to see if the third level domains are the same.
78 if (leftHandThirdLevelDomain == rightHandThirdLevelDomain)
80 // Sort the cookies by the full domain because they share the same third level domain.
81 return (leftHandDomain < rightHandDomain);
83 else // The second level domains are the same, but the third level domains are different.
85 // Sort the cookies by the third level domains.
86 return (leftHandThirdLevelDomain < rightHandThirdLevelDomain);
89 else // The top level domains are the same, but the second level domains are diferent.
91 // Sort the cookies by the second level domain.
92 return (leftHandSecondLevelDomain < rightHandSecondLevelDomain);
95 else // The top level domains are different.
97 // Sort the cookies by the top level domain.
98 return (leftHandTopLevelDomain < rightHandTopLevelDomain);
104 CookiesDialog::CookiesDialog(std::list<QNetworkCookie> *originalCookieListPointer) : QDialog(nullptr), cookieListPointer(originalCookieListPointer)
106 // Set the dialog window title.
107 setWindowTitle(i18nc("The cookies dialog window title", "Cookies"));
109 // Set the window modality.
110 setWindowModality(Qt::WindowModality::ApplicationModal);
112 // Instantiate the cookie settings dialog UI.
113 Ui::CookiesDialog cookiesDialogUi;
116 cookiesDialogUi.setupUi(this);
118 // Get a handle for the tree view.
119 treeViewPointer = cookiesDialogUi.treeView;
121 // Initialize the tree model.
122 treeModelPointer = new QStandardItemModel();
124 // Set the column count.
125 treeModelPointer->setColumnCount(7);
127 // Set the tree header data.
128 treeModelPointer->setHeaderData(0, Qt::Horizontal, i18nc("The cookie Name header.", "Name"));
129 treeModelPointer->setHeaderData(1, Qt::Horizontal, i18nc("The cookie Durable header.", "Durable"));
130 treeModelPointer->setHeaderData(2, Qt::Horizontal, i18nc("The cookie Path header.", "Path"));
131 treeModelPointer->setHeaderData(3, Qt::Horizontal, i18nc("The cookie Expiration Date header.", "Expiration Date"));
132 treeModelPointer->setHeaderData(4, Qt::Horizontal, i18nc("The cookie HTTP Only header.", "HTTP Only"));
133 treeModelPointer->setHeaderData(5, Qt::Horizontal, i18nc("The cookie Secure header.", "Secure"));
134 treeModelPointer->setHeaderData(6, Qt::Horizontal, i18nc("The cookie Value header.", "Value"));
136 // Set the tree header tool tips.
137 treeModelPointer->horizontalHeaderItem(0)->setToolTip(i18nc("The cookie Name tool tip.",
138 "The name identifies the cookie. Each cookie has a unique combination of domain, name, and path."));
139 treeModelPointer->horizontalHeaderItem(1)->setToolTip(i18nc("The cookie Durable tool tip",
140 "Durable cookies pursist across restarts, irrespective of the expiration date. All other cookies are deleted when Privacy Browser closes, irrespective of the expiration date."));
141 treeModelPointer->horizontalHeaderItem(2)->setToolTip(i18nc("The cookie Path tool tip.", "Websites can restrict cookie access to subpath of their URL."));
142 treeModelPointer->horizontalHeaderItem(3)->setToolTip(i18nc("The cookie Expiration Date tool tip.",
143 "Cookies without an expiration date are known as session cookies and are expected to be deleted every time the browser closes."));
144 treeModelPointer->horizontalHeaderItem(4)->setToolTip(i18nc("The cookie HTTP Only tool tip.",
145 "Restrict cookie access to HTTP (and HTTPS). This prevents JavaScript from accessing the cookie, which hardens it against cross-site scripting attacks."));
146 treeModelPointer->horizontalHeaderItem(5)->setToolTip(i18nc("The cookie Secure tool tip.", "Only allow the cookie to be transferred across HTTPS (as opposed to HTTP)."));
147 treeModelPointer->horizontalHeaderItem(6)->setToolTip(i18nc("The cookie Value tool tip.", "The value contains the cookie data."));
149 // Sort the cookie list.
150 cookieListPointer->sort(cookieSortPredicate);
152 // Create the current domain string.
153 QString currentDomainString = "";
155 // Create the current domain item pointer.
156 QStandardItem *currentDomainItemPointer;
158 // Populate the cookie tree view.
159 for (QNetworkCookie cookie : *cookieListPointer)
161 // Get the cookie domain.
162 QString cookieDomain = cookie.domain();
164 // Check to see if the cookie is a member of the current domain.
165 if (cookieDomain != currentDomainString) // Create a new domain in the tree.
167 // Create the domain name item.
168 QStandardItem *domainNameItemPointer = new QStandardItem(cookieDomain);
170 // Add the domain to the tree.
171 treeModelPointer->invisibleRootItem()->appendRow(domainNameItemPointer);
173 // Update the current domain string.
174 currentDomainString = cookieDomain;
176 // Update the current domain item pointer.
177 currentDomainItemPointer = domainNameItemPointer;
180 // Check to see if the cookie is durable.
181 bool isDurable = CookiesDatabase::isDurable(cookie);
183 // Create a list for the cookie items.
184 QList<QStandardItem*> cookieItemList;
186 // Create the cookie items.
187 QStandardItem *nameItemPointer = new QStandardItem(QString(cookie.name()));
188 QStandardItem *durableItemPointer = new QStandardItem(QString(isDurable ? i18n("yes") : i18n("no")));
189 QStandardItem *pathItemPointer = new QStandardItem(QString(cookie.path()));
190 QStandardItem *expirationDateItemPointer = new QStandardItem(QString(cookie.expirationDate().toString()));
191 QStandardItem *isHttpOnlyItemPointer = new QStandardItem(QString(cookie.isHttpOnly() ? i18n("yes") : i18n("no")));
192 QStandardItem *isSecureItemPointer = new QStandardItem(QString(cookie.isSecure() ? i18n("yes") : i18n("no")));
193 QStandardItem *valueItemPointer = new QStandardItem(QString(cookie.value()));
195 // Populate the cookie standard item list.
196 cookieItemList.append(nameItemPointer);
197 cookieItemList.append(durableItemPointer);
198 cookieItemList.append(pathItemPointer);
199 cookieItemList.append(expirationDateItemPointer);
200 cookieItemList.append(isHttpOnlyItemPointer);
201 cookieItemList.append(isSecureItemPointer);
202 cookieItemList.append(valueItemPointer);
204 // Add the cookie to the tree.
205 currentDomainItemPointer->appendRow(cookieItemList);
208 // Auto resize the headers.
209 treeViewPointer->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
211 // Disable stretching the last section. Otherwise, the Value field will be truncated to the width of the window when a row is expanded.
212 treeViewPointer->header()->setStretchLastSection(false);
214 // Don't elide the Value field (or any other field).
215 treeViewPointer->setTextElideMode(Qt::ElideNone);
217 // Indicate that all the rows are the same height, wich improves performance.
218 treeViewPointer->setUniformRowHeights(true);
221 treeViewPointer->setEditTriggers(QAbstractItemView::NoEditTriggers);
223 // Set the tree model.
224 treeViewPointer->setModel(treeModelPointer);
226 // Get a handle for the tree selection model.
227 treeSelectionModelPointer = treeViewPointer->selectionModel();
229 // Listen for selection changes.
230 connect(treeSelectionModelPointer, SIGNAL(selectionChanged(QItemSelection, QItemSelection)), this, SLOT(updateUi()));
232 // Get handles for the buttons.
233 addCookieButtonPointer = cookiesDialogUi.addCookieButton;
234 editCookieButtonPointer = cookiesDialogUi.editCookieButton;
235 deleteCookieButtonPointer = cookiesDialogUi.deleteCookieButton;
236 QDialogButtonBox *dialogButtonBoxPointer = cookiesDialogUi.dialogButtonBox;
237 QPushButton *closeButtonPointer = dialogButtonBoxPointer->button(QDialogButtonBox::Close);
239 // Add a delete all button to the dialog button box.
240 deleteAllButtonPointer = dialogButtonBoxPointer->addButton(i18nc("Delete all cookies button", "Delete all"), QDialogButtonBox::ActionRole);
242 // Set the delete all button icon.
243 deleteAllButtonPointer->setIcon(QIcon::fromTheme("delete"));
245 // Connect the buttons.
246 connect(addCookieButtonPointer, SIGNAL(clicked()), this, SLOT(showAddCookieDialog()));
247 connect(editCookieButtonPointer, SIGNAL(clicked()), this, SLOT(showEditCookieDialog()));
248 connect(deleteCookieButtonPointer, SIGNAL(clicked()), this, SLOT(showDeleteCookieMessageBox()));
249 connect(deleteAllButtonPointer, SIGNAL(clicked()), this, SLOT(showDeleteAllMessageBox()));
250 connect(dialogButtonBoxPointer, SIGNAL(rejected()), this, SLOT(reject()));
252 // Set the cancel button to be the default.
253 closeButtonPointer->setDefault(true);
255 // Create the keyboard shortcuts.
256 QShortcut *aShortcutPointer = new QShortcut(QKeySequence(i18nc("The add cookie key shortcut.", "a")), this);
257 QShortcut *eShortcutPointer = new QShortcut(QKeySequence(i18nc("The edit cookie key shorcut.", "e")), this);
258 QShortcut *dShortcutPointer = new QShortcut(QKeySequence(i18nc("The delete cookie key shortcut.", "d")), this);
259 QShortcut *deleteShortcutPointer = new QShortcut(QKeySequence::Delete, this);
260 QShortcut *lShortcutPointer = new QShortcut(QKeySequence(i18nc("The delete all key shortcut.", "l")), this);
261 QShortcut *cShortcutPointer = new QShortcut(QKeySequence(i18nc("The close key shortcut.", "c")), this);
262 QShortcut *quitShortcutPointer = new QShortcut(QKeySequence::Quit, this);
264 // Connect the keyboard shortcuts to the buttons.
265 connect(aShortcutPointer, SIGNAL(activated()), addCookieButtonPointer, SLOT(click()));
266 connect(eShortcutPointer, SIGNAL(activated()), editCookieButtonPointer, SLOT(click()));
267 connect(dShortcutPointer, SIGNAL(activated()), deleteCookieButtonPointer, SLOT(click()));
268 connect(deleteShortcutPointer, SIGNAL(activated()), deleteCookieButtonPointer, SLOT(click()));
269 connect(lShortcutPointer, SIGNAL(activated()), deleteAllButtonPointer, SLOT(click()));
270 connect(cShortcutPointer, SIGNAL(activated()), closeButtonPointer, SLOT(click()));
271 connect(quitShortcutPointer, SIGNAL(activated()), closeButtonPointer, SLOT(click()));
273 // Edit a cookie when it is double clicked.
274 connect(treeViewPointer, SIGNAL(doubleClicked(QModelIndex)), editCookieButtonPointer, SLOT(click()));
280 void CookiesDialog::addCookieFromDialog(const QNetworkCookie &cookie, const bool &isDurable) const
282 // Add the cookie to the cookie list and the cookie store.
283 emit addCookie(cookie);
285 // Get the new domain string.
286 QString newDomain = cookie.domain();
288 // Check to see if the domain already exists in the model.
289 QList<QStandardItem*> currentDomainItemList = treeModelPointer->findItems(newDomain);
291 // Create a domain item pointer.
292 QStandardItem *domainNameItemPointer;
294 // Prepare the domain item pointer.
295 if (currentDomainItemList.isEmpty()) // The domain doesn't currently exist in the tree.
297 // Create the domain name item.
298 domainNameItemPointer = new QStandardItem(newDomain);
300 // Create the insert domain row number.
301 int insertDomainRowNumber = 0;
303 // Get the number of domains in the tree.
304 int numberOfDomains = treeModelPointer->invisibleRootItem()->rowCount();
306 // Get the new domain strings.
307 QString newDomainTopLevelDomain = newDomain.section('.', -1);
308 QString newDomainSecondLevelDomain = newDomain.section('.', -2);
309 QString newDomainThirdLevelDomain = newDomain.section('.', -3);
311 // Iterate through all the domains.
312 for (int i = 0; i < numberOfDomains; ++i)
314 // Get the current domain strings.
315 QString currentDomain = treeModelPointer->invisibleRootItem()->child(i, 0)->index().data().toString();
316 QString currentDomainTopLevelDomain = currentDomain.section('.', -1);
317 QString currentDomainSecondLevelDomain = currentDomain.section('.', -2);
318 QString currentDomainThirdLevelDomain = currentDomain.section('.', -3);
320 // Check to see if the new domain should be inserted after the current domain.
321 if (newDomainTopLevelDomain > currentDomainTopLevelDomain)
323 // Insert the new domain after the current domain.
324 insertDomainRowNumber = i + 1;
326 else if ((newDomainTopLevelDomain == currentDomainTopLevelDomain) && (newDomainSecondLevelDomain > currentDomainSecondLevelDomain))
328 // Insert the new domain after the current domain.
329 insertDomainRowNumber = i + 1;
331 else if ((newDomainSecondLevelDomain == currentDomainSecondLevelDomain) && (newDomainThirdLevelDomain > currentDomainThirdLevelDomain))
333 // Insert the new domain after the current domain.
334 insertDomainRowNumber = i + 1;
336 else if ((newDomainThirdLevelDomain == currentDomainThirdLevelDomain) && (newDomain > currentDomain))
338 // Insert the new domain after the current domain.
339 insertDomainRowNumber = i + 1;
343 // Add the domain to the tree.
344 treeModelPointer->invisibleRootItem()->insertRow(insertDomainRowNumber, domainNameItemPointer);
346 else // The domain already exists in the tree.
348 // Use the current domain standard item.
349 domainNameItemPointer = currentDomainItemList[0];
352 // Get strings for the new cookie name and path (used later in the placement of the row).
353 QString newCookieName = QString(cookie.name());
354 QString newCookiePath = QString(cookie.path());
356 // Create a cookie item list.
357 QList<QStandardItem*> cookieItemList;
359 // Create the cookie items.
360 QStandardItem *nameItemPointer = new QStandardItem(newCookieName);
361 QStandardItem *durableItemPointer = new QStandardItem(QString(isDurable ? i18n("yes") : i18n("no")));
362 QStandardItem *pathItemPointer = new QStandardItem(newCookiePath);
363 QStandardItem *expirationDateItemPointer = new QStandardItem(QString(cookie.expirationDate().toString()));
364 QStandardItem *isHttpOnlyItemPointer = new QStandardItem(QString(cookie.isHttpOnly() ? i18n("yes") : i18n("no")));
365 QStandardItem *isSecureItemPointer = new QStandardItem(QString(cookie.isSecure() ? i18n("yes") : i18n("no")));
366 QStandardItem *valueItemPointer = new QStandardItem(QString(cookie.value()));
368 // Populate the cookie item list.
369 cookieItemList.append(nameItemPointer);
370 cookieItemList.append(durableItemPointer);
371 cookieItemList.append(pathItemPointer);
372 cookieItemList.append(expirationDateItemPointer);
373 cookieItemList.append(isHttpOnlyItemPointer);
374 cookieItemList.append(isSecureItemPointer);
375 cookieItemList.append(valueItemPointer);
377 // Create the insert cookie row number.
378 int insertCookieRowNumber = 0;
380 // Create the remove existing row tracker.
381 bool removeExistingRow = false;
383 // Get the number of cookies in the domain.
384 int numberOfCookies = domainNameItemPointer->rowCount();
386 // Iterate through the cookies for this domain.
387 for (int i = 0; i < numberOfCookies; ++i)
389 // Get the current cookie name and path at the indicated row.
390 QString currentCookieName = domainNameItemPointer->child(i, 0)->index().data().toString();
391 QString currentCookiePath = domainNameItemPointer->child(i, 2)->index().data().toString();
393 // Check to see if the new cookie should be inserted after the current cookie.
394 if (newCookieName > currentCookieName) // The new cookie name comes after the current cookie name.
396 // Insert the new cookie after the current cookie.
397 insertCookieRowNumber = i + 1;
399 else if ((newCookieName == currentCookieName) && (newCookiePath > currentCookiePath)) // The names are the same, but the new cookie path comes after the current cookie path.
401 // Insert the new cookie after the current cookie.
402 insertCookieRowNumber = i + 1;
404 else if ((newCookieName == currentCookieName) && (newCookiePath == currentCookiePath)) // The cookies are the same.
406 // Remove the existing cookie in this row.
407 removeExistingRow = true;
409 // Insert the cookie in it's place.
410 insertCookieRowNumber = i;
414 // Remove the existing row if it is being edited.
415 if (removeExistingRow)
416 domainNameItemPointer->removeRow(insertCookieRowNumber);
418 // Add the cookie to the tree model.
419 domainNameItemPointer->insertRow(insertCookieRowNumber, cookieItemList);
421 // Get the new cookie model index.
422 QModelIndex newCookieIndex = nameItemPointer->index();
424 // Set the new cookie to be the current index.
425 treeViewPointer->setCurrentIndex(newCookieIndex);
427 // Expand the parent of the new cookie.
428 treeViewPointer->expand(newCookieIndex.parent());
431 void CookiesDialog::deleteCookie(const QModelIndex &modelIndex, const bool &deleteDurableCookies) const
433 // Create a partial cookie.
434 QNetworkCookie partialCookie;
436 // Populate the partial cookie from the current model index.
437 partialCookie.setDomain(modelIndex.parent().siblingAtColumn(0).data().toString());
438 partialCookie.setName(modelIndex.siblingAtColumn(0).data().toString().toUtf8());
439 partialCookie.setPath(modelIndex.siblingAtColumn(2).data().toString());
441 // Create a cookie to delete.
442 QNetworkCookie cookieToDelete;
444 // Check if the cookie is durable.
445 bool isDurable = CookiesDatabase::isDurable(partialCookie);
447 // Only delete durable cookies if directed.
448 if (deleteDurableCookies || !isDurable)
450 // Search for the partial cookie in the cookie list.
451 for (QNetworkCookie cookie : *cookieListPointer)
453 // Store the cookie to delete if it has the same identifier as the partial cookie.
454 if (cookie.hasSameIdentifier(partialCookie))
455 cookieToDelete = cookie;
458 // Remove the cookie from the tree model.
459 treeModelPointer->removeRow(modelIndex.row(), modelIndex.parent());
461 // Delete the cookie from the cookie list and cookie store.
462 emit deleteCookie(cookieToDelete);
464 // Delete the cookie from the durable cookies database.
466 CookiesDatabase::deleteCookie(cookieToDelete);
470 void CookiesDialog::deleteDomain(const QModelIndex &modelIndex, const bool &deleteDurableCookies) const
472 // Get the parent index.
473 QModelIndex parentIndex = modelIndex.parent();
475 // Get the number of cookies in the domain.
476 int numberOfCookies = treeModelPointer->rowCount(modelIndex);
478 // Delete each child cookie, starting from the bottom.
479 for (int i = numberOfCookies; i > 0; --i)
480 deleteCookie(treeModelPointer->index(i-1, 0, modelIndex), deleteDurableCookies);
482 // Remove the domain if all the cookies have been deleted.
483 if (treeModelPointer->rowCount(modelIndex) == 0)
484 treeModelPointer->removeRow(modelIndex.row(), parentIndex);
488 void CookiesDialog::deleteCookieFromDialog(const QNetworkCookie &cookie) const
490 // Get the current model index.
491 QModelIndex currentIndex = treeSelectionModelPointer->currentIndex();
493 // Get the parent index.
494 QModelIndex parentIndex = currentIndex.parent();
496 // Remove the cookie from the tree model.
497 treeModelPointer->removeRow(currentIndex.row(), parentIndex);
499 // Remove the domain from the tree model if its only cookie has been deleted.
500 if (treeModelPointer->rowCount(parentIndex) == 0)
501 treeModelPointer->removeRow(parentIndex.row(), parentIndex.parent());
503 // Delete the cookie from the cookie list and cookie store.
504 emit deleteCookie(cookie);
507 void CookiesDialog::showAddCookieDialog() const
509 // Instantiate an add cookie dialog.
510 QDialog *addCookieDialogPointer = new AddOrEditCookieDialog(AddOrEditCookieDialog::AddCookie);
513 addCookieDialogPointer->show();
515 // Add the cookie if directed.
516 connect(addCookieDialogPointer, SIGNAL(addCookie(QNetworkCookie, bool)), this, SLOT(addCookieFromDialog(QNetworkCookie, bool)));
519 void CookiesDialog::showDeleteAllMessageBox() const
521 // Instantiate a delete all message box.
522 QMessageBox deleteAllCookiesMessageBox;
525 deleteAllCookiesMessageBox.setIcon(QMessageBox::Warning);
527 // Set the window title.
528 deleteAllCookiesMessageBox.setWindowTitle(i18nc("Delete all cookies dialog title", "Delete All Cookies"));
531 deleteAllCookiesMessageBox.setText(i18nc("Delete all cookies dialog text", "Delete all cookies?"));
533 // Create a delete durable cookies check box.
534 QCheckBox deleteDurableCookiesCheckBox(i18nc("Delete durable cookies check box", "Delete even if durable"));
536 // Add the check box to the dialog.
537 deleteAllCookiesMessageBox.setCheckBox(&deleteDurableCookiesCheckBox);
539 // Set the standard buttons.
540 deleteAllCookiesMessageBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
542 // Set the default button.
543 deleteAllCookiesMessageBox.setDefaultButton(QMessageBox::No);
545 // Display the dialog and capture the return value.
546 int returnValue = deleteAllCookiesMessageBox.exec();
548 // Delete all cookies if instructed.
549 if (returnValue == QMessageBox::Yes)
551 // Only delete durable cookies if requested.
552 if (deleteDurableCookiesCheckBox.isChecked()) // Delete everything.
554 // Delete all the cookies.
555 emit deleteAllCookies();
557 // Clear the tree model.
558 treeModelPointer->clear();
560 // Delete the durable cookies from the database.
561 CookiesDatabase::deleteAllCookies();
566 else // Only delete cookies that are not durable.
568 // Get the root model index.
569 QModelIndex rootIndex = treeModelPointer->invisibleRootItem()->index();
571 // Get the number of domains.
572 int numberOfDomains = treeModelPointer->rowCount(rootIndex);
574 // Delete each domain, starting from the bottom.
575 for (int i = numberOfDomains; i > 0; --i)
576 deleteDomain(treeModelPointer->index(i - 1, 0, rootIndex), deleteDurableCookiesCheckBox.isChecked());
581 void CookiesDialog::showDeleteCookieMessageBox() const
583 // Get the current model index.
584 QModelIndex currentIndex = treeSelectionModelPointer->currentIndex();
586 // Determine if a domain is selected.
587 bool isDomain = treeModelPointer->hasChildren(currentIndex);
589 // Instantiate a delete cookie message box.
590 QMessageBox deleteCookieMessageBox;
593 deleteCookieMessageBox.setIcon(QMessageBox::Warning);
595 // Create a delete durable cookies check box.
596 QCheckBox deleteDurableCookiesCheckBox(i18nc("Delete durable cookies check box", "Delete even if durable"));
598 if (isDomain) // A domain is selected.
600 // Get the number of cookies.
601 int numberOfCookiesToDelete = treeModelPointer->rowCount(currentIndex);
603 // Set the window title.
604 deleteCookieMessageBox.setWindowTitle(i18ncp("Delete cookies dialog title", "Delete %1 Cookie", "Delete 1% Cookies", numberOfCookiesToDelete));
607 deleteCookieMessageBox.setText(i18ncp("Delete cookies dialog text", "Delete %1 cookie?", "Delete %1 cookies?", numberOfCookiesToDelete));
609 else // A single cookie is selected.
611 // Set the window title.
612 deleteCookieMessageBox.setWindowTitle(i18nc("Delete cookie dialog title", "Delete 1 Cookie"));
615 deleteCookieMessageBox.setText(i18nc("Delete cookie dialog text", "Delete 1 cookie?"));
618 deleteDurableCookiesCheckBox.setChecked(true);
621 // Add the check box to the dialog.
622 deleteCookieMessageBox.setCheckBox(&deleteDurableCookiesCheckBox);
624 // Set the standard buttons.
625 deleteCookieMessageBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
627 // Set the default button.
628 deleteCookieMessageBox.setDefaultButton(QMessageBox::No);
630 // Display the dialog and capture the return value.
631 int returnValue = deleteCookieMessageBox.exec();
633 // Delete the cookie if instructed.
634 if (returnValue == QMessageBox::Yes)
636 // Delete the cookies according to the selection.
637 if (isDomain) // A domain is selected.
639 // Delete the domain.
640 deleteDomain(currentIndex, deleteDurableCookiesCheckBox.isChecked());
642 else // A single cookie is selected.
644 // Get the parent model index.
645 QModelIndex parentIndex = currentIndex.parent();
647 // Delete the cookie.
648 deleteCookie(currentIndex, deleteDurableCookiesCheckBox.isChecked());
650 // Remove the domain row if its only cookie has been deleted.
651 if (treeModelPointer->rowCount(parentIndex) == 0)
652 treeModelPointer->removeRow(parentIndex.row(), parentIndex.parent());
657 void CookiesDialog::showEditCookieDialog() const
659 // Get the current model index.
660 QModelIndex currentIndex = treeSelectionModelPointer->currentIndex();
662 // Create a partial cookie.
663 QNetworkCookie partialCookie;
665 // Populate the partial cookie from the current model index.
666 partialCookie.setDomain(currentIndex.parent().siblingAtColumn(0).data().toString());
667 partialCookie.setName(currentIndex.siblingAtColumn(0).data().toString().toUtf8());
668 partialCookie.setPath(currentIndex.siblingAtColumn(2).data().toString());
670 // Create a cookie to edit.
671 QNetworkCookie cookieToEdit;
673 // Search for the partial cookie in the cookie list.
674 for (QNetworkCookie cookie : *cookieListPointer)
676 // Store the cookie to edit if it has the same identifier as the partial cookie.
677 if (cookie.hasSameIdentifier(partialCookie))
678 cookieToEdit = cookie;
681 // Instantiate an edit cookie dialog.
682 QDialog *editCookieDialogPointer = new AddOrEditCookieDialog(AddOrEditCookieDialog::EditCookie, &cookieToEdit, currentIndex.siblingAtColumn(1).data().toString() == i18n("yes"));
685 editCookieDialogPointer->show();
687 // Process cookie events.
688 connect(editCookieDialogPointer, SIGNAL(addCookie(QNetworkCookie, bool)), this, SLOT(addCookieFromDialog(QNetworkCookie, bool)));
689 connect(editCookieDialogPointer, SIGNAL(deleteCookie(QNetworkCookie)), this, SLOT(deleteCookieFromDialog(QNetworkCookie)));
692 void CookiesDialog::updateUi() const
694 // Get the current index of the first column.
695 QModelIndex currentIndex = treeSelectionModelPointer->currentIndex().siblingAtColumn(0);
697 // Set the status of the buttons.
698 editCookieButtonPointer->setEnabled(treeSelectionModelPointer->hasSelection() && !treeModelPointer->hasChildren(currentIndex));
699 deleteCookieButtonPointer->setEnabled(treeSelectionModelPointer->hasSelection());;
700 deleteAllButtonPointer->setEnabled(treeModelPointer->hasChildren(treeModelPointer->invisibleRootItem()->index()));
702 // Update the delete cookie button text.
703 if (deleteCookieButtonPointer->isEnabled()) // The button is enabled.
705 if (treeModelPointer->hasChildren(currentIndex)) // A domain is selected.
707 // Update the button text.
708 deleteCookieButtonPointer->setText(i18ncp("Delete cookies button.", "&Delete %1 cookie", "&Delete %1 cookies", treeModelPointer->rowCount(currentIndex)));
710 else // A single cookie is selected.
712 // Update the button text.
713 deleteCookieButtonPointer->setText(i18nc("Delete cookies button.", "&Delete 1 cookie"));
716 else // The button is disabled.
718 // Reset the button text.
719 deleteCookieButtonPointer->setText(i18nc("Delete cookie button.", "&Delete cookie"));