Commit 2f19231b authored by Dawit Alemayehu's avatar Dawit Alemayehu
Browse files

Update URLs copied to clipboard if they change as a result of KIO operations.

BUG: 134960
CCBUG: 318757
FIXED-IN: 4.11
REVIEW: 111776
parent 45b616c2
......@@ -20,6 +20,7 @@
#include "clipboardupdater_p.h"
#include "jobclasses.h"
#include "copyjob.h"
#include "deletejob.h"
#include <QApplication>
#include <QMimeSource>
......@@ -27,9 +28,9 @@
using namespace KIO;
ClipboardUpdater::ClipboardUpdater(Job* job, UpdateMode mode)
ClipboardUpdater::ClipboardUpdater(Job* job, Mode mode)
:QObject(job),
m_updateMode(mode)
m_mode(mode)
{
Q_ASSERT(job);
connect(job, SIGNAL(result(KJob*)), this, SLOT(slotResult(KJob*)));
......@@ -37,11 +38,15 @@ ClipboardUpdater::ClipboardUpdater(Job* job, UpdateMode mode)
static void overwriteClipboardContent(KJob* job)
{
QApplication::clipboard()->clear();
KUrl::List newUrls;
CopyJob* copyJob = qobject_cast<CopyJob*>(job);
FileCopyJob* fileCopyJob = qobject_cast<FileCopyJob*>(job);
if (!copyJob && !fileCopyJob) {
return;
}
KUrl::List newUrls;
if (copyJob) {
Q_FOREACH(const KUrl& url, copyJob->srcUrls()) {
KUrl dUrl = copyJob->destUrl();
......@@ -59,16 +64,21 @@ static void overwriteClipboardContent(KJob* job)
static void updateClipboardContent(KJob* job)
{
CopyJob* copyJob = qobject_cast<CopyJob*>(job);
FileCopyJob* fileCopyJob = qobject_cast<FileCopyJob*>(job);
if (!copyJob && !fileCopyJob) {
return;
}
QClipboard* clipboard = QApplication::clipboard();
KUrl::List clipboardUrls = KUrl::List::fromMimeData( clipboard->mimeData());
KUrl::List clipboardUrls = KUrl::List::fromMimeData(clipboard->mimeData());
bool update = false;
CopyJob* copyJob = qobject_cast<CopyJob*>(job);
FileCopyJob* fileCopyJob = qobject_cast<FileCopyJob*>(job);
if (copyJob) {
Q_FOREACH(const KUrl& url, copyJob->srcUrls()) {
const int index = clipboardUrls.indexOf(url);
if (index > 0) {
if (index > -1) {
KUrl dUrl = copyJob->destUrl();
dUrl.addPath(url.fileName());
clipboardUrls.replace(index, dUrl);
......@@ -77,7 +87,7 @@ static void updateClipboardContent(KJob* job)
}
} else if (fileCopyJob) {
const int index = clipboardUrls.indexOf(fileCopyJob->srcUrl());
if (index > 0) {
if (index > -1) {
clipboardUrls.replace(index, fileCopyJob->destUrl());
update = true;
}
......@@ -86,7 +96,46 @@ static void updateClipboardContent(KJob* job)
if (update) {
QMimeData* mime = new QMimeData();
clipboardUrls.populateMimeData(mime);
QApplication::clipboard()->setMimeData(mime);
clipboard->setMimeData(mime);
}
}
static void removeClipboardContent(KJob* job)
{
SimpleJob* simpleJob = qobject_cast<SimpleJob*>(job);
DeleteJob* deleteJob = qobject_cast<DeleteJob*>(job);
if (!simpleJob && !deleteJob) {
return;
}
KUrl::List deletedUrls;
if (simpleJob) {
deletedUrls << simpleJob->url();
} else if (deleteJob) {
deletedUrls << deleteJob->urls();
}
if (deletedUrls.isEmpty()) {
return;
}
QClipboard* clipboard = QApplication::clipboard();
KUrl::List clipboardUrls = KUrl::List::fromMimeData(clipboard->mimeData());
const int urlCount = clipboardUrls.count();
Q_FOREACH(const KUrl& url, deletedUrls) {
if (clipboardUrls.indexOf(url) != -1) {
clipboardUrls.removeAll(url);
}
}
if (urlCount != clipboardUrls.count()) {
QMimeData* mime = new QMimeData();
if (!clipboardUrls.isEmpty()) {
clipboardUrls.populateMimeData(mime);
}
clipboard->setMimeData(mime);
}
}
......@@ -96,12 +145,35 @@ void ClipboardUpdater::slotResult(KJob* job)
return;
}
switch (m_updateMode) {
switch (m_mode) {
case UpdateContent:
updateClipboardContent(job);
break;
case OverwriteContent:
overwriteClipboardContent(job);
break;
case RemoveContent:
removeClipboardContent(job);
break;
}
}
void ClipboardUpdater::update(const KUrl& srcUrl, const KUrl& destUrl)
{
QClipboard* clipboard = QApplication::clipboard();
if (clipboard->mimeData()->hasUrls()) {
KUrl::List clipboardUrls = KUrl::List::fromMimeData( clipboard->mimeData());
const int index = clipboardUrls.indexOf(srcUrl);
if (index > -1) {
clipboardUrls.replace(index, destUrl);
QMimeData* mime = new QMimeData();
clipboardUrls.populateMimeData(mime);
clipboard->setMimeData(mime);
}
}
}
void ClipboardUpdater::setMode(ClipboardUpdater::Mode mode)
{
m_mode = mode;
}
......@@ -23,6 +23,7 @@
#include <QObject>
class KJob;
class KUrl;
namespace KIO {
class Job;
......@@ -46,18 +47,29 @@ namespace KIO {
Q_OBJECT
public:
enum UpdateMode {
enum Mode {
UpdateContent,
OverwriteContent,
RemoveContent
};
explicit ClipboardUpdater(Job* job, UpdateMode mode);
explicit ClipboardUpdater(Job* job, Mode mode);
/**
* Convenience function that allows renaming of a single url in the clipboard.
*/
static void update(const KUrl& srcUrl, const KUrl& destUrl);
/**
* Sets the mode.
*/
void setMode(Mode m);
private Q_SLOTS:
void slotResult(KJob* job);
private:
UpdateMode m_updateMode;
Mode m_mode;
};
}
......
......@@ -24,6 +24,7 @@
#include "kdirlister.h"
#include "kfileitem.h"
#include "deletejob.h"
#include "clipboardupdater_p.h"
#include <klocale.h>
#include <kdesktopfile.h>
......@@ -2185,7 +2186,9 @@ CopyJob *KIO::move(const KUrl& src, const KUrl& dest, JobFlags flags)
//kDebug(7007) << src << dest;
KUrl::List srcList;
srcList.append( src );
return CopyJobPrivate::newJob(srcList, dest, CopyJob::Move, false, flags);
CopyJob* job = CopyJobPrivate::newJob(srcList, dest, CopyJob::Move, false, flags);
new ClipboardUpdater(job, ClipboardUpdater::UpdateContent);
return job;
}
CopyJob *KIO::moveAs(const KUrl& src, const KUrl& dest, JobFlags flags)
......@@ -2193,13 +2196,17 @@ CopyJob *KIO::moveAs(const KUrl& src, const KUrl& dest, JobFlags flags)
//kDebug(7007) << src << dest;
KUrl::List srcList;
srcList.append( src );
return CopyJobPrivate::newJob(srcList, dest, CopyJob::Move, true, flags);
CopyJob* job = CopyJobPrivate::newJob(srcList, dest, CopyJob::Move, true, flags);
new ClipboardUpdater(job, ClipboardUpdater::UpdateContent);
return job;
}
CopyJob *KIO::move( const KUrl::List& src, const KUrl& dest, JobFlags flags)
{
//kDebug(7007) << src << dest;
return CopyJobPrivate::newJob(src, dest, CopyJob::Move, false, flags);
CopyJob* job = CopyJobPrivate::newJob(src, dest, CopyJob::Move, false, flags);
new ClipboardUpdater(job, ClipboardUpdater::UpdateContent);
return job;
}
CopyJob *KIO::link(const KUrl& src, const KUrl& destDir, JobFlags flags)
......
......@@ -26,6 +26,7 @@
#include "kdirwatch.h"
#include "kprotocolmanager.h"
#include "jobuidelegate.h"
#include "clipboardupdater_p.h"
#include <kdirnotify.h>
#include <klocale.h>
......@@ -485,12 +486,16 @@ DeleteJob *KIO::del( const KUrl& src, JobFlags flags )
{
KUrl::List srcList;
srcList.append( src );
return DeleteJobPrivate::newJob(srcList, flags);
DeleteJob* job = DeleteJobPrivate::newJob(srcList, flags);
new ClipboardUpdater(job, ClipboardUpdater::RemoveContent);
return job;
}
DeleteJob *KIO::del( const KUrl::List& src, JobFlags flags )
{
return DeleteJobPrivate::newJob(src, flags);
DeleteJob* job = DeleteJobPrivate::newJob(src, flags);
new ClipboardUpdater(job, ClipboardUpdater::RemoveContent);
return job;
}
#include "deletejob.moc"
......@@ -21,6 +21,7 @@
#include "job.h"
#include "job_p.h"
#include "clipboardupdater_p.h"
#include <config.h>
......@@ -489,6 +490,7 @@ void SimpleJob::slotFinished( )
org::kde::KDirNotify::emitFileRenamed( src.url(), dst.url() );
org::kde::KDirNotify::emitFileMoved( src.url(), dst.url() );
ClipboardUpdater::update(src, dst);
}
}
emitResult();
......@@ -2480,13 +2482,17 @@ FileCopyJob *KIO::file_copy( const KUrl& src, const KUrl& dest, int permissions,
FileCopyJob *KIO::file_move( const KUrl& src, const KUrl& dest, int permissions,
JobFlags flags )
{
return FileCopyJobPrivate::newJob(src, dest, permissions, true, flags);
FileCopyJob* job = FileCopyJobPrivate::newJob(src, dest, permissions, true, flags);
new ClipboardUpdater(job, ClipboardUpdater::UpdateContent);
return job;
}
SimpleJob *KIO::file_delete( const KUrl& src, JobFlags flags )
{
KIO_ARGS << src << qint8(true); // isFile
return SimpleJobPrivate::newJob(src, CMD_DEL, packedArgs, flags);
SimpleJob* job = SimpleJobPrivate::newJob(src, CMD_DEL, packedArgs, flags);
new ClipboardUpdater(job, ClipboardUpdater::RemoveContent);
return job;
}
//////////
......
......@@ -66,15 +66,14 @@ static KIO::Job *pasteClipboardUrls(const QMimeData* mimeData, const KUrl& destD
if (!urls.isEmpty()) {
const bool move = decodeIsCutSelection(mimeData);
KIO::Job *job = 0;
if (move)
if (move) {
job = KIO::move(urls, destDir, flags);
KIO::ClipboardUpdater* clipboardUpdater = job->findChild<KIO::ClipboardUpdater *>();
Q_ASSERT(clipboardUpdater);
clipboardUpdater->setMode(KIO::ClipboardUpdater::OverwriteContent);
}
else
job = KIO::copy(urls, destDir, flags);
// If moving, update the clipboard contents with the new locations
if (move) {
new KIO::ClipboardUpdater(job, KIO::ClipboardUpdater::OverwriteContent);
}
return job;
}
return 0;
......
......@@ -32,6 +32,7 @@ KIO_UNIT_TESTS(
fileundomanagertest
kfilemetainfotest
dataprotocoltest
clipboardupdatertest
)
KIO_EXECUTABLE_TESTS(
......
/* This file is part of KDE
Copyright (c) 2013 Dawit Alemayehu <adawit@kde.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include <qtest_kde.h>
#include "clipboardupdatertest.h"
#include "kiotesthelper.h"
#include "clipboardupdater_p.h"
#include <kio/job.h>
#include <kio/paste.h>
#include <kio/copyjob.h>
#include <kio/deletejob.h>
#include <kdebug.h>
#include <ktempdir.h>
#include <QClipboard>
#include <QApplication>
#include <QMimeData>
QTEST_KDEMAIN( ClipboardUpdaterTest, GUI )
using namespace KIO;
static KUrl::List tempFiles(const KTempDir& dir, const QString& baseName, int count = 3)
{
KUrl::List urls;
const QString path = dir.name();
for (int i = 1; i < count+1; ++i) {
const QString file = (path + baseName + QString::number(i));
urls << KUrl(file);
createTestFile(file);
}
return urls;
}
void ClipboardUpdaterTest::testPasteAfterRenameFiles()
{
KTempDir dir;
const KUrl::List urls = tempFiles(dir, QLatin1String("rfile"));
QClipboard* clipboard = QApplication::clipboard();
QMimeData* mimeData = new QMimeData();
urls.populateMimeData(mimeData);
clipboard->setMimeData(mimeData);
Q_FOREACH(const KUrl& url, urls) {
KUrl newUrl = url;
newUrl.setFileName(url.fileName() + QLatin1String("_renamed"));
KIO::SimpleJob* job = KIO::rename(url, newUrl, KIO::HideProgressInfo);
QVERIFY(job->exec());
}
const QString pasteDir = dir.name() + QLatin1String("pastedir");
createTestDirectory(pasteDir, NoSymlink);
KIO::Job* job = KIO::pasteClipboard(KUrl(pasteDir), 0);
QVERIFY(job->exec());
QVERIFY(job->error() == 0);
}
void ClipboardUpdaterTest::testPasteAfterMoveFile()
{
KTempDir dir;
const KUrl::List urls = tempFiles(dir, QLatin1String("mfile"), 1);
QClipboard* clipboard = QApplication::clipboard();
QMimeData* mimeData = new QMimeData();
urls.populateMimeData(mimeData);
clipboard->setMimeData(mimeData);
const QString moveDir = dir.name() + QLatin1String("movedir/");
createTestDirectory(moveDir, NoSymlink);
const KUrl srcUrl = urls.first();
KUrl destUrl (moveDir);
destUrl.setFileName(srcUrl.fileName());
KIO::FileCopyJob* mJob = KIO::file_move(srcUrl, destUrl, -1, KIO::HideProgressInfo);
QVERIFY(mJob->exec());
const QString pasteDir = dir.name() + QLatin1String("pastedir");
createTestDirectory(pasteDir, NoSymlink);
KIO::Job* job = KIO::pasteClipboard(KUrl(pasteDir), 0);
QVERIFY(job->exec());
QVERIFY(job->error() == 0);
}
void ClipboardUpdaterTest::testPasteAfterMoveFiles()
{
KTempDir dir;
const KUrl::List urls = tempFiles(dir, QLatin1String("mfile"));
QClipboard* clipboard = QApplication::clipboard();
QMimeData* mimeData = new QMimeData();
urls.populateMimeData(mimeData);
clipboard->setMimeData(mimeData);
const QString moveDir = dir.name() + QLatin1String("movedir");
createTestDirectory(moveDir, NoSymlink);
KIO::CopyJob* mJob = KIO::move(urls, KUrl(moveDir), KIO::HideProgressInfo);
QVERIFY(mJob->exec());
const QString pasteDir = dir.name() + QLatin1String("pastedir");
createTestDirectory(pasteDir, NoSymlink);
KIO::Job* job = KIO::pasteClipboard(KUrl(pasteDir), 0);
QVERIFY(job->exec());
QVERIFY(job->error() == 0);
}
void ClipboardUpdaterTest::testPasteAfterDeleteFile()
{
KTempDir dir;
const KUrl::List urls = tempFiles(dir, QLatin1String("dfile"), 1);
QClipboard* clipboard = QApplication::clipboard();
QMimeData* mimeData = new QMimeData();
urls.populateMimeData(mimeData);
clipboard->setMimeData(mimeData);
SimpleJob* sJob = KIO::file_delete(urls.first(), KIO::HideProgressInfo);
QVERIFY(sJob->exec());
QVERIFY(!clipboard->mimeData()->hasUrls());
const QString pasteDir = dir.name() + QLatin1String("pastedir");
createTestDirectory(pasteDir, NoSymlink);
KIO::Job* job = KIO::pasteClipboard(KUrl(pasteDir), 0);
QVERIFY(!job);
}
void ClipboardUpdaterTest::testPasteAfterDeleteFiles()
{
KTempDir dir;
const KUrl::List urls = tempFiles(dir, QLatin1String("dfile"));
QClipboard* clipboard = QApplication::clipboard();
QMimeData* mimeData = new QMimeData();
urls.populateMimeData(mimeData);
clipboard->setMimeData(mimeData);
DeleteJob* dJob = KIO::del(urls, KIO::HideProgressInfo);
QVERIFY(dJob->exec());
QVERIFY(!clipboard->mimeData()->hasUrls());
const QString pasteDir = dir.name() + QLatin1String("pastedir");
createTestDirectory(pasteDir, NoSymlink);
KIO::Job* job = KIO::pasteClipboard(KUrl(pasteDir), 0);
QVERIFY(!job);
}
#include "clipboardupdatertest.moc"
/* This file is part of KDE
Copyright (c) 2013 Dawit Alemayehu <adawit@kde.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#ifndef CLIPBOARDUPDATETEST_H
#define CLIPBOARDUPDATETEST_H
#include <QObject>
class ClipboardUpdaterTest : public QObject
{
Q_OBJECT
private slots:
void testPasteAfterRenameFiles();
void testPasteAfterMoveFile();
void testPasteAfterMoveFiles();
void testPasteAfterDeleteFile();
void testPasteAfterDeleteFiles();
};
#endif
......@@ -511,14 +511,14 @@ void FileUndoManagerTest::testModifyFileBeforeUndo()
QVERIFY( !QFile::exists( destSubDir() ) );
}
void FileUndoManagerTest::testPasteClipboard()
void FileUndoManagerTest::testPasteClipboardUndo()
{
KUrl::List urls;
urls << sourceList();
const KUrl::List urls (sourceList());
QMimeData* mimeData = new QMimeData();
urls.populateMimeData(mimeData);
mimeData->setData(QLatin1String("application/x-kde-cutselection"), "1");
QApplication::clipboard()->setMimeData(mimeData);
QClipboard* clipboard = QApplication::clipboard();
clipboard->setMimeData(mimeData);
// Paste the contents of the clipboard and check its status
KUrl destDirUrl(destDir());
......@@ -534,13 +534,13 @@ void FileUndoManagerTest::testPasteClipboard()
dUrl.addPath(url.fileName());
urls2 << dUrl;
}
urls = KUrl::List::fromMimeData(QApplication::clipboard()->mimeData());
QCOMPARE(urls2, urls);
KUrl::List clipboardUrls = KUrl::List::fromMimeData(clipboard->mimeData());
QCOMPARE(clipboardUrls, urls2);
// Check if the clipboard was updated after undo operation
doUndo();
urls2 = KUrl::List::fromMimeData(QApplication::clipboard()->mimeData());
QCOMPARE(urls, urls2);
clipboardUrls = KUrl::List::fromMimeData(clipboard->mimeData());
QCOMPARE(clipboardUrls, urls);
}
......
......@@ -39,7 +39,7 @@ private slots:
void testTrashFiles();
void testModifyFileBeforeUndo(); // #20532
void testCreateDir();
void testPasteClipboard(); // #318757
void testPasteClipboardUndo(); // #318757
// TODO find tests that would lead to kio job errors
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment