286 lines
7.9 KiB
C++
286 lines
7.9 KiB
C++
// 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 "importer.h"
|
|
|
|
// Qt
|
|
#include <QDateTime>
|
|
#include <QTemporaryDir>
|
|
#include <QUrl>
|
|
|
|
// KF
|
|
#include <KFileItem>
|
|
#include <KIO/CopyJob>
|
|
#include <KIO/DeleteJob>
|
|
#include <KIO/JobUiDelegate>
|
|
#include <KIO/MkpathJob>
|
|
#include <KIO/SimpleJob>
|
|
#include <KJobWidgets>
|
|
#include <KLocalizedString>
|
|
|
|
// stdc++
|
|
#include <memory>
|
|
|
|
// Local
|
|
#include "gwenview_importer_debug.h"
|
|
#include <QDir>
|
|
#include <filenameformater.h>
|
|
#include <fileutils.h>
|
|
#include <lib/timeutils.h>
|
|
#include <lib/urlutils.h>
|
|
|
|
namespace Gwenview
|
|
{
|
|
struct ImporterPrivate {
|
|
Importer *q = nullptr;
|
|
QWidget *mAuthWindow = nullptr;
|
|
std::unique_ptr<FileNameFormater> mFileNameFormater;
|
|
QUrl mTempImportDirUrl;
|
|
QTemporaryDir *mTempImportDir = nullptr;
|
|
QUrl mDestinationDirUrl;
|
|
|
|
/* @defgroup reset Should be reset in start()
|
|
* @{ */
|
|
QList<QUrl> mUrlList;
|
|
QList<QUrl> mImportedUrlList;
|
|
QList<QUrl> mSkippedUrlList;
|
|
QList<QUrl> mFailedUrlList;
|
|
QList<QUrl> mFailedSubFolderList;
|
|
int mRenamedCount;
|
|
int mProgress;
|
|
int mJobProgress;
|
|
/* @} */
|
|
|
|
QUrl mCurrentUrl;
|
|
|
|
bool createImportDir(const QUrl &url)
|
|
{
|
|
KIO::Job *job = KIO::mkpath(url, QUrl(), KIO::HideProgressInfo);
|
|
KJobWidgets::setWindow(job, mAuthWindow);
|
|
if (!job->exec()) {
|
|
Q_EMIT q->error(i18n("Could not create destination folder."));
|
|
return false;
|
|
}
|
|
|
|
// Check if local and fast url. The check for fast url is needed because
|
|
// otherwise the retrieved date will not be correct: see implementation
|
|
// of TimeUtils::dateTimeForFileItem
|
|
if (UrlUtils::urlIsFastLocalFile(url)) {
|
|
QString tempDirPath = url.toLocalFile() + "/.gwenview_importer-XXXXXX";
|
|
mTempImportDir = new QTemporaryDir(tempDirPath);
|
|
} else {
|
|
mTempImportDir = new QTemporaryDir();
|
|
}
|
|
|
|
if (!mTempImportDir->isValid()) {
|
|
Q_EMIT q->error(i18n("Could not create temporary upload folder."));
|
|
return false;
|
|
}
|
|
|
|
mTempImportDirUrl = QUrl::fromLocalFile(mTempImportDir->path() + QLatin1Char('/'));
|
|
if (!mTempImportDirUrl.isValid()) {
|
|
Q_EMIT q->error(i18n("Could not create temporary upload folder."));
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void importNext()
|
|
{
|
|
if (mUrlList.empty()) {
|
|
q->finalizeImport();
|
|
return;
|
|
}
|
|
mCurrentUrl = mUrlList.takeFirst();
|
|
QUrl dst = mTempImportDirUrl;
|
|
dst.setPath(dst.path() + mCurrentUrl.fileName());
|
|
KIO::Job *job = KIO::copy(mCurrentUrl, dst, KIO::HideProgressInfo | KIO::Overwrite);
|
|
KJobWidgets::setWindow(job, mAuthWindow);
|
|
QObject::connect(job, &KJob::result, q, &Importer::slotCopyDone);
|
|
QObject::connect(job, SIGNAL(percent(KJob *, ulong)), q, SLOT(slotPercent(KJob *, ulong)));
|
|
}
|
|
|
|
void renameImportedUrl(const QUrl &src)
|
|
{
|
|
QUrl dst = mDestinationDirUrl;
|
|
QString fileName;
|
|
if (mFileNameFormater.get()) {
|
|
KFileItem item(src);
|
|
item.setDelayedMimeTypes(true);
|
|
// Get the document time, but do not cache the result because the
|
|
// 'src' url is temporary: if we import "foo/image.jpg" and
|
|
// "bar/image.jpg", both images will be temporarily saved in the
|
|
// 'src' url.
|
|
const QDateTime dateTime = TimeUtils::dateTimeForFileItem(item, TimeUtils::SkipCache);
|
|
fileName = mFileNameFormater->format(src, dateTime);
|
|
} else {
|
|
fileName = src.fileName();
|
|
}
|
|
dst.setPath(dst.path() + QLatin1Char('/') + fileName);
|
|
|
|
FileUtils::RenameResult result;
|
|
// Create additional subfolders if needed (e.g. when extra slashes in FileNameFormater)
|
|
QUrl subFolder = dst.adjusted(QUrl::RemoveFilename);
|
|
KIO::Job *job = KIO::mkpath(subFolder, QUrl(), KIO::HideProgressInfo);
|
|
KJobWidgets::setWindow(job, mAuthWindow);
|
|
if (!job->exec()) { // if subfolder creation fails
|
|
qCWarning(GWENVIEW_IMPORTER_LOG) << "Could not create subfolder:" << subFolder;
|
|
if (!mFailedSubFolderList.contains(subFolder)) {
|
|
mFailedSubFolderList << subFolder;
|
|
}
|
|
result = FileUtils::RenameFailed;
|
|
} else { // if subfolder creation succeeds
|
|
result = FileUtils::rename(src, dst, mAuthWindow);
|
|
}
|
|
|
|
switch (result) {
|
|
case FileUtils::RenamedOK:
|
|
mImportedUrlList << mCurrentUrl;
|
|
break;
|
|
case FileUtils::RenamedUnderNewName:
|
|
mRenamedCount++;
|
|
mImportedUrlList << mCurrentUrl;
|
|
break;
|
|
case FileUtils::Skipped:
|
|
mSkippedUrlList << mCurrentUrl;
|
|
break;
|
|
case FileUtils::RenameFailed:
|
|
mFailedUrlList << mCurrentUrl;
|
|
qCWarning(GWENVIEW_IMPORTER_LOG) << "Rename failed for" << mCurrentUrl;
|
|
}
|
|
q->advance();
|
|
importNext();
|
|
}
|
|
};
|
|
|
|
Importer::Importer(QWidget *parent)
|
|
: QObject(parent)
|
|
, d(new ImporterPrivate)
|
|
{
|
|
d->q = this;
|
|
d->mAuthWindow = parent;
|
|
}
|
|
|
|
Importer::~Importer()
|
|
{
|
|
delete d;
|
|
}
|
|
|
|
void Importer::setAutoRenameFormat(const QString &format)
|
|
{
|
|
if (format.isEmpty()) {
|
|
d->mFileNameFormater.reset(nullptr);
|
|
} else {
|
|
d->mFileNameFormater = std::make_unique<FileNameFormater>(format);
|
|
}
|
|
}
|
|
|
|
void Importer::start(const QList<QUrl> &list, const QUrl &destination)
|
|
{
|
|
d->mDestinationDirUrl = destination;
|
|
d->mUrlList = list;
|
|
d->mImportedUrlList.clear();
|
|
d->mSkippedUrlList.clear();
|
|
d->mFailedUrlList.clear();
|
|
d->mFailedSubFolderList.clear();
|
|
d->mRenamedCount = 0;
|
|
d->mProgress = 0;
|
|
d->mJobProgress = 0;
|
|
|
|
emitProgressChanged();
|
|
Q_EMIT maximumChanged(d->mUrlList.count() * 100);
|
|
|
|
if (!d->createImportDir(destination)) {
|
|
qCWarning(GWENVIEW_IMPORTER_LOG) << "Could not create import dir";
|
|
return;
|
|
}
|
|
d->importNext();
|
|
}
|
|
|
|
void Importer::slotCopyDone(KJob *_job)
|
|
{
|
|
auto job = static_cast<KIO::CopyJob *>(_job);
|
|
const QUrl url = job->destUrl();
|
|
if (job->error()) {
|
|
// Add document to failed url list and proceed with next one
|
|
d->mFailedUrlList << d->mCurrentUrl;
|
|
advance();
|
|
d->importNext();
|
|
return;
|
|
}
|
|
|
|
d->renameImportedUrl(url);
|
|
}
|
|
|
|
void Importer::finalizeImport()
|
|
{
|
|
delete d->mTempImportDir;
|
|
Q_EMIT importFinished();
|
|
}
|
|
|
|
void Importer::advance()
|
|
{
|
|
++d->mProgress;
|
|
d->mJobProgress = 0;
|
|
emitProgressChanged();
|
|
}
|
|
|
|
void Importer::slotPercent(KJob *, unsigned long percent)
|
|
{
|
|
d->mJobProgress = percent;
|
|
emitProgressChanged();
|
|
}
|
|
|
|
void Importer::emitProgressChanged()
|
|
{
|
|
Q_EMIT progressChanged(d->mProgress * 100 + d->mJobProgress);
|
|
}
|
|
|
|
QList<QUrl> Importer::importedUrlList() const
|
|
{
|
|
return d->mImportedUrlList;
|
|
}
|
|
|
|
QList<QUrl> Importer::skippedUrlList() const
|
|
{
|
|
return d->mSkippedUrlList;
|
|
}
|
|
|
|
QList<QUrl> Importer::failedUrlList() const
|
|
{
|
|
return d->mFailedUrlList;
|
|
}
|
|
|
|
QList<QUrl> Importer::failedSubFolderList() const
|
|
{
|
|
return d->mFailedSubFolderList;
|
|
}
|
|
|
|
int Importer::renamedCount() const
|
|
{
|
|
return d->mRenamedCount;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
#include "moc_importer.cpp"
|