2014-11-19 02:23:05 +00:00
|
|
|
|
// 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
|
2015-02-27 11:02:43 +00:00
|
|
|
|
#include "moc_thumbnailpage.cpp"
|
2014-11-19 02:23:05 +00:00
|
|
|
|
|
|
|
|
|
// Qt
|
|
|
|
|
#include <QPushButton>
|
|
|
|
|
#include <QTreeView>
|
|
|
|
|
|
|
|
|
|
// KDE
|
|
|
|
|
#include <KAcceleratorManager>
|
|
|
|
|
#include <KDebug>
|
|
|
|
|
#include <KDirLister>
|
|
|
|
|
#include <KDirModel>
|
|
|
|
|
#include <KIconLoader>
|
|
|
|
|
#include <KIO/NetAccess>
|
2015-09-02 08:54:43 +03:00
|
|
|
|
#include <KLocale>
|
2014-11-19 02:23:05 +00:00
|
|
|
|
|
|
|
|
|
// Local
|
|
|
|
|
#include <lib/kindproxymodel.h>
|
|
|
|
|
#include <lib/gwenviewconfig.h>
|
|
|
|
|
#include <lib/recursivedirmodel.h>
|
2014-11-19 19:44:19 +00:00
|
|
|
|
#include <lib/sorteddirmodel.h>
|
2014-11-19 02:23:05 +00:00
|
|
|
|
#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);
|
2022-05-20 23:54:23 +03:00
|
|
|
|
kindProxyModel->setKindFilter(MimeTypeUtils::KIND_IMAGE);
|
2014-11-19 02:23:05 +00:00
|
|
|
|
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()
|
|
|
|
|
{
|
2023-07-04 15:29:18 +03:00
|
|
|
|
KAcceleratorManager::setNoAccel(mSrcUrlLabel);
|
2014-11-19 02:23:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void setupDstUrlRequester()
|
|
|
|
|
{
|
2023-07-07 22:16:34 +03:00
|
|
|
|
mDstUrlRequester->setStyle(QApplication::style());
|
2014-11-19 02:23:05 +00:00
|
|
|
|
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();
|
|
|
|
|
}
|
2024-05-31 16:58:54 +03:00
|
|
|
|
KFileItem item(entry);
|
2014-11-19 02:23:05 +00:00
|
|
|
|
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);
|
|
|
|
|
}
|
2023-07-04 15:29:18 +03:00
|
|
|
|
d->mSrcUrlLabel->setText(text);
|
2014-11-19 02:23:05 +00:00
|
|
|
|
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);
|
2021-06-25 16:14:14 +03:00
|
|
|
|
if (!item.isDir()) {
|
2014-11-19 02:23:05 +00:00
|
|
|
|
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);
|
2023-06-26 01:41:35 +03:00
|
|
|
|
return item.url().equals(mUrl, KUrl::RemoveTrailingSlash);
|
2014-11-19 02:23:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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
|