251 lines
8.3 KiB
C++

// vim: set tabstop=4 shiftwidth=4 expandtab:
/*
Gwenview: an image viewer
Copyright 2007 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 "fileoperations.h"
// Qt
#include <QFileDialog>
#include <QMenu>
#include <QPushButton>
// KF
#include "kio_version.h"
#include <KIO/CopyJob>
#include <KIO/DeleteJob>
#include <KIO/DeleteOrTrashJob>
#include <KIO/JobUiDelegate>
#include <KIO/SimpleJob>
#include <KJobWidgets>
#include <KLocalizedString>
// Local
#include "gwenview_app_debug.h"
#include "renamedialog.h"
#include <lib/contextmanager.h>
#include <lib/document/documentfactory.h>
#include <lib/thumbnailprovider/thumbnailprovider.h>
namespace Gwenview
{
namespace FileOperations
{
static void copyMoveOrLink(Operation operation, const QList<QUrl> &urlList, QWidget *parent, ContextManager *contextManager)
{
Q_ASSERT(!urlList.isEmpty());
const int numberOfImages = urlList.count();
auto dialog = new QFileDialog(parent->nativeParentWidget(), QString());
dialog->setAcceptMode(QFileDialog::AcceptSave);
dialog->setAttribute(Qt::WA_DeleteOnClose);
dialog->setModal(true);
// Figure out what the window title and buttons should say,
// depending on the operation and how many images are selected
switch (operation) {
case COPY:
if (numberOfImages == 1) {
dialog->setWindowTitle(i18nc("@title:window %1 file name", "Copy %1", urlList.constFirst().fileName()));
} else {
dialog->setWindowTitle(i18ncp("@title:window %1 number of images", "Copy %1 image", "Copy %1 images", numberOfImages));
}
dialog->setLabelText(QFileDialog::DialogLabel::Accept, i18nc("@action:button", "Copy"));
break;
case MOVE:
if (numberOfImages == 1) {
dialog->setWindowTitle(i18nc("@title:window %1 file name", "Move %1", urlList.constFirst().fileName()));
} else {
dialog->setWindowTitle(i18ncp("@title:window %1 number of images", "Move %1 image", "Move %1 images", numberOfImages));
}
dialog->setLabelText(QFileDialog::DialogLabel::Accept, i18nc("@action:button", "Move"));
break;
case LINK:
if (numberOfImages == 1) {
dialog->setWindowTitle(i18nc("@title:window %1 file name", "Link %1", urlList.constFirst().fileName()));
} else {
dialog->setWindowTitle(i18ncp("@title:window %1 number of images", "Link %1 image", "Link %1 images", numberOfImages));
}
dialog->setLabelText(QFileDialog::DialogLabel::Accept, i18nc("@action:button", "Link"));
break;
default:
Q_ASSERT(0);
}
if (numberOfImages == 1) {
dialog->setFileMode(QFileDialog::AnyFile);
dialog->selectUrl(urlList.constFirst());
} else {
dialog->setFileMode(QFileDialog::Directory);
dialog->setOption(QFileDialog::ShowDirsOnly, true);
}
QUrl dirUrl = contextManager->targetDirUrl();
if (!dirUrl.isValid()) {
dirUrl = urlList.constFirst().adjusted(QUrl::RemoveFilename | QUrl::StripTrailingSlash);
}
dialog->setDirectoryUrl(dirUrl);
QObject::connect(dialog, &QDialog::accepted, parent, [=]() {
QUrl destUrl = dialog->selectedUrls().at(0);
KIO::CopyJob *job = nullptr;
switch (operation) {
case COPY:
job = KIO::copy(urlList, destUrl);
break;
case MOVE:
job = KIO::move(urlList, destUrl);
break;
case LINK:
job = KIO::link(urlList, destUrl);
break;
default:
Q_ASSERT(0);
}
KJobWidgets::setWindow(job, parent);
job->uiDelegate()->setAutoErrorHandlingEnabled(true);
if (numberOfImages == 1) {
destUrl = destUrl.adjusted(QUrl::RemoveFilename | QUrl::StripTrailingSlash);
}
contextManager->setTargetDirUrl(destUrl);
});
dialog->show();
}
static void delOrTrash(KIO::JobUiDelegate::DeletionType deletionType, const QList<QUrl> &urlList, QWidget *parent)
{
Q_ASSERT(urlList.count() > 0);
KJob *job = nullptr;
switch (deletionType) {
case KIO::JobUiDelegate::Trash:
job = new KIO::DeleteOrTrashJob(urlList, KIO::AskUserActionInterface::Trash, KIO::AskUserActionInterface::DefaultConfirmation, parent);
break;
case KIO::JobUiDelegate::Delete:
job = new KIO::DeleteOrTrashJob(urlList, KIO::AskUserActionInterface::Delete, KIO::AskUserActionInterface::DefaultConfirmation, parent);
break;
default: // e.g. EmptyTrash
return;
}
Q_ASSERT(job);
KJobWidgets::setWindow(job, parent);
job->start();
for (const QUrl &url : urlList) {
DocumentFactory::instance()->forget(url);
}
}
void copyTo(const QList<QUrl> &urlList, QWidget *parent, ContextManager *contextManager)
{
copyMoveOrLink(COPY, urlList, parent, contextManager);
}
void moveTo(const QList<QUrl> &urlList, QWidget *parent, ContextManager *contextManager)
{
copyMoveOrLink(MOVE, urlList, parent, contextManager);
}
void linkTo(const QList<QUrl> &urlList, QWidget *parent, ContextManager *contextManager)
{
copyMoveOrLink(LINK, urlList, parent, contextManager);
}
void trash(const QList<QUrl> &urlList, QWidget *parent)
{
delOrTrash(KIO::JobUiDelegate::Trash, urlList, parent);
}
void del(const QList<QUrl> &urlList, QWidget *parent)
{
delOrTrash(KIO::JobUiDelegate::Delete, urlList, parent);
}
void showMenuForDroppedUrls(QWidget *parent, const QList<QUrl> &urlList, const QUrl &destUrl)
{
if (urlList.isEmpty()) {
qCWarning(GWENVIEW_APP_LOG) << "urlList is empty!";
return;
}
if (!destUrl.isValid()) {
qCWarning(GWENVIEW_APP_LOG) << "destUrl is not valid!";
return;
}
QMenu menu(parent);
QAction *moveAction = menu.addAction(QIcon::fromTheme(QStringLiteral("edit-move"), QIcon::fromTheme(QStringLiteral("go-jump"))), i18n("Move Here"));
QAction *copyAction = menu.addAction(QIcon::fromTheme(QStringLiteral("edit-copy")), i18n("Copy Here"));
QAction *linkAction = menu.addAction(QIcon::fromTheme(QStringLiteral("edit-link")), i18n("Link Here"));
menu.addSeparator();
menu.addAction(QIcon::fromTheme(QStringLiteral("process-stop")), i18n("Cancel"));
QAction *action = menu.exec(QCursor::pos());
KIO::Job *job = nullptr;
if (action == moveAction) {
job = KIO::move(urlList, destUrl);
} else if (action == copyAction) {
job = KIO::copy(urlList, destUrl);
} else if (action == linkAction) {
job = KIO::link(urlList, destUrl);
} else {
return;
}
Q_ASSERT(job);
KJobWidgets::setWindow(job, parent);
}
void rename(const QUrl &oldUrl, QWidget *parent, ContextManager *contextManager)
{
auto dialog = new RenameDialog(parent);
dialog->setFilename(oldUrl.fileName());
dialog->setAttribute(Qt::WA_DeleteOnClose);
dialog->setModal(true);
QObject::connect(dialog, &QDialog::accepted, parent, [=]() {
const QString name = dialog->filename();
if (name.isEmpty() || name == oldUrl.fileName()) {
return;
}
QUrl newUrl = oldUrl;
newUrl = newUrl.adjusted(QUrl::RemoveFilename);
newUrl.setPath(newUrl.path() + name);
KIO::SimpleJob *job = KIO::rename(oldUrl, newUrl, KIO::HideProgressInfo);
KJobWidgets::setWindow(job, parent);
job->uiDelegate()->setAutoErrorHandlingEnabled(true);
QObject::connect(job, &KJob::result, parent, [contextManager, job, oldUrl, newUrl]() {
if (!job->error()) {
contextManager->setCurrentUrl(newUrl);
ThumbnailProvider::moveThumbnail(oldUrl, newUrl);
}
});
});
dialog->show();
}
} // namespace
} // namespace