• Skip to content
  • Skip to link menu
KDE 4.1 API Reference
  • KDE API Reference
  • kdelibs
  • Sitemap
  • Contact Us
 

KIO

fileundomanager.cpp

Go to the documentation of this file.
00001 /* This file is part of the KDE project
00002    Copyright (C) 2000 Simon Hausmann <hausmann@kde.org>
00003    Copyright (C) 2006, 2008 David Faure <faure@kde.org>
00004 
00005    This library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Library General Public
00007    License as published by the Free Software Foundation; either
00008    version 2 of the License, or (at your option) any later version.
00009 
00010    This library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Library General Public License for more details.
00014 
00015    You should have received a copy of the GNU Library General Public License
00016    along with this library; see the file COPYING.LIB.  If not, write to
00017    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00018    Boston, MA 02110-1301, USA.
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           // Update URL
00176           op.m_dst = it.value();
00177       }
00178   }
00179 
00180   m_cmd.m_opStack.prepend(op);
00181 }
00182 
00183 // TODO merge the signals?
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     // This records what the job does and calls addCommand when done
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: // prevent "wrong" compiler warning because of possibly uninitialized variable
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     /* NOTREACHED */
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     // Make a copy of the command to undo before broadcastPop() pops it.
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     // Note that opStack is empty for simple operations like Mkdir.
00323 
00324     // Let's first ask for confirmation if we need to delete any file (#99898)
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     // Let's have a look at the basic operations we need to undo.
00352     // While we're at it, collect all links that should be deleted.
00353 
00354     it = opStack.begin();
00355     while (it != opStack.end()) // don't cache end() here, erase modifies it
00356     {
00357         bool removeBasicOperation = false;
00358         BasicOperation::Type type = (*it).m_type;
00359         if (type == BasicOperation::Directory && !(*it).m_renamed)
00360         {
00361             // If any directory has to be created/deleted, we'll start with that
00362             d->m_undoState = MAKINGDIRS;
00363             // Collect all the dirs that have to be created in case of a move undo.
00364             if (d->m_current.isMoveCommand())
00365                 d->m_dirStack.push((*it).m_src);
00366             // Collect all dirs that have to be deleted
00367             // from the destination in both cases (copy and move).
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         //kDebug(1203) << "stat result for " << op.m_dst;
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 // Misnamed method: It moves files back, but it also
00478 // renames directories back, recreates symlinks,
00479 // deletes copied files, and restores trashed files.
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); // this should not happen!
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) // dest not stat'ed yet
00507             {
00508                 // Before we delete op.m_dst, let's check if it was modified (#20532)
00509                 kDebug(1203) << "stat" << op.m_dst;
00510                 m_currentJob = KIO::stat(op.m_dst, KIO::HideProgressInfo);
00511                 m_undoState = STATINGFILE; // temporarily
00512                 return; // no pop() yet, we'll finish the work in slotResult
00513             }
00514             else // dest was stat'ed, and the deletion was approved in slotResult
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         // The above KIO jobs are lowlevel, they don't trigger KDirNotify notification
00531         // So we need to do it ourselves (but schedule it to the end of the undo, to compress them)
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 // const ref doesn't work due to QDataStream
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 //  assert(!m_lock);
00623     m_lock = true;
00624     emit q->undoAvailable(q->undoAvailable());
00625 }
00626 
00627 void FileUndoManagerPrivate::slotUnlock()
00628 {
00629 //  assert(m_lock);
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); // DBUS signal
00653 }
00654 
00655 void FileUndoManagerPrivate::broadcastPop()
00656 {
00657     if (!m_syncronized) {
00658         slotPop();
00659         return;
00660     }
00661 
00662     emit pop(); // DBUS signal
00663 }
00664 
00665 void FileUndoManagerPrivate::broadcastLock()
00666 {
00667 //  assert(!m_lock);
00668 
00669     if (!m_syncronized) {
00670         slotLock();
00671         return;
00672     }
00673     emit lock(); // DBUS signal
00674 }
00675 
00676 void FileUndoManagerPrivate::broadcastUnlock()
00677 {
00678 //  assert(m_lock);
00679 
00680     if (!m_syncronized) {
00681         slotUnlock();
00682         return;
00683     }
00684     emit unlock(); // DBUS signal
00685 }
00686 
00687 bool FileUndoManagerPrivate::initializeFromKDesky()
00688 {
00689     // ### workaround for dcop problem and upcoming 2.1 release:
00690     // in case of huge io operations the amount of data sent over
00691     // dcop (containing undo information broadcasted for global undo
00692     // to all konqueror instances) can easily exceed the 64kb limit
00693     // of dcop. In order not to run into trouble we disable global
00694     // undo for now! (Simon)
00695     // ### FIXME: post 2.1
00696     // TODO KDE4: port to DBUS and test
00697     return false;
00698 #if 0
00699     DCOPClient *client = kapp->dcopClient();
00700 
00701     if (client->appId() == "kdesktop") // we are master :)
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); // not sure it should appear in the msgbox
00753     // Possible improvement: only show the time if date is today
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     // Because undo can happen with an accidental Ctrl-Z, we want to always confirm.
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"

KIO

Skip menu "KIO"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • KIO
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • Kross
  • KUtils
  • Nepomuk
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.5.4
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal