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