/* * This file is part of smolbote. It's copyrighted by the contributors recorded * in the version control history of the file, available from its original * location: https://neueland.iserlohn-fortress.net/smolbote.hg * * SPDX-License-Identifier: GPL-3.0 */ #include "window.h" #include "webengine/webprofile.h" #include "webengine/webview.h" #include "widgets/tabwidget.h" #include #include #include #include #include #include #include #include #include "browser.h" Window::Window(const QHash &config, QWidget *parent, Qt::WindowFlags flags) : QMdiSubWindow(parent, flags) , tabWidget(new TabWidget(this)) { // delete this window when it closes setAttribute(Qt::WA_DeleteOnClose, true); resize(800, 600); setWidget(tabWidget); profile = WebProfile::defaultProfile(); { auto *menu = systemMenu(); menu->addSeparator(); auto *profileName_action = menu->addAction(tr("Profile: %1").arg(profile->isOffTheRecord() ? tr("off-the-record") : profile->storageName())); profileName_action->setEnabled(false); auto *loadProfile_menu = menu->addMenu(tr("Load profile")); Browser *instance = qobject_cast(qApp); Q_ASSERT_X(instance != nullptr, "Window::Window", "Could not cast instance"); for(const QString &name : instance->profiles()) { auto *loadAction = loadProfile_menu->addAction(name); connect(loadAction, &QAction::triggered, this, [name, instance, profileName_action, this]() { auto *profile = instance->profile(name); this->setProfile(profile); profileName_action->setText(tr("Profile: %1").arg(name)); }); } #ifdef QT_DEBUG menu->addSeparator(); menu->addAction(tr("Debug menu"))->setEnabled(false); auto *saveSession_action = menu->addAction(tr("Save session")); menu->addAction(tr("Load session"))->setEnabled(false); setSystemMenu(menu); connect(saveSession_action, &QAction::triggered, [this]() { QJsonDocument doc(session()); qDebug("%s", qUtf8Printable(doc.toJson())); }); #endif } // new tab button auto *newTab_button = new QToolButton(this); newTab_button->setIcon(style()->standardIcon(QStyle::SP_FileIcon)); newTab_button->setToolTip(tr("Add tab")); newTab_button->setShortcut(QKeySequence(config.value("window.shortcuts.new"))); connect(newTab_button, &QToolButton::clicked, this, [=]() { auto index = addTab(WebProfile::defaultProfile()->newtab()); tabWidget->setCurrentIndex(index); }); tabWidget->setCornerWidget(newTab_button, Qt::TopRightCorner); // general actions auto *closeTab_shortcut = new QShortcut(QKeySequence(config.value("window.shortcuts.close")), this); connect(closeTab_shortcut, &QShortcut::activated, this, [=]() { tabWidget->deleteTab(tabWidget->currentIndex()); }); auto *leftTab_shortcut = new QShortcut(QKeySequence(config.value("window.shortcuts.left")), this); connect(leftTab_shortcut, &QShortcut::activated, this, [=]() { tabWidget->setCurrentIndex(qMax(0, tabWidget->currentIndex() - 1)); }); auto *rightTab_shortcut = new QShortcut(QKeySequence(config.value("window.shortcuts.right")), this); connect(rightTab_shortcut, &QShortcut::activated, this, [=]() { tabWidget->setCurrentIndex(qMin(tabWidget->currentIndex() + 1, tabWidget->count() - 1)); }); connect(tabWidget, &TabWidget::currentChanged, [this](int index) { if(index < 0) { // last tab has been closed close(); } else { auto *view = dynamic_cast(tabWidget->widget(index)); Q_CHECK_PTR(view); disconnect(titleConnection); disconnect(linkHoveredConnection); connect(view, &WebView::titleChanged, this, &Window::setWindowTitle); setWindowTitle(view->title()); connect(view->page(), &WebPage::linkHovered, this, [this](const QString &url) { if(!url.isEmpty()) emit showStatusMessage(url, 3000); }); emit currentViewChanged(view); } }); } Window::~Window() { delete tabWidget; } void Window::setWindowTitle(const QString &title) { QMdiSubWindow::setWindowTitle(QString("%1 :%2").arg(title, profile->name())); } WebView *Window::currentView() { return qobject_cast(tabWidget->currentWidget()); } WebView *Window::view(int index) const { return qobject_cast(tabWidget->widget(index)); } void Window::setProfile(WebProfile *profile) { Q_ASSERT_X(profile != nullptr, "Window::setProfile", "Tried to set null profile"); this->profile = profile; for(int i = 0; i < tabWidget->count(); ++i) { auto *view = qobject_cast(tabWidget->widget(i)); const auto url = view->url(); view->setPage(new WebPage(profile, view)); view->load(url); } } int Window::addTab(const QUrl &url) { auto *view = new WebView(profile, this); if(!url.isEmpty()) view->load(url); return tabWidget->addTab(view); } void Window::swapToTab(int index) { tabWidget->setCurrentIndex(index); } QJsonObject Window::session() const { QJsonObject obj; obj.insert("profile", QJsonValue("")); QJsonArray tabs; for(int i = 0; i < tabWidget->count(); ++i) { auto *view = qobject_cast(tabWidget->widget(i)); if(view) { tabs.append(view->url().toString()); } } obj.insert("tabs", tabs); return obj; } void Window::restoreSession(const QJsonObject &sessionData) { Q_ASSERT_X(sessionData.value("profile") != QJsonValue::Undefined, "Window::restoreSession", "no profile in json"); auto *profile = WebProfile::defaultProfile(); Q_ASSERT_X(sessionData.value("tabs") != QJsonValue::Undefined, "Window::restoreSession", "no tabs in json"); const QJsonArray tabs = sessionData.value("tabs").toArray(); if(tabs.count() == 0) { // open a newtab auto *view = new WebView(profile, this); view->load(profile->newtab()); tabWidget->addTab(view); return; } for(const auto tab : tabs) { auto *view = new WebView(profile, this); view->load(QUrl::fromUserInput(tab.toString())); tabWidget->addTab(view); } }