• Skip to content
  • Skip to link menu
KDE 4.7 API Reference
  • KDE API Reference
  • kdelibs
  • KDE Home
  • 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 <kjobtrackerinterface.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* const 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   // TODO whitelist, instead
00140   if (op != FileUndoManager::Mkdir && op != FileUndoManager::Put) {
00141       connect(job, SIGNAL(copyingDone(KIO::Job*,KUrl,KUrl,time_t,bool,bool)),
00142               this, SLOT(slotCopyingDone(KIO::Job*,KUrl,KUrl,time_t,bool,bool)));
00143       connect(job, SIGNAL(copyingLinkDone(KIO::Job *,KUrl,QString,KUrl)),
00144               this, SLOT(slotCopyingLinkDone(KIO::Job *,KUrl,QString,KUrl)));
00145   }
00146 }
00147 
00148 CommandRecorder::~CommandRecorder()
00149 {
00150 }
00151 
00152 void CommandRecorder::slotResult(KJob *job)
00153 {
00154     if (job->error())
00155         return;
00156 
00157     FileUndoManager::self()->d->addCommand(m_cmd);
00158 }
00159 
00160 void CommandRecorder::slotCopyingDone(KIO::Job *job, const KUrl &from, const KUrl &to, time_t mtime, bool directory, bool renamed)
00161 {
00162   BasicOperation op;
00163   op.m_valid = true;
00164   op.m_type = directory ? BasicOperation::Directory : BasicOperation::File;
00165   op.m_renamed = renamed;
00166   op.m_src = from;
00167   op.m_dst = to;
00168   op.m_mtime = mtime;
00169 
00170   if (m_cmd.m_type == FileUndoManager::Trash)
00171   {
00172       Q_ASSERT(to.protocol() == "trash");
00173       const QMap<QString, QString> metaData = job->metaData();
00174       QMap<QString, QString>::ConstIterator it = metaData.find("trashURL-" + from.path());
00175       if (it != metaData.constEnd()) {
00176           // Update URL
00177           op.m_dst = it.value();
00178       }
00179   }
00180 
00181   m_cmd.m_opStack.prepend(op);
00182 }
00183 
00184 // TODO merge the signals?
00185 void CommandRecorder::slotCopyingLinkDone(KIO::Job *, const KUrl &from, const QString &target, const KUrl &to)
00186 {
00187   BasicOperation op;
00188   op.m_valid = true;
00189   op.m_type = BasicOperation::Link;
00190   op.m_renamed = false;
00191   op.m_src = from;
00192   op.m_target = target;
00193   op.m_dst = to;
00194   op.m_mtime = -1;
00195   m_cmd.m_opStack.prepend(op);
00196 }
00197 
00199 
00200 class KIO::FileUndoManagerSingleton
00201 {
00202 public:
00203     FileUndoManager self;
00204 };
00205 K_GLOBAL_STATIC(KIO::FileUndoManagerSingleton, globalFileUndoManager)
00206 
00207 FileUndoManager *FileUndoManager::self()
00208 {
00209     return &globalFileUndoManager->self;
00210 }
00211 
00212 
00213 // m_nextCommandIndex is initialized to a high number so that konqueror can
00214 // assign low numbers to closed items loaded "on-demand" from a config file
00215 // in KonqClosedWindowsManager::readConfig and thus maintaining the real
00216 // order of the undo items.
00217 FileUndoManagerPrivate::FileUndoManagerPrivate(FileUndoManager* qq)
00218     : m_uiInterface(new FileUndoManager::UiInterface()),
00219       m_undoJob(0), m_nextCommandIndex(1000), q(qq)
00220 {
00221     m_syncronized = initializeFromKDesky();
00222     (void) new KIOFileUndoManagerAdaptor(this);
00223     const QString dbusPath = "/FileUndoManager";
00224     const QString dbusInterface = "org.kde.kio.FileUndoManager";
00225 
00226     QDBusConnection dbus = QDBusConnection::sessionBus();
00227     dbus.registerObject(dbusPath, this);
00228     dbus.connect(QString(), dbusPath, dbusInterface, "lock", this, SLOT(slotLock()));
00229     dbus.connect(QString(), dbusPath, dbusInterface, "pop", this, SLOT(slotPop()));
00230     dbus.connect(QString(), dbusPath, dbusInterface, "push", this, SLOT(slotPush(QByteArray)));
00231     dbus.connect(QString(), dbusPath, dbusInterface, "unlock", this, SLOT(slotUnlock()));
00232 }
00233 
00234 FileUndoManager::FileUndoManager()
00235 {
00236     d = new FileUndoManagerPrivate(this);
00237     d->m_lock = false;
00238     d->m_currentJob = 0;
00239 }
00240 
00241 FileUndoManager::~FileUndoManager()
00242 {
00243     delete d;
00244 }
00245 
00246 void FileUndoManager::recordJob(CommandType op, const KUrl::List &src, const KUrl &dst, KIO::Job *job)
00247 {
00248     // This records what the job does and calls addCommand when done
00249     (void) new CommandRecorder(op, src, dst, job);
00250     emit jobRecordingStarted(op);
00251 }
00252 
00253 void FileUndoManager::recordCopyJob(KIO::CopyJob* copyJob)
00254 {
00255     CommandType commandType;
00256     switch (copyJob->operationMode()) {
00257     case CopyJob::Copy:
00258         commandType = Copy;
00259         break;
00260     case CopyJob::Move:
00261         commandType = Move;
00262         break;
00263     case CopyJob::Link:
00264     default: // prevent "wrong" compiler warning because of possibly uninitialized variable
00265         commandType = Link;
00266         break;
00267     }
00268     recordJob(commandType, copyJob->srcUrls(), copyJob->destUrl(), copyJob);
00269 }
00270 
00271 void FileUndoManagerPrivate::addCommand(const UndoCommand &cmd)
00272 {
00273     broadcastPush(cmd);
00274     emit q->jobRecordingFinished(cmd.m_type);
00275 }
00276 
00277 bool FileUndoManager::undoAvailable() const
00278 {
00279     return (d->m_commands.count() > 0) && !d->m_lock;
00280 }
00281 
00282 QString FileUndoManager::undoText() const
00283 {
00284     if (d->m_commands.isEmpty())
00285         return i18n("Und&o");
00286 
00287     FileUndoManager::CommandType t = d->m_commands.last().m_type;
00288     switch(t) {
00289     case FileUndoManager::Copy:
00290         return i18n("Und&o: Copy");
00291     case FileUndoManager::Link:
00292         return i18n("Und&o: Link");
00293     case FileUndoManager::Move:
00294         return i18n("Und&o: Move");
00295     case FileUndoManager::Rename:
00296         return i18n("Und&o: Rename");
00297     case FileUndoManager::Trash:
00298         return i18n("Und&o: Trash");
00299     case FileUndoManager::Mkdir:
00300         return i18n("Und&o: Create Folder");
00301     case FileUndoManager::Put:
00302         return i18n("Und&o: Create File");
00303     }
00304     /* NOTREACHED */
00305     return QString();
00306 }
00307 
00308 quint64 FileUndoManager::newCommandSerialNumber()
00309 {
00310     return ++(d->m_nextCommandIndex);
00311 }
00312 
00313 quint64 FileUndoManager::currentCommandSerialNumber() const
00314 {
00315     if(!d->m_commands.isEmpty())
00316     {
00317         const UndoCommand& cmd = d->m_commands.last();
00318         assert(cmd.m_valid);
00319         return cmd.m_serialNumber;
00320     } else
00321         return 0;
00322 }
00323 
00324 void FileUndoManager::undo()
00325 {
00326     // Make a copy of the command to undo before broadcastPop() pops it.
00327     UndoCommand cmd = d->m_commands.last();
00328     assert(cmd.m_valid);
00329     d->m_current = cmd;
00330 
00331     BasicOperation::Stack& opStack = d->m_current.m_opStack;
00332     // Note that opStack is empty for simple operations like Mkdir.
00333 
00334     // Let's first ask for confirmation if we need to delete any file (#99898)
00335     KUrl::List fileCleanupStack;
00336     BasicOperation::Stack::Iterator it = opStack.begin();
00337     for (; it != opStack.end() ; ++it) {
00338         BasicOperation::Type type = (*it).m_type;
00339         if (type == BasicOperation::File && d->m_current.m_type == FileUndoManager::Copy) {
00340             fileCleanupStack.append((*it).m_dst);
00341         }
00342     }
00343     if (d->m_current.m_type == FileUndoManager::Mkdir || d->m_current.m_type == FileUndoManager::Put) {
00344         fileCleanupStack.append(d->m_current.m_dst);
00345     }
00346     if (!fileCleanupStack.isEmpty()) {
00347         if (!d->m_uiInterface->confirmDeletion(fileCleanupStack)) {
00348             return;
00349         }
00350     }
00351 
00352     d->broadcastPop();
00353     d->broadcastLock();
00354 
00355     d->m_dirCleanupStack.clear();
00356     d->m_dirStack.clear();
00357     d->m_dirsToUpdate.clear();
00358 
00359     d->m_undoState = MOVINGFILES;
00360 
00361     // Let's have a look at the basic operations we need to undo.
00362     // While we're at it, collect all links that should be deleted.
00363 
00364     it = opStack.begin();
00365     while (it != opStack.end()) // don't cache end() here, erase modifies it
00366     {
00367         bool removeBasicOperation = false;
00368         BasicOperation::Type type = (*it).m_type;
00369         if (type == BasicOperation::Directory && !(*it).m_renamed)
00370         {
00371             // If any directory has to be created/deleted, we'll start with that
00372             d->m_undoState = MAKINGDIRS;
00373             // Collect all the dirs that have to be created in case of a move undo.
00374             if (d->m_current.isMoveCommand())
00375                 d->m_dirStack.push((*it).m_src);
00376             // Collect all dirs that have to be deleted
00377             // from the destination in both cases (copy and move).
00378             d->m_dirCleanupStack.prepend((*it).m_dst);
00379             removeBasicOperation = true;
00380         }
00381         else if (type == BasicOperation::Link)
00382         {
00383             d->m_fileCleanupStack.prepend((*it).m_dst);
00384 
00385             removeBasicOperation = !d->m_current.isMoveCommand();
00386         }
00387 
00388         if (removeBasicOperation)
00389             it = opStack.erase(it);
00390         else
00391             ++it;
00392     }
00393 
00394     if (d->m_current.m_type == FileUndoManager::Put) {
00395         d->m_fileCleanupStack.append(d->m_current.m_dst);
00396     }
00397 
00398     kDebug(1203) << "starting with" << undoStateToString(d->m_undoState);
00399     d->m_undoJob = new UndoJob(d->m_uiInterface->showProgressInfo());
00400     d->undoStep();
00401 }
00402 
00403 void FileUndoManagerPrivate::stopUndo(bool step)
00404 {
00405     m_current.m_opStack.clear();
00406     m_dirCleanupStack.clear();
00407     m_fileCleanupStack.clear();
00408     m_undoState = REMOVINGDIRS;
00409     m_undoJob = 0;
00410 
00411     if (m_currentJob)
00412         m_currentJob->kill();
00413 
00414     m_currentJob = 0;
00415 
00416     if (step)
00417         undoStep();
00418 }
00419 
00420 void FileUndoManagerPrivate::slotResult(KJob *job)
00421 {
00422     m_currentJob = 0;
00423     if (job->error())
00424     {
00425         m_uiInterface->jobError(static_cast<KIO::Job*>(job));
00426         delete m_undoJob;
00427         stopUndo(false);
00428     }
00429     else if (m_undoState == STATINGFILE)
00430     {
00431         BasicOperation op = m_current.m_opStack.last();
00432         //kDebug(1203) << "stat result for " << op.m_dst;
00433         KIO::StatJob* statJob = static_cast<KIO::StatJob*>(job);
00434         time_t mtime = statJob->statResult().numberValue(KIO::UDSEntry::UDS_MODIFICATION_TIME, -1);
00435         if (mtime != op.m_mtime) {
00436             kDebug(1203) << op.m_dst << " was modified after being copied!";
00437             KDateTime srcTime; srcTime.setTime_t(op.m_mtime); srcTime = srcTime.toLocalZone();
00438             KDateTime destTime; destTime.setTime_t(mtime); destTime = destTime.toLocalZone();
00439             if (!m_uiInterface->copiedFileWasModified(op.m_src, op.m_dst, srcTime, destTime)) {
00440                 stopUndo(false);
00441             }
00442         }
00443     }
00444 
00445     undoStep();
00446 }
00447 
00448 
00449 void FileUndoManagerPrivate::addDirToUpdate(const KUrl& url)
00450 {
00451     if (!m_dirsToUpdate.contains(url))
00452         m_dirsToUpdate.prepend(url);
00453 }
00454 
00455 void FileUndoManagerPrivate::undoStep()
00456 {
00457     m_currentJob = 0;
00458 
00459     if (m_undoState == MAKINGDIRS)
00460         stepMakingDirectories();
00461 
00462     if (m_undoState == MOVINGFILES || m_undoState == STATINGFILE)
00463         stepMovingFiles();
00464 
00465     if (m_undoState == REMOVINGLINKS)
00466         stepRemovingLinks();
00467 
00468     if (m_undoState == REMOVINGDIRS)
00469         stepRemovingDirectories();
00470 
00471     if (m_currentJob) {
00472         if (m_uiInterface)
00473             m_currentJob->ui()->setWindow(m_uiInterface->parentWidget());
00474         QObject::connect(m_currentJob, SIGNAL(result(KJob*)),
00475                          this, SLOT(slotResult(KJob*)));
00476     }
00477 }
00478 
00479 void FileUndoManagerPrivate::stepMakingDirectories()
00480 {
00481     if (!m_dirStack.isEmpty()) {
00482         KUrl dir = m_dirStack.pop();
00483         kDebug(1203) << "creatingDir" << dir;
00484         m_currentJob = KIO::mkdir(dir);
00485         m_undoJob->emitCreatingDir(dir);
00486     }
00487     else
00488         m_undoState = MOVINGFILES;
00489 }
00490 
00491 // Misnamed method: It moves files back, but it also
00492 // renames directories back, recreates symlinks,
00493 // deletes copied files, and restores trashed files.
00494 void FileUndoManagerPrivate::stepMovingFiles()
00495 {
00496     if (!m_current.m_opStack.isEmpty())
00497     {
00498         BasicOperation op = m_current.m_opStack.last();
00499         BasicOperation::Type type = op.m_type;
00500 
00501         assert(op.m_valid);
00502         if (type == BasicOperation::Directory)
00503         {
00504             if (op.m_renamed)
00505             {
00506                 kDebug(1203) << "rename" << op.m_dst << op.m_src;
00507                 m_currentJob = KIO::rename(op.m_dst, op.m_src, KIO::HideProgressInfo);
00508                 m_undoJob->emitMoving(op.m_dst, op.m_src);
00509             }
00510             else
00511                 assert(0); // this should not happen!
00512         }
00513         else if (type == BasicOperation::Link)
00514         {
00515             kDebug(1203) << "symlink" << op.m_target << op.m_src;
00516             m_currentJob = KIO::symlink(op.m_target, op.m_src, KIO::Overwrite | KIO::HideProgressInfo);
00517         }
00518         else if (m_current.m_type == FileUndoManager::Copy)
00519         {
00520             if (m_undoState == MOVINGFILES) // dest not stat'ed yet
00521             {
00522                 // Before we delete op.m_dst, let's check if it was modified (#20532)
00523                 kDebug(1203) << "stat" << op.m_dst;
00524                 m_currentJob = KIO::stat(op.m_dst, KIO::HideProgressInfo);
00525                 m_undoState = STATINGFILE; // temporarily
00526                 return; // no pop() yet, we'll finish the work in slotResult
00527             }
00528             else // dest was stat'ed, and the deletion was approved in slotResult
00529             {
00530                 m_currentJob = KIO::file_delete(op.m_dst, KIO::HideProgressInfo);
00531                 m_undoJob->emitDeleting(op.m_dst);
00532                 m_undoState = MOVINGFILES;
00533             }
00534         }
00535         else if (m_current.isMoveCommand()
00536                   || m_current.m_type == FileUndoManager::Trash)
00537         {
00538             kDebug(1203) << "file_move" << op.m_dst << op.m_src;
00539             m_currentJob = KIO::file_move(op.m_dst, op.m_src, -1, KIO::Overwrite | KIO::HideProgressInfo);
00540             m_undoJob->emitMoving(op.m_dst, op.m_src);
00541         }
00542 
00543         m_current.m_opStack.removeLast();
00544         // The above KIO jobs are lowlevel, they don't trigger KDirNotify notification
00545         // So we need to do it ourselves (but schedule it to the end of the undo, to compress them)
00546         KUrl url(op.m_dst);
00547         url.setPath(url.directory());
00548         addDirToUpdate(url);
00549 
00550         url = op.m_src;
00551         url.setPath(url.directory());
00552         addDirToUpdate(url);
00553     }
00554     else
00555         m_undoState = REMOVINGLINKS;
00556 }
00557 
00558 void FileUndoManagerPrivate::stepRemovingLinks()
00559 {
00560     kDebug(1203) << "REMOVINGLINKS";
00561     if (!m_fileCleanupStack.isEmpty())
00562     {
00563         KUrl file = m_fileCleanupStack.pop();
00564         kDebug(1203) << "file_delete" << file;
00565         m_currentJob = KIO::file_delete(file, KIO::HideProgressInfo);
00566         m_undoJob->emitDeleting(file);
00567 
00568         KUrl url(file);
00569         url.setPath(url.directory());
00570         addDirToUpdate(url);
00571     }
00572     else
00573     {
00574         m_undoState = REMOVINGDIRS;
00575 
00576         if (m_dirCleanupStack.isEmpty() && m_current.m_type == FileUndoManager::Mkdir)
00577             m_dirCleanupStack << m_current.m_dst;
00578     }
00579 }
00580 
00581 void FileUndoManagerPrivate::stepRemovingDirectories()
00582 {
00583     if (!m_dirCleanupStack.isEmpty())
00584     {
00585         KUrl dir = m_dirCleanupStack.pop();
00586         kDebug(1203) << "rmdir" << dir;
00587         m_currentJob = KIO::rmdir(dir);
00588         m_undoJob->emitDeleting(dir);
00589         addDirToUpdate(dir);
00590     }
00591     else
00592     {
00593         m_current.m_valid = false;
00594         m_currentJob = 0;
00595         if (m_undoJob)
00596         {
00597             kDebug(1203) << "deleting undojob";
00598             m_undoJob->emitResult();
00599             m_undoJob = 0;
00600         }
00601         QList<KUrl>::ConstIterator it = m_dirsToUpdate.constBegin();
00602         for(; it != m_dirsToUpdate.constEnd(); ++it) {
00603             kDebug() << "Notifying FilesAdded for " << *it;
00604             org::kde::KDirNotify::emitFilesAdded((*it).url());
00605         }
00606         emit q->undoJobFinished();
00607         broadcastUnlock();
00608     }
00609 }
00610 
00611 // const ref doesn't work due to QDataStream
00612 void FileUndoManagerPrivate::slotPush(QByteArray data)
00613 {
00614     QDataStream strm(&data, QIODevice::ReadOnly);
00615     UndoCommand cmd;
00616     strm >> cmd;
00617     pushCommand(cmd);
00618 }
00619 
00620 void FileUndoManagerPrivate::pushCommand(const UndoCommand& cmd)
00621 {
00622     m_commands.append(cmd);
00623     emit q->undoAvailable(true);
00624     emit q->undoTextChanged(q->undoText());
00625 }
00626 
00627 void FileUndoManagerPrivate::slotPop()
00628 {
00629     m_commands.removeLast();
00630     emit q->undoAvailable(q->undoAvailable());
00631     emit q->undoTextChanged(q->undoText());
00632 }
00633 
00634 void FileUndoManagerPrivate::slotLock()
00635 {
00636 //  assert(!m_lock);
00637     m_lock = true;
00638     emit q->undoAvailable(q->undoAvailable());
00639 }
00640 
00641 void FileUndoManagerPrivate::slotUnlock()
00642 {
00643 //  assert(m_lock);
00644     m_lock = false;
00645     emit q->undoAvailable(q->undoAvailable());
00646 }
00647 
00648 QByteArray FileUndoManagerPrivate::get() const
00649 {
00650     QByteArray data;
00651     QDataStream stream(&data, QIODevice::WriteOnly);
00652     stream << m_commands;
00653     return data;
00654 }
00655 
00656 void FileUndoManagerPrivate::broadcastPush(const UndoCommand &cmd)
00657 {
00658     if (!m_syncronized) {
00659         pushCommand(cmd);
00660         return;
00661     }
00662 
00663     QByteArray data;
00664     QDataStream stream(&data, QIODevice::WriteOnly);
00665     stream << cmd;
00666     emit push(data); // DBUS signal
00667 }
00668 
00669 void FileUndoManagerPrivate::broadcastPop()
00670 {
00671     if (!m_syncronized) {
00672         slotPop();
00673         return;
00674     }
00675 
00676     emit pop(); // DBUS signal
00677 }
00678 
00679 void FileUndoManagerPrivate::broadcastLock()
00680 {
00681 //  assert(!m_lock);
00682 
00683     if (!m_syncronized) {
00684         slotLock();
00685         return;
00686     }
00687     emit lock(); // DBUS signal
00688 }
00689 
00690 void FileUndoManagerPrivate::broadcastUnlock()
00691 {
00692 //  assert(m_lock);
00693 
00694     if (!m_syncronized) {
00695         slotUnlock();
00696         return;
00697     }
00698     emit unlock(); // DBUS signal
00699 }
00700 
00701 bool FileUndoManagerPrivate::initializeFromKDesky()
00702 {
00703     // ### workaround for dcop problem and upcoming 2.1 release:
00704     // in case of huge io operations the amount of data sent over
00705     // dcop (containing undo information broadcasted for global undo
00706     // to all konqueror instances) can easily exceed the 64kb limit
00707     // of dcop. In order not to run into trouble we disable global
00708     // undo for now! (Simon)
00709     // ### FIXME: post 2.1
00710     // TODO KDE4: port to DBUS and test
00711     return false;
00712 #if 0
00713     DCOPClient *client = kapp->dcopClient();
00714 
00715     if (client->appId() == "kdesktop") // we are master :)
00716         return true;
00717 
00718     if (!client->isApplicationRegistered("kdesktop"))
00719         return false;
00720 
00721     d->m_commands = DCOPRef("kdesktop", "FileUndoManager").call("get");
00722     return true;
00723 #endif
00724 }
00725 
00726 void FileUndoManager::setUiInterface(UiInterface* ui)
00727 {
00728     delete d->m_uiInterface;
00729     d->m_uiInterface = ui;
00730 }
00731 
00732 FileUndoManager::UiInterface* FileUndoManager::uiInterface() const
00733 {
00734     return d->m_uiInterface;
00735 }
00736 
00738 
00739 class FileUndoManager::UiInterface::UiInterfacePrivate
00740 {
00741 public:
00742     UiInterfacePrivate()
00743         : m_parentWidget(0), m_showProgressInfo(true)
00744     {}
00745     QWidget* m_parentWidget;
00746     bool m_showProgressInfo;
00747 };
00748 
00749 FileUndoManager::UiInterface::UiInterface()
00750     : d(new UiInterfacePrivate)
00751 {
00752 }
00753 
00754 FileUndoManager::UiInterface::~UiInterface()
00755 {
00756     delete d;
00757 }
00758 
00759 void FileUndoManager::UiInterface::jobError(KIO::Job* job)
00760 {
00761     job->ui()->showErrorMessage();
00762 }
00763 
00764 bool FileUndoManager::UiInterface::copiedFileWasModified(const KUrl& src, const KUrl& dest, const KDateTime& srcTime, const KDateTime& destTime)
00765 {
00766     Q_UNUSED(srcTime); // not sure it should appear in the msgbox
00767     // Possible improvement: only show the time if date is today
00768     const QString timeStr = KGlobal::locale()->formatDateTime(destTime, KLocale::ShortDate);
00769     return KMessageBox::warningContinueCancel(
00770         d->m_parentWidget,
00771         i18n("The file %1 was copied from %2, but since then it has apparently been modified at %3.\n"
00772               "Undoing the copy will delete the file, and all modifications will be lost.\n"
00773               "Are you sure you want to delete %4?", dest.pathOrUrl(), src.pathOrUrl(), timeStr, dest.pathOrUrl()),
00774         i18n("Undo File Copy Confirmation"),
00775         KStandardGuiItem::cont(),
00776         KStandardGuiItem::cancel(),
00777         QString(),
00778         KMessageBox::Notify | KMessageBox::Dangerous) == KMessageBox::Continue;
00779 }
00780 
00781 bool FileUndoManager::UiInterface::confirmDeletion(const KUrl::List& files)
00782 {
00783     KIO::JobUiDelegate uiDelegate;
00784     uiDelegate.setWindow(d->m_parentWidget);
00785     // Because undo can happen with an accidental Ctrl-Z, we want to always confirm.
00786     return uiDelegate.askDeleteConfirmation(files, KIO::JobUiDelegate::Delete, KIO::JobUiDelegate::ForceConfirmation);
00787 }
00788 
00789 QWidget* FileUndoManager::UiInterface::parentWidget() const
00790 {
00791     return d->m_parentWidget;
00792 }
00793 
00794 void FileUndoManager::UiInterface::setParentWidget(QWidget* parentWidget)
00795 {
00796     d->m_parentWidget = parentWidget;
00797 }
00798 
00799 void FileUndoManager::UiInterface::setShowProgressInfo(bool b)
00800 {
00801     d->m_showProgressInfo = b;
00802 }
00803 
00804 bool FileUndoManager::UiInterface::showProgressInfo() const
00805 {
00806     return d->m_showProgressInfo;
00807 }
00808 
00809 void FileUndoManager::UiInterface::virtual_hook(int, void*)
00810 {
00811 }
00812 
00813 #include "fileundomanager_p.moc"
00814 #include "fileundomanager.moc"

KIO

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

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.7.5
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