• Skip to content
  • Skip to link menu
KDE 4.2 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(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           // 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     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: // prevent "wrong" compiler warning because of possibly uninitialized variable
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     /* NOTREACHED */
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     // Make a copy of the command to undo before broadcastPop() pops it.
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     // Note that opStack is empty for simple operations like Mkdir.
00325 
00326     // Let's first ask for confirmation if we need to delete any file (#99898)
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     // Let's have a look at the basic operations we need to undo.
00354     // While we're at it, collect all links that should be deleted.
00355 
00356     it = opStack.begin();
00357     while (it != opStack.end()) // don't cache end() here, erase modifies it
00358     {
00359         bool removeBasicOperation = false;
00360         BasicOperation::Type type = (*it).m_type;
00361         if (type == BasicOperation::Directory && !(*it).m_renamed)
00362         {
00363             // If any directory has to be created/deleted, we'll start with that
00364             d->m_undoState = MAKINGDIRS;
00365             // Collect all the dirs that have to be created in case of a move undo.
00366             if (d->m_current.isMoveCommand())
00367                 d->m_dirStack.push((*it).m_src);
00368             // Collect all dirs that have to be deleted
00369             // from the destination in both cases (copy and move).
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         //kDebug(1203) << "stat result for " << op.m_dst;
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 // Misnamed method: It moves files back, but it also
00480 // renames directories back, recreates symlinks,
00481 // deletes copied files, and restores trashed files.
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); // this should not happen!
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) // dest not stat'ed yet
00509             {
00510                 // Before we delete op.m_dst, let's check if it was modified (#20532)
00511                 kDebug(1203) << "stat" << op.m_dst;
00512                 m_currentJob = KIO::stat(op.m_dst, KIO::HideProgressInfo);
00513                 m_undoState = STATINGFILE; // temporarily
00514                 return; // no pop() yet, we'll finish the work in slotResult
00515             }
00516             else // dest was stat'ed, and the deletion was approved in slotResult
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         // The above KIO jobs are lowlevel, they don't trigger KDirNotify notification
00533         // So we need to do it ourselves (but schedule it to the end of the undo, to compress them)
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 // const ref doesn't work due to QDataStream
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 //  assert(!m_lock);
00625     m_lock = true;
00626     emit q->undoAvailable(q->undoAvailable());
00627 }
00628 
00629 void FileUndoManagerPrivate::slotUnlock()
00630 {
00631 //  assert(m_lock);
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); // DBUS signal
00655 }
00656 
00657 void FileUndoManagerPrivate::broadcastPop()
00658 {
00659     if (!m_syncronized) {
00660         slotPop();
00661         return;
00662     }
00663 
00664     emit pop(); // DBUS signal
00665 }
00666 
00667 void FileUndoManagerPrivate::broadcastLock()
00668 {
00669 //  assert(!m_lock);
00670 
00671     if (!m_syncronized) {
00672         slotLock();
00673         return;
00674     }
00675     emit lock(); // DBUS signal
00676 }
00677 
00678 void FileUndoManagerPrivate::broadcastUnlock()
00679 {
00680 //  assert(m_lock);
00681 
00682     if (!m_syncronized) {
00683         slotUnlock();
00684         return;
00685     }
00686     emit unlock(); // DBUS signal
00687 }
00688 
00689 bool FileUndoManagerPrivate::initializeFromKDesky()
00690 {
00691     // ### workaround for dcop problem and upcoming 2.1 release:
00692     // in case of huge io operations the amount of data sent over
00693     // dcop (containing undo information broadcasted for global undo
00694     // to all konqueror instances) can easily exceed the 64kb limit
00695     // of dcop. In order not to run into trouble we disable global
00696     // undo for now! (Simon)
00697     // ### FIXME: post 2.1
00698     // TODO KDE4: port to DBUS and test
00699     return false;
00700 #if 0
00701     DCOPClient *client = kapp->dcopClient();
00702 
00703     if (client->appId() == "kdesktop") // we are master :)
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); // not sure it should appear in the msgbox
00755     // Possible improvement: only show the time if date is today
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     // Because undo can happen with an accidental Ctrl-Z, we want to always confirm.
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"

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
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.5.7
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