diff options
| author | Felix (xq) Queißner <git@mq32.de> | 2020-06-07 01:06:07 +0200 |
|---|---|---|
| committer | Felix (xq) Queißner <git@mq32.de> | 2020-06-07 01:06:07 +0200 |
| commit | 093bfcc50d5889358ed806096ac5652a9e925cfc (patch) | |
| tree | f0276f86cf9b14309851b9d3136c370503ecea64 /src | |
| parent | d4d353dab0f7c2fe2e1d76f6666f848e077d07dd (diff) | |
| download | kristall-093bfcc50d5889358ed806096ac5652a9e925cfc.tar.gz | |
Implements multi-protocol support. Adds support for HTTP/HTTPS, adds settings to enable/disable protocols
Diffstat (limited to 'src')
| -rw-r--r-- | src/browsertab.cpp | 40 | ||||
| -rw-r--r-- | src/browsertab.hpp | 7 | ||||
| -rw-r--r-- | src/kristall.pro | 8 | ||||
| -rw-r--r-- | src/mainwindow.cpp | 8 | ||||
| -rw-r--r-- | src/mainwindow.hpp | 2 | ||||
| -rw-r--r-- | src/protocolsetup.cpp | 42 | ||||
| -rw-r--r-- | src/protocolsetup.hpp | 28 | ||||
| -rw-r--r-- | src/settingsdialog.cpp | 20 | ||||
| -rw-r--r-- | src/settingsdialog.hpp | 5 | ||||
| -rw-r--r-- | src/settingsdialog.ui | 65 | ||||
| -rw-r--r-- | src/webclient.cpp | 78 | ||||
| -rw-r--r-- | src/webclient.hpp | 38 |
12 files changed, 323 insertions, 18 deletions
diff --git a/src/browsertab.cpp b/src/browsertab.cpp index 5f58704..8dcbe64 100644 --- a/src/browsertab.cpp +++ b/src/browsertab.cpp @@ -25,7 +25,10 @@ BrowserTab::BrowserTab(MainWindow * mainWindow) : { ui->setupUi(this); - connect(&gemini_client, &GeminiClient::requestComplete, this, &BrowserTab::on_gemini_complete); + connect(&web_client, &WebClient::requestComplete, this, &BrowserTab::on_requestComplete); + connect(&web_client, &WebClient::requestFailed, this, &BrowserTab::on_requestFailed); + + connect(&gemini_client, &GeminiClient::requestComplete, this, &BrowserTab::on_requestComplete); connect(&gemini_client, &GeminiClient::protocolViolation, this, &BrowserTab::on_protocolViolation); connect(&gemini_client, &GeminiClient::inputRequired, this, &BrowserTab::on_inputRequired); connect(&gemini_client, &GeminiClient::redirected, this, &BrowserTab::on_redirected); @@ -50,8 +53,8 @@ BrowserTab::~BrowserTab() void BrowserTab::navigateTo(const QUrl &url, PushToHistory mode) { - // TODO: Implement about:// scheme! - if(url.scheme() != "gemini" and url.scheme() != "about") { + if(not mainWindow->protocols.isSchemeSupported(url.scheme())) + { QMessageBox::warning(this, "Kristall", "Unsupported uri scheme: " + url.scheme()); return; } @@ -60,17 +63,27 @@ void BrowserTab::navigateTo(const QUrl &url, PushToHistory mode) this->ui->url_bar->setText(url.toString()); if(not gemini_client.cancelRequest()) { - QMessageBox::warning(this, "Kristall", "Unsupported uri scheme: " + url.scheme()); + QMessageBox::warning(this, "Kristall", "Failed to cancel running gemini request!"); return; } + if(not web_client.cancelRequest()) { + QMessageBox::warning(this, "Kristall", "Failed to cancel running web request!"); + return; + } + + this->redirection_count = 0; + this->successfully_loaded = false; + this->push_to_history_after_load = (mode == PushAfterSuccess); + if(url.scheme() == "gemini") { - this->redirection_count = 0; - this->successfully_loaded = false; - this->push_to_history_after_load = (mode == PushAfterSuccess); gemini_client.startRequest(url); } + else if(url.scheme() == "http" or url.scheme() == "https") + { + web_client.startRequest(url); + } else if(url.scheme() == "about") { this->redirection_count = 0; @@ -80,7 +93,7 @@ void BrowserTab::navigateTo(const QUrl &url, PushToHistory mode) mode = PushImmediate; if(url.path() == "blank") { - this->on_gemini_complete("", "text/gemini"); + this->on_requestComplete("", "text/gemini"); } else if(url.path() == "favourites") { @@ -94,7 +107,7 @@ void BrowserTab::navigateTo(const QUrl &url, PushToHistory mode) document.append("=> " + fav.toString().toUtf8() + "\n"); } - this->on_gemini_complete(document, "text/gemini"); + this->on_requestComplete(document, "text/gemini"); } else { @@ -165,7 +178,12 @@ void BrowserTab::on_refresh_button_clicked() reloadPage(); } -void BrowserTab::on_gemini_complete(const QByteArray &data, const QString &mime) +void BrowserTab::on_requestFailed(const QString &reason) +{ + this->setErrorMessage(QString("Request failed:\n%1").arg(reason)); +} + +void BrowserTab::on_requestComplete(const QByteArray &data, const QString &mime) { qDebug() << "Loaded" << data.length() << "bytes of type" << mime; @@ -394,7 +412,7 @@ void BrowserTab::on_text_browser_anchorClicked(const QUrl &url) if(real_url.isRelative()) real_url = this->current_location.resolved(url); - if(real_url.scheme() != "gemini") { + if(not mainWindow->protocols.isSchemeSupported(real_url.scheme())) { QMessageBox::warning(this, "Kristall", QString("Unsupported url: %1").arg(real_url.toString())); } else { diff --git a/src/browsertab.hpp b/src/browsertab.hpp index 7f0ac35..655d14e 100644 --- a/src/browsertab.hpp +++ b/src/browsertab.hpp @@ -5,11 +5,13 @@ #include <QUrl> #include <QGraphicsScene> #include <QTextDocument> +#include <QNetworkAccessManager> #include "geminiclient.hpp" #include "documentoutlinemodel.hpp" #include "tabbrowsinghistory.hpp" #include "geminirenderer.hpp" +#include "webclient.hpp" namespace Ui { class BrowserTab; @@ -52,7 +54,9 @@ private slots: void on_refresh_button_clicked(); - void on_gemini_complete(QByteArray const & data, QString const & mime); + void on_requestComplete(QByteArray const & data, QString const & mime); + + void on_requestFailed(QString const & reason); void on_protocolViolation(QString const & reason); @@ -98,6 +102,7 @@ public: QUrl current_location; GeminiClient gemini_client; + WebClient web_client; int redirection_count = 0; bool push_to_history_after_load = false; diff --git a/src/kristall.pro b/src/kristall.pro index 6aa5f60..1d2e190 100644 --- a/src/kristall.pro +++ b/src/kristall.pro @@ -23,8 +23,10 @@ SOURCES += \ geminirenderer.cpp \ main.cpp \ mainwindow.cpp \ + protocolsetup.cpp \ settingsdialog.cpp \ - tabbrowsinghistory.cpp + tabbrowsinghistory.cpp \ + webclient.cpp HEADERS += \ browsertab.hpp \ @@ -33,8 +35,10 @@ HEADERS += \ geminiclient.hpp \ geminirenderer.hpp \ mainwindow.hpp \ + protocolsetup.hpp \ settingsdialog.hpp \ - tabbrowsinghistory.hpp + tabbrowsinghistory.hpp \ + webclient.hpp FORMS += \ browsertab.ui \ diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 00f3311..cf12877 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -24,6 +24,7 @@ MainWindow::MainWindow(QWidget *parent) : this->favourites.load(settings); this->current_style.load(settings); + this->protocols.load(settings); ui->favourites_view->setModel(&favourites); @@ -49,7 +50,6 @@ MainWindow::MainWindow(QWidget *parent) : } }); - { settings.beginGroup("Window State"); if(settings.contains("geometry")) { @@ -113,6 +113,7 @@ void MainWindow::saveSettings() { this->favourites.save(settings); this->current_style.save(settings); + this->protocols.save(settings); { settings.beginGroup("Window State"); @@ -122,6 +123,8 @@ void MainWindow::saveSettings() settings.endGroup(); } + + settings.sync(); } void MainWindow::on_browser_tabs_currentChanged(int index) @@ -201,8 +204,8 @@ void MainWindow::on_actionSettings_triggered() SettingsDialog dialog; dialog.setGeminiStyle(this->current_style); - dialog.setStartPage(this->settings.value("start_page").toString()); + dialog.setProtocols(this->protocols); if(dialog.exec() != QDialog::Accepted) return; @@ -211,6 +214,7 @@ void MainWindow::on_actionSettings_triggered() this->settings.setValue("start_page", url.toString()); } + this->protocols = dialog.protocols(); this->current_style = dialog.geminiStyle(); this->saveSettings(); } diff --git a/src/mainwindow.hpp b/src/mainwindow.hpp index 95b096d..e207128 100644 --- a/src/mainwindow.hpp +++ b/src/mainwindow.hpp @@ -8,6 +8,7 @@ #include "favouritecollection.hpp" #include "geminirenderer.hpp" +#include "protocolsetup.hpp" QT_BEGIN_NAMESPACE namespace Ui { class MainWindow; } @@ -69,6 +70,7 @@ private slots: public: QSettings settings; GeminiStyle current_style; + ProtocolSetup protocols; private: Ui::MainWindow *ui; diff --git a/src/protocolsetup.cpp b/src/protocolsetup.cpp new file mode 100644 index 0000000..bbecfa0 --- /dev/null +++ b/src/protocolsetup.cpp @@ -0,0 +1,42 @@ +#include "protocolsetup.hpp" + +ProtocolSetup::ProtocolSetup() +{ +#define MAC(X) this->X = false; + PROTOCOLS(MAC) +#undef MAC + + this->gemini = true; +} + +void ProtocolSetup::save(QSettings &settings) const +{ + settings.beginGroup("Protocols"); +#define MAC(X) settings.setValue(#X, this->X); + PROTOCOLS(MAC) +#undef MAC + settings.endGroup(); +} + +void ProtocolSetup::load(QSettings &settings) +{ + settings.beginGroup("Protocols"); +#define MAC(X) if(settings.contains(#X)) this->X = settings.value(#X).toBool(); + PROTOCOLS(MAC) +#undef MAC + settings.endGroup(); +} + +bool ProtocolSetup::isSchemeSupported(QString const & _scheme) const +{ + auto scheme = _scheme.toLower(); + +#define MAC(X) if(scheme == #X) return this->X; + PROTOCOLS(MAC) +#undef MAC + + // built-in schemes: + if(scheme == "about") return true; + + return false; +} diff --git a/src/protocolsetup.hpp b/src/protocolsetup.hpp new file mode 100644 index 0000000..3cf3ab1 --- /dev/null +++ b/src/protocolsetup.hpp @@ -0,0 +1,28 @@ +#ifndef PROTOCOLSETUP_HPP +#define PROTOCOLSETUP_HPP + +#include <QSettings> + +#define PROTOCOLS(MAC) \ + MAC(http) \ + MAC(https) \ + MAC(gopher) \ + MAC(gemini) \ + MAC(finger) + +struct ProtocolSetup +{ +#define DECL(X) bool X; + PROTOCOLS(DECL) +#undef DECL + + ProtocolSetup(); + + void save(QSettings & settings) const; + + void load(QSettings & settings); + + bool isSchemeSupported(QString const & scheme) const; +}; + +#endif // PROTOCOLSETUP_HPP diff --git a/src/settingsdialog.cpp b/src/settingsdialog.cpp index 33042d5..27a1c12 100644 --- a/src/settingsdialog.cpp +++ b/src/settingsdialog.cpp @@ -99,6 +99,24 @@ void SettingsDialog::setStartPage(const QUrl &url) this->ui->start_page->setText(url.toString()); } +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 +} + void SettingsDialog::reloadStylePreview() { auto const document = R"gemini(# H1 Header @@ -253,7 +271,7 @@ void SettingsDialog::on_auto_theme_currentIndexChanged(int index) } } -void SettingsDialog::on_preview_url_textChanged(const QString &arg1) +void SettingsDialog::on_preview_url_textChanged(const QString &) { this->reloadStylePreview(); } diff --git a/src/settingsdialog.hpp b/src/settingsdialog.hpp index 9df4085..cc51c96 100644 --- a/src/settingsdialog.hpp +++ b/src/settingsdialog.hpp @@ -4,6 +4,7 @@ #include <QDialog> #include "geminirenderer.hpp" +#include "protocolsetup.hpp" namespace Ui { class SettingsDialog; @@ -24,9 +25,11 @@ public: } QUrl startPage() const; - void setStartPage(QUrl const & url); + ProtocolSetup protocols() const; + void setProtocols(ProtocolSetup const & proto); + private slots: void on_std_change_font_clicked(); diff --git a/src/settingsdialog.ui b/src/settingsdialog.ui index b4cc9d6..a26ae70 100644 --- a/src/settingsdialog.ui +++ b/src/settingsdialog.ui @@ -38,6 +38,71 @@ </property> </widget> </item> + <item row="1" column="0"> + <widget class="QLabel" name="label_16"> + <property name="text"> + <string>Enabled Protocols</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QCheckBox" name="enable_gemini"> + <property name="text"> + <string>Gemini</string> + </property> + </widget> + </item> + <item> + <widget class="QCheckBox" name="enable_gopher"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>Gopher</string> + </property> + </widget> + </item> + <item> + <widget class="QCheckBox" name="enable_finger"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>Finger</string> + </property> + </widget> + </item> + <item> + <widget class="QCheckBox" name="enable_http"> + <property name="text"> + <string>HTTP</string> + </property> + </widget> + </item> + <item> + <widget class="QCheckBox" name="enable_https"> + <property name="text"> + <string>HTTPS</string> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> </layout> </widget> <widget class="QWidget" name="style_tab"> diff --git a/src/webclient.cpp b/src/webclient.cpp new file mode 100644 index 0000000..6e9b5ab --- /dev/null +++ b/src/webclient.cpp @@ -0,0 +1,78 @@ +#include "webclient.hpp" + +#include <QNetworkRequest> +#include <QNetworkReply> + +WebClient::WebClient(QObject *parent) : + QObject(parent), + current_reply(nullptr) +{ + manager.setRedirectPolicy(QNetworkRequest::NoLessSafeRedirectPolicy); +} + +WebClient::~WebClient() +{ + +} + +bool WebClient::startRequest(const QUrl &url) +{ + if(this->current_reply != nullptr) + return true; + + this->body.clear(); + + QNetworkRequest request(url); + request.setMaximumRedirectsAllowed(5); + request.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true); + + this->current_reply = manager.get(request); + if(this->current_reply == nullptr) + return false; + + connect(this->current_reply, &QNetworkReply::readyRead, this, &WebClient::on_data); + connect(this->current_reply, &QNetworkReply::finished, this, &WebClient::on_finished); + + return true; +} + +bool WebClient::isInProgress() const +{ + return (this->current_reply != nullptr); +} + +bool WebClient::cancelRequest() +{ + if(this->current_reply != nullptr) + { + this->current_reply->abort(); + this->current_reply = nullptr; + } + this->body.clear(); + return true; +} + +void WebClient::on_data() +{ + this->body.append(this->current_reply->readAll()); +} + +void WebClient::on_finished() +{ + if(this->current_reply->error() != QNetworkReply::NoError) + { + emit this->requestFailed(this->current_reply->errorString()); + } + else + { + auto mime = this->current_reply->header(QNetworkRequest::ContentTypeHeader).toString(); + + qDebug() << this->current_reply->url() << mime; + + emit this->requestComplete(this->body, mime); + + this->body.clear(); + } + this->current_reply->deleteLater(); + this->current_reply = nullptr; +} diff --git a/src/webclient.hpp b/src/webclient.hpp new file mode 100644 index 0000000..bc7c13b --- /dev/null +++ b/src/webclient.hpp @@ -0,0 +1,38 @@ +#ifndef WEBCLIENT_HPP +#define WEBCLIENT_HPP + +#include <QObject> +#include <QNetworkAccessManager> + +class WebClient: public QObject +{ +private: + Q_OBJECT +public: + explicit WebClient(QObject *parent = nullptr); + + ~WebClient() override; + + bool startRequest(QUrl const & url); + + bool isInProgress() const; + + bool cancelRequest(); + +signals: + void requestComplete(QByteArray const & data, QString const & mime); + + void requestFailed(QString const & message); + +private slots: + void on_data(); + void on_finished(); + +private: + QNetworkAccessManager manager; + QNetworkReply * current_reply; + + QByteArray body; +}; + +#endif // WEBCLIENT_HPP |
