kde-extraapps/gwenview/app/browsemainpage.cpp
Ivailo Monev 4d3534da5d gwenview: remove archive support [ci reset]
Signed-off-by: Ivailo Monev <xakepa10@gmail.com>
2021-06-25 16:14:32 +03:00

397 lines
14 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 "moc_browsemainpage.cpp"
// Qt
#include <QtGui/qevent.h>
#include <QMenu>
#include <QSlider>
#include <QToolTip>
#include <QVBoxLayout>
// KDE
#include <KActionCollection>
#include <KActionCategory>
#include <KActionMenu>
#include <KDebug>
#include <KFileItem>
#include <KFilePlacesModel>
#include <KLineEdit>
#include <KLocale>
#include <KSelectAction>
#include <KStatusBar>
#include <KToggleAction>
#include <KUrlNavigator>
// Local
#include <filtercontroller.h>
#include <gvcore.h>
#include <fileoperations.h>
#include <lib/document/documentfactory.h>
#include <lib/gvdebug.h>
#include <lib/gwenviewconfig.h>
#include <lib/sorteddirmodel.h>
#include <lib/sorting.h>
#include <lib/thumbnailview/previewitemdelegate.h>
#include <lib/thumbnailview/thumbnailview.h>
#include <ui_browsemainpage.h>
namespace Gwenview
{
inline Sorting::Enum sortingFromSortAction(const QAction* action)
{
Q_ASSERT(action);
return Sorting::Enum(action->data().toInt());
}
struct BrowseMainPagePrivate : public Ui_BrowseMainPage
{
BrowseMainPage* q;
GvCore* mGvCore;
KFilePlacesModel* mFilePlacesModel;
KUrlNavigator* mUrlNavigator;
SortedDirModel* mDirModel;
int mDocumentCount;
KActionCollection* mActionCollection;
FilterController* mFilterController;
KSelectAction* mSortAction;
QActionGroup* mThumbnailDetailsActionGroup;
PreviewItemDelegate* mDelegate;
void setupWidgets()
{
setupUi(q);
q->layout()->setMargin(0);
// mThumbnailView
mThumbnailView->setModel(mDirModel);
mDelegate = new PreviewItemDelegate(mThumbnailView);
mThumbnailView->setItemDelegate(mDelegate);
mThumbnailView->setSelectionMode(QAbstractItemView::ExtendedSelection);
// mUrlNavigator (use stupid layouting code because KUrlNavigator ctor
// can't be used directly from Designer)
mFilePlacesModel = new KFilePlacesModel(q);
mUrlNavigator = new KUrlNavigator(mFilePlacesModel, KUrl(), mUrlNavigatorContainer);
mUrlNavigatorContainer->setAutoFillBackground(true);
QVBoxLayout* layout = new QVBoxLayout(mUrlNavigatorContainer);
layout->setMargin(0);
layout->addWidget(mUrlNavigator);
QObject::connect(mUrlNavigator, SIGNAL(urlsDropped(KUrl,QDropEvent*)),
q, SLOT(slotUrlsDropped(KUrl,QDropEvent*)));
updateUrlNavigatorBackgroundColor();
// Thumbnail slider
QObject::connect(mThumbnailSlider, SIGNAL(valueChanged(int)),
mThumbnailView, SLOT(setThumbnailWidth(int)));
QObject::connect(mThumbnailView, SIGNAL(thumbnailWidthChanged(int)),
mThumbnailSlider, SLOT(setValue(int)));
}
void setupActions(KActionCollection* actionCollection)
{
KActionCategory* view = new KActionCategory(i18nc("@title actions category - means actions changing smth in interface", "View"), actionCollection);
KAction* action = view->addAction("edit_location", q, SLOT(editLocation()));
action->setText(i18nc("@action:inmenu Navigation Bar", "Edit Location"));
action->setShortcut(Qt::Key_F6);
mSortAction = view->add<KSelectAction>("sort_order");
mSortAction->setText(i18nc("@action:inmenu", "Sort By"));
action = mSortAction->addAction(i18nc("@addAction:inmenu", "Name"));
action->setData(QVariant(Sorting::Name));
action = mSortAction->addAction(i18nc("@addAction:inmenu", "Date"));
action->setData(QVariant(Sorting::Date));
action = mSortAction->addAction(i18nc("@addAction:inmenu", "Size"));
action->setData(QVariant(Sorting::Size));
QObject::connect(mSortAction, SIGNAL(triggered(QAction*)),
q, SLOT(updateSortOrder()));
mThumbnailDetailsActionGroup = new QActionGroup(q);
mThumbnailDetailsActionGroup->setExclusive(false);
KActionMenu* thumbnailDetailsAction = view->add<KActionMenu>("thumbnail_details");
thumbnailDetailsAction->setText(i18nc("@action:inmenu", "Thumbnail Details"));
#define addAction(text, detail) \
action = new KAction(q); \
thumbnailDetailsAction->addAction(action); \
action->setText(text); \
action->setCheckable(true); \
action->setChecked(GwenviewConfig::thumbnailDetails() & detail); \
action->setData(QVariant(detail)); \
mThumbnailDetailsActionGroup->addAction(action); \
QObject::connect(action, SIGNAL(triggered(bool)), \
q, SLOT(updateThumbnailDetails()));
addAction(i18nc("@action:inmenu", "Filename"), PreviewItemDelegate::FileNameDetail);
addAction(i18nc("@action:inmenu", "Date"), PreviewItemDelegate::DateDetail);
addAction(i18nc("@action:inmenu", "Image Size"), PreviewItemDelegate::ImageSizeDetail);
addAction(i18nc("@action:inmenu", "File Size"), PreviewItemDelegate::FileSizeDetail);
#undef addAction
KActionCategory* file = new KActionCategory(i18nc("@title actions category", "File"), actionCollection);
action = file->addAction("add_folder_to_places", q, SLOT(addFolderToPlaces()));
action->setText(i18nc("@action:inmenu", "Add Folder to Places"));
}
void setupFilterController()
{
QMenu* menu = new QMenu(mAddFilterButton);
mFilterController = new FilterController(mFilterFrame, mDirModel);
Q_FOREACH(QAction * action, mFilterController->actionList()) {
menu->addAction(action);
}
mAddFilterButton->setMenu(menu);
}
void setupFullScreenToolBar()
{
mFullScreenToolBar->setIconDimensions(KIconLoader::SizeMedium);
mFullScreenToolBar->setToolButtonStyle(Qt::ToolButtonIconOnly);
#define addAction(name) mFullScreenToolBar->addAction(mActionCollection->action(name))
addAction("browse");
addAction("view");
#undef addAction
mFullScreenToolBar2->setIconDimensions(KIconLoader::SizeMedium);
mFullScreenToolBar2->setToolButtonStyle(Qt::ToolButtonIconOnly);
mFullScreenToolBar2->addAction(mActionCollection->action("leave_fullscreen"));
}
void updateDocumentCountLabel()
{
QString text = i18ncp("@label", "%1 document", "%1 documents", mDocumentCount);
mDocumentCountLabel->setText(text);
}
void setupDocumentCountConnections()
{
QObject::connect(mDirModel, SIGNAL(rowsInserted(QModelIndex,int,int)),
q, SLOT(slotDirModelRowsInserted(QModelIndex,int,int)));
QObject::connect(mDirModel, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
q, SLOT(slotDirModelRowsAboutToBeRemoved(QModelIndex,int,int)));
QObject::connect(mDirModel, SIGNAL(modelReset()),
q, SLOT(slotDirModelReset()));
}
int documentCountInIndexRange(const QModelIndex& parent, int start, int end)
{
int count = 0;
for (int row = start; row <= end; ++row) {
QModelIndex index = mDirModel->index(row, 0, parent);
KFileItem item = mDirModel->itemForIndex(index);
if (!item.isDir()) {
++count;
}
}
return count;
}
void updateUrlNavigatorBackgroundColor()
{
QPalette pal(q->palette());
pal.setColor(QPalette::Window, pal.color(QPalette::Window).dark(110));
mUrlNavigatorContainer->setPalette(pal);
}
};
BrowseMainPage::BrowseMainPage(QWidget* parent, KActionCollection* actionCollection, GvCore* gvCore)
: QWidget(parent)
, d(new BrowseMainPagePrivate)
{
d->q = this;
d->mGvCore = gvCore;
d->mDirModel = gvCore->sortedDirModel();
d->mDocumentCount = 0;
d->mActionCollection = actionCollection;
d->setupWidgets();
d->setupActions(actionCollection);
d->setupFilterController();
d->setupDocumentCountConnections();
loadConfig();
updateSortOrder();
updateThumbnailDetails();
}
BrowseMainPage::~BrowseMainPage()
{
delete d;
}
void BrowseMainPage::loadConfig()
{
setPalette(d->mGvCore->palette(GvCore::NormalPalette));
d->mThumbnailView->setPalette(d->mGvCore->palette(GvCore::NormalViewPalette));
d->mUrlNavigator->setUrlEditable(GwenviewConfig::urlNavigatorIsEditable());
d->mUrlNavigator->setShowFullPath(GwenviewConfig::urlNavigatorShowFullPath());
d->mThumbnailSlider->setValue(GwenviewConfig::thumbnailSize());
d->mThumbnailSlider->updateToolTip();
// If GwenviewConfig::thumbnailSize() returns the current value of
// mThumbnailSlider, it won't emit valueChanged() and the thumbnail view
// won't be updated. That's why we do it ourself.
d->mThumbnailView->setThumbnailAspectRatio(GwenviewConfig::thumbnailAspectRatio());
d->mThumbnailView->setThumbnailWidth(GwenviewConfig::thumbnailSize());
Q_FOREACH(QAction * action, d->mSortAction->actions()) {
if (sortingFromSortAction(action) == GwenviewConfig::sorting()) {
d->mSortAction->setCurrentAction(action);
break;
}
}
}
void BrowseMainPage::saveConfig() const
{
GwenviewConfig::setUrlNavigatorIsEditable(d->mUrlNavigator->isUrlEditable());
GwenviewConfig::setUrlNavigatorShowFullPath(d->mUrlNavigator->showFullPath());
GwenviewConfig::setThumbnailSize(d->mThumbnailSlider->value());
GwenviewConfig::setSorting(sortingFromSortAction(d->mSortAction->currentAction()));
GwenviewConfig::setThumbnailDetails(d->mDelegate->thumbnailDetails());
}
ThumbnailView* BrowseMainPage::thumbnailView() const
{
return d->mThumbnailView;
}
KUrlNavigator* BrowseMainPage::urlNavigator() const
{
return d->mUrlNavigator;
}
void BrowseMainPage::reload()
{
QModelIndexList list = d->mThumbnailView->selectionModel()->selectedIndexes();
Q_FOREACH(const QModelIndex & index, list) {
d->mThumbnailView->reloadThumbnail(index);
}
d->mDirModel->reload();
}
void BrowseMainPage::editLocation()
{
d->mUrlNavigator->setUrlEditable(true);
d->mUrlNavigator->setFocus();
}
void BrowseMainPage::addFolderToPlaces()
{
KUrl url = d->mUrlNavigator->locationUrl();
QString text = url.fileName();
if (text.isEmpty()) {
text = url.pathOrUrl();
}
d->mFilePlacesModel->addPlace(text, url);
}
void BrowseMainPage::slotDirModelRowsInserted(const QModelIndex& parent, int start, int end)
{
int count = d->documentCountInIndexRange(parent, start, end);
if (count > 0) {
d->mDocumentCount += count;
d->updateDocumentCountLabel();
}
}
void BrowseMainPage::slotDirModelRowsAboutToBeRemoved(const QModelIndex& parent, int start, int end)
{
int count = d->documentCountInIndexRange(parent, start, end);
if (count > 0) {
d->mDocumentCount -= count;
d->updateDocumentCountLabel();
}
}
void BrowseMainPage::slotDirModelReset()
{
d->mDocumentCount = 0;
d->updateDocumentCountLabel();
}
void BrowseMainPage::updateSortOrder()
{
const QAction* action = d->mSortAction->currentAction();
GV_RETURN_IF_FAIL(action);
// This works because for now Sorting::Enum maps to KDirModel::ModelColumns
d->mDirModel->setSortRole(sortingFromSortAction(action));
}
void BrowseMainPage::updateThumbnailDetails()
{
PreviewItemDelegate::ThumbnailDetails details = 0;
Q_FOREACH(const QAction * action, d->mThumbnailDetailsActionGroup->actions()) {
if (action->isChecked()) {
details |= PreviewItemDelegate::ThumbnailDetail(action->data().toInt());
}
}
d->mDelegate->setThumbnailDetails(details);
}
void BrowseMainPage::setFullScreenMode(bool fullScreen)
{
setPalette(d->mGvCore->palette(fullScreen ? GvCore::FullScreenPalette : GvCore::NormalPalette));
d->mThumbnailView->setPalette(d->mGvCore->palette(fullScreen ? GvCore::FullScreenViewPalette : GvCore::NormalViewPalette));
d->updateUrlNavigatorBackgroundColor();
d->mUrlNavigatorContainer->setContentsMargins(
fullScreen ? 6 : 0,
0, 0, 0);
PreviewItemDelegate::ContextBarActions actions = PreviewItemDelegate::SelectionAction | PreviewItemDelegate::RotateAction;
if (!fullScreen) {
actions |= PreviewItemDelegate::FullScreenAction;
}
d->mDelegate->setContextBarActions(actions);
d->mFullScreenToolBar->setVisible(fullScreen);
d->mFullScreenToolBar2->setVisible(fullScreen);
if (fullScreen && d->mFullScreenToolBar->actions().isEmpty()) {
d->setupFullScreenToolBar();
}
}
void BrowseMainPage::slotUrlsDropped(const KUrl& destUrl, QDropEvent* event)
{
const KUrl::List urlList = KUrl::List::fromMimeData(event->mimeData());
if (urlList.isEmpty()) {
return;
}
event->acceptProposedAction();
// We can't call FileOperations::showMenuForDroppedUrls() directly because
// we need the slot to return so that the drop event is accepted. Otherwise
// the drop cursor is still visible when the menu is shown.
QMetaObject::invokeMethod(this, "showMenuForDroppedUrls", Qt::QueuedConnection, Q_ARG(KUrl::List, urlList), Q_ARG(KUrl, destUrl));
}
void BrowseMainPage::showMenuForDroppedUrls(const KUrl::List& urlList, const KUrl& destUrl)
{
FileOperations::showMenuForDroppedUrls(d->mUrlNavigator, urlList, destUrl);
}
QToolButton* BrowseMainPage::toggleSideBarButton() const
{
return d->mToggleSideBarButton;
}
} // namespace