aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorFelix (xq) Queißner <git@mq32.de>2020-06-07 01:06:07 +0200
committerFelix (xq) Queißner <git@mq32.de>2020-06-07 01:06:07 +0200
commit093bfcc50d5889358ed806096ac5652a9e925cfc (patch)
treef0276f86cf9b14309851b9d3136c370503ecea64 /src
parentd4d353dab0f7c2fe2e1d76f6666f848e077d07dd (diff)
downloadkristall-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.cpp40
-rw-r--r--src/browsertab.hpp7
-rw-r--r--src/kristall.pro8
-rw-r--r--src/mainwindow.cpp8
-rw-r--r--src/mainwindow.hpp2
-rw-r--r--src/protocolsetup.cpp42
-rw-r--r--src/protocolsetup.hpp28
-rw-r--r--src/settingsdialog.cpp20
-rw-r--r--src/settingsdialog.hpp5
-rw-r--r--src/settingsdialog.ui65
-rw-r--r--src/webclient.cpp78
-rw-r--r--src/webclient.hpp38
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