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

Skip menu "kdelibs-4.11.5 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