860 lines
24 KiB
C++
860 lines
24 KiB
C++
#include "mainwindow.hpp"
|
|
#include "ui_mainwindow.h"
|
|
#include "browsertab.hpp"
|
|
#include "dialogs/settingsdialog.hpp"
|
|
#include <cassert>
|
|
#include <QMessageBox>
|
|
#include <memory>
|
|
#include <QShortcut>
|
|
#include <QKeySequence>
|
|
#include <QFile>
|
|
#include <QTextStream>
|
|
#include <QFileDialog>
|
|
#include <QInputDialog>
|
|
#include <QMouseEvent>
|
|
|
|
#include "ioutil.hpp"
|
|
#include "kristall.hpp"
|
|
#include "widgets/browsertabbar.hpp"
|
|
|
|
#include "dialogs/certificatemanagementdialog.hpp"
|
|
|
|
MainWindow::MainWindow(QApplication * app, QWidget *parent) :
|
|
QMainWindow(parent),
|
|
application(app),
|
|
ui(new Ui::MainWindow),
|
|
url_status(new ElideLabel(this)),
|
|
file_size(new QLabel(this)),
|
|
file_cached(new QLabel(this)),
|
|
file_mime(new QLabel(this)),
|
|
load_time(new QLabel(this))
|
|
{
|
|
this->setAttribute(Qt::WA_DeleteOnClose);
|
|
|
|
ui->setupUi(this);
|
|
|
|
connect( // connect with "this" as context, so the connection will die when the window is destroyed
|
|
kristall::globals().localization.get(), &Localization::translationChanged,
|
|
this, [this]() { this->ui->retranslateUi(this); },
|
|
Qt::DirectConnection
|
|
);
|
|
|
|
this->url_status->setElideMode(Qt::ElideMiddle);
|
|
|
|
this->statusBar()->addWidget(this->url_status);
|
|
this->statusBar()->addPermanentWidget(this->file_cached);
|
|
this->statusBar()->addPermanentWidget(this->file_mime);
|
|
this->statusBar()->addPermanentWidget(this->file_size);
|
|
this->statusBar()->addPermanentWidget(this->load_time);
|
|
|
|
ui->favourites_view->setModel(&kristall::globals().favourites);
|
|
|
|
this->ui->outline_window->setVisible(false);
|
|
this->ui->history_window->setVisible(false);
|
|
this->ui->bookmarks_window->setVisible(false);
|
|
|
|
for(QDockWidget * dock : findChildren<QDockWidget *>())
|
|
{
|
|
QAction * act = dock->toggleViewAction();
|
|
act->setShortcut(dock->property("_shortcut").toString());
|
|
// act->setIcon(dock->windowIcon());
|
|
|
|
this->ui->menuView->addAction(act);
|
|
}
|
|
|
|
connect(this->ui->menuNavigation, &QMenu::aboutToShow, [this]() {
|
|
BrowserTab * tab = this->curTab();
|
|
if(tab != nullptr) {
|
|
ui->actionAdd_to_favourites->setChecked(kristall::globals().favourites.containsUrl(tab->current_location));
|
|
}
|
|
});
|
|
|
|
connect(this->ui->menuView, &QMenu::aboutToShow, [this]() {
|
|
for(QAction * act : this->ui->menuView->actions())
|
|
{
|
|
auto * dock = qvariant_cast<QDockWidget*>(act->data());
|
|
if(dock != nullptr) {
|
|
act->setChecked(dock->isVisible());
|
|
}
|
|
}
|
|
});
|
|
|
|
{
|
|
QShortcut * sc = new QShortcut(QKeySequence("Ctrl+L"), this);
|
|
connect(sc, &QShortcut::activated, this, &MainWindow::on_focus_inputbar);
|
|
}
|
|
|
|
{
|
|
std::string prefix = "Alt+";
|
|
for (char tab = '0'; tab <= '9'; ++tab) {
|
|
std::string shortcut = prefix + tab;
|
|
QShortcut * sc = new QShortcut(QKeySequence(shortcut.c_str()), this);
|
|
connect(sc, &QShortcut::activated, this, [this, tab]()
|
|
{
|
|
// 1-9 goes from the first to the n-th tab, 0 goes to the last one
|
|
setCurrentTabIndex((tab == '0'
|
|
? this->ui->browser_tabs->count()
|
|
: tab-'0') - 1);
|
|
});
|
|
}
|
|
}
|
|
|
|
{
|
|
QShortcut * sc = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_PageDown), this);
|
|
connect(sc, &QShortcut::activated, this, [this](){
|
|
int i = this->currentTabIndex();
|
|
|
|
if (i + 1 >= this->ui->browser_tabs->count())
|
|
i = 0;
|
|
else
|
|
i++;
|
|
|
|
this->setCurrentTabIndex(i);
|
|
});
|
|
}
|
|
|
|
{
|
|
QShortcut * sc = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_PageUp), this);
|
|
connect(sc, &QShortcut::activated, this, [this](){
|
|
int i = this->currentTabIndex();
|
|
|
|
if (!i)
|
|
i = this->ui->browser_tabs->count() - 1;
|
|
else
|
|
i--;
|
|
|
|
this->setCurrentTabIndex(i);
|
|
});
|
|
}
|
|
|
|
this->ui->favourites_view->setContextMenuPolicy(Qt::CustomContextMenu);
|
|
this->ui->history_view->setContextMenuPolicy(Qt::CustomContextMenu);
|
|
|
|
connect(this->ui->browser_tabs->tab_bar, &BrowserTabBar::on_newTabClicked, this, [this]() {
|
|
this->addEmptyTab(true, true);
|
|
});
|
|
|
|
kristall::registerAppWindow(this);
|
|
}
|
|
|
|
MainWindow::~MainWindow()
|
|
{
|
|
delete ui;
|
|
}
|
|
|
|
BrowserTab * MainWindow::addEmptyTab(bool focus_new, bool load_default)
|
|
{
|
|
BrowserTab * tab = new BrowserTab(this);
|
|
|
|
connect(tab, &BrowserTab::destroyed, this, &MainWindow::on_tab_closed);
|
|
connect(tab, &BrowserTab::titleChanged, this, &MainWindow::on_tab_titleChanged);
|
|
connect(tab, &BrowserTab::fileLoaded, this, &MainWindow::on_tab_fileLoaded);
|
|
connect(tab, &BrowserTab::requestStateChanged, this, &MainWindow::on_tab_requestStateChanged);
|
|
|
|
int index = this->ui->browser_tabs->addTab(tab, "Page");
|
|
|
|
if(focus_new) {
|
|
this->setCurrentTabIndex(index);
|
|
}
|
|
|
|
if(load_default) {
|
|
tab->navigateTo(QUrl(kristall::globals().options.start_page), BrowserTab::PushImmediate);
|
|
tab->focusUrlBar();
|
|
} else {
|
|
tab->navigateTo(QUrl("about:blank"), BrowserTab::DontPush);
|
|
}
|
|
|
|
return tab;
|
|
}
|
|
|
|
BrowserTab * MainWindow::addNewTab(bool focus_new, QUrl const & url, bool lazyload, QString defaultTitle)
|
|
{
|
|
auto tab = addEmptyTab(focus_new, false);
|
|
|
|
if (lazyload)
|
|
{
|
|
tab->current_location = url;
|
|
tab->lazy_loading = true;
|
|
}
|
|
|
|
tab->navigateTo(url, BrowserTab::PushImmediate);
|
|
|
|
if (!defaultTitle.isEmpty())
|
|
{
|
|
tab->page_title = defaultTitle;
|
|
emit tab->titleChanged(defaultTitle);
|
|
}
|
|
|
|
return tab;
|
|
}
|
|
|
|
BrowserTab * MainWindow::curTab() const
|
|
{
|
|
// Was getting irritated writing this out all the time
|
|
return qobject_cast<BrowserTab*>(this->ui->browser_tabs->currentWidget());
|
|
}
|
|
|
|
BrowserTab * MainWindow::tabAt(int index) const
|
|
{
|
|
return qobject_cast<BrowserTab*>(this->ui->browser_tabs->widget(index));
|
|
}
|
|
|
|
int MainWindow::tabCount() const
|
|
{
|
|
return this->ui->browser_tabs->count();
|
|
}
|
|
|
|
void MainWindow::setUrlPreview(const QUrl &url)
|
|
{
|
|
if(url.isValid()) {
|
|
auto str = url.toString();
|
|
if(str.length() > 300) {
|
|
str = str.mid(0, 300) + "...";
|
|
}
|
|
this->previewing_url = true;
|
|
this->url_status->setText(str);
|
|
return;
|
|
}
|
|
|
|
this->previewing_url = false;
|
|
this->url_status->setText(this->request_status);
|
|
}
|
|
|
|
void MainWindow::setRequestState(RequestState state)
|
|
{
|
|
switch (state)
|
|
{
|
|
case RequestState::Started:
|
|
{
|
|
this->request_status = tr("Looking up...");
|
|
} break;
|
|
|
|
case RequestState::StartedWeb:
|
|
{
|
|
this->request_status = tr("Loading webpage...");
|
|
} break;
|
|
|
|
case RequestState::HostFound:
|
|
{
|
|
this->request_status = tr("Connecting...");
|
|
} break;
|
|
|
|
case RequestState::Connected:
|
|
{
|
|
this->request_status = tr("Downloading...");
|
|
} break;
|
|
|
|
default:
|
|
{
|
|
this->request_status = "";
|
|
} break;
|
|
}
|
|
|
|
if (!this->previewing_url)
|
|
this->url_status->setText(this->request_status);
|
|
}
|
|
|
|
void MainWindow::viewPageSource()
|
|
{
|
|
BrowserTab * tab = this->curTab();
|
|
if(tab != nullptr) {
|
|
tab->openSourceView();
|
|
}
|
|
}
|
|
|
|
void MainWindow::updateWindowTitle()
|
|
{
|
|
BrowserTab * tab = this->curTab();
|
|
if (tab == nullptr || tab->page_title.isEmpty())
|
|
{
|
|
this->setWindowTitle(tr("Kristall"));
|
|
return;
|
|
}
|
|
this->setWindowTitle(tr("%0 - %1").arg(tab->page_title, tr("Kristall")));
|
|
}
|
|
|
|
void MainWindow::setUiDensity(UIDensity density, bool previewing)
|
|
{
|
|
// If we are previewing, we only update the current tab.
|
|
// If not, we update all tabs as it means user accepted the settings
|
|
// dialog.
|
|
|
|
if (previewing)
|
|
{
|
|
if (not this->curTab())
|
|
return;
|
|
this->curTab()->setUiDensity(density);
|
|
}
|
|
else
|
|
{
|
|
for (int i = 0; i < this->ui->browser_tabs->count(); ++i)
|
|
this->tabAt(i)->setUiDensity(density);
|
|
}
|
|
}
|
|
|
|
QString MainWindow::newGroupDialog()
|
|
{
|
|
QInputDialog dialog { this };
|
|
|
|
dialog.setInputMode(QInputDialog::TextInput);
|
|
dialog.setLabelText(tr("Enter name of the new group:"));
|
|
|
|
if(dialog.exec() != QDialog::Accepted)
|
|
return QString { };
|
|
|
|
kristall::globals().favourites.addGroup(dialog.textValue());
|
|
|
|
return dialog.textValue();
|
|
}
|
|
|
|
void MainWindow::applySettings()
|
|
{
|
|
// Flag open tabs for re-render so theme
|
|
// changes are instantly applied.
|
|
for (int i = 0; i < this->ui->browser_tabs->count(); ++i)
|
|
{
|
|
BrowserTab *t = this->tabAt(i);
|
|
t->refreshOptionalToolbarItems();
|
|
t->refreshToolbarIcons();
|
|
t->needs_rerender = true;
|
|
}
|
|
|
|
// Re-render the currently-open tab if we have one.
|
|
BrowserTab * tab = this->curTab();
|
|
if (tab)
|
|
tab->rerenderPage();
|
|
|
|
// Update new-tab button visibility.
|
|
this->ui->browser_tabs->tab_bar->new_tab_btn->setVisible(kristall::globals().options.enable_newtab_btn);
|
|
}
|
|
|
|
int MainWindow::currentTabIndex()
|
|
{
|
|
return this->ui->browser_tabs->currentIndex();
|
|
}
|
|
|
|
void MainWindow::setCurrentTabIndex(int index)
|
|
{
|
|
this->ui->browser_tabs->setCurrentIndex(index);
|
|
}
|
|
|
|
|
|
void MainWindow::mousePressEvent(QMouseEvent *event)
|
|
{
|
|
QMainWindow::mousePressEvent(event);
|
|
|
|
BrowserTab * tab = this->curTab();
|
|
if (tab == nullptr) return;
|
|
|
|
// Navigate back/forward on mouse buttons 4/5
|
|
if (event->buttons() == Qt::ForwardButton &&
|
|
tab->history.oneForward(tab->current_history_index).isValid())
|
|
{
|
|
tab->navOneForward();
|
|
}
|
|
else if (event->buttons() == Qt::BackButton &&
|
|
tab->history.oneBackward(tab->current_history_index).isValid())
|
|
{
|
|
tab->navOneBackward();
|
|
}
|
|
}
|
|
|
|
void MainWindow::closeEvent(QCloseEvent *event)
|
|
{
|
|
if(kristall::getWindowCount() == 1) {
|
|
kristall::saveSession();
|
|
}
|
|
event->accept();
|
|
}
|
|
|
|
void MainWindow::on_tab_closed()
|
|
{
|
|
// If the user wants, we close the window together with the last tab.
|
|
// tabCount() might be 1 here, as the tab is still counted as "open"
|
|
if(kristall::globals().options.close_window_with_last_tab and (this->tabCount() <= 1))
|
|
{
|
|
this->close();
|
|
}
|
|
}
|
|
|
|
void MainWindow::on_browser_tabs_currentChanged(int index)
|
|
{
|
|
if(index >= 0) {
|
|
BrowserTab * tab = this->tabAt(index);
|
|
|
|
if(tab != nullptr) {
|
|
this->ui->outline_view->setModel(&tab->outline);
|
|
this->ui->outline_view->expandAll();
|
|
|
|
this->ui->history_view->setModel(&tab->history);
|
|
|
|
this->setFileStatus(tab->current_stats);
|
|
|
|
if (tab->needs_rerender)
|
|
{
|
|
tab->rerenderPage();
|
|
}
|
|
else
|
|
{
|
|
tab->refreshFavButton();
|
|
}
|
|
|
|
if (tab->lazy_loading)
|
|
{
|
|
tab->reloadPage();
|
|
}
|
|
|
|
this->setRequestState(tab->request_state);
|
|
} else {
|
|
this->ui->outline_view->setModel(nullptr);
|
|
this->ui->history_view->setModel(nullptr);
|
|
this->setFileStatus(DocumentStats { });
|
|
this->setRequestState(RequestState::None);
|
|
}
|
|
} else {
|
|
this->ui->outline_view->setModel(nullptr);
|
|
this->ui->history_view->setModel(nullptr);
|
|
this->setFileStatus(DocumentStats { });
|
|
this->setRequestState(RequestState::None);
|
|
}
|
|
updateWindowTitle();
|
|
}
|
|
|
|
void MainWindow::on_browser_tabs_tabCloseRequested(int index)
|
|
{
|
|
delete tabAt(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);
|
|
|
|
QString escapedTitle = title;
|
|
|
|
// Set the window title to full title
|
|
if (tab == this->curTab())
|
|
{
|
|
updateWindowTitle();
|
|
}
|
|
|
|
// Set tooltip
|
|
this->ui->browser_tabs->tab_bar->setTabToolTip(index, title);
|
|
|
|
// Shorten lengthy titles for tab bar (45 chars max for now - we assume
|
|
// that Gemini surfers don't usually have loads of tabs open, so the
|
|
// limit is fairly high)
|
|
const int MAX_TITLE_LEN = 45;
|
|
if (escapedTitle.length() > MAX_TITLE_LEN)
|
|
{
|
|
escapedTitle = escapedTitle.mid(0, MAX_TITLE_LEN - 3).trimmed() + "...";
|
|
}
|
|
|
|
this->ui->browser_tabs->setTabText(index, escapedTitle.replace("&", "&&"));
|
|
}
|
|
}
|
|
|
|
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 = this->curTab();
|
|
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(kristall::globals().document_style);
|
|
dialog.setProtocols(kristall::globals().protocols);
|
|
dialog.setOptions(kristall::globals().options);
|
|
dialog.setGeminiSslTrust(kristall::globals().trust.gemini);
|
|
dialog.setHttpsSslTrust(kristall::globals().trust.https);
|
|
dialog.setLocale(kristall::globals().localization->locale);
|
|
|
|
if(dialog.exec() != QDialog::Accepted) {
|
|
kristall::setTheme(kristall::globals().options.theme);
|
|
kristall::globals().localization->setLocale(kristall::globals().localization->locale);
|
|
this->setUiDensity(kristall::globals().options.ui_density, false);
|
|
return;
|
|
}
|
|
|
|
kristall::globals().localization->setLocale(dialog.locale());
|
|
|
|
kristall::globals().trust.gemini = dialog.geminiSslTrust();
|
|
kristall::globals().trust.https = dialog.httpsSslTrust();
|
|
kristall::globals().options = dialog.options();
|
|
|
|
kristall::globals().protocols = dialog.protocols();
|
|
kristall::globals().document_style = dialog.geminiStyle();
|
|
|
|
kristall::saveLocale();
|
|
kristall::applySettings();
|
|
|
|
kristall::saveSettings();
|
|
}
|
|
|
|
void MainWindow::on_actionNew_Tab_triggered()
|
|
{
|
|
this->addEmptyTab(true, true);
|
|
}
|
|
|
|
void MainWindow::on_actionQuit_triggered()
|
|
{
|
|
kristall::saveSession();
|
|
QApplication::quit();
|
|
}
|
|
|
|
void MainWindow::on_actionAbout_triggered()
|
|
{
|
|
QMessageBox::about(this,
|
|
tr("Kristall"),
|
|
tr(R"about(Kristall %1
|
|
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").arg(QApplication::applicationVersion())
|
|
);
|
|
}
|
|
|
|
void MainWindow::on_actionClose_Tab_triggered()
|
|
{
|
|
BrowserTab * tab = this->curTab();
|
|
if(tab != nullptr) {
|
|
delete tab;
|
|
}
|
|
}
|
|
|
|
void MainWindow::on_actionForward_triggered()
|
|
{
|
|
BrowserTab * tab = this->curTab();
|
|
if(tab != nullptr) {
|
|
tab->navOneForward();
|
|
}
|
|
}
|
|
|
|
void MainWindow::on_actionBackward_triggered()
|
|
{
|
|
BrowserTab * tab = this->curTab();
|
|
if(tab != nullptr) {
|
|
tab->navOneBackward();
|
|
}
|
|
}
|
|
|
|
void MainWindow::on_actionRoot_triggered()
|
|
{
|
|
BrowserTab * tab = this->curTab();
|
|
if(tab != nullptr) {
|
|
tab->navigateToRoot();
|
|
}
|
|
}
|
|
|
|
void MainWindow::on_actionParent_triggered()
|
|
{
|
|
BrowserTab * tab = this->curTab();
|
|
if(tab != nullptr) {
|
|
tab->navigateToParent();
|
|
}
|
|
}
|
|
|
|
void MainWindow::on_actionRefresh_triggered()
|
|
{
|
|
BrowserTab * tab = this->curTab();
|
|
if(tab != nullptr) {
|
|
tab->reloadPage();
|
|
}
|
|
}
|
|
|
|
void MainWindow::on_actionAbout_Qt_triggered()
|
|
{
|
|
QMessageBox::aboutQt(this, "Kristall");
|
|
}
|
|
|
|
void MainWindow::setFileStatus(const DocumentStats &stats)
|
|
{
|
|
if(stats.isValid()) {
|
|
this->file_size->setText(IoUtil::size_human(stats.file_size));
|
|
this->file_cached->setText(stats.loaded_from_cache ? tr("(cached)") : "");
|
|
this->file_mime->setText(stats.mime_type.toString(false));
|
|
this->load_time->setText(tr("%1 ms").arg(stats.loading_time));
|
|
} else {
|
|
this->file_size->setText("");
|
|
this->file_cached->setText("");
|
|
this->file_mime->setText("");
|
|
this->load_time->setText("");
|
|
}
|
|
}
|
|
|
|
void MainWindow::on_actionSave_as_triggered()
|
|
{
|
|
BrowserTab * tab = this->curTab();
|
|
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, tr("Kristall"), QString("Could not save file:\r\n%1").arg(file.errorString()));
|
|
}
|
|
}
|
|
}
|
|
|
|
void MainWindow::on_actionGo_to_home_triggered()
|
|
{
|
|
BrowserTab * tab = this->curTab();
|
|
if(tab != nullptr) {
|
|
tab->navigateTo(QUrl(kristall::globals().options.start_page), BrowserTab::PushImmediate);
|
|
}
|
|
}
|
|
|
|
void MainWindow::on_actionAdd_to_favourites_triggered()
|
|
{
|
|
BrowserTab * tab = this->curTab();
|
|
if(tab != nullptr) {
|
|
tab->showFavouritesPopup();
|
|
}
|
|
}
|
|
|
|
void MainWindow::on_tab_fileLoaded(DocumentStats const & stats)
|
|
{
|
|
auto * tab = qobject_cast<BrowserTab*>(sender());
|
|
if(tab != nullptr) {
|
|
int index = this->ui->browser_tabs->indexOf(tab);
|
|
assert(index >= 0);
|
|
if(index == this->currentTabIndex()) {
|
|
setFileStatus(stats);
|
|
this->ui->outline_view->expandAll();
|
|
}
|
|
}
|
|
}
|
|
|
|
void MainWindow::on_tab_requestStateChanged(RequestState state)
|
|
{
|
|
auto * tab = qobject_cast<BrowserTab*>(sender());
|
|
if(tab != nullptr) {
|
|
int index = this->ui->browser_tabs->indexOf(tab);
|
|
assert(index >= 0);
|
|
if(index == this->currentTabIndex()) {
|
|
setRequestState(state);
|
|
}
|
|
}
|
|
}
|
|
|
|
void MainWindow::on_focus_inputbar()
|
|
{
|
|
BrowserTab * tab = this->curTab();
|
|
if(tab != nullptr) {
|
|
tab->focusUrlBar();
|
|
}
|
|
}
|
|
|
|
void MainWindow::on_actionHelp_triggered()
|
|
{
|
|
this->addNewTab(true, QUrl("about:help"));
|
|
}
|
|
|
|
void MainWindow::on_history_view_customContextMenuRequested(const QPoint pos)
|
|
{
|
|
if(auto idx = this->ui->history_view->indexAt(pos); idx.isValid()) {
|
|
BrowserTab * tab = this->curTab();
|
|
if(tab != nullptr) {
|
|
if(QUrl url = tab->history.get(idx); url.isValid()) {
|
|
QMenu menu;
|
|
|
|
connect(menu.addAction(tr("Open here")), &QAction::triggered, [tab, idx]() {
|
|
// We do the same thing as a double click here
|
|
tab->navigateBack(idx);
|
|
});
|
|
|
|
connect(menu.addAction(tr("Open in new tab")), &QAction::triggered, [this, url]() {
|
|
addNewTab(true, url);
|
|
});
|
|
|
|
menu.exec(this->ui->history_view->mapToGlobal(pos));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void MainWindow::on_favourites_view_customContextMenuRequested(const QPoint pos)
|
|
{
|
|
if(auto idx = this->ui->favourites_view->indexAt(pos); idx.isValid()) {
|
|
if(QUrl url = kristall::globals().favourites.getFavourite(idx).destination; url.isValid()) {
|
|
QMenu menu;
|
|
|
|
BrowserTab * tab = this->curTab();
|
|
if(tab != nullptr) {
|
|
connect(menu.addAction(tr("Open here")), &QAction::triggered, [tab, url]() {
|
|
tab->navigateTo(url, BrowserTab::PushImmediate);
|
|
});
|
|
}
|
|
|
|
connect(menu.addAction(tr("Open in new tab")), &QAction::triggered, [this, url]() {
|
|
addNewTab(true, url);
|
|
});
|
|
|
|
menu.addSeparator();
|
|
|
|
connect(menu.addAction(tr("Relocate")), &QAction::triggered, [this, idx]() {
|
|
QInputDialog dialog { this };
|
|
|
|
dialog.setInputMode(QInputDialog::TextInput);
|
|
dialog.setLabelText(tr("Enter new location of this favourite:"));
|
|
dialog.setTextValue(kristall::globals().favourites.getFavourite(idx).destination.toString(QUrl::FullyEncoded));
|
|
|
|
if (dialog.exec() != QDialog::Accepted)
|
|
return;
|
|
|
|
kristall::globals().favourites.editFavouriteDest(idx, QUrl(dialog.textValue()));
|
|
});
|
|
|
|
connect(menu.addAction(tr("Rename")), &QAction::triggered, [this, idx]() {
|
|
QInputDialog dialog { this };
|
|
|
|
dialog.setInputMode(QInputDialog::TextInput);
|
|
dialog.setLabelText(tr("New name of this favourite:"));
|
|
dialog.setTextValue(kristall::globals().favourites.getFavourite(idx).getTitle());
|
|
|
|
if (dialog.exec() != QDialog::Accepted)
|
|
return;
|
|
|
|
kristall::globals().favourites.editFavouriteTitle(idx, dialog.textValue());
|
|
});
|
|
|
|
menu.addSeparator();
|
|
|
|
connect(menu.addAction(tr("Delete")), &QAction::triggered, [idx]() {
|
|
kristall::globals().favourites.destroyFavourite(idx);
|
|
});
|
|
|
|
menu.exec(this->ui->favourites_view->mapToGlobal(pos));
|
|
}
|
|
else if(QString group = kristall::globals().favourites.group(idx); not group.isEmpty()) {
|
|
QMenu menu;
|
|
|
|
connect(menu.addAction(tr("Rename group")), &QAction::triggered, [this, group]() {
|
|
QInputDialog dialog { this };
|
|
|
|
dialog.setInputMode(QInputDialog::TextInput);
|
|
dialog.setLabelText(tr("New name of this group:"));
|
|
dialog.setTextValue(group);
|
|
|
|
if (dialog.exec() != QDialog::Accepted)
|
|
return;
|
|
|
|
if (!kristall::globals().favourites.renameGroup(group, dialog.textValue()))
|
|
QMessageBox::information(this, tr("Kristall"), tr("Rename failed: group name already in use."));
|
|
});
|
|
|
|
menu.addSeparator();
|
|
|
|
connect(menu.addAction(tr("Delete group")), &QAction::triggered, [this, idx]() {
|
|
if (QMessageBox::question(
|
|
this,
|
|
tr("Kristall"),
|
|
tr("Are you sure you want to delete this Favourite Group?\n"
|
|
"All favourites in this group will be lost.\n\n"
|
|
"This action cannot be undone!")
|
|
) != QMessageBox::Yes)
|
|
{
|
|
return;
|
|
}
|
|
kristall::globals().favourites.deleteGroupRecursive(kristall::globals().favourites.group(idx));
|
|
});
|
|
|
|
menu.exec(this->ui->favourites_view->mapToGlobal(pos));
|
|
}
|
|
}
|
|
else {
|
|
QMenu menu;
|
|
|
|
connect(menu.addAction(tr("Create new group...")), &QAction::triggered, [this]() {
|
|
this->newGroupDialog();
|
|
});
|
|
|
|
menu.exec(this->ui->favourites_view->mapToGlobal(pos));
|
|
}
|
|
}
|
|
|
|
void MainWindow::on_actionChangelog_triggered()
|
|
{
|
|
this->addNewTab(true, QUrl("about:updates"));
|
|
}
|
|
|
|
void MainWindow::on_actionManage_Certificates_triggered()
|
|
{
|
|
CertificateManagementDialog dialog { this };
|
|
|
|
dialog.setIdentitySet(kristall::globals().identities);
|
|
if(dialog.exec() != QDialog::Accepted)
|
|
return;
|
|
|
|
kristall::globals().identities = dialog.identitySet();
|
|
|
|
kristall::saveSettings();
|
|
}
|
|
|
|
void MainWindow::on_actionShow_document_source_triggered()
|
|
{
|
|
this->viewPageSource();
|
|
}
|
|
|
|
void MainWindow::on_actionNew_window_triggered()
|
|
{
|
|
kristall::openNewWindow(false);
|
|
}
|
|
|
|
void MainWindow::on_actionClose_Window_triggered()
|
|
{
|
|
this->close();
|
|
}
|
|
|
|
void MainWindow::on_favourites_view_activated(const QModelIndex &index)
|
|
{
|
|
if(auto url = kristall::globals().favourites.getFavourite(index).destination; url.isValid()) {
|
|
this->addNewTab(true, url);
|
|
}
|
|
}
|
|
|
|
void MainWindow::on_history_view_activated(const QModelIndex &index)
|
|
{
|
|
BrowserTab * tab = this->curTab();
|
|
if(tab != nullptr) {
|
|
tab->navigateBack(index);
|
|
}
|
|
}
|
|
|
|
void MainWindow::on_outline_view_activated(const QModelIndex &index)
|
|
{
|
|
this->on_outline_view_clicked(index);
|
|
}
|