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