Rename Local Storage to DOM Storage. https://redmine.stoutner.com/issues/852
[PrivacyBrowserPC.git] / src / dialogs / CookiesDialog.cpp
1 /*
2  * Copyright © 2022 Soren Stoutner <soren@stoutner.com>.
3  *
4  * This file is part of Privacy Browser PC <https://www.stoutner.com/privacy-browser-pc>.
5  *
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.
10  *
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.
15  *
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/>.
18  */
19
20 // Application headers.
21 #include "AddOrEditCookieDialog.h"
22 #include "CookiesDialog.h"
23 #include "ui_CookiesDialog.h"
24
25 // KDE Frameworks headers.
26 #include <KLocalizedString>
27
28 // Qt toolkit headers.
29 #include <QDateTime>
30 #include <QMessageBox>
31 #include <QShortcut>
32 #include <QUrl>
33
34 // Construct the class.
35 bool cookieSortPredicate(const QNetworkCookie &leftHandCookie, const QNetworkCookie &rightHandCookie)
36 {
37     // Check to see if the domains are identical.
38     if (leftHandCookie.domain() == rightHandCookie.domain())
39     {
40         // Check to see if the names are identical.
41         if (leftHandCookie.name() == rightHandCookie.name())
42         {
43             // Sort the cookies by the path.
44             return (leftHandCookie.path() < rightHandCookie.path());
45         }
46         else  // The name are not identical.
47         {
48             // Sort the cookies by the name.
49             return (leftHandCookie.name() < rightHandCookie.name());
50         }
51     }
52     else  // The domains are not identical.
53     {
54         // Get copies of the domains.
55         QString leftHandDomain = leftHandCookie.domain();
56         QString rightHandDomain = rightHandCookie.domain();
57
58         // Get the top level domains.
59         QString leftHandTopLevelDomain = leftHandDomain.section('.', -1);
60         QString rightHandTopLevelDomain = rightHandDomain.section('.', -1);
61
62         // Get the second level domains.
63         QString leftHandSecondLevelDomain = leftHandDomain.section('.', -2);
64         QString rightHandSecondLevelDomain = rightHandDomain.section('.', -2);
65
66         // Get the third level domains.
67         QString leftHandThirdLevelDomain = leftHandDomain.section('.', -3);
68         QString rightHandThirdLevelDomain = rightHandDomain.section('.', -3);
69
70         // Check to see if the top level domains are the same.
71         if (leftHandTopLevelDomain == rightHandTopLevelDomain)
72         {
73             // Check to see if the second level domains are the same.
74             if (leftHandSecondLevelDomain == rightHandSecondLevelDomain)
75             {
76                 // Check to see if the third level domains are the same.
77                 if (leftHandThirdLevelDomain == rightHandThirdLevelDomain)
78                 {
79                     // Sort the cookies by the full domain because they share the same third level domain.
80                     return (leftHandDomain < rightHandDomain);
81                 }
82                 else  // The second level domains are the same, but the third level domains are different.
83                 {
84                     // Sort the cookies by the third level domains.
85                     return (leftHandThirdLevelDomain < rightHandThirdLevelDomain);
86                 }
87             }
88             else  // The top level domains are the same, but the second level domains are diferent.
89             {
90                 // Sort the cookies by the second level domain.
91                 return (leftHandSecondLevelDomain < rightHandSecondLevelDomain);
92             }
93         }
94         else  // The top level domains are different.
95         {
96             // Sort the cookies by the top level domain.
97             return (leftHandTopLevelDomain < rightHandTopLevelDomain);
98         }
99
100     }
101 }
102
103 CookiesDialog::CookiesDialog(std::list<QNetworkCookie> *originalCookieListPointer) : QDialog(nullptr), cookieListPointer(originalCookieListPointer)
104 {
105     // Set the dialog window title.
106     setWindowTitle(i18nc("The cookies dialog window title", "Cookies"));
107
108     // Set the window modality.
109     setWindowModality(Qt::WindowModality::ApplicationModal);
110
111     // Instantiate the cookie settings dialog UI.
112     Ui::CookiesDialog cookiesDialogUi;
113
114     // Setup the UI.
115     cookiesDialogUi.setupUi(this);
116
117     // Get a handle for the tree view.
118     treeViewPointer = cookiesDialogUi.treeView;
119
120     // Initialize the standard item model.
121     standardItemModelPointer = new QStandardItemModel();
122
123     // Set the column count.
124     standardItemModelPointer->setColumnCount(6);
125
126     // Set the header data.
127     standardItemModelPointer->setHeaderData(0, Qt::Horizontal, i18nc("The cookie Name header.", "Name"));
128     standardItemModelPointer->setHeaderData(1, Qt::Horizontal, i18nc("The cookie Path header.", "Path"));
129     standardItemModelPointer->setHeaderData(2, Qt::Horizontal, i18nc("The cookie Expiration Date header.", "Expiration Date"));
130     standardItemModelPointer->setHeaderData(3, Qt::Horizontal, i18nc("The cookie HTTP Only header.", "HTTP Only"));
131     standardItemModelPointer->setHeaderData(4, Qt::Horizontal, i18nc("The cookie Secure header.", "Secure"));
132     standardItemModelPointer->setHeaderData(5, Qt::Horizontal, i18nc("The cookie Value header.", "Value"));
133
134     // Set the header tool tips.
135     standardItemModelPointer->horizontalHeaderItem(0)->setToolTip(i18nc("The cookie Name tool tip.",
136                                                                         "The name identifies the cookie.  Each cookie has a unique combination of domain, name, and path."));
137     standardItemModelPointer->horizontalHeaderItem(1)->setToolTip(i18nc("The cookie Path tool tip.", "Websites can restrict cookie access to subpath of their URL."));
138     standardItemModelPointer->horizontalHeaderItem(2)->setToolTip(i18nc("The cookie Expiration Date tool tip.",
139                                                                         "Cookies without an expiration date are known as session cookies and are expected to be deleted every time the browser closes."));
140     standardItemModelPointer->horizontalHeaderItem(3)->setToolTip(i18nc("The cookie HTTP Only tool tip.",
141                                                                         "Restrict cookie access to HTTP (and HTTPS). This prevents JavaScript from accessing the cookie, which hardens it against cross-site scripting attacks."));
142     standardItemModelPointer->horizontalHeaderItem(4)->setToolTip(i18nc("The cookie Secure tool tip.", "Only allow the cookie to be transferred across HTTPS (as opposed to HTTP)."));
143     standardItemModelPointer->horizontalHeaderItem(5)->setToolTip(i18nc("The cookie Value tool tip.", "The value contains the cookie data."));
144
145     // Sort the cookie list.
146     cookieListPointer->sort(cookieSortPredicate);
147
148     // Create the current domain string.
149     QString currentDomainString = "";
150
151     // Create the current domain standard item pointer.
152     QStandardItem *currentDomainStandardItemPointer;
153
154     // Populate the VBoxLayout.
155     for (QNetworkCookie cookie : *cookieListPointer)
156     {
157         // Get the cookie domain.
158         QString cookieDomain = cookie.domain();
159
160         // Check to see if the cookie is a member of the current domain.
161         if (cookieDomain != currentDomainString)  // Create a new domain in the tree.
162         {
163             // Create a list for the domain standard items.
164             QList<QStandardItem*> domainStandardItemList;
165
166             // Create the new domain standard items.
167             QStandardItem *domainStandardItemPointer = new QStandardItem(cookieDomain);
168             QStandardItem *pathStandardItemPointer = new QStandardItem(QStringLiteral(""));
169             QStandardItem *expirationDateStandardItemPointer = new QStandardItem(QStringLiteral(""));
170             QStandardItem *isHttpOnlyStandardItemPointer = new QStandardItem(QStringLiteral(""));
171             QStandardItem *isSecureStandardItemPointer = new QStandardItem(QStringLiteral(""));
172             QStandardItem *valueStandardItemPointer = new QStandardItem(QStringLiteral(""));
173
174             // Disable editing of the domain.
175             domainStandardItemPointer->setEditable(false);
176             pathStandardItemPointer->setEditable(false);
177             expirationDateStandardItemPointer->setEditable(false);
178             isHttpOnlyStandardItemPointer->setEditable(false);
179             isSecureStandardItemPointer->setEditable(false);
180             valueStandardItemPointer->setEditable(false);
181
182             // Populate the domain standard item list.
183             domainStandardItemList.append(domainStandardItemPointer);
184             domainStandardItemList.append(pathStandardItemPointer);
185             domainStandardItemList.append(expirationDateStandardItemPointer);
186             domainStandardItemList.append(isHttpOnlyStandardItemPointer);
187             domainStandardItemList.append(isSecureStandardItemPointer);
188             domainStandardItemList.append(valueStandardItemPointer);
189
190             // Add the domain to the tree.
191             standardItemModelPointer->invisibleRootItem()->appendRow(domainStandardItemList);
192
193             // Update the current domain string.
194             currentDomainString = cookieDomain;
195
196             // Update the current domain standard item pointer.
197             currentDomainStandardItemPointer = domainStandardItemPointer;
198         }
199
200         // Create a list for the cookie standard items.
201         QList<QStandardItem*> cookieStandardItemList;
202
203         // Create the cookie standard items.
204         QStandardItem *nameStandardItemPointer = new QStandardItem(QString(cookie.name()));
205         QStandardItem *pathStandardItemPointer = new QStandardItem(QString(cookie.path()));
206         QStandardItem *expirationDateStandardItemPointer = new QStandardItem(QString(cookie.expirationDate().toString()));
207         QStandardItem *isHttpOnlyStandardItemPointer = new QStandardItem(QString(cookie.isHttpOnly() ? i18n("yes") : i18n("no")));
208         QStandardItem *isSecureStandardItemPointer = new QStandardItem(QString(cookie.isSecure() ? i18n("yes") : i18n("no")));
209         QStandardItem *valueStandardItemPointer = new QStandardItem(QString(cookie.value()));
210
211         // Disable editing of the cookie standard items.
212         nameStandardItemPointer->setEditable(false);
213         pathStandardItemPointer->setEditable(false);
214         expirationDateStandardItemPointer->setEditable(false);
215         isHttpOnlyStandardItemPointer->setEditable(false);
216         isSecureStandardItemPointer->setEditable(false);
217         valueStandardItemPointer->setEditable(false);
218
219         // Populate the cookie standard item list.
220         cookieStandardItemList.append(nameStandardItemPointer);
221         cookieStandardItemList.append(pathStandardItemPointer);
222         cookieStandardItemList.append(expirationDateStandardItemPointer);
223         cookieStandardItemList.append(isHttpOnlyStandardItemPointer);
224         cookieStandardItemList.append(isSecureStandardItemPointer);
225         cookieStandardItemList.append(valueStandardItemPointer);
226
227         // Add the cookie to the tree.
228         currentDomainStandardItemPointer->appendRow(cookieStandardItemList);
229     }
230
231     // Auto resize the headers.
232     treeViewPointer->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
233
234     // Disable stretching the last section.  Otherwise, the Value field will be truncated to the width of the window when a row is expanded.
235     treeViewPointer->header()->setStretchLastSection(false);
236
237     // Don't elide the Value field (or any other field).
238     treeViewPointer->setTextElideMode(Qt::ElideNone);
239
240     // Indicate that all the rows are the same height, wich improves performance.
241     treeViewPointer->setUniformRowHeights(true);
242
243     // Set the tree view model.
244     treeViewPointer->setModel(standardItemModelPointer);
245
246     // Get a handle for the tree view selection model.
247     treeViewSelectionModelPointer = treeViewPointer->selectionModel();
248
249     // Listen for selection changes.
250     connect(treeViewSelectionModelPointer, SIGNAL(selectionChanged(QItemSelection, QItemSelection)), this, SLOT(updateUi()));
251
252     // Get handles for the buttons.
253     addCookieButtonPointer = cookiesDialogUi.addCookieButton;
254     editCookieButtonPointer = cookiesDialogUi.editCookieButton;
255     deleteCookieButtonPointer = cookiesDialogUi.deleteCookieButton;
256     QDialogButtonBox *dialogButtonBoxPointer = cookiesDialogUi.dialogButtonBox;
257     QPushButton *closeButtonPointer = dialogButtonBoxPointer->button(QDialogButtonBox::Close);
258
259     // Add a delete all button to the dialog button box.
260     deleteAllButtonPointer = dialogButtonBoxPointer->addButton(i18nc("Delete all cookies button", "Delete all"), QDialogButtonBox::ActionRole);
261
262     // Set the delete all button icon.
263     deleteAllButtonPointer->setIcon(QIcon::fromTheme("delete"));
264
265     // Connect the buttons.
266     connect(addCookieButtonPointer, SIGNAL(clicked()), this, SLOT(showAddCookieDialog()));
267     connect(editCookieButtonPointer, SIGNAL(clicked()), this, SLOT(showEditCookieDialog()));
268     connect(deleteCookieButtonPointer, SIGNAL(clicked()), this, SLOT(showDeleteCookieMessageBox()));
269     connect(deleteAllButtonPointer, SIGNAL(clicked()), this, SLOT(showDeleteAllMessageBox()));
270     connect(dialogButtonBoxPointer, SIGNAL(rejected()), this, SLOT(reject()));
271
272     // Set the cancel button to be the default.
273     closeButtonPointer->setDefault(true);
274
275     // Create the keyboard shortcuts.
276     QShortcut *aShortcutPointer = new QShortcut(QKeySequence(i18nc("The add cookie key shortcut.", "a")), this);
277     QShortcut *eShortcutPointer = new QShortcut(QKeySequence(i18nc("The edit cookie key shorcut.", "e")), this);
278     QShortcut *dShortcutPointer = new QShortcut(QKeySequence(i18nc("The delete cookie key shortcut.", "d")), this);
279     QShortcut *deleteShortcutPointer = new QShortcut(QKeySequence::Delete, this);
280     QShortcut *lShortcutPointer = new QShortcut(QKeySequence(i18nc("The delete all key shortcut.", "l")), this);
281     QShortcut *cShortcutPointer = new QShortcut(QKeySequence(i18nc("The close key shortcut.", "c")), this);
282     QShortcut *quitShortcutPointer = new QShortcut(QKeySequence::Quit, this);
283
284     // Connect the keyboard shortcuts to the buttons.
285     connect(aShortcutPointer, SIGNAL(activated()), addCookieButtonPointer, SLOT(click()));
286     connect(eShortcutPointer, SIGNAL(activated()), editCookieButtonPointer, SLOT(click()));
287     connect(dShortcutPointer, SIGNAL(activated()), deleteCookieButtonPointer, SLOT(click()));
288     connect(deleteShortcutPointer, SIGNAL(activated()), deleteCookieButtonPointer, SLOT(click()));
289     connect(lShortcutPointer, SIGNAL(activated()), deleteAllButtonPointer, SLOT(click()));
290     connect(cShortcutPointer, SIGNAL(activated()), closeButtonPointer, SLOT(click()));
291     connect(quitShortcutPointer, SIGNAL(activated()), closeButtonPointer, SLOT(click()));
292
293     // Edit a cookie when it is double clicked.
294     connect(treeViewPointer, SIGNAL(doubleClicked(QModelIndex)), editCookieButtonPointer, SLOT(click()));
295
296     // Update the UI.
297     updateUi();
298 };
299
300 void CookiesDialog::addCookieFromDialog(const QNetworkCookie &cookie) const
301 {
302     // Add the cookie to the cookie list and the cookie store.
303     emit addCookie(cookie);
304
305     // Get the new domain string.
306     QString newDomain = cookie.domain();
307
308     // Check to see if the domain already exists in the model.
309     QList<QStandardItem*> currentDomainStandardItemList = standardItemModelPointer->findItems(newDomain);
310
311     // Create a domain standard item pointer.
312     QStandardItem *domainStandardItemPointer;
313
314     // Prepare the domain standard item pointer.
315     if (currentDomainStandardItemList.isEmpty())  // The domain doesn't currently exist in the tree.
316     {
317         // Create a list for the domain standard items.
318         QList<QStandardItem*> domainStandardItemList;
319
320         // Create the new domain standard items.
321         domainStandardItemPointer = new QStandardItem(newDomain);
322         QStandardItem *pathStandardItemPointer = new QStandardItem(QStringLiteral(""));
323         QStandardItem *expirationDateStandardItemPointer = new QStandardItem(QStringLiteral(""));
324         QStandardItem *isHttpOnlyStandardItemPointer = new QStandardItem(QStringLiteral(""));
325         QStandardItem *isSecureStandardItemPointer = new QStandardItem(QStringLiteral(""));
326         QStandardItem *valueStandardItemPointer = new QStandardItem(QStringLiteral(""));
327
328         // Disable editing of the domain.
329         domainStandardItemPointer->setEditable(false);
330         pathStandardItemPointer->setEditable(false);
331         expirationDateStandardItemPointer->setEditable(false);
332         isHttpOnlyStandardItemPointer->setEditable(false);
333         isSecureStandardItemPointer->setEditable(false);
334         valueStandardItemPointer->setEditable(false);
335
336         // Populate the domain standard item list.
337         domainStandardItemList.append(domainStandardItemPointer);
338         domainStandardItemList.append(pathStandardItemPointer);
339         domainStandardItemList.append(expirationDateStandardItemPointer);
340         domainStandardItemList.append(isHttpOnlyStandardItemPointer);
341         domainStandardItemList.append(isSecureStandardItemPointer);
342         domainStandardItemList.append(valueStandardItemPointer);
343
344         // Create the insert domain row number.
345         int insertDomainRowNumber = 0;
346
347         // Get the number of domains in the tree.
348         int numberOfDomains = standardItemModelPointer->invisibleRootItem()->rowCount();
349
350         // Get the new domain strings.
351         QString newDomainTopLevelDomain = newDomain.section('.', -1);
352         QString newDomainSecondLevelDomain = newDomain.section('.', -2);
353         QString newDomainThirdLevelDomain = newDomain.section('.', -3);
354
355         // Iterate through all the domains.
356         for (int i = 0; i < numberOfDomains; ++i)
357         {
358             // Get the current domain strings.
359             QString currentDomain = standardItemModelPointer->invisibleRootItem()->child(i, 0)->index().data().toString();
360             QString currentDomainTopLevelDomain = currentDomain.section('.', -1);
361             QString currentDomainSecondLevelDomain = currentDomain.section('.', -2);
362             QString currentDomainThirdLevelDomain = currentDomain.section('.', -3);
363
364             // Check to see if the new domain should be inserted after the current domain.
365             if (newDomainTopLevelDomain > currentDomainTopLevelDomain)
366             {
367                 // Insert the new domain after the current domain.
368                 insertDomainRowNumber = i + 1;
369             }
370             else if ((newDomainTopLevelDomain == currentDomainTopLevelDomain) && (newDomainSecondLevelDomain > currentDomainSecondLevelDomain))
371             {
372                 // Insert the new domain after the current domain.
373                 insertDomainRowNumber = i + 1;
374             }
375             else if ((newDomainSecondLevelDomain == currentDomainSecondLevelDomain) && (newDomainThirdLevelDomain > currentDomainThirdLevelDomain))
376             {
377                 // Insert the new domain after the current domain.
378                 insertDomainRowNumber = i + 1;
379             }
380             else if ((newDomainThirdLevelDomain == currentDomainThirdLevelDomain) && (newDomain > currentDomain))
381             {
382                 // Insert the new domain after the current domain.
383                 insertDomainRowNumber = i + 1;
384             }
385         }
386
387         // Add the domain to the tree.
388         standardItemModelPointer->invisibleRootItem()->insertRow(insertDomainRowNumber, domainStandardItemList);
389     }
390     else  // The domain already exists in the tree.
391     {
392         // Use the current domain standard item.
393         domainStandardItemPointer = currentDomainStandardItemList[0];
394     }
395
396     // Get strings for the new cookie name and path (used later in the placement of the row).
397     QString newCookieName = QString(cookie.name());
398     QString newCookiePath = QString(cookie.path());
399
400     // Create a list for the cookie standard items.
401     QList<QStandardItem*> cookieStandardItemList;
402
403     // Create the cookie standard items.
404     QStandardItem *nameStandardItemPointer = new QStandardItem(newCookieName);
405     QStandardItem *pathStandardItemPointer = new QStandardItem(newCookiePath);
406     QStandardItem *expirationDateStandardItemPointer = new QStandardItem(QString(cookie.expirationDate().toString()));
407     QStandardItem *isHttpOnlyStandardItemPointer = new QStandardItem(QString(cookie.isHttpOnly() ? i18n("yes") : i18n("no")));
408     QStandardItem *isSecureStandardItemPointer = new QStandardItem(QString(cookie.isSecure() ? i18n("yes") : i18n("no")));
409     QStandardItem *valueStandardItemPointer = new QStandardItem(QString(cookie.value()));
410
411     // Disable editing of the cookie standard items.
412     nameStandardItemPointer->setEditable(false);
413     pathStandardItemPointer->setEditable(false);
414     expirationDateStandardItemPointer->setEditable(false);
415     isHttpOnlyStandardItemPointer->setEditable(false);
416     isSecureStandardItemPointer->setEditable(false);
417     valueStandardItemPointer->setEditable(false);
418
419     // Populate the cookie standard item list.
420     cookieStandardItemList.append(nameStandardItemPointer);
421     cookieStandardItemList.append(pathStandardItemPointer);
422     cookieStandardItemList.append(expirationDateStandardItemPointer);
423     cookieStandardItemList.append(isHttpOnlyStandardItemPointer);
424     cookieStandardItemList.append(isSecureStandardItemPointer);
425     cookieStandardItemList.append(valueStandardItemPointer);
426
427     // Create the insert cookie row number.
428     int insertCookieRowNumber = 0;
429
430     // Get the number of cookies in the domain.
431     int numberOfCookies = domainStandardItemPointer->rowCount();
432
433     // Iterate through the cookies for this domain.
434     for (int i = 0; i < numberOfCookies; ++i)
435     {
436         // Get the current cookie name and path at the indicated row.
437         QString currentCookieName = domainStandardItemPointer->child(i, 0)->index().data().toString();
438         QString currentCookiePath = domainStandardItemPointer->child(i, 1)->index().data().toString();
439
440         // Check to see if the new cookie should be inserted after the current cookie.
441         if (newCookieName > currentCookieName)
442         {
443             // Insert the new cookie after the current cookie.
444             insertCookieRowNumber = i + 1;
445         }
446         else if ((newCookieName == currentCookieName) && (newCookiePath > currentCookiePath))
447         {
448             // Insert the new cookie after the current cookie.
449             insertCookieRowNumber = i + 1;
450         }
451     }
452
453     // Add the cookie to the tree.
454     domainStandardItemPointer->insertRow(insertCookieRowNumber, cookieStandardItemList);
455
456     // Get the new cookie model index.
457     QModelIndex newCookieIndex = nameStandardItemPointer->index();
458
459     // Set the new cookie to be the current index.
460     treeViewPointer->setCurrentIndex(newCookieIndex);
461
462     // Expand the parent of the new cookie.
463     treeViewPointer->expand(newCookieIndex.parent());
464 }
465
466 void CookiesDialog::deleteCookie(const QModelIndex &modelIndex) const
467 {
468     // Create a partial cookie.
469     QNetworkCookie partialCookie;
470
471     // Populate the partial cookie from the current model index.
472     partialCookie.setDomain(modelIndex.parent().siblingAtColumn(0).data().toString());
473     partialCookie.setName(modelIndex.siblingAtColumn(0).data().toString().toUtf8());
474     partialCookie.setPath(modelIndex.siblingAtColumn(1).data().toString());
475
476     // Create a cookie to delete.
477     QNetworkCookie cookieToDelete;
478
479     // Search for the partial cookie in the cookie list.
480     for (QNetworkCookie cookie : *cookieListPointer)
481     {
482         // Store the cookie to delete if it has the same identifier as the partial cookie.
483         if (cookie.hasSameIdentifier(partialCookie))
484             cookieToDelete = cookie;
485     }
486
487     // Remove the cookie from the tree view.
488     standardItemModelPointer->removeRow(modelIndex.row(), modelIndex.parent());
489
490     // Delete the cookie from the cookie list and cookie store.
491     emit deleteCookie(cookieToDelete);
492 }
493
494 void CookiesDialog::deleteCookieFromDialog(const QNetworkCookie &cookie) const
495 {
496     // Get the current model index.
497     QModelIndex currentIndex = treeViewSelectionModelPointer->currentIndex();
498
499     // Get the parent index.
500     QModelIndex parentIndex = currentIndex.parent();
501
502     // Remove the cookie from the tree view.
503     standardItemModelPointer->removeRow(currentIndex.row(), parentIndex);
504
505     // Remove the domain from the tree view if its only cookie has been deleted.
506     if (standardItemModelPointer->rowCount(parentIndex) == 0)
507         standardItemModelPointer->removeRow(parentIndex.row(), parentIndex.parent());
508
509     // Delete the cookie from the cookie list and cookie store.
510     emit deleteCookie(cookie);
511 }
512
513 void CookiesDialog::showAddCookieDialog() const
514 {
515     // Instantiate an add cookie dialog.
516     QDialog *addCookieDialogPointer = new AddOrEditCookieDialog(AddOrEditCookieDialog::AddCookie);
517
518     // Show the dialog.
519     addCookieDialogPointer->show();
520
521     // Add the cookie if directed.
522     connect(addCookieDialogPointer, SIGNAL(addCookie(QNetworkCookie)), this, SLOT(addCookieFromDialog(QNetworkCookie)));
523 }
524
525 void CookiesDialog::showDeleteAllMessageBox() const
526 {
527     // Instantiate a delete all message box.
528     QMessageBox deleteAllCookiesMessageBox;
529
530     // Set the icon.
531     deleteAllCookiesMessageBox.setIcon(QMessageBox::Warning);
532
533     // Set the window title.
534     deleteAllCookiesMessageBox.setWindowTitle(i18nc("Delete all cookies dialog title", "Delete All Cookies"));
535
536     // Set the text.
537     deleteAllCookiesMessageBox.setText(i18nc("Delete all cookies dialog text", "Delete all cookies?"));
538
539     // Set the standard buttons.
540     deleteAllCookiesMessageBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
541
542     // Set the default button.
543     deleteAllCookiesMessageBox.setDefaultButton(QMessageBox::No);
544
545     // Display the dialog and capture the return value.
546     int returnValue = deleteAllCookiesMessageBox.exec();
547
548     // Delete all cookies if instructed.
549     if (returnValue == QMessageBox::Yes)
550     {
551         // Delete all the cookies.
552         emit deleteAllCookies();
553
554         // Clear the standard item model.
555         standardItemModelPointer->clear();
556
557         // Update the UI.
558         updateUi();
559     }
560 }
561
562 void CookiesDialog::showDeleteCookieMessageBox() const
563 {
564     // Get the current model index.
565     QModelIndex currentIndex = treeViewSelectionModelPointer->currentIndex();
566
567     // Get the parent model index.
568     QModelIndex parentIndex = currentIndex.parent();
569
570     // Determine if a domain is selected.
571     bool isDomain = standardItemModelPointer->hasChildren(currentIndex);
572
573     // Instantiate a delete cookie message box.
574     QMessageBox deleteCookieMessageBox;
575
576     // Set the icon.
577     deleteCookieMessageBox.setIcon(QMessageBox::Warning);
578
579     if (isDomain)
580     {
581         // Get the number of cookies.
582         int numberOfCookiesToDelete = standardItemModelPointer->rowCount(currentIndex);
583
584         // Set the window title.
585         deleteCookieMessageBox.setWindowTitle(i18nc("Delete cookies dialog title", "Delete %1 Cookies", numberOfCookiesToDelete));
586
587         // Set the text.
588         deleteCookieMessageBox.setText(i18nc("Delete cookies dialog text", "Delete %1 cookies?", numberOfCookiesToDelete));
589     }
590     else
591     {
592         // Set the window title.
593         deleteCookieMessageBox.setWindowTitle(i18nc("Delete cookie dialog title", "Delete 1 Cookie"));
594
595         // Set the text.
596         deleteCookieMessageBox.setText(i18nc("Delete cookie dialog text", "Delete 1 cookie?"));
597     }
598
599     // Set the standard buttons.
600     deleteCookieMessageBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
601
602     // Set the default button.
603     deleteCookieMessageBox.setDefaultButton(QMessageBox::No);
604
605     // Display the dialog and capture the return value.
606     int returnValue = deleteCookieMessageBox.exec();
607
608     // Delete the cookie if instructed.
609     if (returnValue == QMessageBox::Yes)
610     {
611         // Delete the cookies according to the selection.
612         if (isDomain)  // A domain is selected.
613         {
614             // Get the number of cookies.
615             int numberOfCookies = standardItemModelPointer->rowCount(currentIndex);
616
617             // Delete each child cookie.
618             for (int i = 0; i < numberOfCookies; ++i)
619             {
620                 // Delete the cookie for the first child.  Once this is deleted, the second child will become the first child.
621                 deleteCookie(standardItemModelPointer->index(0, 0, currentIndex));
622             }
623
624             // Delete the domain from the tree view.
625             standardItemModelPointer->removeRow(currentIndex.row(), parentIndex);
626         }
627         else  // A single cookie is selected.
628         {
629             // Delete the cookie.
630             deleteCookie(currentIndex);
631
632             // Remove the domain row if its only cookie has been deleted.
633             if (standardItemModelPointer->rowCount(parentIndex) == 0)
634                 standardItemModelPointer->removeRow(parentIndex.row(), parentIndex.parent());
635         }
636     }
637 }
638
639 void CookiesDialog::showEditCookieDialog() const
640 {
641     // Get the current model index.
642     QModelIndex currentIndex = treeViewSelectionModelPointer->currentIndex();
643
644     // Create a partial cookie.
645     QNetworkCookie partialCookie;
646
647     // Populate the partial cookie from the current model index.
648     partialCookie.setDomain(currentIndex.parent().siblingAtColumn(0).data().toString());
649     partialCookie.setName(currentIndex.siblingAtColumn(0).data().toString().toUtf8());
650     partialCookie.setPath(currentIndex.siblingAtColumn(1).data().toString());
651
652     // Create a cookie to edit.
653     QNetworkCookie cookieToEdit;
654
655     // Search for the partial cookie in the cookie list.
656     for (QNetworkCookie cookie : *cookieListPointer)
657     {
658         // Store the cookie to edit if it has the same identifier as the partial cookie.
659         if (cookie.hasSameIdentifier(partialCookie))
660             cookieToEdit = cookie;
661     }
662
663     // Instantiate an edit cookie dialog.
664     QDialog *editCookieDialogPointer = new AddOrEditCookieDialog(AddOrEditCookieDialog::EditCookie, &cookieToEdit);
665
666     // Show the dialog.
667     editCookieDialogPointer->show();
668
669     // Process cookie events.
670     connect(editCookieDialogPointer, SIGNAL(addCookie(QNetworkCookie)), this, SLOT(addCookieFromDialog(QNetworkCookie)));
671     connect(editCookieDialogPointer, SIGNAL(deleteCookie(QNetworkCookie)), this, SLOT(deleteCookieFromDialog(QNetworkCookie)));
672 }
673
674 void CookiesDialog::updateUi() const
675 {
676     // Get the current index of the first column.
677     QModelIndex currentIndex = treeViewSelectionModelPointer->currentIndex().siblingAtColumn(0);
678
679     // Set the status of the buttons.
680     editCookieButtonPointer->setEnabled(treeViewSelectionModelPointer->hasSelection() && !standardItemModelPointer->hasChildren(currentIndex));
681     deleteCookieButtonPointer->setEnabled(treeViewSelectionModelPointer->hasSelection());;
682     deleteAllButtonPointer->setEnabled(standardItemModelPointer->hasChildren(standardItemModelPointer->invisibleRootItem()->index()));
683
684     // Update the delete cookie button text.
685     if (deleteCookieButtonPointer->isEnabled())  // The button is enabled.
686     {
687         if (standardItemModelPointer->hasChildren(currentIndex))  // A domain is selected.
688         {
689             // Update the button text.
690             deleteCookieButtonPointer->setText(i18nc("Delete cookies button.", "&Delete %1 cookies", standardItemModelPointer->rowCount(currentIndex)));
691         }
692         else  // A single cookie is selected.
693         {
694             // Update the button text.
695             deleteCookieButtonPointer->setText(i18nc("Delete cookies button.", "&Delete 1 cookie"));
696         }
697     }
698     else  // The button is disabled.
699     {
700         // Reset the button text.
701         deleteCookieButtonPointer->setText(i18nc("Delete cookie button.", "&Delete cookie"));
702     }
703 }