X-Git-Url: https://gitweb.stoutner.com/?p=PrivacyBrowserPC.git;a=blobdiff_plain;f=src%2Fdialogs%2FDomainSettingsDialog.cpp;fp=src%2Fdialogs%2FDomainSettingsDialog.cpp;h=0ebfb1448b85cf822dab246992fa02bcd65df0a3;hp=0000000000000000000000000000000000000000;hb=16118809a11aa423f453a03c47f5263e9dd8b662;hpb=0a7bcc3ab2d2a1015f29293fc9c527c1448a86cf diff --git a/src/dialogs/DomainSettingsDialog.cpp b/src/dialogs/DomainSettingsDialog.cpp new file mode 100644 index 0000000..0ebfb14 --- /dev/null +++ b/src/dialogs/DomainSettingsDialog.cpp @@ -0,0 +1,303 @@ +/* + * Copyright © 2022 Soren Stoutner . + * + * This file is part of 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 . + */ + +// Application headers. +#include "DomainSettingsDialog.h" +#include "ui_DomainSettingsDialog.h" +#include "helpers/DomainsDatabaseHelper.h" + +// Qt toolkit headers. +#include +#include +#include + +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); +} +