mirror of
https://bitbucket.org/smil3y/kde-extraapps.git
synced 2025-02-23 18:32:53 +00:00
397 lines
14 KiB
C++
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
|