351 lines
11 KiB
C++

// vim: set tabstop=4 shiftwidth=4 expandtab:
/*
Gwenview: an image viewer
Copyright 2008 Aurélien Gâteau <agateau@kde.org>
This program 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 2
of the License, or (at your option) any later version.
This program 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 this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Cambridge, MA 02110-1301, USA.
*/
// Self
#include "startmainpage.h"
#include <config-gwenview.h>
// Qt
#include <QListView>
#include <QMenu>
#ifdef GTK_WORKAROUND_BROKE_IN_KF5_PORT
#include <QPlastiqueStyle>
#endif
#include <QIcon>
#include <QStyledItemDelegate>
// KF
#include <KFilePlacesModel>
#include <KLocalizedString>
// Local
#include "gwenview_app_debug.h"
#include <gvcore.h>
#include <lib/dialogguard.h>
#include <lib/flowlayout.h>
#include <lib/gvdebug.h>
#include <lib/gwenviewconfig.h>
#include <lib/scrollerutils.h>
#include <lib/thumbnailprovider/thumbnailprovider.h>
#include <lib/thumbnailview/abstractthumbnailviewhelper.h>
#include <lib/thumbnailview/previewitemdelegate.h>
#include <ui_startmainpage.h>
#ifndef GWENVIEW_SEMANTICINFO_BACKEND_NONE
#include <lib/semanticinfo/tagmodel.h>
#endif
namespace Gwenview
{
class HistoryThumbnailViewHelper : public AbstractThumbnailViewHelper
{
public:
HistoryThumbnailViewHelper(QObject *parent)
: AbstractThumbnailViewHelper(parent)
{
}
void showContextMenu(QWidget *) override
{
}
void showMenuForUrlDroppedOnViewport(QWidget *, const QList<QUrl> &) override
{
}
void showMenuForUrlDroppedOnDir(QWidget *, const QList<QUrl> &, const QUrl &) override
{
}
};
struct StartMainPagePrivate : public Ui_StartMainPage {
StartMainPage *q = nullptr;
GvCore *mGvCore = nullptr;
KFilePlacesModel *mBookmarksModel = nullptr;
ThumbnailProvider *mRecentFilesThumbnailProvider = nullptr;
bool mSearchUiInitialized;
void setupSearchUi()
{
#ifdef GWENVIEW_SEMANTICINFO_BACKEND_BALOO
mTagView->setModel(TagModel::createAllTagsModel(mTagView, mGvCore->semanticInfoBackEnd()));
mTagView->show();
mTagLabel->hide();
#else
mTagView->hide();
mTagLabel->hide();
#endif
}
void updateHistoryTab()
{
mHistoryWidget->setVisible(GwenviewConfig::historyEnabled());
mHistoryDisabledLabel->setVisible(!GwenviewConfig::historyEnabled());
}
void setupHistoryView(ThumbnailView *view)
{
view->setThumbnailViewHelper(new HistoryThumbnailViewHelper(view));
auto delegate = new PreviewItemDelegate(view);
delegate->setContextBarActions(PreviewItemDelegate::NoAction);
delegate->setTextElideMode(Qt::ElideLeft);
view->setItemDelegate(delegate);
view->setThumbnailWidth(128);
view->setCreateThumbnailsForRemoteUrls(false);
QModelIndex index = view->model()->index(0, 0);
if (index.isValid()) {
view->setCurrentIndex(index);
}
}
};
static void initViewPalette(QAbstractItemView *view, const QColor &fgColor)
{
QWidget *viewport = view->viewport();
QPalette palette = viewport->palette();
palette.setColor(viewport->backgroundRole(), Qt::transparent);
palette.setColor(QPalette::WindowText, fgColor);
palette.setColor(QPalette::Text, fgColor);
// QListView uses QStyledItemDelegate, which uses the view palette for
// foreground color, while KFilePlacesView uses the viewport palette.
viewport->setPalette(palette);
view->setPalette(palette);
}
static bool styleIsGtkBased()
{
const char *name = QApplication::style()->metaObject()->className();
return qstrcmp(name, "QGtkStyle") == 0;
}
StartMainPage::StartMainPage(QWidget *parent, GvCore *gvCore)
: QFrame(parent)
, d(new StartMainPagePrivate)
{
d->mRecentFilesThumbnailProvider = nullptr;
d->q = this;
d->mGvCore = gvCore;
d->mSearchUiInitialized = false;
d->setupUi(this);
if (styleIsGtkBased()) {
#ifdef GTK_WORKAROUND_BROKE_IN_KF5_PORT
// Gtk-based styles do not apply the correct background color on tabs.
// As a workaround, use the Plastique style instead.
QStyle *fix = new QPlastiqueStyle();
fix->setParent(this);
d->mHistoryWidget->tabBar()->setStyle(fix);
d->mPlacesTagsWidget->tabBar()->setStyle(fix);
#endif
}
setFrameStyle(QFrame::NoFrame);
// Bookmark view
d->mBookmarksModel = new KFilePlacesModel(this);
d->mBookmarksView->setModel(d->mBookmarksModel);
d->mBookmarksView->setAutoResizeItemsEnabled(false);
connect(d->mBookmarksView, &KFilePlacesView::urlChanged, this, &StartMainPage::urlSelected);
// Tag view
connect(d->mTagView, &QListView::clicked, this, &StartMainPage::slotTagViewClicked);
// Recent folders view
connect(d->mRecentFoldersView, &Gwenview::ThumbnailView::indexActivated, this, &StartMainPage::slotListViewActivated);
connect(d->mRecentFoldersView, &Gwenview::ThumbnailView::customContextMenuRequested, this, &StartMainPage::showContextMenu);
// Recent files view
connect(d->mRecentFilesView, &Gwenview::ThumbnailView::indexActivated, this, &StartMainPage::slotListViewActivated);
connect(d->mRecentFilesView, &Gwenview::ThumbnailView::customContextMenuRequested, this, &StartMainPage::showContextMenu);
d->updateHistoryTab();
connect(GwenviewConfig::self(), &GwenviewConfig::configChanged, this, &StartMainPage::loadConfig);
connect(qApp, &QApplication::paletteChanged, this, [this]() {
applyPalette(d->mGvCore->palette(GvCore::NormalViewPalette));
});
d->mRecentFoldersView->setFocus();
ScrollerUtils::setQScroller(d->mBookmarksView->viewport());
d->mBookmarksView->viewport()->installEventFilter(this);
}
StartMainPage::~StartMainPage()
{
delete d->mRecentFilesThumbnailProvider;
delete d;
}
bool StartMainPage::eventFilter(QObject *, QEvent *event)
{
if (event->type() == QEvent::MouseMove) {
auto mouseEvent = static_cast<QMouseEvent *>(event);
if (mouseEvent->source() == Qt::MouseEventSynthesizedByQt) {
return true;
}
}
return false;
}
void StartMainPage::slotTagViewClicked(const QModelIndex &index)
{
#ifdef GWENVIEW_SEMANTICINFO_BACKEND_BALOO
if (!index.isValid()) {
return;
}
// FIXME: Check label encoding
const QString tag = index.data().toString();
Q_EMIT urlSelected(QUrl("tags:/" + tag));
#endif
}
void StartMainPage::applyPalette(const QPalette &newPalette)
{
QColor fgColor = newPalette.text().color();
QPalette pal = palette();
pal.setBrush(backgroundRole(), newPalette.base());
pal.setBrush(QPalette::Button, newPalette.base());
pal.setBrush(QPalette::WindowText, fgColor);
pal.setBrush(QPalette::ButtonText, fgColor);
pal.setBrush(QPalette::Text, fgColor);
setPalette(pal);
initViewPalette(d->mBookmarksView, fgColor);
initViewPalette(d->mTagView, fgColor);
initViewPalette(d->mRecentFoldersView, fgColor);
initViewPalette(d->mRecentFilesView, fgColor);
}
void StartMainPage::slotListViewActivated(const QModelIndex &index)
{
if (!index.isValid()) {
return;
}
QVariant data = index.data(KFilePlacesModel::UrlRole);
QUrl url = data.toUrl();
// Prevent dir lister error
if (!url.isValid()) {
qCCritical(GWENVIEW_APP_LOG) << "Tried to open an invalid url";
return;
}
Q_EMIT urlSelected(url);
}
void StartMainPage::showEvent(QShowEvent *event)
{
if (GwenviewConfig::historyEnabled()) {
if (!d->mRecentFoldersView->model()) {
d->mRecentFoldersView->setModel(d->mGvCore->recentFoldersModel());
d->setupHistoryView(d->mRecentFoldersView);
}
if (!d->mRecentFilesView->model()) {
d->mRecentFilesView->setModel(d->mGvCore->recentFilesModel());
d->mRecentFilesThumbnailProvider = new ThumbnailProvider();
d->mRecentFilesView->setThumbnailProvider(d->mRecentFilesThumbnailProvider);
d->setupHistoryView(d->mRecentFilesView);
}
}
if (!d->mSearchUiInitialized) {
d->mSearchUiInitialized = true;
d->setupSearchUi();
}
QFrame::showEvent(event);
}
void StartMainPage::showContextMenu(const QPoint &pos)
{
// Create menu
DialogGuard<QMenu> menu(this);
QAction *addAction = menu->addAction(QIcon::fromTheme(QStringLiteral("bookmark-new")), QString());
QAction *forgetAction = menu->addAction(QIcon::fromTheme(QStringLiteral("edit-delete")), QString());
menu->addSeparator();
QAction *forgetAllAction = menu->addAction(QIcon::fromTheme(QStringLiteral("edit-delete-all")), QString());
if (d->mHistoryWidget->currentWidget() == d->mRecentFoldersTab) {
addAction->setText(i18nc("@action Recent Folders view", "Add Folder to Places"));
forgetAction->setText(i18nc("@action Recent Folders view", "Forget This Folder"));
forgetAllAction->setText(i18nc("@action Recent Folders view", "Forget All Folders"));
} else if (d->mHistoryWidget->currentWidget() == d->mRecentFilesTab) {
addAction->setText(i18nc("@action Recent Files view", "Add Containing Folder to Places"));
forgetAction->setText(i18nc("@action Recent Files view", "Forget This File"));
forgetAllAction->setText(i18nc("@action Recent Files view", "Forget All Files"));
} else {
GV_WARN_AND_RETURN("Context menu not implemented on this tab page");
}
const QAbstractItemView *view = qobject_cast<QAbstractItemView *>(sender());
const QModelIndex index = view->indexAt(pos);
addAction->setEnabled(index.isValid());
forgetAction->setEnabled(index.isValid());
// Handle menu
const QAction *action = menu->exec(view->mapToGlobal(pos));
if (!action) {
return;
}
const QVariant data = index.data(KFilePlacesModel::UrlRole);
QUrl url = data.toUrl();
if (action == addAction) {
if (d->mHistoryWidget->currentWidget() == d->mRecentFilesTab) {
url = url.adjusted(QUrl::RemoveFilename);
}
QString text = url.adjusted(QUrl::StripTrailingSlash).fileName();
if (text.isEmpty()) {
text = url.toDisplayString();
}
d->mBookmarksModel->addPlace(text, url);
} else if (action == forgetAction) {
view->model()->removeRow(index.row());
if (d->mHistoryWidget->currentWidget() == d->mRecentFilesTab) {
Q_EMIT recentFileRemoved(url);
}
} else if (action == forgetAllAction) {
view->model()->removeRows(0, view->model()->rowCount());
if (d->mHistoryWidget->currentWidget() == d->mRecentFilesTab) {
Q_EMIT recentFilesCleared();
}
}
}
void StartMainPage::loadConfig()
{
d->updateHistoryTab();
applyPalette(d->mGvCore->palette(GvCore::NormalViewPalette));
}
ThumbnailView *StartMainPage::recentFoldersView() const
{
return d->mRecentFoldersView;
}
} // namespace
#include "moc_startmainpage.cpp"