kristall/src/mainwindow.cpp

399 lines
11 KiB
C++

#include "mainwindow.hpp"
#include "ui_mainwindow.h"
#include "browsertab.hpp"
#include "settingsdialog.hpp"
#include <cassert>
#include <QMessageBox>
#include <memory>
#include <QShortcut>
#include <QKeySequence>
#include <QFile>
#include <QTextStream>
#include <QFileDialog>
#include "ioutil.hpp"
#include "kristall.hpp"
MainWindow::MainWindow(QApplication * app, QWidget *parent) :
QMainWindow(parent),
application(app),
ui(new Ui::MainWindow),
url_status(new QLabel(this)),
file_size(new QLabel(this)),
file_mime(new QLabel(this)),
load_time(new QLabel(this))
{
ui->setupUi(this);
this->statusBar()->addWidget(this->url_status);
this->statusBar()->addPermanentWidget(this->file_mime);
this->statusBar()->addPermanentWidget(this->file_size);
this->statusBar()->addPermanentWidget(this->load_time);
this->favourites.load(global_settings);
this->current_style.load(global_settings);
this->protocols.load(global_settings);
ui->favourites_view->setModel(&favourites);
this->ui->outline_window->setVisible(false);
this->ui->history_window->setVisible(false);
this->ui->clientcert_window->setVisible(false);
this->ui->bookmarks_window->setVisible(false);
for(QDockWidget * dock : findChildren<QDockWidget *>())
{
QAction * act = this->ui->menuView ->addAction(dock->windowTitle());
act->setCheckable(true);
act->setChecked(dock->isVisible());
act->setData(QVariant::fromValue(dock));
connect(act, QOverload<bool>::of(&QAction::triggered), dock, &QDockWidget::setVisible);
}
connect(this->ui->menuNavigation, &QMenu::aboutToShow, [this]() {
BrowserTab * tab = qobject_cast<BrowserTab*>(this->ui->browser_tabs->currentWidget());
if(tab != nullptr) {
ui->actionAdd_to_favourites->setChecked(this->favourites.contains(tab->current_location));
}
});
connect(this->ui->menuView, &QMenu::aboutToShow, [this]() {
for(QAction * act : this->ui->menuView->actions())
{
auto * dock = qvariant_cast<QDockWidget*>(act->data());
act->setChecked(dock->isVisible());
}
});
{
QShortcut * sc = new QShortcut(QKeySequence("Ctrl+L"), this);
connect(sc, &QShortcut::activated, this, &MainWindow::on_focus_inputbar);
}
{
global_settings.beginGroup("Window State");
if(global_settings.contains("geometry")) {
restoreGeometry(global_settings.value("geometry").toByteArray());
}
if(global_settings.contains("state")) {
restoreState(global_settings.value("state").toByteArray());
}
global_settings.endGroup();
}
reloadTheme();
}
MainWindow::~MainWindow()
{
this->saveSettings();
delete ui;
}
BrowserTab * MainWindow::addEmptyTab(bool focus_new, bool load_default)
{
BrowserTab * tab = new BrowserTab(this);
connect(tab, &BrowserTab::titleChanged, this, &MainWindow::on_tab_titleChanged);
connect(tab, &BrowserTab::fileLoaded, this, &MainWindow::on_tab_fileLoaded);
int index = this->ui->browser_tabs->addTab(tab, "Page");
if(focus_new) {
this->ui->browser_tabs->setCurrentIndex(index);
}
if(load_default) {
tab->navigateTo(QUrl(global_settings.value("start_page").toString()), BrowserTab::DontPush);
}
return tab;
}
BrowserTab * MainWindow::addNewTab(bool focus_new, QUrl const & url)
{
auto tab = addEmptyTab(focus_new, false);
tab->navigateTo(url, BrowserTab::PushImmediate);
return tab;
}
void MainWindow::setUrlPreview(const QUrl &url)
{
if(url.isValid()) {
auto str = url.toString();
if(str.length() > 300) {
str = str.mid(0, 300) + "...";
}
this->url_status->setText(str);
}
else {
this->url_status->setText("");
}
}
void MainWindow::saveSettings()
{
this->favourites.save(global_settings);
this->current_style.save(global_settings);
this->protocols.save(global_settings);
{
global_settings.beginGroup("Window State");
global_settings.setValue("geometry", saveGeometry());
global_settings.setValue("state", saveState());
global_settings.endGroup();
}
global_settings.sync();
}
void MainWindow::on_browser_tabs_currentChanged(int index)
{
if(index >= 0) {
BrowserTab * tab = qobject_cast<BrowserTab*>(this->ui->browser_tabs->widget(index));
if(tab != nullptr) {
this->ui->outline_view->setModel(&tab->outline);
this->ui->outline_view->expandAll();
this->ui->history_view->setModel(&tab->history);
} else {
this->ui->outline_view->setModel(nullptr);
this->ui->history_view->setModel(nullptr);
}
} else {
this->ui->outline_view->setModel(nullptr);
this->ui->history_view->setModel(nullptr);
}
}
void MainWindow::on_favourites_view_doubleClicked(const QModelIndex &index)
{
if(auto url = this->favourites.get(index); url.isValid()) {
this->addNewTab(true, url);
}
}
void MainWindow::on_browser_tabs_tabCloseRequested(int index)
{
delete this->ui->browser_tabs->widget(index);
}
void MainWindow::on_history_view_doubleClicked(const QModelIndex &index)
{
BrowserTab * tab = qobject_cast<BrowserTab*>(this->ui->browser_tabs->currentWidget());
if(tab != nullptr) {
tab->navigateBack(index);
}
}
void MainWindow::on_tab_titleChanged(const QString &title)
{
auto * tab = qobject_cast<BrowserTab*>(sender());
if(tab != nullptr) {
int index = this->ui->browser_tabs->indexOf(tab);
assert(index >= 0);
this->ui->browser_tabs->setTabText(index, title);
}
}
void MainWindow::on_tab_locationChanged(const QUrl &url)
{
auto * tab = qobject_cast<BrowserTab*>(sender());
if(tab != nullptr) {
int index = this->ui->browser_tabs->indexOf(tab);
assert(index >= 0);
this->ui->browser_tabs->setTabToolTip(index, url.toString());
}
}
void MainWindow::on_outline_view_clicked(const QModelIndex &index)
{
BrowserTab * tab = qobject_cast<BrowserTab*>(this->ui->browser_tabs->currentWidget());
if(tab != nullptr) {
auto anchor = tab->outline.getAnchor(index);
if(not anchor.isEmpty()) {
tab->scrollToAnchor(anchor);
}
}
}
void MainWindow::on_actionSettings_triggered()
{
SettingsDialog dialog;
dialog.setGeminiStyle(this->current_style);
dialog.setStartPage(global_settings.value("start_page").toString());
dialog.setProtocols(this->protocols);
dialog.setUiTheme(global_settings.value("theme").toString());
if(dialog.exec() != QDialog::Accepted)
return;
if(auto url = dialog.startPage(); url.isValid()) {
global_settings.setValue("start_page", url.toString());
}
global_settings.setValue("theme", dialog.uiTheme());
this->protocols = dialog.protocols();
this->current_style = dialog.geminiStyle();
this->saveSettings();
this->reloadTheme();
}
void MainWindow::on_actionNew_Tab_triggered()
{
this->addEmptyTab(true, true);
}
void MainWindow::on_actionQuit_triggered()
{
QApplication::quit();
}
void MainWindow::on_actionAbout_triggered()
{
QMessageBox::about(this,
"Kristall",
R"about(Kristall, an OpenSource Gemini browser.
Made by Felix "xq" Queißner
This is free software. You can get the source code at
https://github.com/MasterQ32/Kristall)about"
);
}
void MainWindow::on_actionClose_Tab_triggered()
{
BrowserTab * tab = qobject_cast<BrowserTab*>(this->ui->browser_tabs->currentWidget());
if(tab != nullptr) {
delete tab;
}
}
void MainWindow::on_actionForward_triggered()
{
BrowserTab * tab = qobject_cast<BrowserTab*>(this->ui->browser_tabs->currentWidget());
if(tab != nullptr) {
tab->navOneForward();
}
}
void MainWindow::on_actionBackward_triggered()
{
BrowserTab * tab = qobject_cast<BrowserTab*>(this->ui->browser_tabs->currentWidget());
if(tab != nullptr) {
tab->navOneBackback();
}
}
void MainWindow::on_actionRefresh_triggered()
{
BrowserTab * tab = qobject_cast<BrowserTab*>(this->ui->browser_tabs->currentWidget());
if(tab != nullptr) {
tab->reloadPage();
}
}
void MainWindow::on_actionAbout_Qt_triggered()
{
QMessageBox::aboutQt(this, "Kristall");
}
void MainWindow::reloadTheme()
{
QString theme = global_settings.value("theme").toString();
if(theme.isEmpty())
theme = "light";
if(theme == "light")
{
QFile file(":/light.qss");
file.open(QFile::ReadOnly | QFile::Text);
QTextStream stream(&file);
application->setStyleSheet(stream.readAll());
}
else if(theme == "dark")
{
QFile file(":/dark.qss");
file.open(QFile::ReadOnly | QFile::Text);
QTextStream stream(&file);
application->setStyleSheet(stream.readAll());
}
}
void MainWindow::on_actionSave_as_triggered()
{
BrowserTab * tab = qobject_cast<BrowserTab*>(this->ui->browser_tabs->currentWidget());
if(tab != nullptr) {
QFileDialog dialog { this };
dialog.setAcceptMode(QFileDialog::AcceptSave);
dialog.selectFile(tab->current_location.fileName());
if(dialog.exec() !=QFileDialog::Accepted)
return;
QString fileName = dialog.selectedFiles().at(0);
QFile file { fileName };
if(file.open(QFile::WriteOnly))
{
IoUtil::writeAll(file, tab->current_buffer);
}
else
{
QMessageBox::warning(this, "Kristall", QString("Could not save file:\r\n%1").arg(file.errorString()));
}
}
}
void MainWindow::on_actionGo_to_home_triggered()
{
BrowserTab * tab = qobject_cast<BrowserTab*>(this->ui->browser_tabs->currentWidget());
if(tab != nullptr) {
tab->navigateTo(QUrl(global_settings.value("start_page").toString()), BrowserTab::PushAfterSuccess);
}
}
void MainWindow::on_actionAdd_to_favourites_triggered()
{
BrowserTab * tab = qobject_cast<BrowserTab*>(this->ui->browser_tabs->currentWidget());
if(tab != nullptr) {
tab->toggleIsFavourite();
}
}
void MainWindow::on_tab_fileLoaded(qint64 fileSize, const QString &mime, int msec)
{
auto * tab = qobject_cast<BrowserTab*>(sender());
if(tab != nullptr) {
int index = this->ui->browser_tabs->indexOf(tab);
assert(index >= 0);
if(index == this->ui->browser_tabs->currentIndex()) {
this->file_size->setText(IoUtil::size_human(fileSize));
this->file_mime->setText(mime);
this->load_time->setText(QString("%1 ms").arg(msec));
}
}
}
void MainWindow::on_focus_inputbar()
{
BrowserTab * tab = qobject_cast<BrowserTab*>(this->ui->browser_tabs->currentWidget());
if(tab != nullptr) {
tab->focusUrlBar();
}
}
void MainWindow::on_actionHelp_triggered()
{
this->addNewTab(true, QUrl("about:help"));
}