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(i18nc("The source of a file operation", "Source"), src.prettyUrl()),
00121 qMakePair(i18nc("The destination of a file operation", "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 const QMap<QString, QString> metaData = job->metaData();
00173 QMap<QString, QString>::ConstIterator it = metaData.find("trashURL-" + from.path());
00174 if (it != metaData.constEnd()) {
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 emit jobRecordingStarted(op);
00245 }
00246
00247 void FileUndoManager::recordCopyJob(KIO::CopyJob* copyJob)
00248 {
00249 CommandType commandType;
00250 switch (copyJob->operationMode()) {
00251 case CopyJob::Copy:
00252 commandType = Copy;
00253 break;
00254 case CopyJob::Move:
00255 commandType = Move;
00256 break;
00257 case CopyJob::Link:
00258 default:
00259 commandType = Link;
00260 break;
00261 }
00262 recordJob(commandType, copyJob->srcUrls(), copyJob->destUrl(), copyJob);
00263 }
00264
00265 void FileUndoManagerPrivate::addCommand(const UndoCommand &cmd)
00266 {
00267 broadcastPush(cmd);
00268 emit q->jobRecordingFinished(cmd.m_type);
00269 }
00270
00271 bool FileUndoManager::undoAvailable() const
00272 {
00273 return (d->m_commands.count() > 0) && !d->m_lock;
00274 }
00275
00276 QString FileUndoManager::undoText() const
00277 {
00278 if (d->m_commands.isEmpty())
00279 return i18n("Und&o");
00280
00281 FileUndoManager::CommandType t = d->m_commands.top().m_type;
00282 if (t == FileUndoManager::Copy)
00283 return i18n("Und&o: Copy");
00284 else if (t == FileUndoManager::Link)
00285 return i18n("Und&o: Link");
00286 else if (t == FileUndoManager::Move)
00287 return i18n("Und&o: Move");
00288 else if (t == FileUndoManager::Rename)
00289 return i18n("Und&o: Rename");
00290 else if (t == FileUndoManager::Trash)
00291 return i18n("Und&o: Trash");
00292 else if (t == FileUndoManager::Mkdir)
00293 return i18n("Und&o: Create Folder");
00294 else
00295 assert(false);
00296
00297 return QString();
00298 }
00299
00300 quint64 FileUndoManager::newCommandSerialNumber()
00301 {
00302 return ++(d->m_nextCommandIndex);
00303 }
00304
00305 quint64 FileUndoManager::currentCommandSerialNumber() const
00306 {
00307 if(!d->m_commands.isEmpty())
00308 {
00309 const UndoCommand& cmd = d->m_commands.top();
00310 assert(cmd.m_valid);
00311 return cmd.m_serialNumber;
00312 } else
00313 return 0;
00314 }
00315
00316 void FileUndoManager::undo()
00317 {
00318
00319 UndoCommand cmd = d->m_commands.top();
00320 assert(cmd.m_valid);
00321 d->m_current = cmd;
00322
00323 BasicOperation::Stack& opStack = d->m_current.m_opStack;
00324
00325
00326
00327 KUrl::List fileCleanupStack;
00328 QStack<BasicOperation>::Iterator it = opStack.begin();
00329 for (; it != opStack.end() ; ++it) {
00330 BasicOperation::Type type = (*it).m_type;
00331 if (type == BasicOperation::File && d->m_current.m_type == FileUndoManager::Copy) {
00332 fileCleanupStack.append((*it).m_dst);
00333 }
00334 }
00335 if (d->m_current.m_type == FileUndoManager::Mkdir) {
00336 fileCleanupStack.append(d->m_current.m_dst);
00337 }
00338 if (!fileCleanupStack.isEmpty()) {
00339 if (!d->m_uiInterface->confirmDeletion(fileCleanupStack)) {
00340 return;
00341 }
00342 }
00343
00344 d->broadcastPop();
00345 d->broadcastLock();
00346
00347 d->m_dirCleanupStack.clear();
00348 d->m_dirStack.clear();
00349 d->m_dirsToUpdate.clear();
00350
00351 d->m_undoState = MOVINGFILES;
00352
00353
00354
00355
00356 it = opStack.begin();
00357 while (it != opStack.end())
00358 {
00359 bool removeBasicOperation = false;
00360 BasicOperation::Type type = (*it).m_type;
00361 if (type == BasicOperation::Directory && !(*it).m_renamed)
00362 {
00363
00364 d->m_undoState = MAKINGDIRS;
00365
00366 if (d->m_current.isMoveCommand())
00367 d->m_dirStack.push((*it).m_src);
00368
00369
00370 d->m_dirCleanupStack.prepend((*it).m_dst);
00371 removeBasicOperation = true;
00372 }
00373 else if (type == BasicOperation::Link)
00374 {
00375 d->m_linkCleanupStack.prepend((*it).m_dst);
00376
00377 removeBasicOperation = !d->m_current.isMoveCommand();
00378 }
00379
00380 if (removeBasicOperation)
00381 it = opStack.erase(it);
00382 else
00383 ++it;
00384 }
00385
00386 kDebug(1203) << "starting with" << undoStateToString(d->m_undoState);
00387 d->m_undoJob = new UndoJob(d->m_uiInterface->showProgressInfo());
00388 d->undoStep();
00389 }
00390
00391 void FileUndoManagerPrivate::stopUndo(bool step)
00392 {
00393 m_current.m_opStack.clear();
00394 m_dirCleanupStack.clear();
00395 m_linkCleanupStack.clear();
00396 m_undoState = REMOVINGDIRS;
00397 m_undoJob = 0;
00398
00399 if (m_currentJob)
00400 m_currentJob->kill();
00401
00402 m_currentJob = 0;
00403
00404 if (step)
00405 undoStep();
00406 }
00407
00408 void FileUndoManagerPrivate::slotResult(KJob *job)
00409 {
00410 m_currentJob = 0;
00411 if (job->error())
00412 {
00413 m_uiInterface->jobError(static_cast<KIO::Job*>(job));
00414 delete m_undoJob;
00415 stopUndo(false);
00416 }
00417 else if (m_undoState == STATINGFILE)
00418 {
00419 BasicOperation op = m_current.m_opStack.top();
00420
00421 KIO::StatJob* statJob = static_cast<KIO::StatJob*>(job);
00422 time_t mtime = statJob->statResult().numberValue(KIO::UDSEntry::UDS_MODIFICATION_TIME, -1);
00423 if (mtime != op.m_mtime) {
00424 kDebug(1203) << op.m_dst << " was modified after being copied!";
00425 KDateTime srcTime; srcTime.setTime_t(op.m_mtime); srcTime = srcTime.toLocalZone();
00426 KDateTime destTime; destTime.setTime_t(mtime); destTime = destTime.toLocalZone();
00427 if (!m_uiInterface->copiedFileWasModified(op.m_src, op.m_dst, srcTime, destTime)) {
00428 stopUndo(false);
00429 }
00430 }
00431 }
00432
00433 undoStep();
00434 }
00435
00436
00437 void FileUndoManagerPrivate::addDirToUpdate(const KUrl& url)
00438 {
00439 if (!m_dirsToUpdate.contains(url))
00440 m_dirsToUpdate.prepend(url);
00441 }
00442
00443 void FileUndoManagerPrivate::undoStep()
00444 {
00445 m_currentJob = 0;
00446
00447 if (m_undoState == MAKINGDIRS)
00448 stepMakingDirectories();
00449
00450 if (m_undoState == MOVINGFILES || m_undoState == STATINGFILE)
00451 stepMovingFiles();
00452
00453 if (m_undoState == REMOVINGLINKS)
00454 stepRemovingLinks();
00455
00456 if (m_undoState == REMOVINGDIRS)
00457 stepRemovingDirectories();
00458
00459 if (m_currentJob) {
00460 if (m_uiInterface)
00461 m_currentJob->ui()->setWindow(m_uiInterface->parentWidget());
00462 QObject::connect(m_currentJob, SIGNAL(result(KJob*)),
00463 this, SLOT(slotResult(KJob*)));
00464 }
00465 }
00466
00467 void FileUndoManagerPrivate::stepMakingDirectories()
00468 {
00469 if (!m_dirStack.isEmpty()) {
00470 KUrl dir = m_dirStack.pop();
00471 kDebug(1203) << "creatingDir" << dir;
00472 m_currentJob = KIO::mkdir(dir);
00473 m_undoJob->emitCreatingDir(dir);
00474 }
00475 else
00476 m_undoState = MOVINGFILES;
00477 }
00478
00479
00480
00481
00482 void FileUndoManagerPrivate::stepMovingFiles()
00483 {
00484 if (!m_current.m_opStack.isEmpty())
00485 {
00486 BasicOperation op = m_current.m_opStack.top();
00487 BasicOperation::Type type = op.m_type;
00488
00489 assert(op.m_valid);
00490 if (type == BasicOperation::Directory)
00491 {
00492 if (op.m_renamed)
00493 {
00494 kDebug(1203) << "rename" << op.m_dst << op.m_src;
00495 m_currentJob = KIO::rename(op.m_dst, op.m_src, KIO::HideProgressInfo);
00496 m_undoJob->emitMoving(op.m_dst, op.m_src);
00497 }
00498 else
00499 assert(0);
00500 }
00501 else if (type == BasicOperation::Link)
00502 {
00503 kDebug(1203) << "symlink" << op.m_target << op.m_src;
00504 m_currentJob = KIO::symlink(op.m_target, op.m_src, KIO::Overwrite | KIO::HideProgressInfo);
00505 }
00506 else if (m_current.m_type == FileUndoManager::Copy)
00507 {
00508 if (m_undoState == MOVINGFILES)
00509 {
00510
00511 kDebug(1203) << "stat" << op.m_dst;
00512 m_currentJob = KIO::stat(op.m_dst, KIO::HideProgressInfo);
00513 m_undoState = STATINGFILE;
00514 return;
00515 }
00516 else
00517 {
00518 m_currentJob = KIO::file_delete(op.m_dst, KIO::HideProgressInfo);
00519 m_undoJob->emitDeleting(op.m_dst);
00520 m_undoState = MOVINGFILES;
00521 }
00522 }
00523 else if (m_current.isMoveCommand()
00524 || m_current.m_type == FileUndoManager::Trash)
00525 {
00526 kDebug(1203) << "file_move" << op.m_dst << op.m_src;
00527 m_currentJob = KIO::file_move(op.m_dst, op.m_src, -1, KIO::Overwrite | KIO::HideProgressInfo);
00528 m_undoJob->emitMoving(op.m_dst, op.m_src);
00529 }
00530
00531 m_current.m_opStack.pop();
00532
00533
00534 KUrl url(op.m_dst);
00535 url.setPath(url.directory());
00536 addDirToUpdate(url);
00537
00538 url = op.m_src;
00539 url.setPath(url.directory());
00540 addDirToUpdate(url);
00541 }
00542 else
00543 m_undoState = REMOVINGLINKS;
00544 }
00545
00546 void FileUndoManagerPrivate::stepRemovingLinks()
00547 {
00548 kDebug(1203) << "REMOVINGLINKS";
00549 if (!m_linkCleanupStack.isEmpty())
00550 {
00551 KUrl file = m_linkCleanupStack.pop();
00552 kDebug(1203) << "file_delete" << file;
00553 m_currentJob = KIO::file_delete(file, KIO::HideProgressInfo);
00554 m_undoJob->emitDeleting(file);
00555
00556 KUrl url(file);
00557 url.setPath(url.directory());
00558 addDirToUpdate(url);
00559 }
00560 else
00561 {
00562 m_undoState = REMOVINGDIRS;
00563
00564 if (m_dirCleanupStack.isEmpty() && m_current.m_type == FileUndoManager::Mkdir)
00565 m_dirCleanupStack << m_current.m_dst;
00566 }
00567 }
00568
00569 void FileUndoManagerPrivate::stepRemovingDirectories()
00570 {
00571 if (!m_dirCleanupStack.isEmpty())
00572 {
00573 KUrl dir = m_dirCleanupStack.pop();
00574 kDebug(1203) << "rmdir" << dir;
00575 m_currentJob = KIO::rmdir(dir);
00576 m_undoJob->emitDeleting(dir);
00577 addDirToUpdate(dir);
00578 }
00579 else
00580 {
00581 m_current.m_valid = false;
00582 m_currentJob = 0;
00583 if (m_undoJob)
00584 {
00585 kDebug(1203) << "deleting undojob";
00586 m_undoJob->emitResult();
00587 m_undoJob = 0;
00588 }
00589 QList<KUrl>::ConstIterator it = m_dirsToUpdate.constBegin();
00590 for(; it != m_dirsToUpdate.constEnd(); ++it) {
00591 kDebug() << "Notifying FilesAdded for " << *it;
00592 org::kde::KDirNotify::emitFilesAdded((*it).url());
00593 }
00594 emit q->undoJobFinished();
00595 broadcastUnlock();
00596 }
00597 }
00598
00599
00600 void FileUndoManagerPrivate::slotPush(QByteArray data)
00601 {
00602 QDataStream strm(&data, QIODevice::ReadOnly);
00603 UndoCommand cmd;
00604 strm >> cmd;
00605 pushCommand(cmd);
00606 }
00607
00608 void FileUndoManagerPrivate::pushCommand(const UndoCommand& cmd)
00609 {
00610 m_commands.push(cmd);
00611 emit q->undoAvailable(true);
00612 emit q->undoTextChanged(q->undoText());
00613 }
00614
00615 void FileUndoManagerPrivate::slotPop()
00616 {
00617 m_commands.pop();
00618 emit q->undoAvailable(q->undoAvailable());
00619 emit q->undoTextChanged(q->undoText());
00620 }
00621
00622 void FileUndoManagerPrivate::slotLock()
00623 {
00624
00625 m_lock = true;
00626 emit q->undoAvailable(q->undoAvailable());
00627 }
00628
00629 void FileUndoManagerPrivate::slotUnlock()
00630 {
00631
00632 m_lock = false;
00633 emit q->undoAvailable(q->undoAvailable());
00634 }
00635
00636 QByteArray FileUndoManagerPrivate::get() const
00637 {
00638 QByteArray data;
00639 QDataStream stream(&data, QIODevice::WriteOnly);
00640 stream << m_commands;
00641 return data;
00642 }
00643
00644 void FileUndoManagerPrivate::broadcastPush(const UndoCommand &cmd)
00645 {
00646 if (!m_syncronized) {
00647 pushCommand(cmd);
00648 return;
00649 }
00650
00651 QByteArray data;
00652 QDataStream stream(&data, QIODevice::WriteOnly);
00653 stream << cmd;
00654 emit push(data);
00655 }
00656
00657 void FileUndoManagerPrivate::broadcastPop()
00658 {
00659 if (!m_syncronized) {
00660 slotPop();
00661 return;
00662 }
00663
00664 emit pop();
00665 }
00666
00667 void FileUndoManagerPrivate::broadcastLock()
00668 {
00669
00670
00671 if (!m_syncronized) {
00672 slotLock();
00673 return;
00674 }
00675 emit lock();
00676 }
00677
00678 void FileUndoManagerPrivate::broadcastUnlock()
00679 {
00680
00681
00682 if (!m_syncronized) {
00683 slotUnlock();
00684 return;
00685 }
00686 emit unlock();
00687 }
00688
00689 bool FileUndoManagerPrivate::initializeFromKDesky()
00690 {
00691
00692
00693
00694
00695
00696
00697
00698
00699 return false;
00700 #if 0
00701 DCOPClient *client = kapp->dcopClient();
00702
00703 if (client->appId() == "kdesktop")
00704 return true;
00705
00706 if (!client->isApplicationRegistered("kdesktop"))
00707 return false;
00708
00709 d->m_commands = DCOPRef("kdesktop", "FileUndoManager").call("get");
00710 return true;
00711 #endif
00712 }
00713
00714 void FileUndoManager::setUiInterface(UiInterface* ui)
00715 {
00716 delete d->m_uiInterface;
00717 d->m_uiInterface = ui;
00718 }
00719
00720 FileUndoManager::UiInterface* FileUndoManager::uiInterface() const
00721 {
00722 return d->m_uiInterface;
00723 }
00724
00726
00727 class FileUndoManager::UiInterface::UiInterfacePrivate
00728 {
00729 public:
00730 UiInterfacePrivate()
00731 : m_parentWidget(0), m_showProgressInfo(true)
00732 {}
00733 QWidget* m_parentWidget;
00734 bool m_showProgressInfo;
00735 };
00736
00737 FileUndoManager::UiInterface::UiInterface()
00738 : d(new UiInterfacePrivate)
00739 {
00740 }
00741
00742 FileUndoManager::UiInterface::~UiInterface()
00743 {
00744 delete d;
00745 }
00746
00747 void FileUndoManager::UiInterface::jobError(KIO::Job* job)
00748 {
00749 job->ui()->showErrorMessage();
00750 }
00751
00752 bool FileUndoManager::UiInterface::copiedFileWasModified(const KUrl& src, const KUrl& dest, const KDateTime& srcTime, const KDateTime& destTime)
00753 {
00754 Q_UNUSED(srcTime);
00755
00756 const QString timeStr = KGlobal::locale()->formatDateTime(destTime, KLocale::ShortDate);
00757 return KMessageBox::warningContinueCancel(
00758 d->m_parentWidget,
00759 i18n("The file %1 was copied from %2, but since then it has apparently been modified at %3.\n"
00760 "Undoing the copy will delete the file, and all modifications will be lost.\n"
00761 "Are you sure you want to delete %4?", dest.pathOrUrl(), src.pathOrUrl(), timeStr, dest.pathOrUrl()),
00762 i18n("Undo File Copy Confirmation"),
00763 KStandardGuiItem::cont(),
00764 KStandardGuiItem::cancel(),
00765 QString(),
00766 KMessageBox::Notify | KMessageBox::Dangerous) == KMessageBox::Continue;
00767 }
00768
00769 bool FileUndoManager::UiInterface::confirmDeletion(const KUrl::List& files)
00770 {
00771 KIO::JobUiDelegate uiDelegate;
00772 uiDelegate.setWindow(d->m_parentWidget);
00773
00774 return uiDelegate.askDeleteConfirmation(files, KIO::JobUiDelegate::Delete, KIO::JobUiDelegate::ForceConfirmation);
00775 }
00776
00777 QWidget* FileUndoManager::UiInterface::parentWidget() const
00778 {
00779 return d->m_parentWidget;
00780 }
00781
00782 void FileUndoManager::UiInterface::setParentWidget(QWidget* parentWidget)
00783 {
00784 d->m_parentWidget = parentWidget;
00785 }
00786
00787 void FileUndoManager::UiInterface::setShowProgressInfo(bool b)
00788 {
00789 d->m_showProgressInfo = b;
00790 }
00791
00792 bool FileUndoManager::UiInterface::showProgressInfo() const
00793 {
00794 return d->m_showProgressInfo;
00795 }
00796
00797 void FileUndoManager::UiInterface::virtual_hook(int, void*)
00798 {
00799 }
00800
00801 #include "fileundomanager_p.moc"
00802 #include "fileundomanager.moc"