diff --git a/autotests/fileundomanagertest.h b/autotests/fileundomanagertest.h --- a/autotests/fileundomanagertest.h +++ b/autotests/fileundomanagertest.h @@ -44,6 +44,7 @@ void testMkpath(); void testPasteClipboardUndo(); // #318757 void testBatchRename(); + void testUndoCopyOfDeletedFile(); // TODO find tests that would lead to kio job errors diff --git a/autotests/fileundomanagertest.cpp b/autotests/fileundomanagertest.cpp --- a/autotests/fileundomanagertest.cpp +++ b/autotests/fileundomanagertest.cpp @@ -720,5 +720,38 @@ QVERIFY(QFile::exists(srcList.at(2).path())); } +void FileUndoManagerTest::testUndoCopyOfDeletedFile() +{ + const QUrl source = QUrl::fromLocalFile(homeTmpDir() + QStringLiteral("source.txt")); + const QUrl dest = QUrl::fromLocalFile(homeTmpDir() + QStringLiteral("copy.txt")); + + createTestFile(source.toLocalFile(), "foo"); + QVERIFY(QFileInfo::exists(source.toLocalFile())); + + { + auto copyJob = KIO::copy(source, dest, KIO::HideProgressInfo); + copyJob->setUiDelegate(nullptr); + FileUndoManager::self()->recordCopyJob(copyJob); + QVERIFY2(copyJob->exec(), qPrintable(copyJob->errorString())); + QVERIFY(QFileInfo::exists(dest.toLocalFile())); + } + + { + auto deleteJob = KIO::del(dest, KIO::HideProgressInfo); + deleteJob->setUiDelegate(nullptr); + QVERIFY2(deleteJob->exec(), qPrintable(deleteJob->errorString())); + QVERIFY(!QFileInfo::exists(dest.toLocalFile())); + } + + QVERIFY(FileUndoManager::self()->undoAvailable()); + QSignalSpy spyUndoAvailable(FileUndoManager::self(), static_cast(&FileUndoManager::undoAvailable)); + QVERIFY(spyUndoAvailable.isValid()); + // We can't use doUndo() because there is no UndoJob, so the nested event loop would never quit. + FileUndoManager::self()->undo(); + QCOMPARE(spyUndoAvailable.count(), 1); + QVERIFY(!spyUndoAvailable.at(0).at(0).toBool()); + QVERIFY(!FileUndoManager::self()->undoAvailable()); +} + // TODO: add test (and fix bug) for DND of remote urls / "Link here" (creates .desktop files) // Undo (doesn't do anything) // TODO: add test for interrupting a moving operation and then using Undo - bug:91579 diff --git a/src/widgets/fileundomanager.cpp b/src/widgets/fileundomanager.cpp --- a/src/widgets/fileundomanager.cpp +++ b/src/widgets/fileundomanager.cpp @@ -38,6 +38,7 @@ #include #include +#include #include @@ -382,10 +383,14 @@ BasicOperation::Stack::Iterator it = opStack.begin(); for (; it != opStack.end(); ++it) { BasicOperation::Type type = (*it).m_type; + const auto destination = (*it).m_dst; if (type == BasicOperation::File && commandType == FileUndoManager::Copy) { - itemsToDelete.append((*it).m_dst); + if (destination.isLocalFile() && !QFileInfo::exists(destination.toLocalFile())) { + continue; + } + itemsToDelete.append(destination); } else if (commandType == FileUndoManager::Mkpath) { - itemsToDelete.append((*it).m_dst); + itemsToDelete.append(destination); } } if (commandType == FileUndoManager::Mkdir || commandType == FileUndoManager::Put) { @@ -395,6 +400,9 @@ if (!d->m_uiInterface->confirmDeletion(itemsToDelete)) { return; } + } else if (commandType == FileUndoManager::Copy) { + d->slotPop(); + return; } d->slotPop();