Index: src/widgets/fileundomanager.cpp =================================================================== --- src/widgets/fileundomanager.cpp +++ src/widgets/fileundomanager.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -106,12 +107,33 @@ class KIO::UndoJob : public KIO::Job { Q_OBJECT +private: + class UndoJobPrivate : public JobPrivate + { + public: + UndoJobPrivate(bool useElevatedPrivilege) + { + // Do we need this variable at all? + if (useElevatedPrivilege) { + m_privilegeExecutionEnabled = true; + m_operationType = Other; + m_caption = i18n("Undo Changes"); + m_message = i18n("Undoing from this folder requires root privileges. Do you want to continue?"); + } + } + }; + public: - UndoJob(bool showProgressInfo) : KIO::Job() + UndoJob(bool showProgressInfo, bool useElevatedPrivilege = false) + : KIO::Job(*new UndoJobPrivate(useElevatedPrivilege)) { if (showProgressInfo) { KIO::getJobTracker()->registerJob(this); } + + if (useElevatedPrivilege) { + FileUndoManager::self()->d->m_privilegeExecFlag = KIO::PrivilegeExecution; + } } virtual ~UndoJob() {} @@ -236,7 +258,8 @@ // order of the undo items. FileUndoManagerPrivate::FileUndoManagerPrivate(FileUndoManager *qq) : m_uiInterface(new FileUndoManager::UiInterface()), - m_undoJob(nullptr), m_nextCommandIndex(1000), q(qq) + m_undoJob(nullptr), m_nextCommandIndex(1000), + m_privilegeExecFlag(KIO::DefaultFlags), q(qq) { (void) new KIOFileUndoManagerAdaptor(this); const QString dbusPath = QStringLiteral("/FileUndoManager"); @@ -419,7 +442,7 @@ } //qDebug() << "starting with" << undoStateToString(d->m_undoState); - d->m_undoJob = new UndoJob(d->m_uiInterface->showProgressInfo()); + d->m_undoJob = new UndoJob(d->m_uiInterface->showProgressInfo(), true); QMetaObject::invokeMethod(d, "undoStep", Qt::QueuedConnection); } @@ -509,6 +532,7 @@ QUrl dir = m_dirStack.pop(); //qDebug() << "creatingDir" << dir; m_currentJob = KIO::mkdir(dir); + m_currentJob->setParentJob(m_undoJob); m_undoJob->emitCreatingDir(dir); } else { m_undoState = MOVINGFILES; @@ -528,34 +552,38 @@ if (type == BasicOperation::Directory) { if (op.m_renamed) { //qDebug() << "rename" << op.m_dst << op.m_src; - m_currentJob = KIO::rename(op.m_dst, op.m_src, KIO::HideProgressInfo); + m_currentJob = KIO::rename(op.m_dst, op.m_src, KIO::HideProgressInfo | m_privilegeExecFlag); m_undoJob->emitMoving(op.m_dst, op.m_src); } else { assert(0); // this should not happen! } } else if (type == BasicOperation::Link) { //qDebug() << "symlink" << op.m_target << op.m_src; - m_currentJob = KIO::symlink(op.m_target, op.m_src, KIO::Overwrite | KIO::HideProgressInfo); + m_currentJob = KIO::symlink(op.m_target, op.m_src, KIO::Overwrite | KIO::HideProgressInfo | m_privilegeExecFlag); } else if (m_current.m_type == FileUndoManager::Copy) { if (m_undoState == MOVINGFILES) { // dest not stat'ed yet // Before we delete op.m_dst, let's check if it was modified (#20532) //qDebug() << "stat" << op.m_dst; m_currentJob = KIO::stat(op.m_dst, KIO::HideProgressInfo); m_undoState = STATINGFILE; // temporarily return; // no pop() yet, we'll finish the work in slotResult } else { // dest was stat'ed, and the deletion was approved in slotResult - m_currentJob = KIO::file_delete(op.m_dst, KIO::HideProgressInfo); + m_currentJob = KIO::file_delete(op.m_dst, KIO::HideProgressInfo | m_privilegeExecFlag); m_undoJob->emitDeleting(op.m_dst); m_undoState = MOVINGFILES; } } else if (m_current.isMoveCommand() || m_current.m_type == FileUndoManager::Trash) { //qDebug() << "file_move" << op.m_dst << op.m_src; - m_currentJob = KIO::file_move(op.m_dst, op.m_src, -1, KIO::Overwrite | KIO::HideProgressInfo); + m_currentJob = KIO::file_move(op.m_dst, op.m_src, -1, KIO::Overwrite | KIO::HideProgressInfo | m_privilegeExecFlag); m_currentJob->uiDelegateExtension()->createClipboardUpdater(m_currentJob, JobUiDelegateExtension::UpdateContent); m_undoJob->emitMoving(op.m_dst, op.m_src); } + if (m_currentJob) { + m_currentJob->setParentJob(m_undoJob); + } + m_current.m_opStack.removeLast(); // The above KIO jobs are lowlevel, they don't trigger KDirNotify notification // So we need to do it ourselves (but schedule it to the end of the undo, to compress them) @@ -575,7 +603,8 @@ if (!m_fileCleanupStack.isEmpty()) { QUrl file = m_fileCleanupStack.pop(); //qDebug() << "file_delete" << file; - m_currentJob = KIO::file_delete(file, KIO::HideProgressInfo); + m_currentJob = KIO::file_delete(file, KIO::HideProgressInfo | m_privilegeExecFlag); + m_currentJob->setParentJob(m_undoJob); m_undoJob->emitDeleting(file); QUrl url = file.adjusted(QUrl::RemoveFilename | QUrl::StripTrailingSlash); @@ -595,6 +624,7 @@ QUrl dir = m_dirCleanupStack.pop(); //qDebug() << "rmdir" << dir; m_currentJob = KIO::rmdir(dir); + m_currentJob->setParentJob(m_undoJob); m_undoJob->emitDeleting(dir); addDirToUpdate(dir); } else { Index: src/widgets/fileundomanager_p.h =================================================================== --- src/widgets/fileundomanager_p.h +++ src/widgets/fileundomanager_p.h @@ -26,6 +26,8 @@ #include #include +#include + class KJob; namespace KIO @@ -149,6 +151,8 @@ UndoJob *m_undoJob; quint64 m_nextCommandIndex; + JobFlag m_privilegeExecFlag; + FileUndoManager *q; // DBUS interface