• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdelibs-4.10.4 API Reference
  • KDE Home
  • Contact Us
 

KIO

  • kio
  • kio
fileundomanager.cpp
Go to the documentation of this file.
1 /* This file is part of the KDE project
2  Copyright (C) 2000 Simon Hausmann <hausmann@kde.org>
3  Copyright (C) 2006, 2008 David Faure <faure@kde.org>
4 
5  This library is free software; you can redistribute it and/or
6  modify it under the terms of the GNU Library General Public
7  License as published by the Free Software Foundation; either
8  version 2 of the License, or (at your option) any later version.
9 
10  This library is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  Library General Public License for more details.
14 
15  You should have received a copy of the GNU Library General Public License
16  along with this library; see the file COPYING.LIB. If not, write to
17  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  Boston, MA 02110-1301, USA.
19 */
20 
21 #include "fileundomanager.h"
22 #include "fileundomanager_p.h"
23 #include "fileundomanager_adaptor.h"
24 
25 #include <kdatetime.h>
26 #include <kdebug.h>
27 #include <kdirnotify.h>
28 #include <kglobal.h>
29 #include <kio/copyjob.h>
30 #include <kio/job.h>
31 #include <kio/jobuidelegate.h>
32 #include <klocale.h>
33 #include <kmessagebox.h>
34 #include <kjobtrackerinterface.h>
35 
36 #include <QtDBus/QtDBus>
37 
38 #include <assert.h>
39 
40 using namespace KIO;
41 
42 static const char* undoStateToString(UndoState state) {
43  static const char* const s_undoStateToString[] = { "MAKINGDIRS", "MOVINGFILES", "STATINGFILE", "REMOVINGDIRS", "REMOVINGLINKS" };
44  return s_undoStateToString[state];
45 }
46 
47 static QDataStream &operator<<(QDataStream &stream, const KIO::BasicOperation &op)
48 {
49  stream << op.m_valid << (qint8)op.m_type << op.m_renamed
50  << op.m_src << op.m_dst << op.m_target << (qint64)op.m_mtime;
51  return stream;
52 }
53 static QDataStream &operator>>(QDataStream &stream, BasicOperation &op)
54 {
55  qint8 type;
56  qint64 mtime;
57  stream >> op.m_valid >> type >> op.m_renamed
58  >> op.m_src >> op.m_dst >> op.m_target >> mtime;
59  op.m_type = static_cast<BasicOperation::Type>(type);
60  op.m_mtime = mtime;
61  return stream;
62 }
63 
64 static QDataStream &operator<<(QDataStream &stream, const UndoCommand &cmd)
65 {
66  stream << cmd.m_valid << (qint8)cmd.m_type << cmd.m_opStack << cmd.m_src << cmd.m_dst;
67  return stream;
68 }
69 
70 static QDataStream &operator>>(QDataStream &stream, UndoCommand &cmd)
71 {
72  qint8 type;
73  stream >> cmd.m_valid >> type >> cmd.m_opStack >> cmd.m_src >> cmd.m_dst;
74  cmd.m_type = static_cast<FileUndoManager::CommandType>(type);
75  return stream;
76 }
77 
101 class KIO::UndoJob : public KIO::Job
102 {
103 public:
104  UndoJob(bool showProgressInfo) : KIO::Job() {
105  if (showProgressInfo)
106  KIO::getJobTracker()->registerJob(this);
107  }
108  virtual ~UndoJob() {}
109 
110  virtual void kill(bool) {
111  FileUndoManager::self()->d->stopUndo(true);
112  KIO::Job::doKill();
113  }
114 
115  void emitCreatingDir(const KUrl &dir)
116  { emit description(this, i18n("Creating directory"),
117  qMakePair(i18n("Directory"), dir.prettyUrl())); }
118  void emitMoving(const KUrl &src, const KUrl &dest)
119  { emit description(this, i18n("Moving"),
120  qMakePair(i18nc("The source of a file operation", "Source"), src.prettyUrl()),
121  qMakePair(i18nc("The destination of a file operation", "Destination"), dest.prettyUrl())); }
122  void emitDeleting(const KUrl &url)
123  { emit description(this, i18n("Deleting"),
124  qMakePair(i18n("File"), url.prettyUrl())); }
125  void emitResult() { KIO::Job::emitResult(); }
126 };
127 
128 CommandRecorder::CommandRecorder(FileUndoManager::CommandType op, const KUrl::List &src, const KUrl &dst, KIO::Job *job)
129  : QObject(job)
130 {
131  m_cmd.m_type = op;
132  m_cmd.m_valid = true;
133  m_cmd.m_serialNumber = FileUndoManager::self()->newCommandSerialNumber();
134  m_cmd.m_src = src;
135  m_cmd.m_dst = dst;
136  connect(job, SIGNAL(result(KJob*)),
137  this, SLOT(slotResult(KJob*)));
138 
139  // TODO whitelist, instead
140  if (op != FileUndoManager::Mkdir && op != FileUndoManager::Put) {
141  connect(job, SIGNAL(copyingDone(KIO::Job*,KUrl,KUrl,time_t,bool,bool)),
142  this, SLOT(slotCopyingDone(KIO::Job*,KUrl,KUrl,time_t,bool,bool)));
143  connect(job, SIGNAL(copyingLinkDone(KIO::Job*,KUrl,QString,KUrl)),
144  this, SLOT(slotCopyingLinkDone(KIO::Job*,KUrl,QString,KUrl)));
145  }
146 }
147 
148 CommandRecorder::~CommandRecorder()
149 {
150 }
151 
152 void CommandRecorder::slotResult(KJob *job)
153 {
154  if (job->error())
155  return;
156 
157  FileUndoManager::self()->d->addCommand(m_cmd);
158 }
159 
160 void CommandRecorder::slotCopyingDone(KIO::Job *job, const KUrl &from, const KUrl &to, time_t mtime, bool directory, bool renamed)
161 {
162  BasicOperation op;
163  op.m_valid = true;
164  op.m_type = directory ? BasicOperation::Directory : BasicOperation::File;
165  op.m_renamed = renamed;
166  op.m_src = from;
167  op.m_dst = to;
168  op.m_mtime = mtime;
169 
170  if (m_cmd.m_type == FileUndoManager::Trash)
171  {
172  Q_ASSERT(to.protocol() == "trash");
173  const QMap<QString, QString> metaData = job->metaData();
174  QMap<QString, QString>::ConstIterator it = metaData.find("trashURL-" + from.path());
175  if (it != metaData.constEnd()) {
176  // Update URL
177  op.m_dst = it.value();
178  }
179  }
180 
181  m_cmd.m_opStack.prepend(op);
182 }
183 
184 // TODO merge the signals?
185 void CommandRecorder::slotCopyingLinkDone(KIO::Job *, const KUrl &from, const QString &target, const KUrl &to)
186 {
187  BasicOperation op;
188  op.m_valid = true;
189  op.m_type = BasicOperation::Link;
190  op.m_renamed = false;
191  op.m_src = from;
192  op.m_target = target;
193  op.m_dst = to;
194  op.m_mtime = -1;
195  m_cmd.m_opStack.prepend(op);
196 }
197 
199 
200 class KIO::FileUndoManagerSingleton
201 {
202 public:
203  FileUndoManager self;
204 };
205 K_GLOBAL_STATIC(KIO::FileUndoManagerSingleton, globalFileUndoManager)
206 
207 FileUndoManager *FileUndoManager::self()
208 {
209  return &globalFileUndoManager->self;
210 }
211 
212 
213 // m_nextCommandIndex is initialized to a high number so that konqueror can
214 // assign low numbers to closed items loaded "on-demand" from a config file
215 // in KonqClosedWindowsManager::readConfig and thus maintaining the real
216 // order of the undo items.
217 FileUndoManagerPrivate::FileUndoManagerPrivate(FileUndoManager* qq)
218  : m_uiInterface(new FileUndoManager::UiInterface()),
219  m_undoJob(0), m_nextCommandIndex(1000), q(qq)
220 {
221  m_syncronized = initializeFromKDesky();
222  (void) new KIOFileUndoManagerAdaptor(this);
223  const QString dbusPath = "/FileUndoManager";
224  const QString dbusInterface = "org.kde.kio.FileUndoManager";
225 
226  QDBusConnection dbus = QDBusConnection::sessionBus();
227  dbus.registerObject(dbusPath, this);
228  dbus.connect(QString(), dbusPath, dbusInterface, "lock", this, SLOT(slotLock()));
229  dbus.connect(QString(), dbusPath, dbusInterface, "pop", this, SLOT(slotPop()));
230  dbus.connect(QString(), dbusPath, dbusInterface, "push", this, SLOT(slotPush(QByteArray)));
231  dbus.connect(QString(), dbusPath, dbusInterface, "unlock", this, SLOT(slotUnlock()));
232 }
233 
234 FileUndoManager::FileUndoManager()
235 {
236  d = new FileUndoManagerPrivate(this);
237  d->m_lock = false;
238  d->m_currentJob = 0;
239 }
240 
241 FileUndoManager::~FileUndoManager()
242 {
243  delete d;
244 }
245 
246 void FileUndoManager::recordJob(CommandType op, const KUrl::List &src, const KUrl &dst, KIO::Job *job)
247 {
248  // This records what the job does and calls addCommand when done
249  (void) new CommandRecorder(op, src, dst, job);
250  emit jobRecordingStarted(op);
251 }
252 
253 void FileUndoManager::recordCopyJob(KIO::CopyJob* copyJob)
254 {
255  CommandType commandType;
256  switch (copyJob->operationMode()) {
257  case CopyJob::Copy:
258  commandType = Copy;
259  break;
260  case CopyJob::Move:
261  commandType = Move;
262  break;
263  case CopyJob::Link:
264  default: // prevent "wrong" compiler warning because of possibly uninitialized variable
265  commandType = Link;
266  break;
267  }
268  recordJob(commandType, copyJob->srcUrls(), copyJob->destUrl(), copyJob);
269 }
270 
271 void FileUndoManagerPrivate::addCommand(const UndoCommand &cmd)
272 {
273  broadcastPush(cmd);
274  emit q->jobRecordingFinished(cmd.m_type);
275 }
276 
277 bool FileUndoManager::undoAvailable() const
278 {
279  return (d->m_commands.count() > 0) && !d->m_lock;
280 }
281 
282 QString FileUndoManager::undoText() const
283 {
284  if (d->m_commands.isEmpty())
285  return i18n("Und&o");
286 
287  FileUndoManager::CommandType t = d->m_commands.last().m_type;
288  switch(t) {
289  case FileUndoManager::Copy:
290  return i18n("Und&o: Copy");
291  case FileUndoManager::Link:
292  return i18n("Und&o: Link");
293  case FileUndoManager::Move:
294  return i18n("Und&o: Move");
295  case FileUndoManager::Rename:
296  return i18n("Und&o: Rename");
297  case FileUndoManager::Trash:
298  return i18n("Und&o: Trash");
299  case FileUndoManager::Mkdir:
300  return i18n("Und&o: Create Folder");
301  case FileUndoManager::Put:
302  return i18n("Und&o: Create File");
303  }
304  /* NOTREACHED */
305  return QString();
306 }
307 
308 quint64 FileUndoManager::newCommandSerialNumber()
309 {
310  return ++(d->m_nextCommandIndex);
311 }
312 
313 quint64 FileUndoManager::currentCommandSerialNumber() const
314 {
315  if(!d->m_commands.isEmpty())
316  {
317  const UndoCommand& cmd = d->m_commands.last();
318  assert(cmd.m_valid);
319  return cmd.m_serialNumber;
320  } else
321  return 0;
322 }
323 
324 void FileUndoManager::undo()
325 {
326  // Make a copy of the command to undo before broadcastPop() pops it.
327  UndoCommand cmd = d->m_commands.last();
328  assert(cmd.m_valid);
329  d->m_current = cmd;
330 
331  BasicOperation::Stack& opStack = d->m_current.m_opStack;
332  // Note that opStack is empty for simple operations like Mkdir.
333 
334  // Let's first ask for confirmation if we need to delete any file (#99898)
335  KUrl::List fileCleanupStack;
336  BasicOperation::Stack::Iterator it = opStack.begin();
337  for (; it != opStack.end() ; ++it) {
338  BasicOperation::Type type = (*it).m_type;
339  if (type == BasicOperation::File && d->m_current.m_type == FileUndoManager::Copy) {
340  fileCleanupStack.append((*it).m_dst);
341  }
342  }
343  if (d->m_current.m_type == FileUndoManager::Mkdir || d->m_current.m_type == FileUndoManager::Put) {
344  fileCleanupStack.append(d->m_current.m_dst);
345  }
346  if (!fileCleanupStack.isEmpty()) {
347  if (!d->m_uiInterface->confirmDeletion(fileCleanupStack)) {
348  return;
349  }
350  }
351 
352  d->broadcastPop();
353  d->broadcastLock();
354 
355  d->m_dirCleanupStack.clear();
356  d->m_dirStack.clear();
357  d->m_dirsToUpdate.clear();
358 
359  d->m_undoState = MOVINGFILES;
360 
361  // Let's have a look at the basic operations we need to undo.
362  // While we're at it, collect all links that should be deleted.
363 
364  it = opStack.begin();
365  while (it != opStack.end()) // don't cache end() here, erase modifies it
366  {
367  bool removeBasicOperation = false;
368  BasicOperation::Type type = (*it).m_type;
369  if (type == BasicOperation::Directory && !(*it).m_renamed)
370  {
371  // If any directory has to be created/deleted, we'll start with that
372  d->m_undoState = MAKINGDIRS;
373  // Collect all the dirs that have to be created in case of a move undo.
374  if (d->m_current.isMoveCommand())
375  d->m_dirStack.push((*it).m_src);
376  // Collect all dirs that have to be deleted
377  // from the destination in both cases (copy and move).
378  d->m_dirCleanupStack.prepend((*it).m_dst);
379  removeBasicOperation = true;
380  }
381  else if (type == BasicOperation::Link)
382  {
383  d->m_fileCleanupStack.prepend((*it).m_dst);
384 
385  removeBasicOperation = !d->m_current.isMoveCommand();
386  }
387 
388  if (removeBasicOperation)
389  it = opStack.erase(it);
390  else
391  ++it;
392  }
393 
394  if (d->m_current.m_type == FileUndoManager::Put) {
395  d->m_fileCleanupStack.append(d->m_current.m_dst);
396  }
397 
398  kDebug(1203) << "starting with" << undoStateToString(d->m_undoState);
399  d->m_undoJob = new UndoJob(d->m_uiInterface->showProgressInfo());
400  d->undoStep();
401 }
402 
403 void FileUndoManagerPrivate::stopUndo(bool step)
404 {
405  m_current.m_opStack.clear();
406  m_dirCleanupStack.clear();
407  m_fileCleanupStack.clear();
408  m_undoState = REMOVINGDIRS;
409  m_undoJob = 0;
410 
411  if (m_currentJob)
412  m_currentJob->kill();
413 
414  m_currentJob = 0;
415 
416  if (step)
417  undoStep();
418 }
419 
420 void FileUndoManagerPrivate::slotResult(KJob *job)
421 {
422  m_currentJob = 0;
423  if (job->error())
424  {
425  m_uiInterface->jobError(static_cast<KIO::Job*>(job));
426  delete m_undoJob;
427  stopUndo(false);
428  }
429  else if (m_undoState == STATINGFILE)
430  {
431  BasicOperation op = m_current.m_opStack.last();
432  //kDebug(1203) << "stat result for " << op.m_dst;
433  KIO::StatJob* statJob = static_cast<KIO::StatJob*>(job);
434  time_t mtime = statJob->statResult().numberValue(KIO::UDSEntry::UDS_MODIFICATION_TIME, -1);
435  if (mtime != op.m_mtime) {
436  kDebug(1203) << op.m_dst << " was modified after being copied!";
437  KDateTime srcTime; srcTime.setTime_t(op.m_mtime); srcTime = srcTime.toLocalZone();
438  KDateTime destTime; destTime.setTime_t(mtime); destTime = destTime.toLocalZone();
439  if (!m_uiInterface->copiedFileWasModified(op.m_src, op.m_dst, srcTime, destTime)) {
440  stopUndo(false);
441  }
442  }
443  }
444 
445  undoStep();
446 }
447 
448 
449 void FileUndoManagerPrivate::addDirToUpdate(const KUrl& url)
450 {
451  if (!m_dirsToUpdate.contains(url))
452  m_dirsToUpdate.prepend(url);
453 }
454 
455 void FileUndoManagerPrivate::undoStep()
456 {
457  m_currentJob = 0;
458 
459  if (m_undoState == MAKINGDIRS)
460  stepMakingDirectories();
461 
462  if (m_undoState == MOVINGFILES || m_undoState == STATINGFILE)
463  stepMovingFiles();
464 
465  if (m_undoState == REMOVINGLINKS)
466  stepRemovingLinks();
467 
468  if (m_undoState == REMOVINGDIRS)
469  stepRemovingDirectories();
470 
471  if (m_currentJob) {
472  if (m_uiInterface)
473  m_currentJob->ui()->setWindow(m_uiInterface->parentWidget());
474  QObject::connect(m_currentJob, SIGNAL(result(KJob*)),
475  this, SLOT(slotResult(KJob*)));
476  }
477 }
478 
479 void FileUndoManagerPrivate::stepMakingDirectories()
480 {
481  if (!m_dirStack.isEmpty()) {
482  KUrl dir = m_dirStack.pop();
483  kDebug(1203) << "creatingDir" << dir;
484  m_currentJob = KIO::mkdir(dir);
485  m_undoJob->emitCreatingDir(dir);
486  }
487  else
488  m_undoState = MOVINGFILES;
489 }
490 
491 // Misnamed method: It moves files back, but it also
492 // renames directories back, recreates symlinks,
493 // deletes copied files, and restores trashed files.
494 void FileUndoManagerPrivate::stepMovingFiles()
495 {
496  if (!m_current.m_opStack.isEmpty())
497  {
498  BasicOperation op = m_current.m_opStack.last();
499  BasicOperation::Type type = op.m_type;
500 
501  assert(op.m_valid);
502  if (type == BasicOperation::Directory)
503  {
504  if (op.m_renamed)
505  {
506  kDebug(1203) << "rename" << op.m_dst << op.m_src;
507  m_currentJob = KIO::rename(op.m_dst, op.m_src, KIO::HideProgressInfo);
508  m_undoJob->emitMoving(op.m_dst, op.m_src);
509  }
510  else
511  assert(0); // this should not happen!
512  }
513  else if (type == BasicOperation::Link)
514  {
515  kDebug(1203) << "symlink" << op.m_target << op.m_src;
516  m_currentJob = KIO::symlink(op.m_target, op.m_src, KIO::Overwrite | KIO::HideProgressInfo);
517  }
518  else if (m_current.m_type == FileUndoManager::Copy)
519  {
520  if (m_undoState == MOVINGFILES) // dest not stat'ed yet
521  {
522  // Before we delete op.m_dst, let's check if it was modified (#20532)
523  kDebug(1203) << "stat" << op.m_dst;
524  m_currentJob = KIO::stat(op.m_dst, KIO::HideProgressInfo);
525  m_undoState = STATINGFILE; // temporarily
526  return; // no pop() yet, we'll finish the work in slotResult
527  }
528  else // dest was stat'ed, and the deletion was approved in slotResult
529  {
530  m_currentJob = KIO::file_delete(op.m_dst, KIO::HideProgressInfo);
531  m_undoJob->emitDeleting(op.m_dst);
532  m_undoState = MOVINGFILES;
533  }
534  }
535  else if (m_current.isMoveCommand()
536  || m_current.m_type == FileUndoManager::Trash)
537  {
538  kDebug(1203) << "file_move" << op.m_dst << op.m_src;
539  m_currentJob = KIO::file_move(op.m_dst, op.m_src, -1, KIO::Overwrite | KIO::HideProgressInfo);
540  m_undoJob->emitMoving(op.m_dst, op.m_src);
541  }
542 
543  m_current.m_opStack.removeLast();
544  // The above KIO jobs are lowlevel, they don't trigger KDirNotify notification
545  // So we need to do it ourselves (but schedule it to the end of the undo, to compress them)
546  KUrl url(op.m_dst);
547  url.setPath(url.directory());
548  addDirToUpdate(url);
549 
550  url = op.m_src;
551  url.setPath(url.directory());
552  addDirToUpdate(url);
553  }
554  else
555  m_undoState = REMOVINGLINKS;
556 }
557 
558 void FileUndoManagerPrivate::stepRemovingLinks()
559 {
560  kDebug(1203) << "REMOVINGLINKS";
561  if (!m_fileCleanupStack.isEmpty())
562  {
563  KUrl file = m_fileCleanupStack.pop();
564  kDebug(1203) << "file_delete" << file;
565  m_currentJob = KIO::file_delete(file, KIO::HideProgressInfo);
566  m_undoJob->emitDeleting(file);
567 
568  KUrl url(file);
569  url.setPath(url.directory());
570  addDirToUpdate(url);
571  }
572  else
573  {
574  m_undoState = REMOVINGDIRS;
575 
576  if (m_dirCleanupStack.isEmpty() && m_current.m_type == FileUndoManager::Mkdir)
577  m_dirCleanupStack << m_current.m_dst;
578  }
579 }
580 
581 void FileUndoManagerPrivate::stepRemovingDirectories()
582 {
583  if (!m_dirCleanupStack.isEmpty())
584  {
585  KUrl dir = m_dirCleanupStack.pop();
586  kDebug(1203) << "rmdir" << dir;
587  m_currentJob = KIO::rmdir(dir);
588  m_undoJob->emitDeleting(dir);
589  addDirToUpdate(dir);
590  }
591  else
592  {
593  m_current.m_valid = false;
594  m_currentJob = 0;
595  if (m_undoJob)
596  {
597  kDebug(1203) << "deleting undojob";
598  m_undoJob->emitResult();
599  m_undoJob = 0;
600  }
601  QList<KUrl>::ConstIterator it = m_dirsToUpdate.constBegin();
602  for(; it != m_dirsToUpdate.constEnd(); ++it) {
603  kDebug() << "Notifying FilesAdded for " << *it;
604  org::kde::KDirNotify::emitFilesAdded((*it).url());
605  }
606  emit q->undoJobFinished();
607  broadcastUnlock();
608  }
609 }
610 
611 // const ref doesn't work due to QDataStream
612 void FileUndoManagerPrivate::slotPush(QByteArray data)
613 {
614  QDataStream strm(&data, QIODevice::ReadOnly);
615  UndoCommand cmd;
616  strm >> cmd;
617  pushCommand(cmd);
618 }
619 
620 void FileUndoManagerPrivate::pushCommand(const UndoCommand& cmd)
621 {
622  m_commands.append(cmd);
623  emit q->undoAvailable(true);
624  emit q->undoTextChanged(q->undoText());
625 }
626 
627 void FileUndoManagerPrivate::slotPop()
628 {
629  m_commands.removeLast();
630  emit q->undoAvailable(q->undoAvailable());
631  emit q->undoTextChanged(q->undoText());
632 }
633 
634 void FileUndoManagerPrivate::slotLock()
635 {
636 // assert(!m_lock);
637  m_lock = true;
638  emit q->undoAvailable(q->undoAvailable());
639 }
640 
641 void FileUndoManagerPrivate::slotUnlock()
642 {
643 // assert(m_lock);
644  m_lock = false;
645  emit q->undoAvailable(q->undoAvailable());
646 }
647 
648 QByteArray FileUndoManagerPrivate::get() const
649 {
650  QByteArray data;
651  QDataStream stream(&data, QIODevice::WriteOnly);
652  stream << m_commands;
653  return data;
654 }
655 
656 void FileUndoManagerPrivate::broadcastPush(const UndoCommand &cmd)
657 {
658  if (!m_syncronized) {
659  pushCommand(cmd);
660  return;
661  }
662 
663  QByteArray data;
664  QDataStream stream(&data, QIODevice::WriteOnly);
665  stream << cmd;
666  emit push(data); // DBUS signal
667 }
668 
669 void FileUndoManagerPrivate::broadcastPop()
670 {
671  if (!m_syncronized) {
672  slotPop();
673  return;
674  }
675 
676  emit pop(); // DBUS signal
677 }
678 
679 void FileUndoManagerPrivate::broadcastLock()
680 {
681 // assert(!m_lock);
682 
683  if (!m_syncronized) {
684  slotLock();
685  return;
686  }
687  emit lock(); // DBUS signal
688 }
689 
690 void FileUndoManagerPrivate::broadcastUnlock()
691 {
692 // assert(m_lock);
693 
694  if (!m_syncronized) {
695  slotUnlock();
696  return;
697  }
698  emit unlock(); // DBUS signal
699 }
700 
701 bool FileUndoManagerPrivate::initializeFromKDesky()
702 {
703  // ### workaround for dcop problem and upcoming 2.1 release:
704  // in case of huge io operations the amount of data sent over
705  // dcop (containing undo information broadcasted for global undo
706  // to all konqueror instances) can easily exceed the 64kb limit
707  // of dcop. In order not to run into trouble we disable global
708  // undo for now! (Simon)
709  // ### FIXME: post 2.1
710  // TODO KDE4: port to DBUS and test
711  return false;
712 #if 0
713  DCOPClient *client = kapp->dcopClient();
714 
715  if (client->appId() == "kdesktop") // we are master :)
716  return true;
717 
718  if (!client->isApplicationRegistered("kdesktop"))
719  return false;
720 
721  d->m_commands = DCOPRef("kdesktop", "FileUndoManager").call("get");
722  return true;
723 #endif
724 }
725 
726 void FileUndoManager::setUiInterface(UiInterface* ui)
727 {
728  delete d->m_uiInterface;
729  d->m_uiInterface = ui;
730 }
731 
732 FileUndoManager::UiInterface* FileUndoManager::uiInterface() const
733 {
734  return d->m_uiInterface;
735 }
736 
738 
739 class FileUndoManager::UiInterface::UiInterfacePrivate
740 {
741 public:
742  UiInterfacePrivate()
743  : m_parentWidget(0), m_showProgressInfo(true)
744  {}
745  QWidget* m_parentWidget;
746  bool m_showProgressInfo;
747 };
748 
749 FileUndoManager::UiInterface::UiInterface()
750  : d(new UiInterfacePrivate)
751 {
752 }
753 
754 FileUndoManager::UiInterface::~UiInterface()
755 {
756  delete d;
757 }
758 
759 void FileUndoManager::UiInterface::jobError(KIO::Job* job)
760 {
761  job->ui()->showErrorMessage();
762 }
763 
764 bool FileUndoManager::UiInterface::copiedFileWasModified(const KUrl& src, const KUrl& dest, const KDateTime& srcTime, const KDateTime& destTime)
765 {
766  Q_UNUSED(srcTime); // not sure it should appear in the msgbox
767  // Possible improvement: only show the time if date is today
768  const QString timeStr = KGlobal::locale()->formatDateTime(destTime, KLocale::ShortDate);
769  return KMessageBox::warningContinueCancel(
770  d->m_parentWidget,
771  i18n("The file %1 was copied from %2, but since then it has apparently been modified at %3.\n"
772  "Undoing the copy will delete the file, and all modifications will be lost.\n"
773  "Are you sure you want to delete %4?", dest.pathOrUrl(), src.pathOrUrl(), timeStr, dest.pathOrUrl()),
774  i18n("Undo File Copy Confirmation"),
775  KStandardGuiItem::cont(),
776  KStandardGuiItem::cancel(),
777  QString(),
778  KMessageBox::Notify | KMessageBox::Dangerous) == KMessageBox::Continue;
779 }
780 
781 bool FileUndoManager::UiInterface::confirmDeletion(const KUrl::List& files)
782 {
783  KIO::JobUiDelegate uiDelegate;
784  uiDelegate.setWindow(d->m_parentWidget);
785  // Because undo can happen with an accidental Ctrl-Z, we want to always confirm.
786  return uiDelegate.askDeleteConfirmation(files, KIO::JobUiDelegate::Delete, KIO::JobUiDelegate::ForceConfirmation);
787 }
788 
789 QWidget* FileUndoManager::UiInterface::parentWidget() const
790 {
791  return d->m_parentWidget;
792 }
793 
794 void FileUndoManager::UiInterface::setParentWidget(QWidget* parentWidget)
795 {
796  d->m_parentWidget = parentWidget;
797 }
798 
799 void FileUndoManager::UiInterface::setShowProgressInfo(bool b)
800 {
801  d->m_showProgressInfo = b;
802 }
803 
804 bool FileUndoManager::UiInterface::showProgressInfo() const
805 {
806  return d->m_showProgressInfo;
807 }
808 
809 void FileUndoManager::UiInterface::virtual_hook(int, void*)
810 {
811 }
812 
813 #include "fileundomanager_p.moc"
814 #include "fileundomanager.moc"
This file is part of the KDE documentation.
Documentation copyright © 1996-2013 The KDE developers.
Generated on Mon Jul 15 2013 05:11:45 by doxygen 1.8.3.1 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

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-4.10.4 API Reference

Skip menu "kdelibs-4.10.4 API Reference"
  • 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
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal