]> gitweb.stoutner.com Git - PrivacyBrowserPC.git/commitdiff
Filter options implementation.
authorSoren Stoutner <soren@stoutner.com>
Sun, 9 Jun 2024 03:47:22 +0000 (20:47 -0700)
committerSoren Stoutner <soren@stoutner.com>
Sun, 9 Jun 2024 03:47:22 +0000 (20:47 -0700)
23 files changed:
src/delegates/CMakeLists.txt
src/delegates/ViewAndCopyDelegate.cpp [new file with mode: 0644]
src/delegates/ViewAndCopyDelegate.h [new file with mode: 0644]
src/delegates/ViewOnlyDelegate.cpp
src/delegates/ViewOnlyDelegate.h
src/dialogs/FilterListsDialog.cpp
src/dialogs/RequestDetailDialog.cpp
src/dialogs/RequestDetailDialog.h
src/dialogs/RequestsDialog.cpp
src/enums/FilterOptionEnum.h [new file with mode: 0644]
src/helpers/FilterListHelper.cpp
src/helpers/FilterListHelper.h
src/helpers/UserAgentHelper.cpp
src/structs/EntryStruct.h
src/structs/FilterListStruct.h
src/structs/OverrideStruct.h [new file with mode: 0644]
src/structs/UrlStruct.h [new file with mode: 0644]
src/uis/AddTabWidget.ui
src/uis/FilterListsDialog.ui
src/uis/RequestDetailDialog.ui
src/uis/RequestsDialog.ui
src/uis/TabWidget.ui
src/widgets/TabWidget.cpp

index d26efe712c25eb21d256ea048597f0515910710e..440ec44f5540fec1a61430956ff3e69fba816193 100644 (file)
@@ -1,6 +1,6 @@
-# Copyright 2022-2023 Soren Stoutner <soren@stoutner.com>.
+# Copyright 2022-2024 Soren Stoutner <soren@stoutner.com>.
 #
-# This file is part of Privacy Browser PC <https://www.stoutner.com/privacy-browser-pc>.
+# This file is part of Privacy Browser PC <https://www.stoutner.com/privacy-browser-pc/>.
 #
 # Privacy Browser PC is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -18,5 +18,6 @@
 
 # List the sources to include in the executable.
 target_sources(privacybrowser PRIVATE
+    ViewAndCopyDelegate.cpp
     ViewOnlyDelegate.cpp
 )
