danbooru-client/src/mainwindow.cpp

351 lines
11 KiB
C++

/*
* Copyright 2015 Luca Beltrame <lbeltrame@kde.org>
*
* This file is part of Danbooru Client.
*
* Danbooru Client is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Danbooru Client is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Danbooru Client. If not, see <http://www.gnu.org/licenses/>.
*/
#include <KStatusBar>
#include <QAction>
#include <QQuickWidget>
#include <QQmlContext>
#include <QApplication>
#include <QGuiApplication>
#include <QStandardPaths>
#include <QUrl>
#include <QDebug>
#include <QDockWidget>
#include <QQuickItem>
#include <kactioncollection.h>
#include <KStandardAction>
#include <KLocalizedString>
#include <KDeclarative/KDeclarative>
#include <KConfigDialog>
#include <KToggleAction>
#include "libdanbooru/danbooruservice.h"
#include "libdanbooru/danboorupost.h"
#include "libdanbooru/danboorupool.h"
#include "model/danboorupostmodel.h"
#include "model/danboorupoolmodel.h"
#include "mainwindow.h"
#include "danbooruconnectwidget.h"
#include "danboorusearchwidget.h"
#include "danboorusettings.h"
#include "generalpage.h"
namespace Danbooru
{
QHash<int, DanbooruPost::Rating> DanbooruMainWindow::ratingMap = {
{0, DanbooruPost::Safe},
{1, DanbooruPost::Questionable},
{2, DanbooruPost::Explicit}
};
DanbooruMainWindow::DanbooruMainWindow(QWidget *parent)
: KXmlGuiWindow(parent),
m_view(new QQuickWidget(this)),
m_model(new DanbooruPostModel(this)),
m_poolModel(new DanbooruPoolModel(this)),
m_service(new DanbooruService()),
m_connectWidget(nullptr),
m_searchWidget(new DanbooruSearchWidget(this)),
m_tableView(new QTableView(this)),
m_cache(nullptr)
{
m_service->setParent(this);
setCentralWidget(m_view);
// QCoreApplication::setAttribute(Qt::AA_DontCreateNativeWidgetSiblings);
qmlRegisterType<Danbooru::DanbooruPost>("DanbooruClient", 1, 0, "DanbooruPost");
qmlRegisterType<Danbooru::DanbooruService>("DanbooruClient", 1, 0, "DanbooruService");
qRegisterMetaType<DanbooruPost::Rating>();
loadSettings();
// TODO Configurable
m_cache = new KImageCache(qApp->applicationName(), DanbooruSettings::self()->cacheSize());
m_service->setImageCache(m_cache);
// Set up declarative bindings for the QQuickWidget
m_view->setResizeMode(QQuickWidget::SizeRootObjectToView);
KDeclarative::KDeclarative declarative;
declarative.setDeclarativeEngine(m_view->engine());
declarative.setupBindings();
auto qmlViewPath = QStandardPaths::locate(QStandardPaths::GenericDataLocation,
qApp->applicationName() + QChar('/') + QLatin1Literal("danbooruimageview.qml"));
QQmlContext *ctxt = m_view->rootContext();
ctxt->setContextProperty("danbooruModel", m_model);
ctxt->setContextProperty("danbooruService", m_service);
m_view->setSource(QUrl::fromLocalFile(qmlViewPath));
m_view->rootObject()->setProperty("poolMode", QVariant(false));
QVector<QUrl> boardsList = { QUrl("http://konachan.com"), QUrl("https://yande.re") };
m_connectWidget = new DanbooruConnectWidget(boardsList, this);
statusBar()->addPermanentWidget(m_connectWidget);
m_connectWidget->hide();
setupDockWidgets();
// then, setup our actions
setupActions();
// add a status bar
statusBar()->show();
setupGUI(KXmlGuiWindow::ToolBar|Keys|Save|Create|StatusBar, "danbooru-clientui.rc");
// connections
connect(m_connectWidget, &DanbooruConnectWidget::accepted, [this]() {
m_service->setBoardUrl(m_connectWidget->boardUrl());
if (!m_connectWidget->isAnonymous() && !m_connectWidget->username().isEmpty()
&& !m_connectWidget->password().isEmpty()) {
m_service->setUserName(m_connectWidget->username());
m_service->setPassword(m_connectWidget->password());
}
actionCollection()->action(QLatin1String("fetch"))->setEnabled(true);
actionCollection()->action(QLatin1String("find"))->setEnabled(true);
actionCollection()->action(QLatin1String("poolDownload"))->setEnabled(true);
if (DanbooruSettings::self()->autoDownload()) {
m_view->rootObject()->setProperty("poolMode", QVariant(false));
m_service->setPostTags(QStringList());
m_service->getPostList();
}
m_connectWidget->hide();
});
connect(m_connectWidget, &DanbooruConnectWidget::rejected, [this]() {
m_connectWidget->hide();
});
connect(m_service, &Danbooru::DanbooruService::postDownloaded, m_model,
&Danbooru::DanbooruPostModel::addPost);
connect(m_service, &Danbooru::DanbooruService::poolDownloaded, m_poolModel,
&DanbooruPoolModel::addPool);
connect(m_service, &Danbooru::DanbooruService::poolDownloadFinished, [this]() {
m_tableView->resizeColumnsToContents();
}
);
connect(m_tableView, &QTableView::doubleClicked, [this](QModelIndex index) {
auto pool = m_poolModel->poolAt(index.row());
m_model->clear();
m_view->rootObject()->setProperty("poolMode", QVariant(true));
m_service->getPool(pool->id());
});
connect(m_searchWidget, &DanbooruSearchWidget::accepted, [this]() {
QDockWidget* searchDockWidget = findChild<QDockWidget*>(QLatin1String("SearchView"));
searchDockWidget->hide();
m_model->clear();
m_service->setPostTags(m_searchWidget->selectedTags());
m_view->rootObject()->setProperty("poolMode", QVariant(false));
m_service->getPostList();
});
connect(m_searchWidget, &DanbooruSearchWidget::rejected, [this]() {
QDockWidget* searchDockWidget = findChild<QDockWidget*>(QLatin1String("SearchView"));
searchDockWidget->hide();
});
}
DanbooruMainWindow::~DanbooruMainWindow()
{
}
void DanbooruMainWindow::loadSettings()
{
m_service->setBlacklist(DanbooruSettings::self()->tagBlacklist());
m_service->setMaxPosts(DanbooruSettings::self()->maxPosts());
m_service->setMaximumAllowedRating(ratingMap.value(DanbooruSettings::self()->maxRating()));
m_service->setMaxPosts(DanbooruSettings::self()->maxPosts());
}
void DanbooruMainWindow::setupActions()
{
QAction *connectAction = new QAction(
QIcon::fromTheme(QLatin1String("document-open-remote")),
i18n("Connect..."),
this);
QAction *fetchAction = new QAction(QIcon::fromTheme(QLatin1String("download")),
i18n("Download"), this);
KToggleAction *findAction = new KToggleAction(QIcon::fromTheme(QLatin1String("edit-find")),
i18n("Search"), this);
KToggleAction *poolAction = new KToggleAction(QIcon::fromTheme(QLatin1String("image-x-generic")),
i18n("Pools"), this);
fetchAction->setEnabled(false);
findAction->setEnabled(false);
poolAction->setEnabled(false);
poolAction->setChecked(false);
findAction->setChecked(false);
actionCollection()->addAction(QLatin1String("connect"), connectAction);
actionCollection()->addAction(QLatin1String("fetch"), fetchAction);
actionCollection()->addAction(QLatin1String("find"), findAction);
actionCollection()->addAction(QLatin1String("poolDownload"), poolAction);
actionCollection()->setDefaultShortcut(connectAction, KStandardShortcut::Open);
actionCollection()->setDefaultShortcut(findAction, KStandardShortcut::Find);
KStandardAction::quit(qApp, SLOT(quit()), actionCollection());
KStandardAction::preferences(this, SLOT(optionsPreferences()), actionCollection());
connect(connectAction, &QAction::triggered, this, &DanbooruMainWindow::connectToBoard);
connect(fetchAction, &QAction::triggered, this, &DanbooruMainWindow::downloadPosts);
connect(poolAction, &KToggleAction::toggled, [this](bool checked) {
if (!m_service) {
return;
}
QDockWidget* poolDockWidget = findChild<QDockWidget*>(QLatin1String("PoolView"));
if (checked) {
if (m_poolModel->rowCount() == 0) {
m_service->getPoolList();
}
poolDockWidget->show();
m_tableView->show();
} else {
poolDockWidget->hide();
m_tableView->hide();
}
});
connect(findAction, &KToggleAction::toggled, [this](bool checked) {
QDockWidget* searchDockWidget = findChild<QDockWidget*>(QLatin1String("SearchView"));
if (checked) {
searchDockWidget->show();
m_searchWidget->show();
} else {
searchDockWidget->hide();
m_searchWidget->hide();
}
});
}
void DanbooruMainWindow::setupDockWidgets() {
// Set up PoolWidget
m_tableView->setModel(m_poolModel);
QDockWidget* poolDockWidget = new QDockWidget(i18n("Pools"), this);
poolDockWidget->setAllowedAreas(Qt::BottomDockWidgetArea);
poolDockWidget->setWidget(m_tableView);
poolDockWidget->setObjectName("PoolView");
// Prevent the use of winId() when detached, leads to QQuickWidget bugs
poolDockWidget->setFeatures(QDockWidget::DockWidgetClosable);
addDockWidget(Qt::BottomDockWidgetArea, poolDockWidget);
m_tableView->hide();
poolDockWidget->hide();
// Find widget
QDockWidget *searchDockWidget = new QDockWidget(QLatin1String(""), this);
searchDockWidget->setAllowedAreas(Qt::TopDockWidgetArea);
searchDockWidget->setWidget(m_searchWidget);
searchDockWidget->setObjectName("SearchView");
// FIXME: Get rid of the close button in the widget
searchDockWidget->setFeatures(QDockWidget::NoDockWidgetFeatures);
addDockWidget(Qt::TopDockWidgetArea, searchDockWidget);
searchDockWidget->hide();
m_searchWidget->hide();
searchDockWidget->setTitleBarWidget(new QWidget(this));
// Connections
connect(poolDockWidget, &QDockWidget::visibilityChanged, [this](bool visible) {
actionCollection()->action(QLatin1String("poolDownload"))->setChecked(visible);
});
connect(searchDockWidget, &QDockWidget::visibilityChanged, [this](bool visible) {
actionCollection()->action(QLatin1String("find"))->setChecked(visible);
});
}
void DanbooruMainWindow::connectToBoard()
{
if (!m_view) {
return;
}
m_model->clear();
m_poolModel->clear();
m_service->reset();
m_connectWidget->show();
}
void DanbooruMainWindow::downloadPosts()
{
if (!m_service) {
return;
}
m_model->clear();
m_service->setPostTags(QStringList());
m_view->rootObject()->setProperty("poolMode", QVariant(false));
m_service->getPostList();
}
void DanbooruMainWindow::optionsPreferences()
{
KConfigDialog* dialog = new KConfigDialog(this, "danboorusettings",
DanbooruSettings::self());
dialog->addPage(new GeneralPage(DanbooruSettings::self(), this), i18n("General"),
"table");
connect(dialog, &KConfigDialog::settingsChanged, this, &DanbooruMainWindow::loadSettings);
dialog->show();
}
} // namespace Danbooru