]> gitweb.stoutner.com Git - PrivacyBrowserPC.git/blobdiff - src/dialogs/DomainSettingsDialog.cpp
Switch the Domain Settings implementation to a Dialog.
[PrivacyBrowserPC.git] / src / dialogs / DomainSettingsDialog.cpp
diff --git a/src/dialogs/DomainSettingsDialog.cpp b/src/dialogs/DomainSettingsDialog.cpp
new file mode 100644 (file)
index 0000000..0ebfb14
--- /dev/null
@@ -0,0 +1,303 @@
+/*
+ * Copyright © 2022 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 "DomainSettingsDialog.h"
+#include "ui_DomainSettingsDialog.h"
+#include "helpers/DomainsDatabaseHelper.h"
+
+// Qt toolkit headers.
+#include <QInputDialog>
+#include <QMessageBox>
+#include <QPushButton>
+
+DomainSettingsDialog::DomainSettingsDialog(QWidget *parent) : QDialog(parent)
+{
+    // Instantiate the domain settings view UI.
+    Ui::DomainSettingsDialog domainSettingsDialogUi;
+
+    // Setup the UI.
+    domainSettingsDialogUi.setupUi(this);
+
+    // Get handles for the views.
+    domainsListViewPointer = domainSettingsDialogUi.domainsListView;
+    domainSettingsWidgetPointer = domainSettingsDialogUi.domainSettingsWidget;
+    domainNameLineEditPointer = domainSettingsDialogUi.domainNameLineEdit;
+    javaScriptComboBoxPointer = domainSettingsDialogUi.javaScriptComboBox;
+    QPushButton *addDomainButtonPointer = domainSettingsDialogUi.addDomainButton;
+    deleteDomainButtonPointer = domainSettingsDialogUi.deleteDomainButton;
+    QDialogButtonBox *dialogButtonBoxPointer = domainSettingsDialogUi.dialogButtonBox;
+    applyButtonPointer = dialogButtonBoxPointer->button(QDialogButtonBox::StandardButton::Apply);
+    resetButtonPointer = dialogButtonBoxPointer->button(QDialogButtonBox::StandardButton::Reset);
+
+    // Create a table model.
+    domainsTableModelPointer = new QSqlTableModel(nullptr, QSqlDatabase::database(DomainsDatabaseHelper::CONNECTION_NAME));
+
+    // Set the table for the model.
+    domainsTableModelPointer->setTable(DomainsDatabaseHelper::DOMAINS_TABLE);
+
+    // Set the edit strategy to be manual.
+    domainsTableModelPointer->setEditStrategy(QSqlTableModel::EditStrategy::OnManualSubmit);
+
+    // Sort the output alphabetically.
+    domainsTableModelPointer->setSort(1, Qt::SortOrder::AscendingOrder);
+
+    // Set the model for the list view.
+    domainsListViewPointer->setModel(domainsTableModelPointer);
+
+    // Set the visible column to be the domain name.
+    domainsListViewPointer->setModelColumn(1);
+
+    // Disable editing of the list view.
+    domainsListViewPointer->setEditTriggers(QAbstractItemView::NoEditTriggers);
+
+    // Read the data from the database and apply it to the table model.
+    domainsTableModelPointer->select();
+
+    // Select the first entry in the list view.
+    domainsListViewPointer->setCurrentIndex(domainsTableModelPointer->index(0, domainsTableModelPointer->fieldIndex(DomainsDatabaseHelper::DOMAIN_NAME)));
+
+    // Populate the domain settings.
+    domainSelected(domainsListViewPointer->selectionModel()->currentIndex());
+
+    // Handle clicks on the domains.
+    connect(domainsListViewPointer, SIGNAL(activated(QModelIndex)), this, SLOT(domainSelected(QModelIndex)));
+
+    // Connect the domain settings.
+    connect(domainNameLineEditPointer, SIGNAL(textEdited(QString)), this, SLOT(domainNameChanged(QString)));
+    connect(javaScriptComboBoxPointer, SIGNAL(currentIndexChanged(int)), this, SLOT(javaScriptChanged(int)));
+
+    // Connect the buttons.
+    connect(addDomainButtonPointer, SIGNAL(released()), this, SLOT(showAddMessageBox()));
+    connect(deleteDomainButtonPointer, SIGNAL(released()), this, SLOT(showDeleteMessageBox()));
+    connect(resetButtonPointer, SIGNAL(released()), this, SLOT(reset()));
+    connect(dialogButtonBoxPointer, SIGNAL(accepted()), this, SLOT(ok()));
+    connect(applyButtonPointer, SIGNAL(released()), this, SLOT(apply()));
+    connect(dialogButtonBoxPointer, SIGNAL(rejected()), this, SLOT(cancel()));
+
+    // Update the UI.
+    updateUi();
+}
+
+void DomainSettingsDialog::apply() const
+{
+    // Get the current index.
+    QModelIndex currentIndex = domainsListViewPointer->currentIndex();
+
+    // Get the ID of the current index row.
+    QVariant currentId = currentIndex.siblingAtColumn(domainsTableModelPointer->fieldIndex(DomainsDatabaseHelper::_ID)).data();
+
+    // Submit all pending changes.
+    domainsTableModelPointer->submitAll();
+
+    // Find the new index for the selected id.  The `1` keeps searching after the first match.
+    QModelIndexList newIndexList = domainsTableModelPointer->match(currentIndex.siblingAtColumn(domainsTableModelPointer->fieldIndex(DomainsDatabaseHelper::_ID)), Qt::DisplayRole, currentId,
+                                                                   1, Qt::MatchWrap);
+
+    // Select the new index.
+    domainsListViewPointer->setCurrentIndex(newIndexList[0].siblingAtColumn(domainsTableModelPointer->fieldIndex(DomainsDatabaseHelper::DOMAIN_NAME)));
+
+    // Update the UI.
+    updateUi();
+}
+
+void DomainSettingsDialog::cancel()
+{
+    // Revert all pending changes.
+    domainsTableModelPointer->revertAll();
+
+    // Close the dialog.
+    reject();
+}
+
+void DomainSettingsDialog::domainNameChanged(QString updatedDomainName) const
+{
+    // Update the domains table model.
+    domainsTableModelPointer->setData(domainsListViewPointer->selectionModel()->currentIndex(), updatedDomainName);
+
+    // Update the UI.
+    updateUi();
+}
+
+
+void DomainSettingsDialog::domainSelected(QModelIndex modelIndex) const
+{
+    // Populate the domain name line edit pointer.
+    domainNameLineEditPointer->setText(modelIndex.data().toString());
+
+    // Populate the JavaScript combo box.
+    javaScriptComboBoxPointer->setCurrentIndex(modelIndex.siblingAtColumn(domainsTableModelPointer->fieldIndex(DomainsDatabaseHelper::JAVASCRIPT)).data().toInt());
+
+    // Update the UI.
+    updateUi();
+}
+
+void DomainSettingsDialog::javaScriptChanged(int newIndex) const
+{
+    // Update the domains table model.
+    domainsTableModelPointer->setData(domainsListViewPointer->selectionModel()->currentIndex().siblingAtColumn(domainsTableModelPointer->fieldIndex(DomainsDatabaseHelper::JAVASCRIPT)),
+                                      newIndex);
+
+    // Update the UI.
+    updateUi();
+}
+
+
+void DomainSettingsDialog::ok()
+{
+    // Submit all pending changes.
+    domainsTableModelPointer->submitAll();
+
+    // Close the dialog.
+    accept();
+}
+
+void DomainSettingsDialog::reset() const
+{
+    // Cancel all pending changes.
+    domainsTableModelPointer->revertAll();
+
+    // Repopulate the domain name line edit.
+    domainNameLineEditPointer->setText(domainsListViewPointer->currentIndex().data().toString());
+
+    // Update the UI.
+    updateUi();
+}
+
+void DomainSettingsDialog::showAddMessageBox()
+{
+    // Create an OK flag.
+    bool okClicked;
+
+    // Display a dialog to request the new domain name from the user.
+    QString newDomainName = QInputDialog::getText(this, i18nc("Add domain dialog title", "Add Domain"),
+                                                  i18nc("Add domain message.  The \n\n are newline codes that should be retained",
+                                                        "Add a new domain.  Doing so will also save any pending changes that have been made to other domains.\n\n"
+                                                        "*. may be prepended to a domain to include all subdomains (eg. *.stoutner.com)."),
+                                                  QLineEdit::Normal, QString(), &okClicked);
+
+    // Add the new domain if the user clicked OK.
+    if (okClicked)
+    {
+        // Create a new domain record.
+        QSqlRecord newDomainRecord = QSqlDatabase::database(DomainsDatabaseHelper::CONNECTION_NAME).record(DomainsDatabaseHelper::DOMAINS_TABLE);
+
+        // Add the new domain name.
+        newDomainRecord.setValue(domainsTableModelPointer->fieldIndex(DomainsDatabaseHelper::DOMAIN_NAME), newDomainName);
+
+        // Set the default value of `0` for the other columns.
+        newDomainRecord.setValue(domainsTableModelPointer->fieldIndex(DomainsDatabaseHelper::JAVASCRIPT), 0);
+
+        // Insert the new domain.  `-1` appends it to the end.
+        domainsTableModelPointer->insertRecord(-1, newDomainRecord);
+
+        // Submit all pending changes.
+        domainsTableModelPointer->submitAll();
+
+        // Find the index for the new domain.  `-1` allows for multiple entries to be returned.
+        QModelIndexList newDomainIndex = domainsTableModelPointer->match(domainsTableModelPointer->index(0, domainsTableModelPointer->fieldIndex(DomainsDatabaseHelper::DOMAIN_NAME)),
+                                                                         Qt::DisplayRole, newDomainName, -1, Qt::MatchWrap);
+
+        // Move to the new domain.  If there are multiple domains with the same name, the new one should be the last in the list.
+        domainsListViewPointer->setCurrentIndex(newDomainIndex[newDomainIndex.size() - 1]);
+
+        // Populate the domain settings.
+        domainSelected(domainsListViewPointer->selectionModel()->currentIndex());
+
+        // Update the UI.
+        updateUi();
+    }
+}
+
+void DomainSettingsDialog::showDeleteMessageBox() const
+{
+    // Instantiate a delete dialog message box.
+    QMessageBox deleteDialogMessageBox;
+
+    // Set the icon.
+    deleteDialogMessageBox.setIcon(QMessageBox::Warning);
+
+    // Set the window title.
+    deleteDialogMessageBox.setWindowTitle(i18nc("Delete domain dialog title", "Delete Domain"));
+
+    // Set the text.
+    deleteDialogMessageBox.setText(i18nc("Delete domain main message", "Delete the current domain?"));
+
+    // Set the informative text.
+    deleteDialogMessageBox.setInformativeText(i18nc("Delete domain secondary message", "Doing so will also save any pending changes that have been made to other domains."));
+
+    // Set the standard buttons.
+    deleteDialogMessageBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
+
+    // Set the default button.
+    deleteDialogMessageBox.setDefaultButton(QMessageBox::No);
+
+    // Display the dialog and capture the return value.
+    int returnValue = deleteDialogMessageBox.exec();
+
+    if (returnValue == QMessageBox::Yes)
+    {
+        // Get the current index.
+        QModelIndex currentIndex = domainsListViewPointer->currentIndex();
+
+        // Delete the current row.
+        domainsTableModelPointer->removeRow(domainsListViewPointer->selectionModel()->currentIndex().row());
+
+        // Submit all pending changes.
+        domainsTableModelPointer->submitAll();
+
+        // Select the row next to the deleted item if one exists.
+        if (domainsTableModelPointer->rowCount() > 0)
+        {
+            // Check the row of the deleted item.
+            if (currentIndex.row() == 0)  // The first row was deleted.
+            {
+                // Reselect the current index.
+                domainsListViewPointer->setCurrentIndex(currentIndex);
+            }
+            else  // A subsequent row was deleted.
+            {
+                // Select the crow above the deleted itemm.
+                domainsListViewPointer->setCurrentIndex(currentIndex.siblingAtRow(currentIndex.row() - 1));
+            }
+
+            // Populate the domain settings.
+            domainSelected(domainsListViewPointer->currentIndex());
+        }
+
+        // Update the Ui.
+        updateUi();
+    }
+}
+
+void DomainSettingsDialog::updateUi() const
+{
+    // Update the delete button status.
+    deleteDomainButtonPointer->setEnabled(domainsListViewPointer->selectionModel()->hasSelection());
+
+    // Update the apply button status.
+    applyButtonPointer->setEnabled(domainsTableModelPointer->isDirty());
+
+    // Update the reset button status.
+    resetButtonPointer->setEnabled(domainsTableModelPointer->isDirty());
+
+    // Display the domain settings if there is at least one domain.
+    domainSettingsWidgetPointer->setVisible(domainsTableModelPointer->rowCount() > 0);
+}
+