diff --git a/src/delegates/ViewAndCopyDelegate.cpp b/src/delegates/ViewAndCopyDelegate.cpp
new file mode 100644 (file)
index 0000000..d3eb1f3
--- /dev/null
@@ -0,0 +1,44 @@
+ /*
+ * Copyright 2024 Soren Stoutner <soren@stoutner.com>.
+ *
+ * This file is part of Privacy Browser PC <https://www.stoutner.com/privacy-browser-pc/>.
+ *
+ * Privacy Browser PC is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Privacy Browser PC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Privacy Browser PC.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+// Application headers.
+#include "ViewAndCopyDelegate.h"
+
+// Qt toolkit headers.
+#include <QLineEdit>
+
+ViewAndCopyDelegate::ViewAndCopyDelegate(QObject *parentObjectPointer) : QStyledItemDelegate(parentObjectPointer) {}
+
+QWidget* ViewAndCopyDelegate::createEditor(QWidget *parentWidgetPointer, const QStyleOptionViewItem &styleOptionViewItem, const QModelIndex &modelIndex) const
+{
+    // Instruct the compiler to ignore the unused variables.
+    (void) styleOptionViewItem;
+
+    // Get the data string from the model index.
+    QString dataString = modelIndex.data().toString();
+
+    // Create a line edit.
+    QLineEdit *lineEditPointer = new QLineEdit(dataString, parentWidgetPointer);
+
+    // Set the line edit to be read only.
+    lineEditPointer->setReadOnly(true);
+
+    // Return the line edit.
+    return lineEditPointer;
+}
diff --git a/src/delegates/ViewAndCopyDelegate.h b/src/delegates/ViewAndCopyDelegate.h
new file mode 100644 (file)
index 0000000..722add4
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2024 Soren Stoutner <soren@stoutner.com>.
+ *
+ * This file is part of Privacy Browser PC <https://www.stoutner.com/privacy-browser-pc/>.
+ *
+ * Privacy Browser PC is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Privacy Browser PC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Privacy Browser PC.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef VIEWANDCOPYDELEGATE_H
+#define VIEWANDCOPYDELEGATE_H
+
+// Qt toolkit headers.
+#include <QStyledItemDelegate>
+
+class ViewAndCopyDelegate : public QStyledItemDelegate
+{
+    // Include the Q_OBJECT macro.
+    Q_OBJECT
+
+public:
+    // The default constructor.
+    explicit ViewAndCopyDelegate(QObject *parenObjectPointer = nullptr);
+
+    // The public functions.
+    QWidget* createEditor(QWidget *parentWidgetPointer, const QStyleOptionViewItem &styleOptionViewItem, const QModelIndex &modelIndex) const override;
+};
+#endif
index ab7f873bc2e3f6d86a8ddb165358c36cb7995290..3bfc991296dd7c660f8d70c41c13f355d1fedfd4 100644 (file)
@@ -1,7 +1,7 @@
  /*
- * Copyright © 2022 Soren Stoutner <soren@stoutner.com>.
+ * Copyright 2022, 2024 Soren Stoutner <soren@stoutner.com>.
  *
- * This file is part of Privacy Browser PC <https://www.stoutner.com/privacy-browser-pc>.
+ * This file is part of Privacy Browser PC <https://www.stoutner.com/privacy-browser-pc/>.
  *
  * Privacy Browser PC is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -20,7 +20,7 @@
 // Application headers.
 #include "ViewOnlyDelegate.h"
 
-ViewOnlyDelegate::ViewOnlyDelegate(QObject *parentPointer) : QStyledItemDelegate(parentPointer) {}
+ViewOnlyDelegate::ViewOnlyDelegate(QObject *parentObjectPointer) : QStyledItemDelegate(parentObjectPointer) {}
 
 QWidget* ViewOnlyDelegate::createEditor(QWidget *parentWidgetPointer, const QStyleOptionViewItem &styleOptionsViewItem, const QModelIndex &modelIndex) const
 {
index 774335c69d08fe00330d2aaf434ef696431491e9..db73dbf6677ee6e4bdc24d070a7b41f7cb1ef1ef 100644 (file)
@@ -1,7 +1,7 @@
 /*
- * Copyright © 2022 Soren Stoutner <soren@stoutner.com>.
+ * Copyright 2022, 2024 Soren Stoutner <soren@stoutner.com>.
  *
- * This file is part of Privacy Browser PC <https://www.stoutner.com/privacy-browser-pc>.
+ * This file is part of Privacy Browser PC <https://www.stoutner.com/privacy-browser-pc/>.
  *
  * Privacy Browser PC is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -30,7 +30,7 @@ class ViewOnlyDelegate : public QStyledItemDelegate
 
 public:
     // The default constructor.
-    explicit ViewOnlyDelegate(QObject *parentPointer = nullptr);
+    explicit ViewOnlyDelegate(QObject *parentObjectPointer = nullptr);
 
     // The public functions.
     QWidget* createEditor(QWidget *parentWidgetPointer, const QStyleOptionViewItem &styleOptionsViewItem, const QModelIndex &modelIndex) const override;
index dbba88e25863c6026c03acae73b7df7189fa0933..0ab6753780d1abe958ee75cd9830b8b5f46aebbe 100644 (file)
@@ -21,6 +21,7 @@
 #include "FilterListsDialog.h"
 #include "GlobalVariables.h"
 #include "ui_FilterListsDialog.h"
+#include "delegates/ViewAndCopyDelegate.h"
 
 // Qt toolkit headers.
 #include <QFile>
@@ -48,6 +49,12 @@ FilterListsDialog::FilterListsDialog(QWidget *parentWidgetPointer) : QDialog(par
     sublistTableWidgetPointer = filterListsDialogUi.sublistTableWidget;
     QDialogButtonBox *dialogButtonBoxPointer = filterListsDialogUi.dialogButtonBox;
 
+    // Create a view and copy delegate.
+    ViewAndCopyDelegate *viewAndCopyDelegate = new ViewAndCopyDelegate(this);
+
+    // Set the sublist table widget allow copying but not editing.
+    sublistTableWidgetPointer->setItemDelegate(viewAndCopyDelegate);
+
     // Connect the combo boxes.
     connect(filterListComboBoxPointer, SIGNAL(currentIndexChanged(int)), this, SLOT(populateFilterListTextEdit(int)));
     connect(sublistComboBoxPointer, SIGNAL(currentIndexChanged(int)), this, SLOT(populateTableWidget(int)));
@@ -113,14 +120,20 @@ void FilterListsDialog::populateFilterListTextEdit(int filterListComboBoxInt) co
     // Clear the sublist combo box.
     sublistComboBoxPointer->clear();
 
-    // Calculate the size of the main filter list.
+    // Calculate the size of the filter lists.
+    int mainAllowListSize = distance(filterListStructPointer->mainAllowList.begin(), filterListStructPointer->mainAllowList.end());
     int mainBlockListSize = distance(filterListStructPointer->mainBlockList.begin(), filterListStructPointer->mainBlockList.end());
+    int initialDomainBlockListSize = distance(filterListStructPointer->initialDomainBlockList.begin(), filterListStructPointer->initialDomainBlockList.end());
 
     // Get the translated filter list names.
+    QString mainAllowListName = globalFilterListHelperPointer->getSublistName(FilterListHelper::MAIN_ALLOWLIST);
     QString mainBlockListName = globalFilterListHelperPointer->getSublistName(FilterListHelper::MAIN_BLOCKLIST);
+    QString initialDomainBlockListName = globalFilterListHelperPointer->getSublistName(FilterListHelper::INITIAL_DOMAIN_BLOCKLIST);
 
     // Populate the sublist combo box.
+    sublistComboBoxPointer->addItem(i18nc("The main allow list", "%1 - %2", mainAllowListName, mainAllowListSize));
     sublistComboBoxPointer->addItem(i18nc("The main block list", "%1 - %2", mainBlockListName, mainBlockListSize));
+    sublistComboBoxPointer->addItem(i18nc("The initial domain block list", "%1 - %2", initialDomainBlockListName, initialDomainBlockListSize));
 }
 
 void FilterListsDialog::populateTableWidget(int sublistComboBoxIndex) const
@@ -163,21 +176,55 @@ void FilterListsDialog::populateTableWidget(int sublistComboBoxIndex) const
     // Populate the filter list forward list.
     switch (sublistComboBoxIndex)
     {
-        case 0:  // Main block list.
+        case FilterListHelper::MAIN_ALLOWLIST:  // The main allow list.
+            filterListForwardList = filterListStructPointer->mainAllowList;
+            break;
+
+        case FilterListHelper::MAIN_BLOCKLIST:  // The main block list.
             filterListForwardList = filterListStructPointer->mainBlockList;
             break;
+
+        case FilterListHelper::INITIAL_DOMAIN_BLOCKLIST:  // The initial domain block list.
+            filterListForwardList = filterListStructPointer->initialDomainBlockList;
+            break;
     }
 
     // Create the columns.
-    sublistTableWidgetPointer->setColumnCount(2);
+    sublistTableWidgetPointer->setColumnCount(15);
 
     // Create the table headers.
     QTableWidgetItem *appliedEntryHeaderItemPointer = new QTableWidgetItem(i18nc("Sublist applied entry header", "Applied Entry"));
+    QTableWidgetItem *thirdPartyHeaderItemPointer = new QTableWidgetItem(i18nc("Sublist third-party header", "Third-Party"));
+    QTableWidgetItem *fontHeaderItemPointer = new QTableWidgetItem(i18nc("Sublist font header", "Font"));
+    QTableWidgetItem *imageHeaderItemPointer = new QTableWidgetItem(i18nc("Sublist image header", "Image"));
+    QTableWidgetItem *mainFrameHeaderItemPointer = new QTableWidgetItem(i18nc("Sublist main frame header", "Main Frame"));
+    QTableWidgetItem *mediaHeaderItemPointer = new QTableWidgetItem(i18nc("Sublist media header", "Media"));
+    QTableWidgetItem *objectHeaderItemPointer = new QTableWidgetItem(i18nc("Sublist object header", "Object"));
+    QTableWidgetItem *otherHeaderItemPointer = new QTableWidgetItem(i18nc("Sublist object header", "Other"));
+    QTableWidgetItem *pingHeaderItemPointer = new QTableWidgetItem(i18nc("Sublist ping header", "Ping"));
+    QTableWidgetItem *scriptHeaderItemPointer = new QTableWidgetItem(i18nc("Sublist script header", "Script"));
+    QTableWidgetItem *styleSheetHeaderItemPointer = new QTableWidgetItem(i18nc("Sublist style sheet header", "Style Sheet"));
+    QTableWidgetItem *subFrameHeaderItemPointer = new QTableWidgetItem(i18nc("Sublist sub frame header", "Sub Frame"));
+    QTableWidgetItem *xmlHttpRequestHeaderItemPointer = new QTableWidgetItem(i18nc("XML HTTP request header", "XML HTTP Request"));
+    QTableWidgetItem *filterOptionsHeaderItemPointer = new QTableWidgetItem(i18nc("Sublist filter options header", "Filter Options"));
     QTableWidgetItem *originalEntryHeaderItemPointer = new QTableWidgetItem(i18nc("Sublist original entry header", "Original Entry"));
 
     // Set the horizontal headers.
     sublistTableWidgetPointer->setHorizontalHeaderItem(0, appliedEntryHeaderItemPointer);
-    sublistTableWidgetPointer->setHorizontalHeaderItem(1, originalEntryHeaderItemPointer);
+    sublistTableWidgetPointer->setHorizontalHeaderItem(1, thirdPartyHeaderItemPointer);
+    sublistTableWidgetPointer->setHorizontalHeaderItem(2, fontHeaderItemPointer);
+    sublistTableWidgetPointer->setHorizontalHeaderItem(3, imageHeaderItemPointer);
+    sublistTableWidgetPointer->setHorizontalHeaderItem(4, mainFrameHeaderItemPointer);
+    sublistTableWidgetPointer->setHorizontalHeaderItem(5, mediaHeaderItemPointer);
+    sublistTableWidgetPointer->setHorizontalHeaderItem(6, objectHeaderItemPointer);
+    sublistTableWidgetPointer->setHorizontalHeaderItem(7, otherHeaderItemPointer);
+    sublistTableWidgetPointer->setHorizontalHeaderItem(8, pingHeaderItemPointer);
+    sublistTableWidgetPointer->setHorizontalHeaderItem(9, scriptHeaderItemPointer);
+    sublistTableWidgetPointer->setHorizontalHeaderItem(10, styleSheetHeaderItemPointer);
+    sublistTableWidgetPointer->setHorizontalHeaderItem(11, subFrameHeaderItemPointer);
+    sublistTableWidgetPointer->setHorizontalHeaderItem(12, xmlHttpRequestHeaderItemPointer);
+    sublistTableWidgetPointer->setHorizontalHeaderItem(13, filterOptionsHeaderItemPointer);
+    sublistTableWidgetPointer->setHorizontalHeaderItem(14, originalEntryHeaderItemPointer);
 
     // Initialize the row counter.
     int rowCounter = 0;
@@ -192,11 +239,37 @@ void FilterListsDialog::populateTableWidget(int sublistComboBoxIndex) const
 
         // Create the entry items.
         QTableWidgetItem *appliedEntryItemPointer = new QTableWidgetItem(entryStructPointer->appliedEntry);
+        QTableWidgetItem *thirdPartyItemPointer = new QTableWidgetItem(globalFilterListHelperPointer->getFilterOptionDispositionString(entryStructPointer->thirdParty));
+        QTableWidgetItem *fontItemPointer = new QTableWidgetItem(globalFilterListHelperPointer->getFilterOptionDispositionString(entryStructPointer->font));
+        QTableWidgetItem *imageItemPointer = new QTableWidgetItem(globalFilterListHelperPointer->getFilterOptionDispositionString(entryStructPointer->image));
+        QTableWidgetItem *mainFrameItemPointer = new QTableWidgetItem(globalFilterListHelperPointer->getFilterOptionDispositionString(entryStructPointer->mainFrame));
+        QTableWidgetItem *mediaItemPointer = new QTableWidgetItem(globalFilterListHelperPointer->getFilterOptionDispositionString(entryStructPointer->media));
+        QTableWidgetItem *objectItemPointer = new QTableWidgetItem(globalFilterListHelperPointer->getFilterOptionDispositionString(entryStructPointer->object));
+        QTableWidgetItem *otherItemPointer = new QTableWidgetItem(globalFilterListHelperPointer->getFilterOptionDispositionString(entryStructPointer->other));
+        QTableWidgetItem *pingItemPointer = new QTableWidgetItem(globalFilterListHelperPointer->getFilterOptionDispositionString(entryStructPointer->ping));
+        QTableWidgetItem *scriptItemPointer = new QTableWidgetItem(globalFilterListHelperPointer->getFilterOptionDispositionString(entryStructPointer->script));
+        QTableWidgetItem *styleSheetItemPointer = new QTableWidgetItem(globalFilterListHelperPointer->getFilterOptionDispositionString(entryStructPointer->styleSheet));
+        QTableWidgetItem *subFrameItemPointer = new QTableWidgetItem(globalFilterListHelperPointer->getFilterOptionDispositionString(entryStructPointer->subFrame));
+        QTableWidgetItem *xmlHttpRequestItemPointer = new QTableWidgetItem(globalFilterListHelperPointer->getFilterOptionDispositionString(entryStructPointer->xmlHttpRequest));
+        QTableWidgetItem *filterOptionsItemPointer = new QTableWidgetItem(entryStructPointer->filterOptions);
         QTableWidgetItem *originalEntryItemPointer = new QTableWidgetItem(entryStructPointer->originalEntry);
 
         // Add the entries to the table.
         sublistTableWidgetPointer->setItem(rowCounter, 0, appliedEntryItemPointer);
-        sublistTableWidgetPointer->setItem(rowCounter, 1, originalEntryItemPointer);
+        sublistTableWidgetPointer->setItem(rowCounter, 1, thirdPartyItemPointer);
+        sublistTableWidgetPointer->setItem(rowCounter, 2, fontItemPointer);
+        sublistTableWidgetPointer->setItem(rowCounter, 3, imageItemPointer);
+        sublistTableWidgetPointer->setItem(rowCounter, 4, mainFrameItemPointer);
+        sublistTableWidgetPointer->setItem(rowCounter, 5, mediaItemPointer);
+        sublistTableWidgetPointer->setItem(rowCounter, 6, objectItemPointer);
+        sublistTableWidgetPointer->setItem(rowCounter, 7, otherItemPointer);
+        sublistTableWidgetPointer->setItem(rowCounter, 8, pingItemPointer);
+        sublistTableWidgetPointer->setItem(rowCounter, 9, scriptItemPointer);
+        sublistTableWidgetPointer->setItem(rowCounter, 10, styleSheetItemPointer);
+        sublistTableWidgetPointer->setItem(rowCounter, 11, subFrameItemPointer);
+        sublistTableWidgetPointer->setItem(rowCounter, 12, xmlHttpRequestItemPointer);
+        sublistTableWidgetPointer->setItem(rowCounter, 13, filterOptionsItemPointer);
+        sublistTableWidgetPointer->setItem(rowCounter, 14, originalEntryItemPointer);
 
         // Increment the row counter.
         ++rowCounter;
index bdc4b6ae136da38f6f327e5147c2e681c64865a3..14947fda0b29bf26771be1b67021692086b29e04 100644 (file)
 #include "ui_RequestDetailDialog.h"
 #include "structs/RequestStruct.h"
 
-// Qt toolkit headers.
-#include <QDebug>
-
 // KDE Frameworks headers.
 #include <KActionCollection>
 #include <KColorScheme>
 
+// Qt toolkit headers.
+#include <QShortcut>
+
 // Construct the class.
-RequestDetailDialog::RequestDetailDialog(QWidget *parentWidgetPointer, QByteArray &requestStructByteArray) : QDialog(parentWidgetPointer)
+RequestDetailDialog::RequestDetailDialog(QWidget *parentWidgetPointer, QTableWidget *tableWidgetPointer, const int initialRow) :
+                                         QDialog(parentWidgetPointer), currentRow(initialRow), tableWidgetPointer(tableWidgetPointer)
+{
+    // Set the window modality.
+    setWindowModality(Qt::WindowModality::ApplicationModal);
+
+    // Instantiate the request detail dialog UI.
+    Ui::RequestDetailDialog requestDetailDialogUi;
+
+    // Setup the UI.
+    requestDetailDialogUi.setupUi(this);
+
+    // Get handles for the views.
+    dispositionLineEditPointer = requestDetailDialogUi.dispositionLineEdit;
+    urlLineEditPointer = requestDetailDialogUi.urlLineEdit;
+    requestMethodLineEditPointer = requestDetailDialogUi.requestMethodLineEdit;
+    navigationTypeLineEditPointer = requestDetailDialogUi.navigationTypeLineEdit;
+    resourceTypeLineEditPointer = requestDetailDialogUi.resourceTypeLineEdit;
+    horizontalLinePointer = requestDetailDialogUi.horizontalLine;
+    filterListLabelPointer = requestDetailDialogUi.filterListLabel;
+    filterListLineEditPointer = requestDetailDialogUi.filterListLineEdit;
+    sublistLabelPointer = requestDetailDialogUi.sublistLabel;
+    sublistLineEditPointer = requestDetailDialogUi.sublistListLineEdit;
+    appliedEntryLabelPointer = requestDetailDialogUi.appliedEntryLabel;
+    appliedEntryLineEditPointer = requestDetailDialogUi.appliedEntryLineEdit;
+    originalEntryLabelPointer = requestDetailDialogUi.originalEntryLabel;
+    originalEntryLineEditPointer = requestDetailDialogUi.originalEntryLineEdit;
+    previousButtonPointer = requestDetailDialogUi.previousButton;
+    nextButtonPointer = requestDetailDialogUi.nextButton;
+    QDialogButtonBox *dialogButtonBoxPointer = requestDetailDialogUi.dialogButtonBox;
+    QPushButton *closeButtonPointer = dialogButtonBoxPointer->button(QDialogButtonBox::StandardButton::Close);
+
+    // Make the close button the default.
+    closeButtonPointer->setDefault(true);
+
+    // Get the disposition line edit palettes.
+    normalBackgroundPalette = dispositionLineEditPointer->palette();
+    negativeBackgroundPalette = normalBackgroundPalette;
+    positiveBackgroundPalette = normalBackgroundPalette;
+
+    // Modify the palettes.
+    KColorScheme::adjustBackground(negativeBackgroundPalette, KColorScheme::NegativeBackground);
+    KColorScheme::adjustBackground(positiveBackgroundPalette, KColorScheme::PositiveBackground);
+
+    // Connect the buttons.
+    connect(previousButtonPointer, SIGNAL(clicked()), this, SLOT(previous()));
+    connect(nextButtonPointer, SIGNAL(clicked()), this, SLOT(next()));
+    connect(dialogButtonBoxPointer, SIGNAL(rejected()), this, SLOT(close()));
+
+    // Create the keyboard shortcuts.
+    QShortcut *previousShortcutPointer = new QShortcut(Qt::Key_Left, this);
+    QShortcut *nextShortcutPointer = new QShortcut(Qt::Key_Right, this);
+
+    // Connect the keyboard shortcuts to the buttons.
+    connect(previousShortcutPointer, SIGNAL(activated()), previousButtonPointer, SLOT(click()));
+    connect(nextShortcutPointer, SIGNAL(activated()), nextButtonPointer, SLOT(click()));
+
+    // Populate the dialog.
+    populateDialog(currentRow);
+}
+
+void RequestDetailDialog::populateDialog(const int row)
 {
+    // Set the window title.
+    setWindowTitle(i18nc("The request detail dialog window title", "Request %1 Detail", row + 1));
+
+    // Select the row in the table widget (this displays the correct row highlighted in the background of the dialog).
+    tableWidgetPointer->selectRow(row);
+
+    // Get the first table widget item in the row.
+    QTableWidgetItem *rowFirstTableWidgetItemPointer = tableWidgetPointer->item(row, 0);
+
+    // Get the data variant.
+    QVariant dataVariant = rowFirstTableWidgetItemPointer->data(Qt::UserRole);
+
+    // Get the request struct byte array from the data variant.
+    QByteArray requestStructByteArray = dataVariant.toByteArray();
+
+    // Determine if previous should be enabled.
+    bool previousEnabled = (row > 0);
+
+    // Determine if next should be enabled.
+    bool nextEnabled = (row < (tableWidgetPointer->rowCount() - 1));
+
     // Create a request struct data stream reader.
     QDataStream requestStructDataStreamReader(requestStructByteArray);
 
@@ -50,45 +132,6 @@ RequestDetailDialog::RequestDetailDialog(QWidget *parentWidgetPointer, QByteArra
     requestStructDataStreamReader >> requestStructPointer->sublistInt;
     requestStructDataStreamReader >> requestStructPointer->urlString;
 
-    qDebug().noquote().nospace() << "Disposition:  " << requestStructPointer->dispositionInt;
-    qDebug().noquote().nospace() << "Applied Entry:  " << requestStructPointer->entryStruct.appliedEntry;
-    qDebug().noquote().nospace() << "Original Entry:  " << requestStructPointer->entryStruct.originalEntry;
-    qDebug().noquote().nospace() << "Filter List:  " << requestStructPointer->filterListTitle;
-    qDebug().noquote().nospace() << "Request Method:  " << requestStructPointer->requestMethodString;
-    qDebug().noquote().nospace() << "Navigation Type:  " << requestStructPointer->navigationTypeInt;
-    qDebug().noquote().nospace() << "Resource Type:  " << requestStructPointer->resourceTypeInt;
-    qDebug().noquote().nospace() << "Sublist:  " << requestStructPointer->sublistInt;
-    qDebug().noquote().nospace() << "URL:  " << requestStructPointer->urlString;
-
-    // Set the window title.
-    setWindowTitle(i18nc("The request detail dialog window title", "Request Detail"));
-
-    // Set the window modality.
-    setWindowModality(Qt::WindowModality::ApplicationModal);
-
-    // Instantiate the request detail dialog UI.
-    Ui::RequestDetailDialog requestDetailDialogUi;
-
-    // Setup the UI.
-    requestDetailDialogUi.setupUi(this);
-
-    // Get handles for the views.
-    QLineEdit *dispositionLineEditPointer = requestDetailDialogUi.dispositionLineEdit;
-    QLineEdit *urlLineEditPointer = requestDetailDialogUi.urlLineEdit;
-    QLineEdit *requestMethodLineEditPointer = requestDetailDialogUi.requestMethodLineEdit;
-    QLineEdit *navigationTypeLineEditPointer = requestDetailDialogUi.navigationTypeLineEdit;
-    QLineEdit *resourceTypeLineEditPointer = requestDetailDialogUi.resourceTypeLineEdit;
-    QFrame *horizontalLinePointer = requestDetailDialogUi.horizontalLine;
-    QLabel *filterListLabelPointer = requestDetailDialogUi.filterListLabel;
-    QLineEdit *filterListLineEditPointer = requestDetailDialogUi.filterListLineEdit;
-    QLabel *sublistLabelPointer = requestDetailDialogUi.sublistLabel;
-    QLineEdit *sublistLineEditPointer = requestDetailDialogUi.sublistListLineEdit;
-    QLabel *appliedEntryLabelPointer = requestDetailDialogUi.appliedEntryLabel;
-    QLineEdit *appliedEntryLineEditPointer = requestDetailDialogUi.appliedEntryLineEdit;
-    QLabel *originalEntryLabelPointer = requestDetailDialogUi.originalEntryLabel;
-    QLineEdit *originalEntryLineEditPointer = requestDetailDialogUi.originalEntryLineEdit;
-    QDialogButtonBox *dialogButtonBoxPointer = requestDetailDialogUi.dialogButtonBox;
-
     // Populate the views.
     dispositionLineEditPointer->setText(globalFilterListHelperPointer->getDispositionString(requestStructPointer->dispositionInt));
     urlLineEditPointer->setText(requestStructPointer->urlString);
@@ -100,21 +143,19 @@ RequestDetailDialog::RequestDetailDialog(QWidget *parentWidgetPointer, QByteArra
     appliedEntryLineEditPointer->setText(requestStructPointer->entryStruct.appliedEntry);
     originalEntryLineEditPointer->setText(requestStructPointer->entryStruct.originalEntry);
 
-    // Get the disposition line edit palettes.
-    QPalette normalBackgroundPalette = dispositionLineEditPointer->palette();
-    QPalette negativeBackgroundPalette = normalBackgroundPalette;
-    QPalette positiveBackgroundPalette = normalBackgroundPalette;
-
-    // Modify the palettes.
-    KColorScheme::adjustBackground(negativeBackgroundPalette, KColorScheme::NegativeBackground);
-    KColorScheme::adjustBackground(positiveBackgroundPalette, KColorScheme::PositiveBackground);
+    // Set the button status.
+    previousButtonPointer->setEnabled(previousEnabled);
+    nextButtonPointer->setEnabled(nextEnabled);
 
     // Modify the interface based on the disposition.
     switch (requestStructPointer->dispositionInt)
     {
         case FilterListHelper::DEFAULT:
         {
-            // Hide the filter list views.
+            // Reset the disposition line edit background.
+            dispositionLineEditPointer->setPalette(normalBackgroundPalette);
+
+            // Hide the views.
             horizontalLinePointer->hide();
             filterListLabelPointer->hide();
             filterListLineEditPointer->hide();
@@ -133,6 +174,17 @@ RequestDetailDialog::RequestDetailDialog(QWidget *parentWidgetPointer, QByteArra
             // Colorize the disposition line edit background.
             dispositionLineEditPointer->setPalette(positiveBackgroundPalette);
 
+            // Show the views.
+            horizontalLinePointer->show();
+            filterListLabelPointer->show();
+            filterListLineEditPointer->show();
+            sublistLabelPointer->show();
+            sublistLineEditPointer->show();
+            appliedEntryLabelPointer->show();
+            appliedEntryLineEditPointer->show();
+            originalEntryLabelPointer->show();
+            originalEntryLineEditPointer->show();
+
             break;
         }
 
@@ -141,10 +193,36 @@ RequestDetailDialog::RequestDetailDialog(QWidget *parentWidgetPointer, QByteArra
             // Colorize the disposition line edit background.
             dispositionLineEditPointer->setPalette(negativeBackgroundPalette);
 
+            // Show the views.
+            horizontalLinePointer->show();
+            filterListLabelPointer->show();
+            filterListLineEditPointer->show();
+            sublistLabelPointer->show();
+            sublistLineEditPointer->show();
+            appliedEntryLabelPointer->show();
+            appliedEntryLineEditPointer->show();
+            originalEntryLabelPointer->show();
+            originalEntryLineEditPointer->show();
+
             break;
         }
     }
+}
 
-    // Connect the buttons.
-    connect(dialogButtonBoxPointer, SIGNAL(rejected()), this, SLOT(close()));
+void RequestDetailDialog::previous()
+{
+    // Update the current row.
+    --currentRow;
+
+    // Populate the dialog.
+    populateDialog(currentRow);
+}
+
+void RequestDetailDialog::next()
+{
+    // Update the current row.
+    ++currentRow;
+
+    // Populate the dialog.
+    populateDialog(currentRow);
 }
index d33f65ed1dcdc403541078c0ca6894a8a4bd7360..c15fcad132ad08fff09c16c3e8167ca5e88e7382 100644 (file)
@@ -22,6 +22,8 @@
 
 // Qt toolkit headers.
 #include <QDialog>
+#include <QLabel>
+#include <QTableWidget>
 
 class RequestDetailDialog : public QDialog
 {
@@ -30,6 +32,38 @@ class RequestDetailDialog : public QDialog
 
 public:
     // The primary constructor.
-    explicit RequestDetailDialog(QWidget *parentWidgetPointer, QByteArray &requestStructByteArray);
+    explicit RequestDetailDialog(QWidget *parentWidgetPointer, QTableWidget *tableWidgetPointer, const int initialRow);
+
+private Q_SLOTS:
+    // The private slots.
+    void next();
+    void previous();
+
+private:
+    // The private variables.
+    QLabel *appliedEntryLabelPointer;
+    QLineEdit *appliedEntryLineEditPointer;
+    int currentRow;
+    QLineEdit *dispositionLineEditPointer;
+    QLabel *filterListLabelPointer;
+    QLineEdit *filterListLineEditPointer;
+    QFrame *horizontalLinePointer;
+    QLineEdit *navigationTypeLineEditPointer;
+    QPalette negativeBackgroundPalette;
+    QPushButton *nextButtonPointer;
+    QPalette normalBackgroundPalette;
+    QLabel *originalEntryLabelPointer;
+    QLineEdit *originalEntryLineEditPointer;
+    QPushButton *previousButtonPointer;
+    QPalette positiveBackgroundPalette;
+    QLineEdit *requestMethodLineEditPointer;
+    QLineEdit *resourceTypeLineEditPointer;
+    QLabel *sublistLabelPointer;
+    QLineEdit *sublistLineEditPointer;
+    QTableWidget *tableWidgetPointer;
+    QLineEdit *urlLineEditPointer;
+
+    // The private functions.
+    void populateDialog(const int row);
 };
 #endif
index 0d240e7ef6ff3bc1790405629ecaff850b516360..82535e87c69d254bd697e27a05584fc7f1b9e9c7 100644 (file)
@@ -158,23 +158,14 @@ RequestsDialog::RequestsDialog(QWidget *parentWidgetPointer, QList<RequestStruct
     // Connect the buttons.
     connect(dialogButtonBoxPointer, SIGNAL(rejected()), this, SLOT(close()));
 
-    // Open the request detail dialog when
+    // Open the request detail dialog when a cell is clicked.
     connect(tableWidgetPointer, SIGNAL(cellClicked(int, int)), this, SLOT(showRequestDetailDialog(int)));
 }
 
 void RequestsDialog::showRequestDetailDialog(int row)
 {
-    // Get the first table widget item in the row.
-    QTableWidgetItem *rowFirstTableWidgetItemPointer = tableWidgetPointer->item(row, 0);
-
-    // Get the data variant.
-    QVariant dataVariant = rowFirstTableWidgetItemPointer->data(Qt::UserRole);
-
-    // Get the request struct byte array from the data variant.
-    QByteArray requestStructByteArray = dataVariant.toByteArray();
-
     // Instantiate the request details dialog.
-    RequestDetailDialog *requestDetailDialogPointer = new RequestDetailDialog(this, requestStructByteArray);
+    RequestDetailDialog *requestDetailDialogPointer = new RequestDetailDialog(this, tableWidgetPointer, row);
 
     // Show the dialog.
     requestDetailDialogPointer->show();
diff --git a/src/enums/FilterOptionEnum.h b/src/enums/FilterOptionEnum.h
new file mode 100644 (file)
index 0000000..8c01510
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2024 Soren Stoutner <soren@stoutner.com>.
+ *
+ * This file is part of Privacy Browser PC <https://www.stoutner.com/privacy-browser-pc/>.
+ *
+ * Privacy Browser PC is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Privacy Browser PC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Privacy Browser PC.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef FILTEROPTIONENUM_H
+#define FILTEROPTIONENUM_H
+
+struct FilterOptionEnum
+{
+    enum Disposition
+    {
+        Null = 0,
+        Apply = 1,
+        Override = 2,
+    };
+};
+#endif
index e49af5b20e5f2d7a09a4fa0e517f2b888d31c65a..f84112b58531ad17f1262eb68dd5e7dff5161403 100644 (file)
@@ -19,6 +19,7 @@
 
 // Application headers.
 #include "FilterListHelper.h"
+#include "structs/OverrideStruct.h"
 
 // Qt toolkit headers.
 #include <QDebug>
@@ -36,6 +37,11 @@ FilterListHelper::FilterListHelper()
     ALLOWED_STRING = i18nc("Allowed disposition", "Allowed");
     BLOCKED_STRING = i18nc("Blocked disposition", "Blocked");
 
+    // Populate the translated filter option disposition strings.  Translated entries cannot be public static const.
+    FILTER_OPTION_NULL = QString();
+    FILTER_OPTION_APPLY = i18nc("Apply filter option", "Apply");
+    FILTER_OPTION_OVERRIDE = i18nc("Override filter option", "Override");
+
     // Populate the translated navigation type strings.  Translated entries cannot be public static const.
     NAVIGATION_TYPE_LINK = i18nc("Navigation type link", "Link");
     NAVIGATION_TYPE_TYPED = i18nc("Navigation type typed", "Typed");
@@ -69,7 +75,9 @@ FilterListHelper::FilterListHelper()
     RESOURCE_TYPE_UNKNOWN = i18nc("Resource type unknown", "Unknown");
 
     // Populate the translated sublist strings.  Translated entries cannot be public static const.
+    MAIN_ALLOWLIST_STRING = i18nc("Main allowlist sublist", "Main Allow List");
     MAIN_BLOCKLIST_STRING = i18nc("Main blocklist sublist", "Main Block List");
+    INITIAL_DOMAIN_BLOCKLIST_STRING = i18nc("Initial domain blocklist string", "Initial Domain Block List");
 
     // Populate the filter lists.
     ultraListStructPointer = populateFilterList(QLatin1String(":/filterlists/ultralist.txt"));
@@ -81,47 +89,154 @@ FilterListHelper::FilterListHelper()
 
 bool FilterListHelper::checkFilterLists(QWebEngineUrlRequestInfo &urlRequestInfo, RequestStruct *requestStructPointer) const
 {
-    // Initiate a status tracker.  If the tracker changes to false, all process of the request will be stopped.
-    bool status = true;
+    // Initiate a continue checking tracker.  If the tracker changes to false, all process of the request will be stopped.
+    bool continueChecking = true;
+
+    // Create a URL struct.
+    UrlStruct urlStruct;
+
+    // Get the URLs.
+    QUrl firstPartyUrl = urlRequestInfo.firstPartyUrl();
+    QUrl requestUrl = urlRequestInfo.requestUrl();
+
+    // Get the hosts.
+    QString firstPartyHost = firstPartyUrl.host();
+    QString requestHost = requestUrl.host();
+
+    // Determine if this is a third-party request.
+    urlStruct.isThirdPartyRequest = (firstPartyHost != requestHost);
+
+    // Get the request URL string.
+    urlStruct.urlString = requestUrl.toString();
+
+    // Create a URL string with separators.
+    urlStruct.urlStringWithSeparators = urlStruct.urlString;
+
+    // Replace the separators characters with `^`.
+    urlStruct.urlStringWithSeparators.replace(QLatin1Char(':'), QLatin1Char('^'));
+    urlStruct.urlStringWithSeparators.replace(QLatin1Char('/'), QLatin1Char('^'));
+    urlStruct.urlStringWithSeparators.replace(QLatin1Char('?'), QLatin1Char('^'));
+    urlStruct.urlStringWithSeparators.replace(QLatin1Char('='), QLatin1Char('^'));
+    urlStruct.urlStringWithSeparators.replace(QLatin1Char('&'), QLatin1Char('^'));
+
+    // Add a `^` to the end of the string.
+    urlStruct.urlStringWithSeparators.append(QLatin1Char('^'));
+
+    // Create truncated URL strings and initially populate it with the original URL strings.
+    urlStruct.truncatedUrlString = urlStruct.urlString;
+    urlStruct.truncatedUrlStringWithSeparators = urlStruct.urlStringWithSeparators;
+
+    // Get the index of the beginning of the fully qualified domain name.
+    int fqdnIndex = urlStruct.truncatedUrlString.indexOf(QLatin1String("://")) + 3;
+
+    // Truncate the URL to the beginning of the fully qualified domain name.
+    urlStruct.truncatedUrlString.remove(0, fqdnIndex);
+    urlStruct.truncatedUrlStringWithSeparators.remove(0, fqdnIndex);
 
     // Check UltraList.
-    status = checkIndividualList(urlRequestInfo, requestStructPointer, ultraListStructPointer);
+    continueChecking = checkIndividualList(urlRequestInfo, urlStruct, requestStructPointer, ultraListStructPointer);
 
-    // check UltraPrivacy if the status is still true.
-    if (status) {
-        status = checkIndividualList(urlRequestInfo, requestStructPointer, ultraPrivacyStructPointer);
-    }
+    // Check UltraPrivacy.
+    if (continueChecking)
+        continueChecking = checkIndividualList(urlRequestInfo, urlStruct, requestStructPointer, ultraPrivacyStructPointer);
 
-    // Return the status.
-    return status;
+    // Check EasyList.
+    if (continueChecking)
+        continueChecking = checkIndividualList(urlRequestInfo, urlStruct, requestStructPointer, easyListStructPointer);
+
+    // Check EasyPrivacy.
+    if (continueChecking)
+        continueChecking = checkIndividualList(urlRequestInfo, urlStruct, requestStructPointer, easyPrivacyStructPointer);
+
+    if (continueChecking)
+        continueChecking = checkIndividualList(urlRequestInfo, urlStruct, requestStructPointer, fanboyAnnoyanceStructPointer);
+
+    // Return the continue checking status.
+    return continueChecking;
 }
 
-bool FilterListHelper::checkIndividualList(QWebEngineUrlRequestInfo &urlRequestInfo, RequestStruct *requestStructPointer, FilterListStruct *filterListStruct) const
+bool FilterListHelper::blockRequest(QWebEngineUrlRequestInfo &urlRequestInfo, RequestStruct *requestStructPointer, const QString &filterListTitle, const int sublistInt,
+                                    EntryStruct *entryStructPointer) const
 {
-    // Get the request URL.
-    QUrl url = urlRequestInfo.requestUrl();
+    // Block the request.
+    urlRequestInfo.block(true);
 
-    // Get the request URL string.
-    QString urlString = url.toString();
+    // Populate the request struct.
+    populateRequestStruct(requestStructPointer, BLOCKED, filterListTitle, sublistInt, entryStructPointer);
+
+    // Log the block.
+    //qDebug().noquote().nospace() << "Blocked request:  " << urlRequestInfo.firstPartyUrl() << ",  Filter list entry:  " << entryStructPointer->appliedEntry;
+
+    // Returning `false` stops all processing of the request.
+    return false;
+}
+
+bool FilterListHelper::checkIndividualList(QWebEngineUrlRequestInfo &urlRequestInfo, UrlStruct &urlStruct, RequestStruct *requestStructPointer, FilterListStruct *filterListStructPointer) const
+{
+    // Check the main allow list.
+    for (auto filterListEntry = filterListStructPointer->mainAllowList.begin(); filterListEntry != filterListStructPointer->mainAllowList.end(); ++filterListEntry)
+    {
+        // Get the entry struct.
+        EntryStruct *entryStructPointer = *filterListEntry;
+
+        // TODO.  Temporarily ignore empty applied entries.
+        if (!entryStructPointer->appliedEntry.isEmpty())
+        {
+            // Check if the URL string contains the applied entry.
+            if (urlStruct.urlString.contains(entryStructPointer->appliedEntry) || urlStruct.urlStringWithSeparators.contains(entryStructPointer->appliedEntry))
+            {
+                // Allow the request.
+                urlRequestInfo.block(false);
+
+                // Populate the request struct.
+                populateRequestStruct(requestStructPointer, ALLOWED, filterListStructPointer->title, MAIN_ALLOWLIST, entryStructPointer);
+
+                // Log the allow.
+                //qDebug().noquote().nospace() << "Allowed request:  " << urlStruct.urlString << ", Filter list entry:  " << entryStructPointer->appliedEntry;
+
+                // Returning `false` stops all processing of the request.
+                return false;
+            }
+        }
+    }
 
     // Check the main block list.
-    for (auto filterListEntry = filterListStruct->mainBlockList.begin(); filterListEntry != filterListStruct->mainBlockList.end(); ++filterListEntry) {
+    for (auto filterListEntry = filterListStructPointer->mainBlockList.begin(); filterListEntry != filterListStructPointer->mainBlockList.end(); ++filterListEntry)
+    {
         // Get the entry struct.
         EntryStruct *entryStructPointer = *filterListEntry;
 
-        // Check if the URL string contains the applied entry
-        if (urlString.contains(entryStructPointer->appliedEntry)) {
-            // Block the request.
-            urlRequestInfo.block(true);
+        // TODO.  Temporarily ignore empty applied entries.
+        if (!entryStructPointer->appliedEntry.isEmpty())
+        {
+            // Check if the URL string contains the applied entry.
+            if (urlStruct.urlString.contains(entryStructPointer->appliedEntry) || urlStruct.urlStringWithSeparators.contains(entryStructPointer->appliedEntry))
+            {
+                // Check the third-party status.
+                bool continueChecking = checkThirdParty(urlRequestInfo, requestStructPointer, urlStruct.isThirdPartyRequest, filterListStructPointer->title, MAIN_BLOCKLIST, entryStructPointer);
 
-            // Populate the request struct.
-            populateRequestStruct(requestStructPointer, BLOCKED, filterListStruct->title, MAIN_BLOCKLIST, entryStructPointer->appliedEntry, entryStructPointer->originalEntry);
+                // Stop processing the filter lists if continue checking is `false`.  Returning false halts all processing at upper levels.
+                if (continueChecking == false)
+                    return false;
+            }
+        }
+    }
+
+    // Check the initial domain block list.
+    for (auto filterListEntry = filterListStructPointer->initialDomainBlockList.begin(); filterListEntry != filterListStructPointer->initialDomainBlockList.end(); ++filterListEntry)
+    {
+        // Get the entry struct.
+        EntryStruct *entryStructPointer = *filterListEntry;
 
-            // Log the block.
-            //qDebug().noquote().nospace() << "Blocked request:  " << urlString << ",  Filter list entry:  " << entryStructPointer->appliedEntry;
+        // Check if the truncated URL string begins with the applied entry.
+        if (urlStruct.truncatedUrlString.startsWith(entryStructPointer->appliedEntry) || urlStruct.truncatedUrlStringWithSeparators.startsWith(entryStructPointer->appliedEntry))
+        {
+            // Check the third-party status.
+            bool continueChecking = checkThirdParty(urlRequestInfo, requestStructPointer, urlStruct.isThirdPartyRequest, filterListStructPointer->title, INITIAL_DOMAIN_BLOCKLIST, entryStructPointer);
 
-            // Returning `false` stops all processing of the request.
-            return false;
+            // Stop processing the filter lists if continue checking is `false`.  Returning false halts all processing at upper levels.
+            if (continueChecking == false)
+                return false;
         }
     }
 
@@ -129,6 +244,57 @@ bool FilterListHelper::checkIndividualList(QWebEngineUrlRequestInfo &urlRequestI
     return true;
 }
 
+bool FilterListHelper::checkThirdParty(QWebEngineUrlRequestInfo &urlRequestInfo, RequestStruct *requestStructPointer, const bool isThirdPartyRequest, const QString &filterListTitle,
+                                       const int sublistInt, EntryStruct *entryStructPointer) const
+{
+    // Check third-party status.
+    if (entryStructPointer->thirdParty == FilterOptionEnum::Disposition::Null)  // Ignore third-party status.
+    {
+        // Check if filter options are applied.
+        if (entryStructPointer->hasFilterOptions)  // Filter options are applied.
+        {
+            // Process the filter options.
+            return processFilterOptions(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer);
+        }
+        else  // Filter options are not applied.
+        {
+            // Block the request.
+            return blockRequest(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer);
+        }
+    }
+    else if ((entryStructPointer->thirdParty == FilterOptionEnum::Disposition::Apply) && isThirdPartyRequest)  // Block third-party request.
+    {
+        // Check if filter options are applied.
+        if (entryStructPointer->hasFilterOptions)  // Filter options are applied.
+        {
+            // Process the filter options.
+            return processFilterOptions(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer);
+        }
+        else  // Filter options are not applied.
+        {
+            // Block the request.
+            return blockRequest(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer);
+        }
+    }
+    else if ((entryStructPointer->thirdParty == FilterOptionEnum::Disposition::Override) && !isThirdPartyRequest)  // Block first-party requests.
+    {
+        // Check if filter options are applied.
+        if (entryStructPointer->hasFilterOptions)  // Filter options are applied.
+        {
+            // Process the filter options.
+            return processFilterOptions(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer);
+        }
+        else  // Filter options are not applied.
+        {
+            // Block the request.
+            return blockRequest(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer);
+        }
+    }
+
+    // Returning `true` continues to process the filter lists.  Returning `false` halts all processing of the filter lists.
+    return true;
+}
+
 QString FilterListHelper::getDispositionString(int dispositionInt) const
 {
     // Return the translated disposition string.
@@ -140,6 +306,17 @@ QString FilterListHelper::getDispositionString(int dispositionInt) const
     }
 }
 
+QString FilterListHelper::getFilterOptionDispositionString(const FilterOptionEnum::Disposition filterOptionDisposition) const
+{
+    // Return the translated filter option disposition string.
+    switch (filterOptionDisposition)
+    {
+        case FilterOptionEnum::Disposition::Apply: return FILTER_OPTION_APPLY;
+        case FilterOptionEnum::Disposition::Override: return FILTER_OPTION_OVERRIDE;
+        default: return FILTER_OPTION_NULL;
+    }
+}
+
 QString FilterListHelper::getNavigationTypeString(int navigationTypeInt) const
 {
     // Return the translated navigation type string.
@@ -189,7 +366,9 @@ QString FilterListHelper::getSublistName(int sublistInt) const
     // Return the name of the requested sublist.
     switch (sublistInt)
     {
+        case MAIN_ALLOWLIST: return MAIN_ALLOWLIST_STRING;
         case MAIN_BLOCKLIST: return MAIN_BLOCKLIST_STRING;
+        case INITIAL_DOMAIN_BLOCKLIST: return INITIAL_DOMAIN_BLOCKLIST_STRING;
         default: return QString();  // The default return should never be reached.
     }
 }
@@ -223,12 +402,32 @@ FilterListStruct* FilterListHelper::populateFilterList(const QString &filterList
         entryStructPointer->originalEntry = filterListString;
 
         // Process the entry.
-        if (filterListString.startsWith(QLatin1Char('['))) {  // The line starts with `[`, which is the file format.
+        if (filterListString.isEmpty())  // Ignore empty lines.
+        {
+            // Do nothing.
+
+            // Log the dropping of the line.
+            //qDebug().noquote().nospace() << filterListString << " NOT added from " << filterListFileName << " (empty line).";
+        }
+        else if (filterListString.startsWith(QLatin1Char('[')))  // The line starts with `[`, which is the file format.
+        {
             // Do nothing.
 
             // Log the dropping of the line.
-            //qDebug().noquote().nospace() << filterListString << " NOT added from " << filterListFileName;
-        } else if (filterListString.startsWith(QLatin1Char('!'))) {  // The line starts with `!`, which are comments.
+            //qDebug().noquote().nospace() << filterListString << " NOT added from " << filterListFileName << " (file format).";
+        }
+        else if (filterListString.contains(QLatin1String("##")) ||
+                 filterListString.contains(QLatin1String("#?#")) ||
+                 filterListString.contains(QLatin1String("#@#")) ||
+                 filterListString.contains(QLatin1String("#$#")))  // The line contains unimplemented content filtering.
+        {
+            // Do nothing.
+
+            // Log the dropping of the line.
+            //qDebug().noquote().nospace() << filterListString << " NOT added from " << filterListFileName << " (content filtering).";
+        }
+        else if (filterListString.startsWith(QLatin1Char('!')))  // The line starts with `!`, which are comments.
+        {
             if (filterListString.startsWith(QLatin1String("! Title: ")))  // The line contains the title.
             {
                 // Add the title to the filter list struct.
@@ -250,15 +449,349 @@ FilterListStruct* FilterListHelper::populateFilterList(const QString &filterList
 
             // Log the dropping of the line.
             //qDebug().noquote().nospace() << originalFilterListString << " NOT added from " << filterListFileName;
-        } else {  // Process the entry.
-            // Add the applied entry to the struct.
-            entryStructPointer->appliedEntry = filterListString;
+        }
+        else  // Process the filter options.
+        {
+            // Split any filter options from the end of the string.
+            QStringList splitEntryStringList = filterListString.split(QLatin1Char('$'));
+
+            // Store the entry without the filter options as the filter list string.
+            filterListString = splitEntryStringList[0];
+
+            // Create a popup only filter option tracker.
+            bool popupOnlyFilterOption = false;
+
+            // Process the filter options if they exist.
+            if (splitEntryStringList.size() > 1)
+            {
+                // Store the filter options.
+                entryStructPointer->filterOptions = splitEntryStringList[1];
+
+                // Split the filter options.
+                QStringList filterOptionsList = splitEntryStringList[1].split(QLatin1Char(','));
+
+                // Check if the entry has a single popup filter option as Qt WebEngine doesn't know how to process them.
+                if ((filterOptionsList.size() == 1) && (filterOptionsList[0] == QLatin1String("popup")))  // This entry has a single popup filter option.
+                {
+                    // Set the popup only filter option flag.
+                    popupOnlyFilterOption = true;
+                }
+                else  // This entry has filter options besides popup.
+                {
+                    // Initialize an override struct.
+                    OverrideStruct overrideStruct;
+
+                    // Populate the filter options entries.
+                    foreach (QString filterOption, filterOptionsList)
+                    {
+                        // Populate the third-party options.
+                        if (filterOption == QLatin1String("third-party")) entryStructPointer->thirdParty = FilterOptionEnum::Disposition::Apply;
+                        if (filterOption == QLatin1String("~third-party")) entryStructPointer->thirdParty = FilterOptionEnum::Disposition::Override;
+
+                        // Populate the filter options.
+                        if (filterOption == QLatin1String("document"))
+                        {
+                            // Populate the main frame option.
+                            entryStructPointer->mainFrame = FilterOptionEnum::Disposition::Apply;
+
+                            // Set the filter options flag.
+                            entryStructPointer->hasFilterOptions = true;
+                        }
+
+                        if (filterOption == QLatin1String("font"))
+                        {
+                            // Populate the font option.
+                            entryStructPointer->font = FilterOptionEnum::Disposition::Apply;
+
+                            // Set the filter options flag.
+                            entryStructPointer->hasFilterOptions = true;
+                        }
+
+                        if (filterOption == QLatin1String("image"))
+                        {
+                            // Populate the image option.
+                            entryStructPointer->image = FilterOptionEnum::Disposition::Apply;
+
+                            // Set the filter options flag.
+                            entryStructPointer->hasFilterOptions = true;
+                        }
+
+                        if (filterOption == QLatin1String("media"))
+                        {
+                            // Populate the media option.
+                            entryStructPointer->media = FilterOptionEnum::Disposition::Apply;
+
+                            // Set the filter options flag.
+                            entryStructPointer->hasFilterOptions = true;
+                        }
+
+                        if (filterOption == QLatin1String("object"))
+                        {
+                            // Populate the object option.
+                            entryStructPointer->object = FilterOptionEnum::Disposition::Apply;
+
+                            // Set the filter options flag.
+                            entryStructPointer->hasFilterOptions = true;
+                        }
+
+                        if (filterOption == QLatin1String("other"))
+                        {
+                            // Populate the other option.
+                            entryStructPointer->other = FilterOptionEnum::Disposition::Apply;
+
+                            // Set the filter options flag.
+                            entryStructPointer->hasFilterOptions = true;
+                        }
+
+                        if (filterOption == QLatin1String("ping"))
+                        {
+                            // Populate the ping option.
+                            entryStructPointer->ping = FilterOptionEnum::Disposition::Apply;
+
+                            // Set the filter options flag.
+                            entryStructPointer->hasFilterOptions = true;
+                        }
+
+                        if (filterOption == QLatin1String("script"))
+                        {
+                            // Populate the script option.
+                            entryStructPointer->script = FilterOptionEnum::Disposition::Apply;
+
+                            // Set the filter options flag.
+                            entryStructPointer->hasFilterOptions = true;
+                        }
+
+                        if (filterOption == QLatin1String("stylesheet"))
+                        {
+                            // Populate the script option.
+                            entryStructPointer->styleSheet = FilterOptionEnum::Disposition::Apply;
+
+                            // Set the filter options flag.
+                            entryStructPointer->hasFilterOptions = true;
+                        }
+
+                        if (filterOption == QLatin1String("subdocument"))
+                        {
+                            // Populate the sub resource option.
+                            entryStructPointer->subFrame = FilterOptionEnum::Disposition::Apply;
+
+                            // Set the filter options flag.
+                            entryStructPointer->hasFilterOptions = true;
+                        }
+
+                        if (filterOption == QLatin1String("xmlhttprequest"))
+                        {
+                            //Populate the XML HTTP request option.
+                            entryStructPointer->xmlHttpRequest = FilterOptionEnum::Disposition::Apply;
+
+                            // Set the filter options flag.
+                            entryStructPointer->hasFilterOptions = true;
+                        }
+
+                        // Populate the override struct.
+                        if (filterOption == QLatin1String("~document"))
+                        {
+                            // Populate the override struct.
+                            overrideStruct.hasOverride = true;
+                            overrideStruct.mainFrame = true;
+                        }
+
+                        if (filterOption == QLatin1String("~font"))
+                        {
+                            // Populate the override struct.
+                            overrideStruct.hasOverride = true;
+                            overrideStruct.font = true;
+                        }
+
+                        if (filterOption == QLatin1String("~image"))
+                        {
+                            // Populate the override struct.
+                            overrideStruct.hasOverride = true;
+                            overrideStruct.image = true;
+                        }
+
+                        if (filterOption == QLatin1String("~media"))
+                        {
+                            // Populate the override struct.
+                            overrideStruct.hasOverride = true;
+                            overrideStruct.media = true;
+                        }
+
+                        if (filterOption == QLatin1String("~object"))
+                        {
+                            // Populate the override struct.
+                            overrideStruct.hasOverride = true;
+                            overrideStruct.object = true;
+                        }
+
+                        if (filterOption == QLatin1String("~other"))
+                        {
+                            // Populate the override struct.
+                            overrideStruct.hasOverride = true;
+                            overrideStruct.other = true;
+                        }
+
+                        if (filterOption == QLatin1String("~ping"))
+                        {
+                            // Populate the override struct.
+                            overrideStruct.hasOverride = true;
+                            overrideStruct.ping = true;
+                        }
+
+                        if (filterOption == QLatin1String("~script"))
+                        {
+                            // Populate the override struct.
+                            overrideStruct.hasOverride = true;
+                            overrideStruct.script = true;
+                        }
+
+                        if (filterOption == QLatin1String("~stylesheet"))
+                        {
+                            // Populate the override struct.
+                            overrideStruct.hasOverride = true;
+                            overrideStruct.styleSheet = true;
+                        }
+
+                        if (filterOption == QLatin1String("~subdocument"))
+                        {
+                            // Populate the override struct.
+                            overrideStruct.hasOverride = true;
+                            overrideStruct.subFrame = true;
+                        }
+
+                        if (filterOption == QLatin1String("~xmlhttprequest"))
+                        {
+                            // Populate the override struct.
+                            overrideStruct.hasOverride = true;
+                            overrideStruct.xmlHttpRequest = true;
+                        }
+                    }
+
+                    // Apply the overrides.
+                    if (overrideStruct.hasOverride)
+                    {
+                        // Font.
+                        if (overrideStruct.font)
+                            entryStructPointer->font = FilterOptionEnum::Disposition::Override;
+                        else
+                            entryStructPointer->font = FilterOptionEnum::Disposition::Apply;
+
+                        // Image.
+                        if (overrideStruct.image)
+                            entryStructPointer->image = FilterOptionEnum::Disposition::Override;
+                        else
+                            entryStructPointer->image = FilterOptionEnum::Disposition::Apply;
+
+                        // Main Frame (document).
+                        if (overrideStruct.mainFrame)
+                            entryStructPointer->mainFrame = FilterOptionEnum::Disposition::Override;
+                        else
+                            entryStructPointer->mainFrame = FilterOptionEnum::Disposition::Apply;
+
+                        // Media.
+                        if (overrideStruct.media)
+                            entryStructPointer->media = FilterOptionEnum::Disposition::Override;
+                        else
+                            entryStructPointer->media = FilterOptionEnum::Disposition::Apply;
+
+                        // Object.
+                        if (overrideStruct.object)
+                            entryStructPointer->object = FilterOptionEnum::Disposition::Override;
+                        else
+                            entryStructPointer->object = FilterOptionEnum::Disposition::Apply;
+
+                        // Other.
+                        if (overrideStruct.other)
+                            entryStructPointer->other = FilterOptionEnum::Disposition::Override;
+                        else
+                            entryStructPointer->other = FilterOptionEnum::Disposition::Apply;
+
+                        // Ping.
+                        if (overrideStruct.ping)
+                            entryStructPointer->ping = FilterOptionEnum::Disposition::Override;
+                        else
+                            entryStructPointer->ping = FilterOptionEnum::Disposition::Apply;
+
+                        //  Script.
+                        if (overrideStruct.script)
+                            entryStructPointer->script = FilterOptionEnum::Disposition::Override;
+                        else
+                            entryStructPointer->script = FilterOptionEnum::Disposition::Apply;
+
+                        // Style Sheet.
+                        if (overrideStruct.styleSheet)
+                            entryStructPointer->styleSheet = FilterOptionEnum::Disposition::Override;
+                        else
+                            entryStructPointer->styleSheet = FilterOptionEnum::Disposition::Apply;
+
+                        // Sub Resource.
+                        if (overrideStruct.subFrame)
+                            entryStructPointer->subFrame = FilterOptionEnum::Disposition::Override;
+                        else
+                            entryStructPointer->subFrame = FilterOptionEnum::Disposition::Apply;
+
+                        // XML HTTP Request.
+                        if (overrideStruct.xmlHttpRequest)
+                            entryStructPointer->xmlHttpRequest = FilterOptionEnum::Disposition::Override;
+                        else
+                            entryStructPointer->xmlHttpRequest = FilterOptionEnum::Disposition::Apply;
+                    }
+                }
+            }
+
+            // Drop entries that only have a single popup filter option as Qt WebEngine doesn't know how to process them.
+            if (popupOnlyFilterOption)  // This entry has a single popup filter option.
+            {
+                // Do nothing.
+
+                // Log the dropping of the line.
+                //qDebug().noquote().nospace() << entryStructPointer->originalEntry << " NOT added from " << filterListFileName << " (single popup filter option).";
+            }
+            else if (filterListString.startsWith(QLatin1String("@@")))  // Process an allow list entry.
+            {
+                // Remove the initial `@@`.
+                filterListString.remove(0, 2);
 
-            // Add the filter list entry struct to the main block list.
-            filterListStructPointer->mainBlockList.push_front(entryStructPointer);
+                // Remove any initial and trailing asterisks.
+                removeInitialAndTrailingAsterisks(filterListString);
 
-            // Log the addition to the filter list.
-            //qDebug().noquote().nospace() << originalFilterListString << " added from " << filterListFileName;
+                // Add the applied entry to the struct.
+                entryStructPointer->appliedEntry = filterListString;
+
+                // Add the filter list entry struct to the main allow list.
+                filterListStructPointer->mainAllowList.push_front(entryStructPointer);
+
+                // Log the addition to the filter list.
+                //qDebug().noquote().nospace() << entryStructPointer->originalEntry << " added to Main Allow List from " << filterListFileName << ".";
+            }
+            else if (filterListString.startsWith(QLatin1String("||")))  // Process an initial domain allow list entry.
+            {
+                // Remove the initial `||`.
+                filterListString.remove(0, 2);
+
+                // Add the applied entry to the struct.
+                entryStructPointer->appliedEntry = filterListString;
+
+                // Add the filter list entry struct to the initial domain block list.
+                filterListStructPointer->initialDomainBlockList.push_front(entryStructPointer);
+
+                // Log the addition to the filter list.
+                //qDebug().noquote().nospace() << entryStructPointer->originalEntry << " added to Initial Domain Block List from " << filterListFileName << ".";
+            }
+            else  // Process a block list entry.
+            {
+                // Remove any initial and trailing asterisks.
+                removeInitialAndTrailingAsterisks(filterListString);
+
+                // Add the applied entry to the struct.
+                entryStructPointer->appliedEntry = filterListString;
+
+                // Add the filter list entry struct to the main block list.
+                filterListStructPointer->mainBlockList.push_front(entryStructPointer);
+
+                // Log the addition to the filter list.
+                //qDebug().noquote().nospace() << entryStructPointer->originalEntry << " added to Main Block List from " << filterListFileName << ".";
+            }
         }
     }
 
@@ -269,13 +802,117 @@ FilterListStruct* FilterListHelper::populateFilterList(const QString &filterList
     return filterListStructPointer;
 }
 
-void FilterListHelper::populateRequestStruct(RequestStruct *requestStructPointer, const int disposition, const QString &filterListTitle, const int sublistInt, const QString &appliedEntry,
-                                             const QString &originalEntry) const
+void FilterListHelper::populateRequestStruct(RequestStruct *requestStructPointer, const int disposition, const QString &filterListTitle, const int sublistInt, EntryStruct *entryStructPointer) const
 {
     // Populate the request struct.
     requestStructPointer->dispositionInt = disposition;
     requestStructPointer->filterListTitle = filterListTitle;
     requestStructPointer->sublistInt = sublistInt;
-    requestStructPointer->entryStruct.appliedEntry = appliedEntry;
-    requestStructPointer->entryStruct.originalEntry = originalEntry;
+    requestStructPointer->entryStruct.appliedEntry = entryStructPointer->appliedEntry;
+    requestStructPointer->entryStruct.originalEntry = entryStructPointer->originalEntry;
+}
+
+bool FilterListHelper::processFilterOptions(QWebEngineUrlRequestInfo &urlRequestInfo, RequestStruct *requestStructPointer, const QString &filterListTitle, const int sublistInt,
+                                            EntryStruct *entryStructPointer) const
+{
+    // Block font requests.
+    if ((entryStructPointer->font == FilterOptionEnum::Disposition::Apply) && (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeFontResource))
+    {
+        // Block the request.
+        return blockRequest(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer);
+    }
+
+    // Block image requests.
+    if ((entryStructPointer->image == FilterOptionEnum::Disposition::Apply) && (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeImage))
+    {
+        // Block the request.
+        return blockRequest(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer);
+    }
+
+    // Block main frame requests.
+    if ((entryStructPointer->mainFrame == FilterOptionEnum::Disposition::Apply) && ((requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeMainFrame) ||
+                                                                                    (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeNavigationPreloadMainFrame)))
+    {
+        // Block the request.
+        return blockRequest(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer);
+    }
+
+    // Block media requests.
+    if ((entryStructPointer->media == FilterOptionEnum::Disposition::Apply) && (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeMedia))
+    {
+        // Block the request.
+        return blockRequest(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer);
+    }
+
+    // Block object requests.
+    if ((entryStructPointer->object == FilterOptionEnum::Disposition::Apply) && (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeObject))
+    {
+        // Block the request.
+        return blockRequest(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer);
+    }
+
+    // Block other requests.
+    if ((entryStructPointer->other == FilterOptionEnum::Disposition::Apply) && ((requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeSubResource) ||
+                                                                                (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeWorker) ||
+                                                                                (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeSharedWorker) ||
+                                                                                (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypePrefetch) ||
+                                                                                (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeFavicon) ||
+                                                                                (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeServiceWorker) ||
+                                                                                (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeCspReport) ||
+                                                                                (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypePluginResource) ||
+                                                                                (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeUnknown)))
+    {
+        // Block the request.
+        return blockRequest(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer);
+    }
+
+    // Block ping requests
+    if ((entryStructPointer->ping == FilterOptionEnum::Disposition::Apply) && (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypePing))
+    {
+        // Block the request.
+        return blockRequest(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer);
+    }
+
+    // Block script requests.
+    if ((entryStructPointer->script == FilterOptionEnum::Disposition::Apply) && (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeScript))
+    {
+        // Block the request.
+        return blockRequest(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer);
+    }
+
+    // Block style sheet requests.
+    if ((entryStructPointer->styleSheet == FilterOptionEnum::Disposition::Apply) && (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeStylesheet))
+    {
+        // Block the request.
+        return blockRequest(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer);
+    }
+
+    // Block sub resource requests.
+    if ((entryStructPointer->subFrame == FilterOptionEnum::Disposition::Apply) && ((requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeSubFrame) ||
+                                                                                   (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeNavigationPreloadSubFrame)))
+    {
+        // Block the request.
+        return blockRequest(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer);
+    }
+
+    // Block XML HTTP requests.
+    if ((entryStructPointer->xmlHttpRequest == FilterOptionEnum::Disposition::Apply) && (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeXhr))
+    {
+        // Block the request.
+        return blockRequest(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer);
+    }
+
+    // Returning true continues processing the filter list.
+    return true;
+}
+
+void FilterListHelper::removeInitialAndTrailingAsterisks(QString &filterListEntry) const
+{
+    // Remove the initial asterisk if it exists.
+    if (filterListEntry.startsWith(QLatin1Char('*')))
+        filterListEntry.remove(0, 1);
+
+    // Remove the final asterisk if it exists.
+    if (filterListEntry.endsWith(QLatin1Char('*')))
+        filterListEntry.chop(1);
 }
index 5bd9ad261c146e2e0d01e17a162c33f10f5ebb55..f8bfdf1cc887810e37a6764c8f2b3b11b6fa2ada 100644 (file)
@@ -23,6 +23,7 @@
 // Application headers.
 #include "structs/FilterListStruct.h"
 #include "structs/RequestStruct.h"
+#include "structs/UrlStruct.h"
 
 // Qt framework headers.
 #include <QString>
@@ -40,7 +41,9 @@ public:
     static const int BLOCKED = 2;
 
     // The public static sublist constant integers.
-    static const int MAIN_BLOCKLIST = 0;
+    static const int MAIN_ALLOWLIST = 0;
+    static const int MAIN_BLOCKLIST = 1;
+    static const int INITIAL_DOMAIN_BLOCKLIST = 2;
 
     // The public variables.
     FilterListStruct *easyListStructPointer;
@@ -52,6 +55,7 @@ public:
     // The public functions.
     bool checkFilterLists(QWebEngineUrlRequestInfo &urlRequestInfo, RequestStruct *requestStructPointer) const;
     QString getDispositionString(int dispositionInt) const;
+    QString getFilterOptionDispositionString(const FilterOptionEnum::Disposition filterOptionDisposition) const;
     QString getNavigationTypeString(int navigationTypeInt) const;
     QString getResourceTypeString(int resourceTypeInt) const;
     QString getSublistName(int sublistInt) const;
@@ -62,6 +66,11 @@ private:
     QString ALLOWED_STRING;
     QString BLOCKED_STRING;
 
+    // The private translated filter option dispositions.
+    QString FILTER_OPTION_NULL;
+    QString FILTER_OPTION_APPLY;
+    QString FILTER_OPTION_OVERRIDE;
+
     // The private translated navigation type strings.
     QString NAVIGATION_TYPE_LINK;
     QString NAVIGATION_TYPE_TYPED;
@@ -95,12 +104,19 @@ private:
     QString RESOURCE_TYPE_UNKNOWN;
 
     // The private translated sublist strings.
+    QString MAIN_ALLOWLIST_STRING;
     QString MAIN_BLOCKLIST_STRING;
+    QString INITIAL_DOMAIN_BLOCKLIST_STRING;
 
     // The private functions.
-    bool checkIndividualList(QWebEngineUrlRequestInfo &urlRequestInfo, RequestStruct *requestStructPointer, FilterListStruct *filterListStruct) const;
+    bool blockRequest(QWebEngineUrlRequestInfo &urlRequestInfo, RequestStruct *requestStructPointer, const QString &filterListTitle, const int sublistInt, EntryStruct *entryStructPointer) const;
+    bool checkIndividualList(QWebEngineUrlRequestInfo &urlRequestInfo, UrlStruct &urlStruct, RequestStruct *requestStructPointer, FilterListStruct *filterListStructPointer) const;
+    bool checkThirdParty(QWebEngineUrlRequestInfo &urlRequestInfo, RequestStruct *requestStructPointer, const bool isThirdPartyRequest, const QString &filterListTitle, const int sublistInt,
+                         EntryStruct *entryStructPointer) const;
     FilterListStruct* populateFilterList(const QString &filterListFileName) const;
-    void populateRequestStruct(RequestStruct *requestStructPointer, const int disposition, const QString &filterListTitle, const int sublistInt, const QString &appliedEntry,
-                               const QString &originalEntry) const;
+    void populateRequestStruct(RequestStruct *requestStructPointer, const int disposition, const QString &filterListTitle, const int sublistInt, EntryStruct *entryStructPointer) const;
+    bool processFilterOptions(QWebEngineUrlRequestInfo &urlRequestInfo, RequestStruct *requestStructPointer, const QString &filterListTitle, const int sublistInt,
+                              EntryStruct *entryStructPointer) const;
+    void removeInitialAndTrailingAsterisks(QString &filterListEntry) const;
 };
 #endif
index 1cd885d9341ca4f17d4f08e018f9bc022df4ed73..03e7b8bdc710d990c9129120584093e9db68bb4c 100644 (file)
@@ -39,11 +39,11 @@ const QString UserAgentHelper::SAFARI_MACOS_DATABASE = QLatin1String("Safari mac
 // Define the public user agent constants.
 const QString UserAgentHelper::PRIVACY_BROWSER_USER_AGENT = QLatin1String("PrivacyBrowser/1.0");
 const QString UserAgentHelper::FIREFOX_LINUX_USER_AGENT = QLatin1String("Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0");
-const QString UserAgentHelper::CHROMIUM_LINUX_USER_AGENT = QLatin1String("Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36");
-const QString UserAgentHelper::FIREFOX_WINDOWS_USER_AGENT = QLatin1String("Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:122.0) Gecko/20100101 Firefox/122.0");
-const QString UserAgentHelper::CHROME_WINDOWS_USER_AGENT = QLatin1String("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36");
-const QString UserAgentHelper::EDGE_WINDOWS_USER_AGENT = QLatin1String("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36 Edg/121.0.0.0");
-const QString UserAgentHelper::SAFARI_MACOS_USER_AGENT = QLatin1String("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Safari/605.1.15");
+const QString UserAgentHelper::CHROMIUM_LINUX_USER_AGENT = QLatin1String("Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36");
+const QString UserAgentHelper::FIREFOX_WINDOWS_USER_AGENT = QLatin1String("Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:126.0) Gecko/20100101 Firefox/126.0");
+const QString UserAgentHelper::CHROME_WINDOWS_USER_AGENT = QLatin1String("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36");
+const QString UserAgentHelper::EDGE_WINDOWS_USER_AGENT = QLatin1String("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36 Edg/125.0.0.0");
+const QString UserAgentHelper::SAFARI_MACOS_USER_AGENT = QLatin1String("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_Z) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.5 Safari/605.1.15");
 
 // Construct the class.
 UserAgentHelper::UserAgentHelper() {
index 068d9c98b4e78796f67601b70ac1e535e848bf9e..67a43eb391834d3c3fa02116bde9729c0e0f5a3e 100644 (file)
@@ -1,4 +1,4 @@
- /*
+/*
  * Copyright 2024 Soren Stoutner <soren@stoutner.com>.
  *
  * This file is part of Privacy Browser PC <https://www.stoutner.com/privacy-browser-pc/>.
 #ifndef ENTRYSTRUCT_H
 #define ENTRYSTRUCT_H
 
+// Application headers.
+#include "enums/FilterOptionEnum.h"
+
 // Qt toolkit headers.
 #include <QString>
 
 struct EntryStruct
 {
+    // The strings.
     QString appliedEntry;
+    QString filterOptions;
     QString originalEntry;
+
+    // The filter options flag.
+    bool hasFilterOptions = false;
+
+    // The filter options.
+    FilterOptionEnum::Disposition font = FilterOptionEnum::Disposition::Null;
+    FilterOptionEnum::Disposition image = FilterOptionEnum::Disposition::Null;
+    FilterOptionEnum::Disposition mainFrame = FilterOptionEnum::Disposition::Null;
+    FilterOptionEnum::Disposition media = FilterOptionEnum::Disposition::Null;
+    FilterOptionEnum::Disposition object = FilterOptionEnum::Disposition::Null;
+    FilterOptionEnum::Disposition other = FilterOptionEnum::Disposition::Null;
+    FilterOptionEnum::Disposition ping = FilterOptionEnum::Disposition::Null;
+    FilterOptionEnum::Disposition script = FilterOptionEnum::Disposition::Null;
+    FilterOptionEnum::Disposition styleSheet = FilterOptionEnum::Disposition::Null;
+    FilterOptionEnum::Disposition subFrame = FilterOptionEnum::Disposition::Null;
+    FilterOptionEnum::Disposition thirdParty = FilterOptionEnum::Disposition::Null;
+    FilterOptionEnum::Disposition xmlHttpRequest = FilterOptionEnum::Disposition::Null;
 };
 #endif
index aacc6c0fb5a96125ca22d5e90a80e8d453275897..ef560d1485aedb53a4bb82c2a8d06edf67b506e5 100644 (file)
@@ -34,6 +34,8 @@ struct FilterListStruct
     QString title;
     QString version;
     QString filePath;
-    std::forward_list<EntryStruct*> mainBlockList;
+    std::forward_list<EntryStruct *> mainAllowList;
+    std::forward_list<EntryStruct *> mainBlockList;
+    std::forward_list<EntryStruct *> initialDomainBlockList;
 };
 #endif
diff --git a/src/structs/OverrideStruct.h b/src/structs/OverrideStruct.h
new file mode 100644 (file)
index 0000000..0568a79
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2024 Soren Stoutner <soren@stoutner.com>.
+ *
+ * This file is part of Privacy Browser PC <https://www.stoutner.com/privacy-browser-pc/>.
+ *
+ * Privacy Browser PC is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Privacy Browser PC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Privacy Browser PC.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef OVERRIDESTRUCT_H
+#define OVERRIDESTRUCT_H
+
+struct OverrideStruct
+{
+    bool hasOverride = false;
+    bool font = false;
+    bool image = false;
+    bool mainFrame = false;
+    bool media = false;
+    bool object = false;
+    bool other = false;
+    bool ping = false;
+    bool script = false;
+    bool styleSheet = false;
+    bool subFrame = false;
+    bool xmlHttpRequest = false;
+};
+#endif
diff --git a/src/structs/UrlStruct.h b/src/structs/UrlStruct.h
new file mode 100644 (file)
index 0000000..ea135d0
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2024 Soren Stoutner <soren@stoutner.com>.
+ *
+ * This file is part of Privacy Browser PC <https://www.stoutner.com/privacy-browser-pc/>.
+ *
+ * Privacy Browser PC is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Privacy Browser PC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Privacy Browser PC.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef URLSTRUCT_H
+#define URLSTRUCT_H
+
+// Qt toolkit headers.
+#include <QString>
+
+struct UrlStruct
+{
+    QString urlString;
+    QString urlStringWithSeparators;
+    QString truncatedUrlString;
+    QString truncatedUrlStringWithSeparators;
+    bool isThirdPartyRequest;
+};
+#endif
index 74d3c5713b11fea3c5ef4011e6205619e08a31d6..d4eda1e944316bdab12933ce705d976a4964e9ee 100644 (file)
@@ -3,7 +3,7 @@
 <!--
   Copyright 2022 Soren Stoutner <soren@stoutner.com>.
 
-  This file is part of Privacy Browser PC <https://www.stoutner.com/privacy-browser-pc>.
+  This file is part of Privacy Browser PC <https://www.stoutner.com/privacy-browser-pc/>.
 
   Privacy Browser PC is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
index 4047303b0968483917b8e0712d7504363767f32b..17366f5a128eaacfba8de5efbc62b1087a273bd1 100644 (file)
         <layout class="QVBoxLayout">
             <!-- Main content. -->
             <item>
-                <layout class="QHBoxLayout">
+                <widget class="QSplitter">
+                    <property name="orientation">
+                        <enum>Qt::Horizontal</enum>
+                    </property>
+
+                    <property name="handleWidth">
+                        <number>5</number>
+                    </property>
+
                     <!-- Left column. -->
-                    <item>
+                    <widget class="QWidget">
                         <layout class="QVBoxLayout">
                             <!-- Filter list combo box. -->
                             <item>
                                     <property name="readOnly">
                                         <bool>true</bool>
                                     </property>
+
+                                    <property name="lineWrapMode">
+                                        <enum>QTextEdit::NoWrap</enum>
+                                    </property>
                                 </widget>
                             </item>
                         </layout>
-                    </item>
+                    </widget>
 
                     <!-- Right column. -->
-                    <item>
+                    <widget class="QWidget">
                         <layout class="QVBoxLayout">
                             <!-- Sublist combo box. -->
                             <item>
                             <!-- Sublist table. -->
                             <item>
                                 <widget class="QTableWidget" name="sublistTableWidget">
-                                    <property name="editTriggers">
-                                        <set>QAbstractItemView::NoEditTriggers</set>
-                                    </property>
-
                                     <property name="horizontalScrollMode">
                                         <enum>QAbstractItemView::ScrollPerPixel</enum>
                                     </property>
                                 </widget>
                             </item>
                         </layout>
-                    </item>
-                </layout>
+                    </widget>
+                </widget>
             </item>
 
             <!-- Buttons. -->
index a0a322b2c0d2d33d2623611c75b46d291820763b..899fe31a06bf518900b2e60f6a556486401076de 100644 (file)
                             <property name="readOnly">
                                 <bool>true</bool>
                             </property>
+
+                            <!-- Disabling focus allows the arrow keys to activate the buttons. -->
+                            <property name="focusPolicy">
+                                <enum>Qt::NoFocus</enum>
+                            </property>
                         </widget>
                     </item>
                 </layout>
                             <property name="readOnly">
                                 <bool>true</bool>
                             </property>
+
+                            <!-- Disabling focus allows the arrow keys to activate the buttons. -->
+                            <property name="focusPolicy">
+                                <enum>Qt::NoFocus</enum>
+                            </property>
                         </widget>
                     </item>
                 </layout>
                             <property name="readOnly">
                                 <bool>true</bool>
                             </property>
+
+                            <!-- Disabling focus allows the arrow keys to activate the buttons. -->
+                            <property name="focusPolicy">
+                                <enum>Qt::NoFocus</enum>
+                            </property>
                         </widget>
                     </item>
 
                             <property name="readOnly">
                                 <bool>true</bool>
                             </property>
+
+                            <!-- Disabling focus allows the arrow keys to activate the buttons. -->
+                            <property name="focusPolicy">
+                                <enum>Qt::NoFocus</enum>
+                            </property>
                         </widget>
                     </item>
 
                             <property name="readOnly">
                                 <bool>true</bool>
                             </property>
+
+                            <!-- Disabling focus allows the arrow keys to activate the buttons. -->
+                            <property name="focusPolicy">
+                                <enum>Qt::NoFocus</enum>
+                            </property>
                         </widget>
                     </item>
                 </layout>
                             <property name="readOnly">
                                 <bool>true</bool>
                             </property>
+
+                            <!-- Disabling focus allows the arrow keys to activate the buttons. -->
+                            <property name="focusPolicy">
+                                <enum>Qt::NoFocus</enum>
+                            </property>
                         </widget>
                     </item>
                 </layout>
                             <property name="readOnly">
                                 <bool>true</bool>
                             </property>
+
+                            <!-- Disabling focus allows the arrow keys to activate the buttons. -->
+                            <property name="focusPolicy">
+                                <enum>Qt::NoFocus</enum>
+                            </property>
                         </widget>
                     </item>
                 </layout>
                             <property name="readOnly">
                                 <bool>true</bool>
                             </property>
+
+                            <!-- Disabling focus allows the arrow keys to activate the buttons. -->
+                            <property name="focusPolicy">
+                                <enum>Qt::NoFocus</enum>
+                            </property>
                         </widget>
                     </item>
                 </layout>
                             <property name="readOnly">
                                 <bool>true</bool>
                             </property>
+
+                            <!-- Disabling focus allows the arrow keys to activate the buttons. -->
+                            <property name="focusPolicy">
+                                <enum>Qt::NoFocus</enum>
+                            </property>
                         </widget>
                     </item>
                 </layout>
                 </spacer>
             </item>
 
-            <!-- Close button - dialog button box. -->
             <item>
-                <widget class="QDialogButtonBox" name="dialogButtonBox">
-                    <property name="standardButtons">
-                        <set>QDialogButtonBox::Close</set>
-                    </property>
-                </widget>
+                <layout class="QHBoxLayout">
+                    <!-- Previous button.  -->
+                    <item>
+                        <widget class="QPushButton" name="previousButton">
+                            <property name="text">
+                                <string>Previous</string>
+                            </property>
+
+                            <property name="icon">
+                                <iconset theme="go-previous" />
+                            </property>
+                        </widget>
+                    </item>
+
+                    <!-- Next button.  -->
+                    <item>
+                        <widget class="QPushButton" name="nextButton">
+                            <property name="text">
+                                <string>Next</string>
+                            </property>
+
+                            <property name="icon">
+                                <iconset theme="go-next" />
+                            </property>
+                        </widget>
+                    </item>
+
+                    <!-- Close button - dialog button box. -->
+                    <item>
+                        <widget class="QDialogButtonBox" name="dialogButtonBox">
+                            <property name="standardButtons">
+                                <set>QDialogButtonBox::Close</set>
+                            </property>
+                        </widget>
+                    </item>
+                </layout>
             </item>
         </layout>
     </widget>
index 34999484ac734c5c4c096e6caedd0d23e253563c..3bbb9d0f3fbaca77b18c1f0e6a4f1df1289a9102 100644 (file)
             <!-- Requests table. -->
             <item>
                 <widget class="QTableWidget" name="tableWidget">
-                    <property name="editTriggers">
-                        <set>QAbstractItemView::NoEditTriggers</set>
-                    </property>
-
                     <property name="horizontalScrollMode">
                         <enum>QAbstractItemView::ScrollPerPixel</enum>
                     </property>
index 521526db433df80ee3ee78098b659ae49898d611..7a546f536a205c194d99a184466494f0af1c911a 100644 (file)
@@ -1,9 +1,9 @@
 <?xml version="1.0" encoding="UTF-8"?>
 
 <!--
-  Copyright © 2022 Soren Stoutner <soren@stoutner.com>.
+  Copyright 2022 Soren Stoutner <soren@stoutner.com>.
 
-  This file is part of Privacy Browser PC <https://www.stoutner.com/privacy-browser-pc>.
+  This file is part of Privacy Browser PC <https://www.stoutner.com/privacy-browser-pc/>.
 
   Privacy Browser PC is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
index 0728ecc7cd4375ef81e03a76421b30af1f401673..e98ac31c38e6c3da93d1dddd114e6d45685e37d4 100644 (file)
@@ -22,7 +22,6 @@
 #include "TabWidget.h"
 #include "Settings.h"
 #include "ui_AddTabWidget.h"
-#include "ui_Tab.h"
 #include "ui_TabWidget.h"
 #include "databases/CookiesDatabase.h"
 #include "dialogs/SaveDialog.h"
@@ -44,6 +43,7 @@
 #include <QPrintDialog>
 #include <QPrintPreviewDialog>
 #include <QPrinter>
+#include <QSplitter>
 
 // Initialize the public static variables.
 QString TabWidget::webEngineDefaultUserAgent = QLatin1String("");