From 75ec461eeaa851cb5c53f4cfffc434e3e529ed1d Mon Sep 17 00:00:00 2001 From: "Felix (xq) Queißner" Date: Mon, 22 Jun 2020 21:10:04 +0200 Subject: Restructures the project source and cleans up a bit --- src/dialogs/certificateiodialog.cpp | 126 ++++ src/dialogs/certificateiodialog.hpp | 50 ++ src/dialogs/certificateiodialog.ui | 127 ++++ src/dialogs/certificatemanagementdialog.cpp | 308 +++++++++ src/dialogs/certificatemanagementdialog.hpp | 45 ++ src/dialogs/certificatemanagementdialog.ui | 294 +++++++++ src/dialogs/certificateselectiondialog.cpp | 130 ++++ src/dialogs/certificateselectiondialog.hpp | 54 ++ src/dialogs/certificateselectiondialog.ui | 172 +++++ src/dialogs/newidentitiydialog.cpp | 81 +++ src/dialogs/newidentitiydialog.hpp | 41 ++ src/dialogs/newidentitiydialog.ui | 118 ++++ src/dialogs/settingsdialog.cpp | 613 ++++++++++++++++++ src/dialogs/settingsdialog.hpp | 143 +++++ src/dialogs/settingsdialog.ui | 940 ++++++++++++++++++++++++++++ 15 files changed, 3242 insertions(+) create mode 100644 src/dialogs/certificateiodialog.cpp create mode 100644 src/dialogs/certificateiodialog.hpp create mode 100644 src/dialogs/certificateiodialog.ui create mode 100644 src/dialogs/certificatemanagementdialog.cpp create mode 100644 src/dialogs/certificatemanagementdialog.hpp create mode 100644 src/dialogs/certificatemanagementdialog.ui create mode 100644 src/dialogs/certificateselectiondialog.cpp create mode 100644 src/dialogs/certificateselectiondialog.hpp create mode 100644 src/dialogs/certificateselectiondialog.ui create mode 100644 src/dialogs/newidentitiydialog.cpp create mode 100644 src/dialogs/newidentitiydialog.hpp create mode 100644 src/dialogs/newidentitiydialog.ui create mode 100644 src/dialogs/settingsdialog.cpp create mode 100644 src/dialogs/settingsdialog.hpp create mode 100644 src/dialogs/settingsdialog.ui (limited to 'src/dialogs') diff --git a/src/dialogs/certificateiodialog.cpp b/src/dialogs/certificateiodialog.cpp new file mode 100644 index 0000000..8c9fcd5 --- /dev/null +++ b/src/dialogs/certificateiodialog.cpp @@ -0,0 +1,126 @@ +#include "certificateiodialog.hpp" +#include "ui_certificateiodialog.h" + +#include +#include +#include + +CertificateIoDialog::CertificateIoDialog(QWidget *parent) : + QDialog(parent), + ui(new Ui::CertificateIoDialog) +{ + ui->setupUi(this); + + this->ui->key_type->clear(); + this->ui->key_type->addItem("RSA", QVariant::fromValue(QSsl::Rsa)); + this->ui->key_type->addItem("ECDSA", QVariant::fromValue(QSsl::Ec)); + + this->updateUI(); +} + +CertificateIoDialog::~CertificateIoDialog() +{ + delete ui; +} + +void CertificateIoDialog::setIoMode(CertificateIoDialog::IoMode mode) +{ + this->current_mode = mode; + if(mode == Export) { + this->setWindowTitle(tr("Export Certificate")); + } else { + this->setWindowTitle(tr("Import Certificate")); + } + this->ui->key_type->setEnabled(mode == Import); + this->updateUI(); +} + +QSsl::KeyAlgorithm CertificateIoDialog::keyAlgorithm() const +{ + return QSsl::KeyAlgorithm(this->ui->key_type->currentData().toInt()); +} + +void CertificateIoDialog::setKeyAlgorithm(QSsl::KeyAlgorithm alg) +{ + this->ui->key_type->setCurrentIndex(-1); + for(int i = 0; i< this->ui->key_type->count(); i++) { + if(this->ui->key_type->itemData(i).toInt() == int(alg)) { + this->ui->key_type->setCurrentIndex(i); + break; + } + } +} + +QString CertificateIoDialog::keyFileName() const +{ + return this->ui->key_file_name->text(); +} + +QString CertificateIoDialog::certificateFileName() const +{ + return this->ui->certificate_file_name->text(); +} + +void CertificateIoDialog::on_select_certificate_file_button_clicked() +{ + QFileDialog dialog { this }; + + dialog.setNameFilter("Certificate File(*.pem *.der)"); + dialog.setAcceptMode((this->current_mode == Export) ? QFileDialog::AcceptSave : QFileDialog::AcceptOpen); + dialog.selectFile(this->ui->certificate_file_name->text()); + + if(dialog.exec() != QDialog::Accepted) + return; + + this->ui->certificate_file_name->setText(dialog.selectedFiles().first()); + + this->updateUI(); +} + +void CertificateIoDialog::on_select_key_file_button_clicked() +{ + QFileDialog dialog { this }; + + dialog.setNameFilter("Certificate File(*.pem *.der)"); + dialog.setAcceptMode((this->current_mode == Export) ? QFileDialog::AcceptSave : QFileDialog::AcceptOpen); + dialog.selectFile(this->ui->key_file_name->text()); + + if(dialog.exec() != QDialog::Accepted) + return; + + this->ui->key_file_name->setText(dialog.selectedFiles().first()); + + this->updateUI(); +} + +void CertificateIoDialog::on_certificate_file_name_textChanged(const QString &arg1) +{ + Q_UNUSED(arg1) + this->updateUI(); +} + +void CertificateIoDialog::on_key_file_name_textChanged(const QString &arg1) +{ + Q_UNUSED(arg1) + this->updateUI(); +} + +void CertificateIoDialog::updateUI() +{ + QString cert_file_name = certificateFileName(); + QString key_file_name = keyFileName(); + + bool ok = true; + + ok &= (cert_file_name.endsWith(".pem") or cert_file_name.endsWith(".der")); + ok &= (key_file_name.endsWith(".pem") or key_file_name.endsWith(".der")); + + ok &= (this->ui->key_type->currentIndex() >= 0); + + if(current_mode == Import) { + ok &= QFile(cert_file_name).exists(); + ok &= QFile(key_file_name).exists(); + } + + this->ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(ok); +} diff --git a/src/dialogs/certificateiodialog.hpp b/src/dialogs/certificateiodialog.hpp new file mode 100644 index 0000000..590b282 --- /dev/null +++ b/src/dialogs/certificateiodialog.hpp @@ -0,0 +1,50 @@ +#ifndef CERTIFICATEIODIALOG_HPP +#define CERTIFICATEIODIALOG_HPP + +#include +#include + +namespace Ui { +class CertificateIoDialog; +} + +class CertificateIoDialog : public QDialog +{ + Q_OBJECT +public: + enum IoMode { + Import, + Export + }; +public: + explicit CertificateIoDialog(QWidget *parent = nullptr); + ~CertificateIoDialog(); + + IoMode mode() const { return this->current_mode; } + void setIoMode(IoMode mode); + + QSsl::KeyAlgorithm keyAlgorithm() const; + void setKeyAlgorithm(QSsl::KeyAlgorithm alg); + + QString keyFileName() const; + QString certificateFileName() const; + +private slots: + void on_select_certificate_file_button_clicked(); + + void on_select_key_file_button_clicked(); + + void on_certificate_file_name_textChanged(const QString &arg1); + + void on_key_file_name_textChanged(const QString &arg1); + +private: + void updateUI(); + +private: + Ui::CertificateIoDialog *ui; + + IoMode current_mode; +}; + +#endif // CERTIFICATEIODIALOG_HPP diff --git a/src/dialogs/certificateiodialog.ui b/src/dialogs/certificateiodialog.ui new file mode 100644 index 0000000..074df28 --- /dev/null +++ b/src/dialogs/certificateiodialog.ui @@ -0,0 +1,127 @@ + + + CertificateIoDialog + + + + 0 + 0 + 411 + 160 + + + + Dialog + + + + + + + + Key Type + + + + + + + false + + + false + + + + + + + Key File + + + + + + + + + + + + ... + + + + + + + + + Certificate File + + + + + + + + + + + + ... + + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + CertificateIoDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + CertificateIoDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/src/dialogs/certificatemanagementdialog.cpp b/src/dialogs/certificatemanagementdialog.cpp new file mode 100644 index 0000000..5141b30 --- /dev/null +++ b/src/dialogs/certificatemanagementdialog.cpp @@ -0,0 +1,308 @@ +#include "certificatemanagementdialog.hpp" +#include "ui_certificatemanagementdialog.h" + +#include "kristall.hpp" + +#include "newidentitiydialog.hpp" +#include "certificateiodialog.hpp" +#include "ioutil.hpp" + +#include +#include + +CertificateManagementDialog::CertificateManagementDialog(QWidget *parent) : + QDialog(parent), + ui(new Ui::CertificateManagementDialog), + selected_identity { nullptr } +{ + ui->setupUi(this); + + this->ui->certificates->setModel(&global_identities); + this->ui->certificates->expandAll(); + + connect( + this->ui->certificates->selectionModel(), + &QItemSelectionModel::currentChanged, + this, + &CertificateManagementDialog::on_certificates_selected + ); + on_certificates_selected(QModelIndex { }, QModelIndex { }); +} + +CertificateManagementDialog::~CertificateManagementDialog() +{ + delete ui; +} + +void CertificateManagementDialog::on_certificates_selected(QModelIndex const& index, QModelIndex const & previous) +{ + Q_UNUSED(previous); + + selected_identity = global_identities.getMutableIdentity(index); + + this->ui->export_cert_button->setEnabled(selected_identity != nullptr); + + if(selected_identity != nullptr) + { + auto & cert = *selected_identity; + this->ui->groupBox->setEnabled(true); + this->ui->cert_display_name->setText(cert.display_name); + this->ui->cert_common_name->setText(cert.certificate.subjectInfo(QSslCertificate::CommonName).join(", ")); + this->ui->cert_expiration_date->setDateTime(cert.certificate.expiryDate()); + this->ui->cert_livetime->setText(QString("%1 days").arg(QDateTime::currentDateTime().daysTo(cert.certificate.expiryDate()))); + this->ui->cert_fingerprint->setPlainText(toFingerprintString(cert.certificate)); + this->ui->cert_notes->setPlainText(cert.user_notes); + + this->ui->cert_host_filter->setText(cert.host_filter); + this->ui->cert_auto_enable->setEnabled(not cert.host_filter.isEmpty()); + this->ui->cert_auto_enable->setChecked(cert.auto_enable); + + this->ui->delete_cert_button->setEnabled(true); + } + else + { + this->ui->groupBox->setEnabled(false); + this->ui->cert_display_name->setText(""); + this->ui->cert_common_name->setText(""); + this->ui->cert_expiration_date->setDateTime(QDateTime { }); + this->ui->cert_livetime->setText(""); + this->ui->cert_fingerprint->setPlainText(""); + this->ui->cert_host_filter->setText(""); + this->ui->cert_auto_enable->setChecked(false); + + if(auto group_name = global_identities.group(index); not group_name.isEmpty()) { + this->ui->delete_cert_button->setEnabled(global_identities.canDeleteGroup(group_name)); + } else { + this->ui->delete_cert_button->setEnabled(false); + } + } +} + +void CertificateManagementDialog::on_cert_notes_textChanged() +{ + if(this->selected_identity != nullptr) { + this->selected_identity->user_notes = this->ui->cert_notes->toPlainText(); + } +} + +void CertificateManagementDialog::on_cert_display_name_textChanged(const QString &arg1) +{ + Q_UNUSED(arg1) + if(this->selected_identity != nullptr) { + this->selected_identity->display_name = this->ui->cert_display_name->text(); + } +} + +void CertificateManagementDialog::on_delete_cert_button_clicked() +{ + auto index = this->ui->certificates->currentIndex(); + + if(global_identities.getMutableIdentity(index) != nullptr) + { + auto answer = QMessageBox::question( + this, + "Kristall", + "Do you really want to delete this certificate?\r\n\r\nYou will not be able to restore the identity after this!", + QMessageBox::Yes | QMessageBox::No, + QMessageBox::No + ); + if(answer != QMessageBox::Yes) + return; + if(not global_identities.destroyIdentity(index)) { + QMessageBox::warning(this, "Kristall", "Could not destroy identity!"); + } + } + else if(auto group_name = global_identities.group(index); not group_name.isEmpty()) { + + auto answer = QMessageBox::question( + this, + "Kristall", + QString("Do you want to delete the group '%1'").arg(group_name) + ); + if(answer != QMessageBox::Yes) + return; + + if(not global_identities.deleteGroup(group_name)) { + QMessageBox::warning(this, "Kristall", "Could not delete group!"); + } + } +} + +void CertificateManagementDialog::on_export_cert_button_clicked() +{ + if(this->selected_identity == nullptr) + return; + CertificateIoDialog dialog { this }; + + dialog.setKeyAlgorithm(this->selected_identity->private_key.algorithm()); + dialog.setIoMode(CertificateIoDialog::Export); + + if(dialog.exec() != QDialog::Accepted) + return; + + { + QFile cert_file { dialog.certificateFileName() }; + if(not cert_file.open(QFile::WriteOnly)) { + QMessageBox::warning( + this, + "Kristall", + tr("The file %1 could not be found!").arg(dialog.certificateFileName()) + ); + return; + } + + QByteArray cert_blob; + if(dialog.certificateFileName().endsWith(".der")) { + cert_blob = this->selected_identity->certificate.toDer(); + } else { + cert_blob = this->selected_identity->certificate.toPem(); + } + + if(not IoUtil::writeAll(cert_file, cert_blob)) { + QMessageBox::warning( + this, + "Kristall", + tr("The file %1 could not be created found!").arg(dialog.certificateFileName()) + ); + return; + } + } + + { + QFile key_file { dialog.keyFileName() }; + if(not key_file.open(QFile::WriteOnly)) { + QMessageBox::warning( + this, + "Kristall", + tr("The file %1 could not be found!").arg(dialog.keyFileName()) + ); + return; + } + + QByteArray key_blob; + if(dialog.keyFileName().endsWith(".der")) { + key_blob = this->selected_identity->private_key.toDer(); + } else { + key_blob = this->selected_identity->private_key.toPem(); + } + + if(not IoUtil::writeAll(key_file, key_blob)) { + QMessageBox::warning( + this, + "Kristall", + tr("The file %1 could not be created found!").arg(dialog.keyFileName()) + ); + return; + } + } +} + +void CertificateManagementDialog::on_import_cert_button_clicked() +{ + CertificateIoDialog dialog { this }; + + dialog.setIoMode(CertificateIoDialog::Import); + + if(dialog.exec() != QDialog::Accepted) + return; + + QFile cert_file { dialog.certificateFileName() }; + if(not cert_file.open(QFile::ReadOnly)) { + QMessageBox::warning( + this, + "Kristall", + tr("The file %1 could not be found!").arg(dialog.certificateFileName()) + ); + return; + } + + QFile key_file { dialog.keyFileName() }; + if(not key_file.open(QFile::ReadOnly)) { + QMessageBox::warning( + this, + "Kristall", + tr("The file %1 could not be found!").arg(dialog.keyFileName()) + ); + return; + } + + CryptoIdentity ident; + ident.private_key = QSslKey { + &key_file, + dialog.keyAlgorithm(), + dialog.keyFileName().endsWith(".der") ? QSsl::Der : QSsl::Pem, + QSsl::PrivateKey + }; + ident.certificate = QSslCertificate { + &cert_file, + dialog.keyFileName().endsWith(".der") ? QSsl::Der : QSsl::Pem, + }; + ident.user_notes = tr("Imported from:\r\nkey: %1\r\n:cert: %2").arg(dialog.keyFileName()).arg(dialog.certificateFileName()); + ident.display_name = "Imported Certificate"; + ident.auto_enable = false; + ident.host_filter = ""; + ident.is_persistent = true; + + if(ident.private_key.isNull()) { + QMessageBox::warning( + this, + "Kristall", + tr("The key file %1 could not be loaded. Please verify your key file.").arg(dialog.keyFileName()) + ); + return; + } + + if(ident.certificate.isNull()) { + QMessageBox::warning( + this, + "Kristall", + tr("The certificate file %1 could not be loaded. Please verify your certificate.").arg(dialog.keyFileName()) + ); + return; + } + + if(not global_identities.addCertificate(tr("Imported Certificates"), ident)) { + QMessageBox::warning( + this, + "Kristall", + tr("Failed to import the certificate.") + ); + } +} + +void CertificateManagementDialog::on_create_cert_button_clicked() +{ + NewIdentitiyDialog dialog { this }; + + dialog.setGroupName(global_identities.group(this->ui->certificates->currentIndex())); + + if(dialog.exec() != QDialog::Accepted) + return; + + auto id = dialog.createIdentity(); + if(not id.isValid()) + return; + id.is_persistent = true; + + global_identities.addCertificate( + dialog.groupName(), + id); +} + +void CertificateManagementDialog::on_cert_host_filter_textChanged(const QString &host_filter) +{ + if(this->selected_identity != nullptr) { + this->ui->cert_auto_enable->setEnabled(not host_filter.isEmpty()); + this->selected_identity->host_filter = host_filter; + } else { + this->ui->cert_auto_enable->setEnabled(false); + } + +} + +void CertificateManagementDialog::on_cert_auto_enable_clicked(bool checked) +{ + if(this->selected_identity != nullptr) { + this->selected_identity->auto_enable = checked; + } +} diff --git a/src/dialogs/certificatemanagementdialog.hpp b/src/dialogs/certificatemanagementdialog.hpp new file mode 100644 index 0000000..0d7178a --- /dev/null +++ b/src/dialogs/certificatemanagementdialog.hpp @@ -0,0 +1,45 @@ +#ifndef CERTIFICATEMANAGEMENTDIALOG_HPP +#define CERTIFICATEMANAGEMENTDIALOG_HPP + +#include + +#include "cryptoidentity.hpp" + +namespace Ui { +class CertificateManagementDialog; +} + +class CertificateManagementDialog : public QDialog +{ + Q_OBJECT + +public: + explicit CertificateManagementDialog(QWidget *parent = nullptr); + ~CertificateManagementDialog(); + +private slots: + void on_cert_notes_textChanged(); + + void on_cert_display_name_textChanged(const QString &arg1); + + void on_delete_cert_button_clicked(); + + void on_export_cert_button_clicked(); + + void on_import_cert_button_clicked(); + + void on_create_cert_button_clicked(); + + void on_cert_host_filter_textChanged(const QString &arg1); + + void on_cert_auto_enable_clicked(bool checked); + +private: + void on_certificates_selected(const QModelIndex &index, QModelIndex const & previous); +private: + Ui::CertificateManagementDialog *ui; + + CryptoIdentity * selected_identity; +}; + +#endif // CERTIFICATEMANAGEMENTDIALOG_HPP diff --git a/src/dialogs/certificatemanagementdialog.ui b/src/dialogs/certificatemanagementdialog.ui new file mode 100644 index 0000000..82dd788 --- /dev/null +++ b/src/dialogs/certificatemanagementdialog.ui @@ -0,0 +1,294 @@ + + + CertificateManagementDialog + + + + 0 + 0 + 731 + 480 + + + + Certificate Manager + + + + + + + + + + + 0 + + + + + true + + + true + + + QAbstractItemView::DragDrop + + + Qt::MoveAction + + + false + + + + + + + + + Craete new certificate + + + Create... + + + + + + + + + + Import certificate + + + Import... + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + false + + + Export certificate + + + Export... + + + + + + + + + + false + + + Delete certificate + + + Delete + + + + + + + + + + + + + + true + + + Certificate + + + + + + + + Display Name + + + + + + + + + + Common Name + + + + + + + true + + + + + + + Expiration Date + + + + + + + true + + + true + + + + + + + Expires in + + + + + + + true + + + ??? days + + + + + + + Fingerprint + + + + + + + Notes + + + + + + + true + + + + + + + + + + Host Filter + + + + + + + gemini://* + + + + + + + If this is checked, Kristall will automatically enable this certificate when visiting a URL matching the host filter + + + Auto-Enable Certificate + + + + + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + CertificateManagementDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + CertificateManagementDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/src/dialogs/certificateselectiondialog.cpp b/src/dialogs/certificateselectiondialog.cpp new file mode 100644 index 0000000..f4dab38 --- /dev/null +++ b/src/dialogs/certificateselectiondialog.cpp @@ -0,0 +1,130 @@ +#include "certificateselectiondialog.hpp" +#include "ui_certificateselectiondialog.h" + +#include "certificatehelper.hpp" +#include "kristall.hpp" +#include "newidentitiydialog.hpp" + +#include +#include +#include + +CertificateSelectionDialog::CertificateSelectionDialog(QWidget *parent) : + QDialog(parent), + ui(new Ui::CertificateSelectionDialog) +{ + ui->setupUi(this); + this->ui->server_request->setVisible(false); + + this->ui->certificates->setModel(&global_identities); + this->ui->certificates->expandAll(); + + connect(this->ui->certificates->selectionModel(), &QItemSelectionModel::currentChanged, this, &CertificateSelectionDialog::on_currentChanged); +} + +CertificateSelectionDialog::~CertificateSelectionDialog() +{ + delete ui; +} + +void CertificateSelectionDialog::setServerQuery(const QString &query) +{ + this->ui->server_request->setText(query); + this->ui->server_request->setVisible(not query.isEmpty()); +} + +CryptoIdentity CertificateSelectionDialog::identity() const +{ + return cryto_identity; +} + +void CertificateSelectionDialog::on_use_temp_cert_30m_clicked() +{ + acceptTemporaryWithTimeout(QDateTime::currentDateTime().addSecs(1800 * 12)); +} + +void CertificateSelectionDialog::on_use_temp_cert_1h_clicked() +{ + acceptTemporaryWithTimeout(QDateTime::currentDateTime().addSecs(3600)); +} + +void CertificateSelectionDialog::on_use_temp_cert_12h_clicked() +{ + acceptTemporaryWithTimeout(QDateTime::currentDateTime().addSecs(3600 * 12)); +} + +void CertificateSelectionDialog::on_use_temp_cert_24h_clicked() +{ + acceptTemporaryWithTimeout(QDateTime::currentDateTime().addDays(1)); +} + +void CertificateSelectionDialog::on_use_temp_cert_48h_clicked() +{ + acceptTemporaryWithTimeout(QDateTime::currentDateTime().addDays(2)); +} + +void CertificateSelectionDialog::acceptTemporaryWithTimeout(QDateTime timeout) +{ + std::default_random_engine rng; + rng.seed(QDateTime::currentDateTime().toMSecsSinceEpoch()); + + std::uniform_int_distribution distr(0, 255); + + char items[8]; + for(auto & c : items) { + c = distr(rng); + } + + this->cryto_identity = CertificateHelper::createNewIdentity( + QByteArray(items, sizeof items).toBase64(QByteArray::OmitTrailingEquals), + timeout); + + this->accept(); +} + +void CertificateSelectionDialog::on_currentChanged(const QModelIndex ¤t, const QModelIndex &previous) +{ + Q_UNUSED(current) + Q_UNUSED(previous) + auto id = global_identities.getIdentity(current); + + this->ui->use_selected_cert->setEnabled(id.isValid()); +} + +void CertificateSelectionDialog::on_create_new_cert_clicked() +{ + NewIdentitiyDialog dialog { this }; + + if(dialog.exec() != QDialog::Accepted) + return; + + auto id = dialog.createIdentity(); + if(not id.isValid()) + return; + id.is_persistent = true; + + global_identities.addCertificate( + dialog.groupName(), + id); +} + +void CertificateSelectionDialog::on_use_selected_cert_clicked() +{ + auto sel = this->ui->certificates->selectionModel()->currentIndex(); + this->cryto_identity = global_identities.getIdentity(sel); + if(this->cryto_identity.isValid()) { + this->accept(); + } else { + qDebug() << "Tried to use an invalid identity when the button should not be enabled. This is a bug!"; + } +} + +void CertificateSelectionDialog::on_certificates_doubleClicked(const QModelIndex &index) +{ + this->cryto_identity = global_identities.getIdentity(index); + if(this->cryto_identity.isValid()) { + this->accept(); + } else { + qDebug() << "Tried to use an invalid identity when the button should not be enabled. This is a bug!"; + } +} diff --git a/src/dialogs/certificateselectiondialog.hpp b/src/dialogs/certificateselectiondialog.hpp new file mode 100644 index 0000000..e628f5c --- /dev/null +++ b/src/dialogs/certificateselectiondialog.hpp @@ -0,0 +1,54 @@ +#ifndef CERTIFICATESELECTIONDIALOG_HPP +#define CERTIFICATESELECTIONDIALOG_HPP + +#include + +#include "cryptoidentity.hpp" + +namespace Ui { +class CertificateSelectionDialog; +} + +class CertificateSelectionDialog : public QDialog +{ + Q_OBJECT + +public: + explicit CertificateSelectionDialog(QWidget *parent = nullptr); + ~CertificateSelectionDialog(); + + void setServerQuery(QString const & query); + + CryptoIdentity identity() const; + +private slots: + void on_use_temp_cert_30m_clicked(); + + void on_use_temp_cert_1h_clicked(); + + void on_use_temp_cert_12h_clicked(); + + void on_use_temp_cert_24h_clicked(); + + void on_use_temp_cert_48h_clicked(); + + void on_create_new_cert_clicked(); + + void on_use_selected_cert_clicked(); + + void on_certificates_doubleClicked(const QModelIndex &index); + +private: + //! Creates an anonymous identity with a randomly chosen name that + //! will time out on `timeout`, then accepts the dialog. + void acceptTemporaryWithTimeout(QDateTime timeout); + + + void on_currentChanged(const QModelIndex ¤t, const QModelIndex &previous); +private: + Ui::CertificateSelectionDialog *ui; + + CryptoIdentity cryto_identity; +}; + +#endif // CERTIFICATESELECTIONDIALOG_HPP diff --git a/src/dialogs/certificateselectiondialog.ui b/src/dialogs/certificateselectiondialog.ui new file mode 100644 index 0000000..d6128f9 --- /dev/null +++ b/src/dialogs/certificateselectiondialog.ui @@ -0,0 +1,172 @@ + + + CertificateSelectionDialog + + + + 0 + 0 + 474 + 355 + + + + Select client certificate + + + + :/icons/certificate.svg:/icons/certificate.svg + + + + + + Select existing certificate: + + + + + + + + 75 + true + + + + TextLabel + + + true + + + + + + + true + + + + + + + + + Create new identity + + + + :/icons/plus.svg:/icons/plus.svg + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + false + + + Use + + + + + + + + + Qt::Horizontal + + + + + + + Create transient session certificate: + + + + + + + + + 30 Minutes + + + + + + + 1 Hour + + + + + + + 12 Hours + + + + + + + 24 Hours + + + + + + + 48 Hours + + + + + + + + + QDialogButtonBox::Cancel + + + + + + + + + + + buttonBox + rejected() + CertificateSelectionDialog + reject() + + + 236 + 333 + + + 236 + 177 + + + + + diff --git a/src/dialogs/newidentitiydialog.cpp b/src/dialogs/newidentitiydialog.cpp new file mode 100644 index 0000000..af2a97e --- /dev/null +++ b/src/dialogs/newidentitiydialog.cpp @@ -0,0 +1,81 @@ +#include "newidentitiydialog.hpp" +#include "ui_newidentitiydialog.h" + +#include "certificatehelper.hpp" +#include "kristall.hpp" + +#include +#include + +NewIdentitiyDialog::NewIdentitiyDialog(QWidget *parent) : + QDialog(parent), + ui(new Ui::NewIdentitiyDialog) +{ + ui->setupUi(this); + + ui->display_name->setText("Unnamed"); + ui->common_name->setText("Unnamed"); + ui->expiration_date->setDate(QDate::currentDate().addYears(1)); + ui->expiration_date->setTime(QTime(12, 00)); + + ui->group->clear(); + for(auto group_name : global_identities.groups()) + { + ui->group->addItem(group_name); + } +} + +NewIdentitiyDialog::~NewIdentitiyDialog() +{ + delete ui; +} + +CryptoIdentity NewIdentitiyDialog::createIdentity() const +{ + auto id = CertificateHelper::createNewIdentity( + this->ui->common_name->text(), + this->ui->expiration_date->dateTime() + ); + id.display_name = this->ui->display_name->text(); + return id; +} + +QString NewIdentitiyDialog::groupName() const +{ + return this->ui->group->currentText(); +} + +void NewIdentitiyDialog::setGroupName(const QString &name) +{ + this->ui->group->setCurrentText(name); +} + +void NewIdentitiyDialog::updateUI() +{ + bool is_ok = true; + + is_ok &= (not this->ui->group->currentText().isEmpty()); + is_ok &= (not this->ui->common_name->text().isEmpty()); + is_ok &= (not this->ui->display_name->text().isEmpty()); + is_ok &= (this->ui->expiration_date->dateTime() > QDateTime::currentDateTime()); + + this->ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(is_ok); +} + +void NewIdentitiyDialog::on_group_editTextChanged(const QString &arg1) +{ + Q_UNUSED(arg1); + this->updateUI(); +} + +void NewIdentitiyDialog::on_display_name_textChanged(const QString &arg1) +{ + Q_UNUSED(arg1); + this->updateUI(); +} + +void NewIdentitiyDialog::on_common_name_textChanged(const QString &arg1) +{ + Q_UNUSED(arg1); + this->updateUI(); +} diff --git a/src/dialogs/newidentitiydialog.hpp b/src/dialogs/newidentitiydialog.hpp new file mode 100644 index 0000000..83d740b --- /dev/null +++ b/src/dialogs/newidentitiydialog.hpp @@ -0,0 +1,41 @@ +#ifndef NEWIDENTITIYDIALOG_HPP +#define NEWIDENTITIYDIALOG_HPP + +#include + +#include "cryptoidentity.hpp" + +namespace Ui { +class NewIdentitiyDialog; +} + +class NewIdentitiyDialog : public QDialog +{ + Q_OBJECT + +public: + explicit NewIdentitiyDialog(QWidget *parent = nullptr); + ~NewIdentitiyDialog(); + + //! Creates a new identity from the currently set + //! user settings. + CryptoIdentity createIdentity() const; + + QString groupName() const; + void setGroupName(QString const & name); + +private slots: + void on_group_editTextChanged(const QString &arg1); + + void on_display_name_textChanged(const QString &arg1); + + void on_common_name_textChanged(const QString &arg1); + +private: + void updateUI(); + +private: + Ui::NewIdentitiyDialog *ui; +}; + +#endif // NEWIDENTITIYDIALOG_HPP diff --git a/src/dialogs/newidentitiydialog.ui b/src/dialogs/newidentitiydialog.ui new file mode 100644 index 0000000..556ac93 --- /dev/null +++ b/src/dialogs/newidentitiydialog.ui @@ -0,0 +1,118 @@ + + + NewIdentitiyDialog + + + + 0 + 0 + 328 + 191 + + + + Create new certificate + + + + :/icons/certificate.svg:/icons/certificate.svg + + + + + + + + Display Name + + + + + + + Expiration Date + + + + + + + + + + + + + + + + Common Name + + + + + + + Group + + + + + + + true + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + + + buttonBox + accepted() + NewIdentitiyDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + NewIdentitiyDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/src/dialogs/settingsdialog.cpp b/src/dialogs/settingsdialog.cpp new file mode 100644 index 0000000..ebd1664 --- /dev/null +++ b/src/dialogs/settingsdialog.cpp @@ -0,0 +1,613 @@ +#include "settingsdialog.hpp" +#include "ui_settingsdialog.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "kristall.hpp" + +SettingsDialog::SettingsDialog(QWidget *parent) : + QDialog(parent), + ui(new Ui::SettingsDialog), + current_style() +{ + ui->setupUi(this); + + static_assert(DocumentStyle::Fixed == 0); + static_assert(DocumentStyle::AutoDarkTheme == 1); + static_assert(DocumentStyle::AutoLightTheme == 2); + + this->ui->auto_theme->clear(); + this->ui->auto_theme->addItem(tr("Disabled"), QVariant::fromValue(DocumentStyle::Fixed)); + this->ui->auto_theme->addItem(tr("Dark Theme"), QVariant::fromValue(DocumentStyle::AutoDarkTheme)); + this->ui->auto_theme->addItem(tr("Light Theme"), QVariant::fromValue(DocumentStyle::AutoLightTheme)); + + this->ui->ui_theme->clear(); + this->ui->ui_theme->addItem(tr("OS Default"), QVariant::fromValue(int(Theme::os_default))); + this->ui->ui_theme->addItem(tr("Light"), QVariant::fromValue(int(Theme::light))); + this->ui->ui_theme->addItem(tr("Dark"), QVariant::fromValue(int(Theme::dark))); + + setGeminiStyle(DocumentStyle { }); + + int items = global_settings.beginReadArray("Themes"); + + this->predefined_styles.clear(); + for(int i = 0; i < items; i++) + { + global_settings.setArrayIndex(i); + + QString name = global_settings.value("name").toString(); + + DocumentStyle style; + style.load(global_settings); + + this->predefined_styles.insert(name, style); + } + + global_settings.endArray(); + + this->ui->presets->clear(); + for(auto const & style_name : this->predefined_styles.keys()) + { + this->ui->presets->addItem(style_name); + } + + if(items > 0) { + on_presets_currentIndexChanged(0); + } else { + this->on_presets_currentIndexChanged(-1); + } + + this->ui->redirection_mode->clear(); + this->ui->redirection_mode->addItem("Ask for cross-scheme or cross-host redirection", int(GenericSettings::WarnOnHostChange | GenericSettings::WarnOnSchemeChange)); + this->ui->redirection_mode->addItem("Ask for cross-scheme redirection", int(GenericSettings::WarnOnSchemeChange)); + this->ui->redirection_mode->addItem("Ask for cross-host redirection", int(GenericSettings::WarnOnHostChange)); + this->ui->redirection_mode->addItem("Ask for all redirection", int(GenericSettings::WarnAlways)); + this->ui->redirection_mode->addItem("Silently redirect everything", int(GenericSettings::WarnNever)); +} + +SettingsDialog::~SettingsDialog() +{ + delete ui; +} + +static QString formatFont(QFont const & font) +{ + QString style; + if(font.italic() and font.bold()) + style = "bold, italic"; + else if(font.italic()) + style = "italic"; + else if(font.bold()) + style = "bold"; + else + style = "regular"; + + return QString("%1 (%2pt, %3)") + .arg(font.family()) + .arg(font.pointSizeF()) + .arg(style); +} + +void SettingsDialog::setGeminiStyle(DocumentStyle const &style) +{ + static const QString COLOR_STYLE("border: 1px solid black; padding: 4px; background-color : %1; color : %2;"); + + this->current_style = style; + + this->ui->auto_theme->setCurrentIndex(this->current_style.theme); + + this->ui->page_margin->setValue(this->current_style.margin); + + auto setFontAndColor = [this](QLabel * label, QFont font, QColor color) + { + label->setText(formatFont(font)); + label->setStyleSheet(COLOR_STYLE + .arg(this->current_style.background_color.name()) + .arg(color.name())); + }; + + ui->bg_preview->setStyleSheet(COLOR_STYLE + .arg(this->current_style.background_color.name()) + .arg("#FF00FF")); + + ui->quote_preview->setStyleSheet(COLOR_STYLE + .arg(this->current_style.blockquote_color.name()) + .arg("#FF00FF")); + + ui->link_local_preview->setStyleSheet(COLOR_STYLE + .arg(this->current_style.background_color.name()) + .arg(this->current_style.internal_link_color.name())); + + ui->link_foreign_preview->setStyleSheet(COLOR_STYLE + .arg(this->current_style.background_color.name()) + .arg(this->current_style.external_link_color.name())); + + ui->link_cross_preview->setStyleSheet(COLOR_STYLE + .arg(this->current_style.background_color.name()) + .arg(this->current_style.cross_scheme_link_color.name())); + + setFontAndColor(this->ui->std_preview, this->current_style.standard_font, this->current_style.standard_color); + setFontAndColor(this->ui->pre_preview, this->current_style.preformatted_font, this->current_style.preformatted_color); + setFontAndColor(this->ui->h1_preview, this->current_style.h1_font, this->current_style.h1_color); + setFontAndColor(this->ui->h2_preview, this->current_style.h2_font, this->current_style.h2_color); + setFontAndColor(this->ui->h3_preview, this->current_style.h3_font, this->current_style.h3_color); + + this->reloadStylePreview(); +} + +ProtocolSetup SettingsDialog::protocols() const +{ + ProtocolSetup protocols; +#define M(X) \ + protocols.X = this->ui->enable_##X->isChecked(); + PROTOCOLS(M) +#undef M + return protocols; +} + +void SettingsDialog::setProtocols(ProtocolSetup const & protocols) +{ +#define M(X) \ + this->ui->enable_##X->setChecked(protocols.X); + PROTOCOLS(M) + #undef M +} + +SslTrust SettingsDialog::geminiSslTrust() const +{ + return this->ui->gemini_trust_editor->trust(); +} + +void SettingsDialog::setGeminiSslTrust(const SslTrust &trust) +{ + return this->ui->gemini_trust_editor->setTrust(trust); +} + +SslTrust SettingsDialog::httpsSslTrust() const +{ + return this->ui->https_trust_editor->trust(); +} + +void SettingsDialog::setHttpsSslTrust(const SslTrust &trust) +{ + this->ui->https_trust_editor->setTrust(trust); +} + +void SettingsDialog::setOptions(const GenericSettings &options) +{ + this->current_options = options; + + this->ui->ui_theme->setCurrentIndex(0); + for(int i = 0; i < this->ui->ui_theme->count(); i++) { + if(this->ui->ui_theme->itemData(i).toInt() == int(options.theme)) { + this->ui->ui_theme->setCurrentIndex(i); + break; + } + } + + this->ui->start_page->setText(this->current_options.start_page); + + if(this->current_options.gophermap_display == GenericSettings::PlainText) { + this->ui->gophermap_text->setChecked(true); + } else { + this->ui->gophermap_icon->setChecked(true); + } + + if(this->current_options.text_display == GenericSettings::PlainText) { + this->ui->fancypants_off->setChecked(true); + } else { + this->ui->fancypants_on->setChecked(true); + } + + if(this->current_options.enable_text_decoration) { + this->ui->texthl_on->setChecked(true); + } else { + this->ui->texthl_off->setChecked(true); + } + + if(this->current_options.use_os_scheme_handler) { + this->ui->scheme_os_default->setChecked(true); + } else { + this->ui->scheme_error->setChecked(true); + } + + this->ui->max_redirects->setValue(this->current_options.max_redirections); + + this->ui->redirection_mode->setCurrentIndex(0); + for(int i = 0; i < this->ui->redirection_mode->count(); i++) + { + if(this->ui->redirection_mode->itemData(i).toInt() == this->current_options.redirection_policy) { + this->ui->redirection_mode->setCurrentIndex(i); + break; + } + } + + this->ui->network_timeout->setValue(this->current_options.network_timeout); +} + +GenericSettings SettingsDialog::options() const +{ + return this->current_options; +} + +void SettingsDialog::reloadStylePreview() +{ + QFile document_src { ":/about/style-preview.gemini" }; + bool ok = document_src.open(QFile::ReadOnly); + assert(ok and "failed to find style-preview.gemini!"); + + auto const document = document_src.readAll(); + + QString host = this->ui->preview_url->text(); + if(host.length() == 0) + host = "preview"; + + QUrl url { QUrl(QString("about://%1/foobar").arg(host)) }; + + DocumentOutlineModel outline; + auto doc = GeminiRenderer::render( + document, + url, + current_style.derive(url), + outline + ); + + ui->style_preview->setStyleSheet(QString("QTextBrowser { background-color: %1; }") + .arg(doc->background_color.name())); + ui->style_preview->setDocument(doc.get()); + preview_document = std::move(doc); +} + +void SettingsDialog::updateFont(QFont & input) +{ + QFontDialog dialog { this }; + + dialog.setCurrentFont(input); + + if(dialog.exec() == QDialog::Accepted) { + input = dialog.currentFont(); + setGeminiStyle(current_style); + } +} + +void SettingsDialog::on_std_change_font_clicked() +{ + updateFont(current_style.standard_font); +} + +void SettingsDialog::on_pre_change_font_clicked() +{ + updateFont(current_style.preformatted_font); +} + +void SettingsDialog::on_h1_change_font_clicked() +{ + updateFont(current_style.h1_font); +} + +void SettingsDialog::on_h2_change_font_clicked() +{ + updateFont(current_style.h2_font); +} + +void SettingsDialog::on_h3_change_font_clicked() +{ + updateFont(current_style.h3_font); +} + +void SettingsDialog::updateColor(QColor &input) +{ + QColorDialog dialog { this }; + + dialog.setCurrentColor(input); + + if(dialog.exec() == QDialog::Accepted) { + input = dialog.currentColor(); + setGeminiStyle(current_style); + } +} + +void SettingsDialog::on_std_change_color_clicked() +{ + updateColor(current_style.standard_color); +} + +void SettingsDialog::on_pre_change_color_clicked() +{ + updateColor(current_style.preformatted_color); +} + +void SettingsDialog::on_h1_change_color_clicked() +{ + updateColor(current_style.h1_color); +} + +void SettingsDialog::on_h2_change_color_clicked() +{ + updateColor(current_style.h2_color); +} + +void SettingsDialog::on_h3_change_color_clicked() +{ + updateColor(current_style.h3_color); +} + +void SettingsDialog::on_bg_change_color_clicked() +{ + updateColor(current_style.background_color); +} + +void SettingsDialog::on_link_local_change_color_clicked() +{ + updateColor(current_style.internal_link_color); +} + +void SettingsDialog::on_link_foreign_change_color_clicked() +{ + updateColor(current_style.external_link_color); +} + +void SettingsDialog::on_link_cross_change_color_clicked() +{ + updateColor(current_style.cross_scheme_link_color); +} +void SettingsDialog::on_quote_change_color_clicked() +{ + updateColor(current_style.blockquote_color); +} + +void SettingsDialog::on_link_local_prefix_textChanged(const QString &text) +{ + current_style.internal_link_prefix = text; + reloadStylePreview(); +} + +void SettingsDialog::on_link_foreign_prefix_textChanged(const QString &text) +{ + current_style.external_link_prefix = text; + reloadStylePreview(); +} + +void SettingsDialog::on_auto_theme_currentIndexChanged(int index) +{ + if(index >= 0) { + current_style.theme = DocumentStyle::Theme(index); + reloadStylePreview(); + } +} + +void SettingsDialog::on_preview_url_textChanged(const QString &) +{ + this->reloadStylePreview(); +} + +void SettingsDialog::on_page_margin_valueChanged(double value) +{ + this->current_style.margin = value; + this->reloadStylePreview(); +} + +void SettingsDialog::on_presets_currentIndexChanged(int index) +{ + this->ui->preset_load->setEnabled(index >= 0); + this->ui->preset_save->setEnabled(index >= 0); + this->ui->preset_export->setEnabled(index >= 0); +} + +void SettingsDialog::on_preset_new_clicked() +{ + QInputDialog dlg { this }; + dlg.setInputMode(QInputDialog::TextInput); + dlg.setOkButtonText("Save"); + dlg.setCancelButtonText("Cancel"); + dlg.setLabelText("Enter the name of your new preset:"); + + if(dlg.exec() != QInputDialog::Accepted) + return; + QString name = dlg.textValue(); + + bool override = false; + if(this->predefined_styles.contains(name)) + { + auto response = QMessageBox::question(this, "Kristall", QString("A style with the name '%1' already exists! Replace?").arg(name)); + if(response != QMessageBox::Yes) + return; + override = true; + } + + this->predefined_styles.insert(name, this->current_style); + + if(not override) + { + this->ui->presets->addItem(name); + } +} + +void SettingsDialog::on_preset_save_clicked() +{ + QString name = this->ui->presets->currentText(); + if(name.isEmpty()) + return; + + auto response = QMessageBox::question(this, "Kristall", QString("Do you want to override the style '%1'?").arg(name)); + if(response != QMessageBox::Yes) + return; + + this->predefined_styles.insert(name, this->current_style); +} + + +void SettingsDialog::on_preset_load_clicked() +{ + QString name = this->ui->presets->currentText(); + if(name.isEmpty()) + return; + + auto response = QMessageBox::question(this, "Kristall", QString("Do you want to load the style '%1'?\r\nThis will discard all currently set up values!").arg(name)); + if(response != QMessageBox::Yes) + return; + + this->setGeminiStyle(this->predefined_styles.value(name)); +} + + +void SettingsDialog::on_SettingsDialog_accepted() +{ + global_settings.beginWriteArray("Themes", this->predefined_styles.size()); + + int index = 0; + for(auto const & style_name : this->predefined_styles.keys()) + { + global_settings.setArrayIndex(index); + + global_settings.setValue("name", style_name); + this->predefined_styles.value(style_name).save(global_settings); + + index += 1; + } + global_settings.endArray(); +} + +void SettingsDialog::on_preset_import_clicked() +{ + QFileDialog dialog { this }; + dialog.setAcceptMode(QFileDialog::AcceptOpen); + dialog.selectNameFilter("Kristall Theme (*.kthm)"); + + if(dialog.exec() !=QFileDialog::Accepted) + return; + + QString fileName = dialog.selectedFiles().at(0); + + QSettings import_settings { fileName, QSettings::IniFormat }; + + QString name; + + name = import_settings.value("name").toString(); + + while(name.isEmpty()) + { + QInputDialog dlg { this }; + dlg.setInputMode(QInputDialog::TextInput); + dlg.setOkButtonText("Save"); + dlg.setCancelButtonText("Cancel"); + dlg.setLabelText("Imported preset has no name.\r\nPlease enter a name for the preset:"); + if(dlg.exec() != QDialog::Accepted) + return; + name = dlg.textValue(); + } + + bool override = false; + if(this->predefined_styles.contains(name)) + { + auto response = QMessageBox::question(this, "Kristall", QString("Do you want to override the style '%1'?").arg(name)); + if(response != QMessageBox::Yes) + return; + override = true; + } + + DocumentStyle style; + style.load(import_settings); + + this->predefined_styles.insert(name, style); + + if(not override) + { + this->ui->presets->addItem(name); + } +} + +void SettingsDialog::on_preset_export_clicked() +{ + QString name = this->ui->presets->currentText(); + if(name.isEmpty()) + return; + + QFileDialog dialog { this }; + dialog.setAcceptMode(QFileDialog::AcceptSave); + dialog.selectNameFilter("Kristall Theme (*.kthm)"); + dialog.selectFile(QString("%1.kthm").arg(name)); + + if(dialog.exec() !=QFileDialog::Accepted) + return; + + QString fileName = dialog.selectedFiles().at(0); + + QSettings export_settings { fileName, QSettings::IniFormat }; + export_settings.setValue("name", name); + this->predefined_styles.value(name).save(export_settings); + export_settings.sync(); +} + +void SettingsDialog::on_start_page_textChanged(const QString &start_page) +{ + this->current_options.start_page = start_page; +} + +void SettingsDialog::on_ui_theme_currentIndexChanged(int index) +{ + this->current_options.theme = Theme(this->ui->ui_theme->itemData(index).toInt()); +} + +void SettingsDialog::on_fancypants_on_clicked() +{ + this->current_options.text_display = GenericSettings::FormattedText; +} + +void SettingsDialog::on_fancypants_off_clicked() +{ + this->current_options.text_display = GenericSettings::PlainText; +} + +void SettingsDialog::on_texthl_on_clicked() +{ + this->current_options.enable_text_decoration = true; +} + +void SettingsDialog::on_texthl_off_clicked() +{ + this->current_options.enable_text_decoration = false; +} + +void SettingsDialog::on_gophermap_icon_clicked() +{ + this->current_options.gophermap_display = GenericSettings::FormattedText; +} + +void SettingsDialog::on_gophermap_text_clicked() +{ + this->current_options.gophermap_display = GenericSettings::PlainText; +} + +void SettingsDialog::on_scheme_os_default_clicked() +{ + this->current_options.use_os_scheme_handler = true; +} + +void SettingsDialog::on_scheme_error_clicked() +{ + this->current_options.use_os_scheme_handler = false; +} + +void SettingsDialog::on_redirection_mode_currentIndexChanged(int index) +{ + this->current_options.redirection_policy = GenericSettings::RedirectionWarning(this->ui->redirection_mode->itemData(index).toInt()); +} + +void SettingsDialog::on_max_redirects_valueChanged(int max_redirections) +{ + this->current_options.max_redirections = max_redirections; +} + +void SettingsDialog::on_network_timeout_valueChanged(int timeout) +{ + this->current_options.network_timeout = timeout; +} diff --git a/src/dialogs/settingsdialog.hpp b/src/dialogs/settingsdialog.hpp new file mode 100644 index 0000000..045b861 --- /dev/null +++ b/src/dialogs/settingsdialog.hpp @@ -0,0 +1,143 @@ +#ifndef SETTINGSDIALOG_HPP +#define SETTINGSDIALOG_HPP + +#include + +#include "renderers/geminirenderer.hpp" +#include "protocolsetup.hpp" +#include "documentstyle.hpp" +#include "ssltrust.hpp" +#include "kristall.hpp" + +namespace Ui { +class SettingsDialog; +} + +class SettingsDialog : public QDialog +{ + Q_OBJECT + +public: + explicit SettingsDialog(QWidget *parent = nullptr); + ~SettingsDialog(); + + void setGeminiStyle(DocumentStyle const & style); + + DocumentStyle geminiStyle() const { + return current_style; + } + + ProtocolSetup protocols() const; + void setProtocols(ProtocolSetup const & proto); + + SslTrust geminiSslTrust() const; + void setGeminiSslTrust(SslTrust const & trust); + + SslTrust httpsSslTrust() const; + void setHttpsSslTrust(SslTrust const & trust); + + GenericSettings options() const; + void setOptions(GenericSettings const & options); + +private slots: + void on_std_change_font_clicked(); + + void on_pre_change_font_clicked(); + + void on_h1_change_font_clicked(); + + void on_h2_change_font_clicked(); + + void on_h3_change_font_clicked(); + + void on_std_change_color_clicked(); + + void on_pre_change_color_clicked(); + + void on_h1_change_color_clicked(); + + void on_h2_change_color_clicked(); + + void on_h3_change_color_clicked(); + + void on_bg_change_color_clicked(); + + void on_link_local_change_color_clicked(); + + void on_link_foreign_change_color_clicked(); + + void on_link_cross_change_color_clicked(); + + void on_link_local_prefix_textChanged(const QString &arg1); + + void on_link_foreign_prefix_textChanged(const QString &arg1); + + void on_auto_theme_currentIndexChanged(int index); + + void on_preview_url_textChanged(const QString &arg1); + + void on_page_margin_valueChanged(double arg1); + + void on_presets_currentIndexChanged(int index); + + void on_preset_new_clicked(); + + void on_SettingsDialog_accepted(); + + void on_quote_change_color_clicked(); + + void on_preset_save_clicked(); + + void on_preset_load_clicked(); + + void on_preset_import_clicked(); + + void on_preset_export_clicked(); + + void on_start_page_textChanged(const QString &arg1); + + void on_ui_theme_currentIndexChanged(int index); + + void on_fancypants_on_clicked(); + + void on_fancypants_off_clicked(); + + void on_texthl_on_clicked(); + + void on_texthl_off_clicked(); + + void on_gophermap_icon_clicked(); + + void on_gophermap_text_clicked(); + + void on_scheme_os_default_clicked(); + + void on_scheme_error_clicked(); + + void on_redirection_mode_currentIndexChanged(int index); + + void on_max_redirects_valueChanged(int arg1); + + void on_network_timeout_valueChanged(int arg1); + +private: + void reloadStylePreview(); + + void updateFont(QFont & input); + + void updateColor(QColor & input); + +private: + Ui::SettingsDialog *ui; + + DocumentStyle current_style; + std::unique_ptr preview_document; + + QMap predefined_styles; + + SslTrust current_trust; + + GenericSettings current_options; +}; + +#endif // SETTINGSDIALOG_HPP diff --git a/src/dialogs/settingsdialog.ui b/src/dialogs/settingsdialog.ui new file mode 100644 index 0000000..9acbca6 --- /dev/null +++ b/src/dialogs/settingsdialog.ui @@ -0,0 +1,940 @@ + + + SettingsDialog + + + + 0 + 0 + 850 + 650 + + + + Settings + + + + .. + + + + + + 2 + + + + + .. + + + Generic + + + + + + UI Theme + + + + + + + + + + Start Page: + + + + + + + about://blank + + + + + + + Enabled Protocols + + + + + + + + + Gemini + + + + + + + true + + + Gopher + + + + + + + true + + + Finger + + + + + + + HTTP + + + + + + + HTTPS + + + + + + + + + Text Rendering + + + + + + + + + Fancy + + + true + + + textRenderingBtnGroup + + + + + + + Always plain text + + + textRenderingBtnGroup + + + + + + + + + Enable text highlights + + + + + + + + + On (Experimental) + + + textHighlightsBtnGroup + + + + + + + Off + + + true + + + textHighlightsBtnGroup + + + + + + + + + Gopher Map + + + + + + + + + Use icons + + + true + + + gophermapBtnGroup + + + + + + + Use text only + + + gophermapBtnGroup + + + + + + + + + Unknown Scheme + + + + + + + + + Use OS default handler + + + buttonGroup + + + + + + + Display error message + + + buttonGroup + + + + + + + + + Max. Number of Redirections + + + + + + + 5 + + + + + + + Redirection Handling + + + + + + + + + + Network Timeout + + + + + + + ms + + + 100 + + + 90000 + + + + + + + + + .. + + + Style + + + + + + 5 + + + + + + + + + + Qt::PlainText + + + + + + + + + + + .. + + + + + + + + + Background Color + + + + + + + Standard Font + + + + + + + + + QFrame::NoFrame + + + This text will be displayed for normal text. + + + + + + + + + + + .. + + + + + + + + + + + .. + + + + + + + + + Preformatted Font + + + + + + + + + QFrame::NoFrame + + + This text will be displayed for preformatted text. + + + + + + + + + + + .. + + + + + + + + + + + .. + + + + + + + + + H1 Font + + + + + + + + + QFrame::NoFrame + + + This text will be displayed for a level 1 heading. + + + + + + + + + + + .. + + + + + + + + + + + .. + + + + + + + + + H2 Font + + + + + + + + + QFrame::NoFrame + + + This text will be displayed for a level 2 heading. + + + + + + + + + + + .. + + + + + + + + + + + .. + + + + + + + + + H3 Font + + + + + + + + + border: 1px solid black; + + + QFrame::NoFrame + + + This text will be displayed for a level 3 heading. + + + Qt::PlainText + + + + + + + + + + + .. + + + + + + + + + + + .. + + + + + + + + + Local Link Color + + + + + + + Foreign Link Color + + + + + + + Cross-Scheme-Color + + + + + + + Local Link Prefix + + + + + + + Extern Link Prefix + + + + + + + + + + + + + + + + + + + + + + + This is a local reference + + + Qt::PlainText + + + + + + + + + + + .. + + + + + + + + + + + This is a foreign reference + + + Qt::PlainText + + + + + + + + + + + .. + + + + + + + + + + + This reference is cross-scheme + + + Qt::PlainText + + + + + + + + + + + .. + + + + + + + + + Auto-Theme Generation + + + + + + + + + + Page Margin + + + + + + + px + + + 0 + + + 350.000000000000000 + + + + + + + + + + + + Save as new preset + + + ... + + + + .. + + + + + + + Override current preset + + + ... + + + + .. + + + + + + + Load preset + + + ... + + + + .. + + + + + + + Imports preset… + + + -1 + + + ... + + + + .. + + + + + + + Export preset… + + + ... + + + + .. + + + + + + + + + Presets + + + + + + + Block Quote Background + + + + + + + + + + + + + + + + ... + + + + .. + + + + + + + + + + + + + false + + + + + + + host.name + + + + + + + + + + + .. + + + Gemini TLS + + + + + + + + + + + .. + + + HTTPS TLS + + + + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + SslTrustEditor + QWidget +
widgets/ssltrusteditor.hpp
+ 1 +
+
+ + + + buttonBox + rejected() + SettingsDialog + reject() + + + 325 + 470 + + + 286 + 274 + + + + + buttonBox + accepted() + SettingsDialog + accept() + + + 257 + 470 + + + 157 + 274 + + + + + + + + + + +
-- cgit v1.2.3