kde-extraapps/gwenview/importer/thumbnailpage.cpp
Ivailo Monev 16d3998931 gwenview: drop the tree view
Signed-off-by: Ivailo Monev <xakepa10@gmail.com>
2023-07-04 15:30:08 +03:00

385 lines
11 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// vim: set tabstop=4 shiftwidth=4 expandtab:
/*
Gwenview: an image viewer
Copyright 2009 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_thumbnailpage.cpp"
// Qt
#include <QPushButton>
#include <QTreeView>
// KDE
#include <KAcceleratorManager>
#include <KDebug>
#include <KDirLister>
#include <KDirModel>
#include <KIconLoader>
#include <KIO/NetAccess>
#include <KLocale>
// Local
#include <lib/kindproxymodel.h>
#include <lib/gwenviewconfig.h>
#include <lib/recursivedirmodel.h>
#include <lib/sorteddirmodel.h>
#include <lib/thumbnailview/abstractthumbnailviewhelper.h>
#include <lib/thumbnailview/previewitemdelegate.h>
#include <documentdirfinder.h>
#include <importerconfigdialog.h>
#include <serializedurlmap.h>
#include <ui_thumbnailpage.h>
namespace Gwenview
{
static const int DEFAULT_THUMBNAIL_SIZE = 128;
static const qreal DEFAULT_THUMBNAIL_ASPECT_RATIO = 3. / 2.;
static const char* URL_FOR_BASE_URL_GROUP = "UrlForBaseUrl";
class ImporterThumbnailViewHelper : public AbstractThumbnailViewHelper
{
public:
ImporterThumbnailViewHelper(QObject* parent)
: AbstractThumbnailViewHelper(parent)
{}
void showContextMenu(QWidget*)
{}
void showMenuForUrlDroppedOnViewport(QWidget*, const KUrl::List&)
{}
void showMenuForUrlDroppedOnDir(QWidget*, const KUrl::List&, const KUrl&)
{}
};
inline KFileItem itemForIndex(const QModelIndex& index)
{
return index.data(KDirModel::FileItemRole).value<KFileItem>();
}
struct ThumbnailPagePrivate : public Ui_ThumbnailPage
{
ThumbnailPage* q;
SerializedUrlMap mUrlMap;
KIcon mSrcBaseIcon;
QString mSrcBaseName;
KUrl mSrcBaseUrl;
KUrl mSrcUrl;
RecursiveDirModel* mRecursiveDirModel;
QAbstractItemModel* mFinalModel;
QPushButton* mImportSelectedButton;
QPushButton* mImportAllButton;
KUrl::List mUrlList;
void setupDirModel()
{
mRecursiveDirModel = new RecursiveDirModel(q);
KindProxyModel* kindProxyModel = new KindProxyModel(q);
kindProxyModel->setKindFilter(MimeTypeUtils::KIND_IMAGE);
kindProxyModel->setSourceModel(mRecursiveDirModel);
QSortFilterProxyModel *sortModel = new QSortFilterProxyModel(q);
sortModel->setDynamicSortFilter(true);
sortModel->setSourceModel(kindProxyModel);
sortModel->sort(0);
mFinalModel = sortModel;
QObject::connect(
mFinalModel, SIGNAL(rowsInserted(QModelIndex,int,int)),
q, SLOT(updateImportButtons()));
QObject::connect(
mFinalModel, SIGNAL(rowsRemoved(QModelIndex,int,int)),
q, SLOT(updateImportButtons()));
QObject::connect(
mFinalModel, SIGNAL(modelReset()),
q, SLOT(updateImportButtons()));
}
void setupIcons()
{
const KIconLoader::Group group = KIconLoader::NoGroup;
const int size = KIconLoader::SizeHuge;
mSrcIconLabel->setPixmap(KIconLoader::global()->loadIcon("camera-photo", group, size));
mDstIconLabel->setPixmap(KIconLoader::global()->loadIcon("computer", group, size));
}
void setupSrcUrlWidgets()
{
KAcceleratorManager::setNoAccel(mSrcUrlLabel);
}
void setupDstUrlRequester()
{
mDstUrlRequester->setMode(KFile::Directory | KFile::LocalOnly);
}
void setupThumbnailView()
{
mThumbnailView->setModel(mFinalModel);
mThumbnailView->setSelectionMode(QAbstractItemView::ExtendedSelection);
mThumbnailView->setThumbnailViewHelper(new ImporterThumbnailViewHelper(q));
PreviewItemDelegate* delegate = new PreviewItemDelegate(mThumbnailView);
delegate->setThumbnailDetails(PreviewItemDelegate::FileNameDetail);
delegate->setContextBarActions(PreviewItemDelegate::SelectionAction);
mThumbnailView->setItemDelegate(delegate);
// Colors
int value = GwenviewConfig::viewBackgroundValue();
QColor bgColor = QColor::fromHsv(0, 0, value);
QColor fgColor = value > 128 ? Qt::black : Qt::white;
QPalette pal = mThumbnailView->palette();
pal.setColor(QPalette::Base, bgColor);
pal.setColor(QPalette::Text, fgColor);
mThumbnailView->setPalette(pal);
QObject::connect(mSlider, SIGNAL(valueChanged(int)),
mThumbnailView, SLOT(setThumbnailWidth(int)));
QObject::connect(mThumbnailView, SIGNAL(thumbnailWidthChanged(int)),
mSlider, SLOT(setValue(int)));
int thumbnailSize = DEFAULT_THUMBNAIL_SIZE;
mSlider->setValue(thumbnailSize);
mSlider->updateToolTip();
mThumbnailView->setThumbnailAspectRatio(DEFAULT_THUMBNAIL_ASPECT_RATIO);
mThumbnailView->setThumbnailWidth(thumbnailSize);
QObject::connect(
mThumbnailView->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
q, SLOT(updateImportButtons()));
}
void setupButtonBox()
{
QObject::connect(mConfigureButton, SIGNAL(clicked()),
q, SLOT(showConfigDialog()));
mImportSelectedButton = mButtonBox->addButton(
i18n("Import Selected"), QDialogButtonBox::AcceptRole,
q, SLOT(slotImportSelected()));
mImportAllButton = mButtonBox->addButton(
i18n("Import All"), QDialogButtonBox::AcceptRole,
q, SLOT(slotImportAll()));
QObject::connect(
mButtonBox, SIGNAL(rejected()),
q, SIGNAL(rejected()));
}
KUrl urlForBaseUrl() const
{
KUrl url = mUrlMap.value(mSrcBaseUrl);
if (!url.isValid()) {
return KUrl();
}
KIO::UDSEntry entry;
bool ok = KIO::NetAccess::stat(url, entry, q);
if (!ok) {
return KUrl();
}
KFileItem item(entry, url, true /* delayedMimeTypes */);
return item.isDir() ? url : KUrl();
}
void rememberUrl(const KUrl& url)
{
mUrlMap.insert(mSrcBaseUrl, url);
}
};
ThumbnailPage::ThumbnailPage()
: d(new ThumbnailPagePrivate)
{
d->q = this;
d->mUrlMap.setConfigGroup(KConfigGroup(KGlobal::config(), URL_FOR_BASE_URL_GROUP));
d->setupUi(this);
d->setupIcons();
d->setupDirModel();
d->setupSrcUrlWidgets();
d->setupDstUrlRequester();
d->setupThumbnailView();
d->setupButtonBox();
updateImportButtons();
}
ThumbnailPage::~ThumbnailPage()
{
delete d;
}
void ThumbnailPage::setSourceUrl(const KUrl& srcBaseUrl, const QString& iconName, const QString& name)
{
d->mSrcBaseIcon = KIcon(iconName);
d->mSrcBaseName = name;
const int size = KIconLoader::SizeHuge;
d->mSrcIconLabel->setPixmap(d->mSrcBaseIcon.pixmap(size));
d->mSrcBaseUrl = srcBaseUrl;
d->mSrcBaseUrl.adjustPath(KUrl::AddTrailingSlash);
KUrl url = d->urlForBaseUrl();
if (url.isValid()) {
openUrl(url);
} else {
DocumentDirFinder* finder = new DocumentDirFinder(srcBaseUrl);
connect(finder, SIGNAL(done(KUrl,DocumentDirFinder::Status)),
SLOT(slotDocumentDirFinderDone(KUrl,DocumentDirFinder::Status)));
finder->start();
}
}
void ThumbnailPage::slotDocumentDirFinderDone(const KUrl& url, DocumentDirFinder::Status /*status*/)
{
d->rememberUrl(url);
openUrl(url);
}
void ThumbnailPage::openUrl(const KUrl& url)
{
d->mSrcUrl = url;
QString path = KUrl::relativeUrl(d->mSrcBaseUrl, d->mSrcUrl);
QString text;
if (path.isEmpty() || path == "./") {
text = d->mSrcBaseName;
} else {
path = QUrl::fromPercentEncoding(path.toUtf8());
path.replace("/", QString::fromUtf8(" "));
text = QString::fromUtf8("%1 %2").arg(d->mSrcBaseName).arg(path);
}
d->mSrcUrlLabel->setText(text);
d->mRecursiveDirModel->setUrl(url);
}
KUrl::List ThumbnailPage::urlList() const
{
return d->mUrlList;
}
void ThumbnailPage::setDestinationUrl(const KUrl& url)
{
d->mDstUrlRequester->setUrl(url);
}
KUrl ThumbnailPage::destinationUrl() const
{
return d->mDstUrlRequester->url();
}
void ThumbnailPage::slotImportSelected()
{
importList(d->mThumbnailView->selectionModel()->selectedIndexes());
}
void ThumbnailPage::slotImportAll()
{
QModelIndexList list;
QAbstractItemModel* model = d->mThumbnailView->model();
for (int row = model->rowCount() - 1; row >= 0; --row) {
list << model->index(row, 0);
}
importList(list);
}
void ThumbnailPage::importList(const QModelIndexList& list)
{
d->mUrlList.clear();
Q_FOREACH(const QModelIndex & index, list) {
KFileItem item = itemForIndex(index);
if (!item.isDir()) {
d->mUrlList << item.url();
}
// FIXME: Handle dirs (do we want to import recursively?)
}
emit importRequested();
}
void ThumbnailPage::updateImportButtons()
{
d->mImportSelectedButton->setEnabled(d->mThumbnailView->selectionModel()->hasSelection());
d->mImportAllButton->setEnabled(d->mThumbnailView->model()->rowCount(QModelIndex()) > 0);
}
void ThumbnailPage::showConfigDialog()
{
ImporterConfigDialog dialog(this);
dialog.exec();
}
/**
* This model allows only the url passed in the constructor to appear at the root
* level. This makes it possible to select the url, but not its siblings.
* It also provides custom role values for the root item.
*/
class OnlyBaseUrlProxyModel : public QSortFilterProxyModel
{
public:
OnlyBaseUrlProxyModel(const KUrl& url, const KIcon& icon, const QString& name, QObject* parent)
: QSortFilterProxyModel(parent)
, mUrl(url)
, mIcon(icon)
, mName(name)
{}
bool filterAcceptsRow(int sourceRow, const QModelIndex& sourceParent) const // reimp
{
if (sourceParent.isValid()) {
return true;
}
QModelIndex index = sourceModel()->index(sourceRow, 0);
KFileItem item = itemForIndex(index);
return item.url().equals(mUrl, KUrl::RemoveTrailingSlash);
}
QVariant data(const QModelIndex& index, int role) const // reimp
{
if (index.parent().isValid()) {
return QSortFilterProxyModel::data(index, role);
}
switch (role) {
case Qt::DisplayRole:
return mName;
case Qt::DecorationRole:
return mIcon;
case Qt::ToolTipRole:
return mUrl.pathOrUrl();
default:
return QSortFilterProxyModel::data(index, role);
}
}
private:
KUrl mUrl;
KIcon mIcon;
QString mName;
};
} // namespace