00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "fileundomanager.h"
00022 #include "fileundomanager_p.h"
00023 #include "fileundomanager_adaptor.h"
00024
00025 #include <kdatetime.h>
00026 #include <kdebug.h>
00027 #include <kdirnotify.h>
00028 #include <kglobal.h>
00029 #include <kio/copyjob.h>
00030 #include <kio/job.h>
00031 #include <kio/jobuidelegate.h>
00032 #include <klocale.h>
00033 #include <kmessagebox.h>
00034 #include <kuiserverjobtracker.h>
00035
00036 #include <QtDBus/QtDBus>
00037
00038 #include <assert.h>
00039
00040 using namespace KIO;
00041
00042 static const char* undoStateToString(UndoState state) {
00043 static const char* s_undoStateToString[] = { "MAKINGDIRS", "MOVINGFILES", "STATINGFILE", "REMOVINGDIRS", "REMOVINGLINKS" };
00044 return s_undoStateToString[state];
00045 }
00046
00047 static QDataStream &operator<<(QDataStream &stream, const KIO::BasicOperation &op)
00048 {
00049 stream << op.m_valid << (qint8)op.m_type << op.m_renamed
00050 << op.m_src << op.m_dst << op.m_target << (qint64)op.m_mtime;
00051 return stream;
00052 }
00053 static QDataStream &operator>>(QDataStream &stream, BasicOperation &op)
00054 {
00055 qint8 type;
00056 qint64 mtime;
00057 stream >> op.m_valid >> type >> op.m_renamed
00058 >> op.m_src >> op.m_dst >> op.m_target >> mtime;
00059 op.m_type = static_cast<BasicOperation::Type>(type);
00060 op.m_mtime = mtime;
00061 return stream;
00062 }
00063
00064 static QDataStream &operator<<(QDataStream &stream, const UndoCommand &cmd)
00065 {
00066 stream << cmd.m_valid << (qint8)cmd.m_type << cmd.m_opStack << cmd.m_src << cmd.m_dst;
00067 return stream;
00068 }
00069
00070 static QDataStream &operator>>(QDataStream &stream, UndoCommand &cmd)
00071 {
00072 qint8 type;
00073 stream >> cmd.m_valid >> type >> cmd.m_opStack >> cmd.m_src >> cmd.m_dst;
00074 cmd.m_type = static_cast<FileUndoManager::CommandType>(type);
00075 return stream;
00076 }
00077
00101 class KIO::UndoJob : public KIO::Job
00102 {
00103 public:
00104 UndoJob(bool showProgressInfo) : KIO::Job() {
00105 if (showProgressInfo)
00106 KIO::getJobTracker()->registerJob(this);
00107 }
00108 virtual ~UndoJob() {}
00109
00110 virtual void kill(bool) {
00111 FileUndoManager::self()->d->stopUndo(true);
00112 KIO::Job::doKill();
00113 }
00114
00115 void emitCreatingDir(const KUrl &dir)
00116 { emit description(this, i18n("Creating directory"),
00117 qMakePair(i18n("Directory"), dir.prettyUrl())); }
00118 void emitMoving(const KUrl &src, const KUrl &dest)
00119 { emit description(this, i18n("Moving"),
00120 qMakePair(i18n("Source"), src.prettyUrl()),
00121 qMakePair(i18n("Destination"), dest.prettyUrl())); }
00122 void emitDeleting(const KUrl &url)
00123 { emit description(this, i18n("Deleting"),
00124 qMakePair(i18n("File"), url.prettyUrl())); }
00125 void emitResult() { KIO::Job::emitResult(); }
00126 };
00127
00128 CommandRecorder::CommandRecorder(FileUndoManager::CommandType op, const KUrl::List &src, const KUrl &dst, KIO::Job *job)
00129 : QObject(job)
00130 {
00131 m_cmd.m_type = op;
00132 m_cmd.m_valid = true;
00133 m_cmd.m_serialNumber = FileUndoManager::self()->newCommandSerialNumber();
00134 m_cmd.m_src = src;
00135 m_cmd.m_dst = dst;
00136 connect(job, SIGNAL(result(KJob*)),
00137 this, SLOT(slotResult(KJob*)));
00138
00139 if (op != FileUndoManager::Mkdir) {
00140 connect(job, SIGNAL(copyingDone(KIO::Job*,KUrl,KUrl,time_t,bool,bool)),
00141 this, SLOT(slotCopyingDone(KIO::Job*,KUrl,KUrl,time_t,bool,bool)));
00142 connect(job, SIGNAL(copyingLinkDone(KIO::Job *,KUrl,QString,KUrl)),
00143 this, SLOT(slotCopyingLinkDone(KIO::Job *,KUrl,QString,KUrl)));
00144 }
00145 }
00146
00147 CommandRecorder::~CommandRecorder()
00148 {
00149 }
00150
00151 void CommandRecorder::slotResult(KJob *job)
00152 {
00153 if (job->error())
00154 return;
00155
00156 FileUndoManager::self()->d->addCommand(m_cmd);
00157 }
00158
00159 void CommandRecorder::slotCopyingDone(KIO::Job *job, const KUrl &from, const KUrl &to, time_t mtime, bool directory, bool renamed)
00160 {
00161 BasicOperation op;
00162 op.m_valid = true;
00163 op.m_type = directory ? BasicOperation::Directory : BasicOperation::File;
00164 op.m_renamed = renamed;
00165 op.m_src = from;
00166 op.m_dst = to;
00167 op.m_mtime = mtime;
00168
00169 if (m_cmd.m_type == FileUndoManager::Trash)
00170 {
00171 Q_ASSERT(to.protocol() == "trash");
00172 QMap<QString, QString> metaData = job->metaData();
00173 QMap<QString, QString>::ConstIterator it = metaData.find("trashURL-" + from.path());
00174 if (it != metaData.end()) {
00175
00176 op.m_dst = it.value();
00177 }
00178 }
00179
00180 m_cmd.m_opStack.prepend(op);
00181 }
00182
00183
00184 void CommandRecorder::slotCopyingLinkDone(KIO::Job *, const KUrl &from, const QString &target, const KUrl &to)
00185 {
00186 BasicOperation op;
00187 op.m_valid = true;
00188 op.m_type = BasicOperation::Link;
00189 op.m_renamed = false;
00190 op.m_src = from;
00191 op.m_target = target;
00192 op.m_dst = to;
00193 op.m_mtime = -1;
00194 m_cmd.m_opStack.prepend(op);
00195 }
00196
00198
00199 class KIO::FileUndoManagerSingleton
00200 {
00201 public:
00202 FileUndoManager self;
00203 };
00204 K_GLOBAL_STATIC(KIO::FileUndoManagerSingleton, globalFileUndoManager)
00205
00206 FileUndoManager *FileUndoManager::self()
00207 {
00208 return &globalFileUndoManager->self;
00209 }
00210
00211 FileUndoManagerPrivate::FileUndoManagerPrivate(FileUndoManager* qq)
00212 : m_uiInterface(new FileUndoManager::UiInterface()),
00213 m_undoJob(0), m_nextCommandIndex(0), q(qq)
00214 {
00215 m_syncronized = initializeFromKDesky();
00216 (void) new KIOFileUndoManagerAdaptor(this);
00217 const QString dbusPath = "/FileUndoManager";
00218 const QString dbusInterface = "org.kde.kio.FileUndoManager";
00219
00220 QDBusConnection dbus = QDBusConnection::sessionBus();
00221 dbus.registerObject(dbusPath, this);
00222 dbus.connect(QString(), dbusPath, dbusInterface, "lock", this, SLOT(slotLock()));
00223 dbus.connect(QString(), dbusPath, dbusInterface, "pop", this, SLOT(slotPop()));
00224 dbus.connect(QString(), dbusPath, dbusInterface, "push", this, SLOT(slotPush(QByteArray)));
00225 dbus.connect(QString(), dbusPath, dbusInterface, "unlock", this, SLOT(slotUnlock()));
00226 }
00227
00228 FileUndoManager::FileUndoManager()
00229 {
00230 d = new FileUndoManagerPrivate(this);
00231 d->m_lock = false;
00232 d->m_currentJob = 0;
00233 }
00234
00235 FileUndoManager::~FileUndoManager()
00236 {
00237 delete d;
00238 }
00239
00240 void FileUndoManager::recordJob(CommandType op, const KUrl::List &src, const KUrl &dst, KIO::Job *job)
00241 {
00242
00243 (void) new CommandRecorder(op, src, dst, job);
00244 }
00245
00246 void FileUndoManager::recordCopyJob(KIO::CopyJob* copyJob)
00247 {
00248 CommandType commandType;
00249 switch (copyJob->operationMode()) {
00250 case CopyJob::Copy:
00251 commandType = Copy;
00252 break;
00253 case CopyJob::Move:
00254 commandType = Move;
00255 break;
00256 case CopyJob::Link:
00257 default:
00258 commandType = Link;
00259 break;
00260 }
00261 recordJob(commandType, copyJob->srcUrls(), copyJob->destUrl(), copyJob);
00262 }
00263
00264 void FileUndoManagerPrivate::addCommand(const UndoCommand &cmd)
00265 {
00266 broadcastPush(cmd);
00267 }
00268
00269 bool FileUndoManager::undoAvailable() const
00270 {
00271 return (d->m_commands.count() > 0) && !d->m_lock;
00272 }
00273
00274 QString FileUndoManager::undoText() const
00275 {
00276 if (d->m_commands.isEmpty())
00277 return i18n("Und&o");
00278
00279 FileUndoManager::CommandType t = d->m_commands.top().m_type;
00280 if (t == FileUndoManager::Copy)
00281 return i18n("Und&o: Copy");
00282 else if (t == FileUndoManager::Link)
00283 return i18n("Und&o: Link");
00284 else if (t == FileUndoManager::Move)
00285 return i18n("Und&o: Move");
00286 else if (t == FileUndoManager::Rename)
00287 return i18n("Und&o: Rename");
00288 else if (t == FileUndoManager::Trash)
00289 return i18n("Und&o: Trash");
00290 else if (t == FileUndoManager::Mkdir)
00291 return i18n("Und&o: Create Folder");
00292 else
00293 assert(false);
00294
00295 return QString();
00296 }
00297
00298 quint64 FileUndoManager::newCommandSerialNumber()
00299 {
00300 return ++(d->m_nextCommandIndex);
00301 }
00302
00303 quint64 FileUndoManager::currentCommandSerialNumber() const
00304 {
00305 if(!d->m_commands.isEmpty())
00306 {
00307 const UndoCommand& cmd = d->m_commands.top();
00308 assert(cmd.m_valid);
00309 return cmd.m_serialNumber;
00310 } else
00311 return 0;
00312 }
00313
00314 void FileUndoManager::undo()
00315 {
00316
00317 UndoCommand cmd = d->m_commands.top();
00318 assert(cmd.m_valid);
00319 d->m_current = cmd;
00320
00321 BasicOperation::Stack& opStack = d->m_current.m_opStack;
00322
00323
00324
00325 KUrl::List fileCleanupStack;
00326 QStack<BasicOperation>::Iterator it = opStack.begin();
00327 for (; it != opStack.end() ; ++it) {
00328 BasicOperation::Type type = (*it).m_type;
00329 if (type == BasicOperation::File && d->m_current.m_type == FileUndoManager::Copy) {
00330 fileCleanupStack.append((*it).m_dst);
00331 }
00332 }
00333 if (d->m_current.m_type == FileUndoManager::Mkdir) {
00334 fileCleanupStack.append(d->m_current.m_dst);
00335 }
00336 if (!fileCleanupStack.isEmpty()) {
00337 if (!d->m_uiInterface->confirmDeletion(fileCleanupStack)) {
00338 return;
00339 }
00340 }
00341
00342 d->broadcastPop();
00343 d->broadcastLock();
00344
00345 d->m_dirCleanupStack.clear();
00346 d->m_dirStack.clear();
00347 d->m_dirsToUpdate.clear();
00348
00349 d->m_undoState = MOVINGFILES;
00350
00351
00352
00353
00354 it = opStack.begin();
00355 while (it != opStack.end())
00356 {
00357 bool removeBasicOperation = false;
00358 BasicOperation::Type type = (*it).m_type;
00359 if (type == BasicOperation::Directory && !(*it).m_renamed)
00360 {
00361
00362 d->m_undoState = MAKINGDIRS;
00363
00364 if (d->m_current.isMoveCommand())
00365 d->m_dirStack.push((*it).m_src);
00366
00367
00368 d->m_dirCleanupStack.prepend((*it).m_dst);
00369 removeBasicOperation = true;
00370 }
00371 else if (type == BasicOperation::Link)
00372 {
00373 d->m_linkCleanupStack.prepend((*it).m_dst);
00374
00375 removeBasicOperation = !d->m_current.isMoveCommand();
00376 }
00377
00378 if (removeBasicOperation)
00379 it = opStack.erase(it);
00380 else
00381 ++it;
00382 }
00383
00384 kDebug(1203) << "starting with" << undoStateToString(d->m_undoState);
00385 d->m_undoJob = new UndoJob(d->m_uiInterface->showProgressInfo());
00386 d->undoStep();
00387 }
00388
00389 void FileUndoManagerPrivate::stopUndo(bool step)
00390 {
00391 m_current.m_opStack.clear();
00392 m_dirCleanupStack.clear();
00393 m_linkCleanupStack.clear();
00394 m_undoState = REMOVINGDIRS;
00395 m_undoJob = 0;
00396
00397 if (m_currentJob)
00398 m_currentJob->kill();
00399
00400 m_currentJob = 0;
00401
00402 if (step)
00403 undoStep();
00404 }
00405
00406 void FileUndoManagerPrivate::slotResult(KJob *job)
00407 {
00408 m_currentJob = 0;
00409 if (job->error())
00410 {
00411 m_uiInterface->jobError(static_cast<KIO::Job*>(job));
00412 delete m_undoJob;
00413 stopUndo(false);
00414 }
00415 else if (m_undoState == STATINGFILE)
00416 {
00417 BasicOperation op = m_current.m_opStack.top();
00418
00419 KIO::StatJob* statJob = static_cast<KIO::StatJob*>(job);
00420 time_t mtime = statJob->statResult().numberValue(KIO::UDSEntry::UDS_MODIFICATION_TIME, -1);
00421 if (mtime != op.m_mtime) {
00422 kDebug(1203) << op.m_dst << " was modified after being copied!";
00423 KDateTime srcTime; srcTime.setTime_t(op.m_mtime); srcTime = srcTime.toLocalZone();
00424 KDateTime destTime; destTime.setTime_t(mtime); destTime = destTime.toLocalZone();
00425 if (!m_uiInterface->copiedFileWasModified(op.m_src, op.m_dst, srcTime, destTime)) {
00426 stopUndo(false);
00427 }
00428 }
00429 }
00430
00431 undoStep();
00432 }
00433
00434
00435 void FileUndoManagerPrivate::addDirToUpdate(const KUrl& url)
00436 {
00437 if (!m_dirsToUpdate.contains(url))
00438 m_dirsToUpdate.prepend(url);
00439 }
00440
00441 void FileUndoManagerPrivate::undoStep()
00442 {
00443 m_currentJob = 0;
00444
00445 if (m_undoState == MAKINGDIRS)
00446 stepMakingDirectories();
00447
00448 if (m_undoState == MOVINGFILES || m_undoState == STATINGFILE)
00449 stepMovingFiles();
00450
00451 if (m_undoState == REMOVINGLINKS)
00452 stepRemovingLinks();
00453
00454 if (m_undoState == REMOVINGDIRS)
00455 stepRemovingDirectories();
00456
00457 if (m_currentJob) {
00458 if (m_uiInterface)
00459 m_currentJob->ui()->setWindow(m_uiInterface->parentWidget());
00460 QObject::connect(m_currentJob, SIGNAL(result(KJob*)),
00461 this, SLOT(slotResult(KJob*)));
00462 }
00463 }
00464
00465 void FileUndoManagerPrivate::stepMakingDirectories()
00466 {
00467 if (!m_dirStack.isEmpty()) {
00468 KUrl dir = m_dirStack.pop();
00469 kDebug(1203) << "creatingDir" << dir;
00470 m_currentJob = KIO::mkdir(dir);
00471 m_undoJob->emitCreatingDir(dir);
00472 }
00473 else
00474 m_undoState = MOVINGFILES;
00475 }
00476
00477
00478
00479
00480 void FileUndoManagerPrivate::stepMovingFiles()
00481 {
00482 if (!m_current.m_opStack.isEmpty())
00483 {
00484 BasicOperation op = m_current.m_opStack.top();
00485 BasicOperation::Type type = op.m_type;
00486
00487 assert(op.m_valid);
00488 if (type == BasicOperation::Directory)
00489 {
00490 if (op.m_renamed)
00491 {
00492 kDebug(1203) << "rename" << op.m_dst << op.m_src;
00493 m_currentJob = KIO::rename(op.m_dst, op.m_src, KIO::HideProgressInfo);
00494 m_undoJob->emitMoving(op.m_dst, op.m_src);
00495 }
00496 else
00497 assert(0);
00498 }
00499 else if (type == BasicOperation::Link)
00500 {
00501 kDebug(1203) << "symlink" << op.m_target << op.m_src;
00502 m_currentJob = KIO::symlink(op.m_target, op.m_src, KIO::Overwrite | KIO::HideProgressInfo);
00503 }
00504 else if (m_current.m_type == FileUndoManager::Copy)
00505 {
00506 if (m_undoState == MOVINGFILES)
00507 {
00508
00509 kDebug(1203) << "stat" << op.m_dst;
00510 m_currentJob = KIO::stat(op.m_dst, KIO::HideProgressInfo);
00511 m_undoState = STATINGFILE;
00512 return;
00513 }
00514 else
00515 {
00516 m_currentJob = KIO::file_delete(op.m_dst, KIO::HideProgressInfo);
00517 m_undoJob->emitDeleting(op.m_dst);
00518 m_undoState = MOVINGFILES;
00519 }
00520 }
00521 else if (m_current.isMoveCommand()
00522 || m_current.m_type == FileUndoManager::Trash)
00523 {
00524 kDebug(1203) << "file_move" << op.m_dst << op.m_src;
00525 m_currentJob = KIO::file_move(op.m_dst, op.m_src, -1, KIO::Overwrite | KIO::HideProgressInfo);
00526 m_undoJob->emitMoving(op.m_dst, op.m_src);
00527 }
00528
00529 m_current.m_opStack.pop();
00530
00531
00532 KUrl url(op.m_dst);
00533 url.setPath(url.directory());
00534 addDirToUpdate(url);
00535
00536 url = op.m_src;
00537 url.setPath(url.directory());
00538 addDirToUpdate(url);
00539 }
00540 else
00541 m_undoState = REMOVINGLINKS;
00542 }
00543
00544 void FileUndoManagerPrivate::stepRemovingLinks()
00545 {
00546 kDebug(1203) << "REMOVINGLINKS";
00547 if (!m_linkCleanupStack.isEmpty())
00548 {
00549 KUrl file = m_linkCleanupStack.pop();
00550 kDebug(1203) << "file_delete" << file;
00551 m_currentJob = KIO::file_delete(file, KIO::HideProgressInfo);
00552 m_undoJob->emitDeleting(file);
00553
00554 KUrl url(file);
00555 url.setPath(url.directory());
00556 addDirToUpdate(url);
00557 }
00558 else
00559 {
00560 m_undoState = REMOVINGDIRS;
00561
00562 if (m_dirCleanupStack.isEmpty() && m_current.m_type == FileUndoManager::Mkdir)
00563 m_dirCleanupStack << m_current.m_dst;
00564 }
00565 }
00566
00567 void FileUndoManagerPrivate::stepRemovingDirectories()
00568 {
00569 if (!m_dirCleanupStack.isEmpty())
00570 {
00571 KUrl dir = m_dirCleanupStack.pop();
00572 kDebug(1203) << "rmdir" << dir;
00573 m_currentJob = KIO::rmdir(dir);
00574 m_undoJob->emitDeleting(dir);
00575 addDirToUpdate(dir);
00576 }
00577 else
00578 {
00579 m_current.m_valid = false;
00580 m_currentJob = 0;
00581 if (m_undoJob)
00582 {
00583 kDebug(1203) << "deleting undojob";
00584 m_undoJob->emitResult();
00585 m_undoJob = 0;
00586 }
00587 QList<KUrl>::ConstIterator it = m_dirsToUpdate.begin();
00588 for(; it != m_dirsToUpdate.end(); ++it) {
00589 kDebug() << "Notifying FilesAdded for " << *it;
00590 org::kde::KDirNotify::emitFilesAdded((*it).url());
00591 }
00592 emit q->undoJobFinished();
00593 broadcastUnlock();
00594 }
00595 }
00596
00597
00598 void FileUndoManagerPrivate::slotPush(QByteArray data)
00599 {
00600 QDataStream strm(&data, QIODevice::ReadOnly);
00601 UndoCommand cmd;
00602 strm >> cmd;
00603 pushCommand(cmd);
00604 }
00605
00606 void FileUndoManagerPrivate::pushCommand(const UndoCommand& cmd)
00607 {
00608 m_commands.push(cmd);
00609 emit q->undoAvailable(true);
00610 emit q->undoTextChanged(q->undoText());
00611 }
00612
00613 void FileUndoManagerPrivate::slotPop()
00614 {
00615 m_commands.pop();
00616 emit q->undoAvailable(q->undoAvailable());
00617 emit q->undoTextChanged(q->undoText());
00618 }
00619
00620 void FileUndoManagerPrivate::slotLock()
00621 {
00622
00623 m_lock = true;
00624 emit q->undoAvailable(q->undoAvailable());
00625 }
00626
00627 void FileUndoManagerPrivate::slotUnlock()
00628 {
00629
00630 m_lock = false;
00631 emit q->undoAvailable(q->undoAvailable());
00632 }
00633
00634 QByteArray FileUndoManagerPrivate::get() const
00635 {
00636 QByteArray data;
00637 QDataStream stream(&data, QIODevice::WriteOnly);
00638 stream << m_commands;
00639 return data;
00640 }
00641
00642 void FileUndoManagerPrivate::broadcastPush(const UndoCommand &cmd)
00643 {
00644 if (!m_syncronized) {
00645 pushCommand(cmd);
00646 return;
00647 }
00648
00649 QByteArray data;
00650 QDataStream stream(&data, QIODevice::WriteOnly);
00651 stream << cmd;
00652 emit push(data);
00653 }
00654
00655 void FileUndoManagerPrivate::broadcastPop()
00656 {
00657 if (!m_syncronized) {
00658 slotPop();
00659 return;
00660 }
00661
00662 emit pop();
00663 }
00664
00665 void FileUndoManagerPrivate::broadcastLock()
00666 {
00667
00668
00669 if (!m_syncronized) {
00670 slotLock();
00671 return;
00672 }
00673 emit lock();
00674 }
00675
00676 void FileUndoManagerPrivate::broadcastUnlock()
00677 {
00678
00679
00680 if (!m_syncronized) {
00681 slotUnlock();
00682 return;
00683 }
00684 emit unlock();
00685 }
00686
00687 bool FileUndoManagerPrivate::initializeFromKDesky()
00688 {
00689
00690
00691
00692
00693
00694
00695
00696
00697 return false;
00698 #if 0
00699 DCOPClient *client = kapp->dcopClient();
00700
00701 if (client->appId() == "kdesktop")
00702 return true;
00703
00704 if (!client->isApplicationRegistered("kdesktop"))
00705 return false;
00706
00707 d->m_commands = DCOPRef("kdesktop", "FileUndoManager").call("get");
00708 return true;
00709 #endif
00710 }
00711
00712 void FileUndoManager::setUiInterface(UiInterface* ui)
00713 {
00714 delete d->m_uiInterface;
00715 d->m_uiInterface = ui;
00716 }
00717
00718 FileUndoManager::UiInterface* FileUndoManager::uiInterface() const
00719 {
00720 return d->m_uiInterface;
00721 }
00722
00724
00725 class FileUndoManager::UiInterface::UiInterfacePrivate
00726 {
00727 public:
00728 UiInterfacePrivate()
00729 : m_parentWidget(0), m_showProgressInfo(true)
00730 {}
00731 QWidget* m_parentWidget;
00732 bool m_showProgressInfo;
00733 };
00734
00735 FileUndoManager::UiInterface::UiInterface()
00736 : d(new UiInterfacePrivate)
00737 {
00738 }
00739
00740 FileUndoManager::UiInterface::~UiInterface()
00741 {
00742 delete d;
00743 }
00744
00745 void FileUndoManager::UiInterface::jobError(KIO::Job* job)
00746 {
00747 job->ui()->showErrorMessage();
00748 }
00749
00750 bool FileUndoManager::UiInterface::copiedFileWasModified(const KUrl& src, const KUrl& dest, const KDateTime& srcTime, const KDateTime& destTime)
00751 {
00752 Q_UNUSED(srcTime);
00753
00754 const QString timeStr = KGlobal::locale()->formatDateTime(destTime, KLocale::ShortDate);
00755 return KMessageBox::warningContinueCancel(
00756 d->m_parentWidget,
00757 i18n("The file %1 was copied from %2, but since then it has apparently been modified at %3.\n"
00758 "Undoing the copy will delete the file, and all modifications will be lost.\n"
00759 "Are you sure you want to delete %4?", dest.pathOrUrl(), src.pathOrUrl(), timeStr, dest.pathOrUrl()),
00760 i18n("Undo File Copy Confirmation"),
00761 KStandardGuiItem::cont(),
00762 KStandardGuiItem::cancel(),
00763 QString(),
00764 KMessageBox::Notify | KMessageBox::Dangerous) == KMessageBox::Continue;
00765 }
00766
00767 bool FileUndoManager::UiInterface::confirmDeletion(const KUrl::List& files)
00768 {
00769 KIO::JobUiDelegate uiDelegate;
00770 uiDelegate.setWindow(d->m_parentWidget);
00771
00772 return uiDelegate.askDeleteConfirmation(files, KIO::JobUiDelegate::Delete, KIO::JobUiDelegate::ForceConfirmation);
00773 }
00774
00775 QWidget* FileUndoManager::UiInterface::parentWidget() const
00776 {
00777 return d->m_parentWidget;
00778 }
00779
00780 void FileUndoManager::UiInterface::setParentWidget(QWidget* parentWidget)
00781 {
00782 d->m_parentWidget = parentWidget;
00783 }
00784
00785 void FileUndoManager::UiInterface::setShowProgressInfo(bool b)
00786 {
00787 d->m_showProgressInfo = b;
00788 }
00789
00790 bool FileUndoManager::UiInterface::showProgressInfo() const
00791 {
00792 return d->m_showProgressInfo;
00793 }
00794
00795 void FileUndoManager::UiInterface::virtual_hook(int, void*)
00796 {
00797 }
00798
00799 #include "fileundomanager_p.moc"
00800 #include "fileundomanager.moc"