KIO

deletejob.cpp
1 /*
2  This file is part of the KDE libraries
3  SPDX-FileCopyrightText: 2000 Stephan Kulow <[email protected]>
4  SPDX-FileCopyrightText: 2000-2009 David Faure <[email protected]>
5  SPDX-FileCopyrightText: 2000 Waldo Bastian <[email protected]>
6 
7  SPDX-License-Identifier: LGPL-2.0-or-later
8 */
9 
10 #include "deletejob.h"
11 
12 #include "../utils_p.h"
13 #include "job.h" // buildErrorString
14 #include "kcoredirlister.h"
15 #include "kprotocolmanager.h"
16 #include "listjob.h"
17 #include "statjob.h"
18 #include <KDirWatch>
19 #include <kdirnotify.h>
20 
21 #include <KLocalizedString>
22 #include <kio/jobuidelegatefactory.h>
23 
24 #include <QDir>
25 #include <QFile>
26 #include <QFileInfo>
27 #include <QMetaObject>
28 #include <QPointer>
29 #include <QThread>
30 #include <QTimer>
31 
32 #include "job_p.h"
33 
34 extern bool kio_resolve_local_urls; // from copyjob.cpp, abused here to save a symbol.
35 
36 static bool isHttpProtocol(const QString &protocol)
37 {
38  return (protocol.startsWith(QLatin1String("webdav"), Qt::CaseInsensitive) || protocol.startsWith(QLatin1String("http"), Qt::CaseInsensitive));
39 }
40 
41 namespace KIO
42 {
43 enum DeleteJobState {
44  DELETEJOB_STATE_STATING,
45  DELETEJOB_STATE_DELETING_FILES,
46  DELETEJOB_STATE_DELETING_DIRS,
47 };
48 
49 class DeleteJobIOWorker : public QObject
50 {
51  Q_OBJECT
52 
53 Q_SIGNALS:
54  void rmfileResult(bool succeeded, bool isLink);
55  void rmddirResult(bool succeeded);
56 
57 public Q_SLOTS:
58 
59  /**
60  * Deletes the file @p url points to
61  * The file must be a LocalFile
62  */
63  void rmfile(const QUrl &url, bool isLink)
64  {
65  Q_EMIT rmfileResult(QFile::remove(url.toLocalFile()), isLink);
66  }
67 
68  /**
69  * Deletes the directory @p url points to
70  * The directory must be a LocalFile
71  */
72  void rmdir(const QUrl &url)
73  {
74  Q_EMIT rmddirResult(QDir().rmdir(url.toLocalFile()));
75  }
76 };
77 
78 class DeleteJobPrivate : public KIO::JobPrivate
79 {
80 public:
81  explicit DeleteJobPrivate(const QList<QUrl> &src)
82  : state(DELETEJOB_STATE_STATING)
83  , m_processedFiles(0)
84  , m_processedDirs(0)
85  , m_totalFilesDirs(0)
86  , m_srcList(src)
87  , m_currentStat(m_srcList.begin())
88  , m_reportTimer(nullptr)
89  {
90  }
91  DeleteJobState state;
92  int m_processedFiles;
93  int m_processedDirs;
94  int m_totalFilesDirs;
95  QUrl m_currentURL;
96  QList<QUrl> files;
97  QList<QUrl> symlinks;
99  QList<QUrl> m_srcList;
100  QList<QUrl>::iterator m_currentStat;
101  QSet<QString> m_parentDirs;
102  QTimer *m_reportTimer;
103  DeleteJobIOWorker *m_ioworker = nullptr;
104  QThread *m_thread = nullptr;
105 
106  void statNextSrc();
107  DeleteJobIOWorker *worker();
108  void currentSourceStated(bool isDir, bool isLink);
109  void finishedStatPhase();
110  void deleteNextFile();
111  void deleteNextDir();
112  void restoreDirWatch() const;
113  void slotReport();
114  void slotStart();
115  void slotEntries(KIO::Job *, const KIO::UDSEntryList &list);
116 
117  /// Callback of worker rmfile
118  void rmFileResult(bool result, bool isLink);
119  /// Callback of worker rmdir
120  void rmdirResult(bool result);
121  void deleteFileUsingJob(const QUrl &url, bool isLink);
122  void deleteDirUsingJob(const QUrl &url);
123 
124  ~DeleteJobPrivate() override;
125 
126  Q_DECLARE_PUBLIC(DeleteJob)
127 
128  static inline DeleteJob *newJob(const QList<QUrl> &src, JobFlags flags)
129  {
130  DeleteJob *job = new DeleteJob(*new DeleteJobPrivate(src));
132  if (!(flags & HideProgressInfo)) {
134  }
135  if (!(flags & NoPrivilegeExecution)) {
136  job->d_func()->m_privilegeExecutionEnabled = true;
137  job->d_func()->m_operationType = Delete;
138  }
139  return job;
140  }
141 };
142 
143 } // namespace KIO
144 
145 using namespace KIO;
146 
147 DeleteJob::DeleteJob(DeleteJobPrivate &dd)
148  : Job(dd)
149 {
150  Q_D(DeleteJob);
151 
152  d->m_reportTimer = new QTimer(this);
153  connect(d->m_reportTimer, &QTimer::timeout, this, [d]() {
154  d->slotReport();
155  });
156  // this will update the report dialog with 5 Hz, I think this is fast enough, aleXXX
157  d->m_reportTimer->start(200);
158 
159  QTimer::singleShot(0, this, [d]() {
160  d->slotStart();
161  });
162 }
163 
164 DeleteJob::~DeleteJob()
165 {
166 }
167 
168 DeleteJobPrivate::~DeleteJobPrivate()
169 {
170  if (m_thread) {
171  m_thread->quit();
172  m_thread->wait();
173  delete m_thread;
174  }
175 }
176 
178 {
179  return d_func()->m_srcList;
180 }
181 
182 void DeleteJobPrivate::slotStart()
183 {
184  statNextSrc();
185 }
186 
187 DeleteJobIOWorker *DeleteJobPrivate::worker()
188 {
189  Q_Q(DeleteJob);
190 
191  if (!m_ioworker) {
192  m_thread = new QThread();
193 
194  m_ioworker = new DeleteJobIOWorker;
195  m_ioworker->moveToThread(m_thread);
196  QObject::connect(m_thread, &QThread::finished, m_ioworker, &QObject::deleteLater);
197  QObject::connect(m_ioworker, &DeleteJobIOWorker::rmfileResult, q, [=](bool result, bool isLink) {
198  this->rmFileResult(result, isLink);
199  });
200  QObject::connect(m_ioworker, &DeleteJobIOWorker::rmddirResult, q, [=](bool result) {
201  this->rmdirResult(result);
202  });
203  m_thread->start();
204  }
205 
206  return m_ioworker;
207 }
208 
209 void DeleteJobPrivate::slotReport()
210 {
211  Q_Q(DeleteJob);
212  Q_EMIT q->deleting(q, m_currentURL);
213 
214  // TODO: maybe we could skip everything else when (flags & HideProgressInfo) ?
215  JobPrivate::emitDeleting(q, m_currentURL);
216 
217  switch (state) {
218  case DELETEJOB_STATE_STATING:
219  q->setTotalAmount(KJob::Files, files.count());
220  q->setTotalAmount(KJob::Directories, dirs.count());
221  break;
222  case DELETEJOB_STATE_DELETING_DIRS:
223  q->setProcessedAmount(KJob::Directories, m_processedDirs);
224  q->emitPercent(m_processedFiles + m_processedDirs, m_totalFilesDirs);
225  break;
226  case DELETEJOB_STATE_DELETING_FILES:
227  q->setProcessedAmount(KJob::Files, m_processedFiles);
228  q->emitPercent(m_processedFiles, m_totalFilesDirs);
229  break;
230  }
231 }
232 
233 void DeleteJobPrivate::slotEntries(KIO::Job *job, const UDSEntryList &list)
234 {
237  for (; it != end; ++it) {
238  const UDSEntry &entry = *it;
240 
241  Q_ASSERT(!displayName.isEmpty());
242  if (displayName != QLatin1String("..") && displayName != QLatin1String(".")) {
243  QUrl url;
244  const QString urlStr = entry.stringValue(KIO::UDSEntry::UDS_URL);
245  if (!urlStr.isEmpty()) {
246  url = QUrl(urlStr);
247  } else {
248  url = static_cast<SimpleJob *>(job)->url(); // assumed to be a dir
249  url.setPath(Utils::concatPaths(url.path(), displayName));
250  }
251 
252  // qDebug() << displayName << "(" << url << ")";
253  if (entry.isLink()) {
254  symlinks.append(url);
255  } else if (entry.isDir()) {
256  dirs.append(url);
257  } else {
258  files.append(url);
259  }
260  }
261  }
262 }
263 
264 void DeleteJobPrivate::statNextSrc()
265 {
266  Q_Q(DeleteJob);
267  // qDebug();
268  if (m_currentStat != m_srcList.end()) {
269  m_currentURL = (*m_currentStat);
270 
271  // if the file system doesn't support deleting, we do not even stat
272  if (!KProtocolManager::supportsDeleting(m_currentURL)) {
273  QPointer<DeleteJob> that = q;
274  ++m_currentStat;
275  Q_EMIT q->warning(q, buildErrorString(ERR_CANNOT_DELETE, m_currentURL.toDisplayString()));
276  if (that) {
277  statNextSrc();
278  }
279  return;
280  }
281  // Stat it
282  state = DELETEJOB_STATE_STATING;
283 
284  // Fast path for KFileItems in directory views
285  while (m_currentStat != m_srcList.end()) {
286  m_currentURL = (*m_currentStat);
287  const KFileItem cachedItem = KCoreDirLister::cachedItemForUrl(m_currentURL);
288  if (cachedItem.isNull()) {
289  break;
290  }
291  // qDebug() << "Found cached info about" << m_currentURL << "isDir=" << cachedItem.isDir() << "isLink=" << cachedItem.isLink();
292  currentSourceStated(cachedItem.isDir(), cachedItem.isLink());
293  ++m_currentStat;
294  }
295 
296  // Hook for unit test to disable the fast path.
297  if (!kio_resolve_local_urls) {
298  // Fast path for local files
299  // (using a loop, instead of a huge recursion)
300  while (m_currentStat != m_srcList.end() && (*m_currentStat).isLocalFile()) {
301  m_currentURL = (*m_currentStat);
302  QFileInfo fileInfo(m_currentURL.toLocalFile());
303  currentSourceStated(fileInfo.isDir(), fileInfo.isSymLink());
304  ++m_currentStat;
305  }
306  }
307  if (m_currentStat == m_srcList.end()) {
308  // Done, jump to the last else of this method
309  statNextSrc();
310  } else {
311  KIO::SimpleJob *job = KIO::statDetails(m_currentURL, StatJob::SourceSide, KIO::StatBasic, KIO::HideProgressInfo);
312  // qDebug() << "stat'ing" << m_currentURL;
313  q->addSubjob(job);
314  }
315  } else {
316  if (!q->hasSubjobs()) { // don't go there yet if we're still listing some subdirs
317  finishedStatPhase();
318  }
319  }
320 }
321 
322 void DeleteJobPrivate::finishedStatPhase()
323 {
324  m_totalFilesDirs = files.count() + symlinks.count() + dirs.count();
325  slotReport();
326  // Now we know which dirs hold the files we're going to delete.
327  // To speed things up and prevent double-notification, we disable KDirWatch
328  // on those dirs temporarily (using KDirWatch::self, that's the instance
329  // used by e.g. kdirlister).
330  for (const QString &dir : std::as_const(m_parentDirs)) {
332  }
333  state = DELETEJOB_STATE_DELETING_FILES;
334  deleteNextFile();
335 }
336 
337 void DeleteJobPrivate::rmFileResult(bool result, bool isLink)
338 {
339  if (result) {
340  m_processedFiles++;
341 
342  if (isLink) {
343  symlinks.removeFirst();
344  } else {
345  files.removeFirst();
346  }
347 
348  deleteNextFile();
349  } else {
350  // fallback if QFile::remove() failed (we'll use the job's error handling in that case)
351  deleteFileUsingJob(m_currentURL, isLink);
352  }
353 }
354 
355 void DeleteJobPrivate::deleteFileUsingJob(const QUrl &url, bool isLink)
356 {
357  Q_Q(DeleteJob);
358 
359  SimpleJob *job;
360  if (isHttpProtocol(url.scheme())) {
362  } else {
364  job->setParentJob(q);
365  }
366 
367  if (isLink) {
368  symlinks.removeFirst();
369  } else {
370  files.removeFirst();
371  }
372 
373  q->addSubjob(job);
374 }
375 
376 void DeleteJobPrivate::deleteNextFile()
377 {
378  // qDebug();
379 
380  // if there is something else to delete
381  // the loop is run using callbacks slotResult and rmFileResult
382  if (!files.isEmpty() || !symlinks.isEmpty()) {
383  // Take first file to delete out of list
384  QList<QUrl>::iterator it = files.begin();
385  const bool isLink = (it == files.end()); // No more files
386  if (isLink) {
387  it = symlinks.begin(); // Pick up a symlink to delete
388  }
389  m_currentURL = (*it);
390 
391  // If local file, try do it directly
392  if (m_currentURL.isLocalFile()) {
393  // separate thread will do the work
394  DeleteJobIOWorker *w = worker();
395  auto rmfileFunc = [this, w, isLink]() {
396  w->rmfile(m_currentURL, isLink);
397  };
399  } else {
400  // if remote, use a job
401  deleteFileUsingJob(m_currentURL, isLink);
402  }
403  return;
404  }
405 
406  state = DELETEJOB_STATE_DELETING_DIRS;
407  deleteNextDir();
408 }
409 
410 void DeleteJobPrivate::rmdirResult(bool result)
411 {
412  if (result) {
413  m_processedDirs++;
414  dirs.removeLast();
415  deleteNextDir();
416  } else {
417  // fallback
418  deleteDirUsingJob(m_currentURL);
419  }
420 }
421 
422 void DeleteJobPrivate::deleteDirUsingJob(const QUrl &url)
423 {
424  Q_Q(DeleteJob);
425 
426  // Call rmdir - works for KIO workers with canDeleteRecursive too,
427  // CMD_DEL will trigger the recursive deletion in the worker.
428  SimpleJob *job = KIO::rmdir(url);
429  job->setParentJob(q);
430  job->addMetaData(QStringLiteral("recurse"), QStringLiteral("true"));
431  dirs.removeLast();
432  q->addSubjob(job);
433 }
434 
435 void DeleteJobPrivate::deleteNextDir()
436 {
437  Q_Q(DeleteJob);
438 
439  if (!dirs.isEmpty()) { // some dirs to delete ?
440 
441  // the loop is run using callbacks slotResult and rmdirResult
442  // Take first dir to delete out of list - last ones first !
443  QList<QUrl>::iterator it = --dirs.end();
444  m_currentURL = (*it);
445  // If local dir, try to rmdir it directly
446  if (m_currentURL.isLocalFile()) {
447  // delete it on separate worker thread
448  DeleteJobIOWorker *w = worker();
449  auto rmdirFunc = [this, w]() {
450  w->rmdir(m_currentURL);
451  };
453  } else {
454  deleteDirUsingJob(m_currentURL);
455  }
456  return;
457  }
458 
459  // Re-enable watching on the dirs that held the deleted files
460  restoreDirWatch();
461 
462  // Finished - tell the world
463  if (!m_srcList.isEmpty()) {
464  // qDebug() << "KDirNotify'ing FilesRemoved" << m_srcList;
465 #ifndef KIO_ANDROID_STUB
466  org::kde::KDirNotify::emitFilesRemoved(m_srcList);
467 #endif
468  }
469  if (m_reportTimer != nullptr) {
470  m_reportTimer->stop();
471  }
472  // display final numbers
473  q->setProcessedAmount(KJob::Directories, m_processedDirs);
474  q->setProcessedAmount(KJob::Files, m_processedFiles);
475  q->emitPercent(m_processedFiles + m_processedDirs, m_totalFilesDirs);
476 
477  q->emitResult();
478 }
479 
480 void DeleteJobPrivate::restoreDirWatch() const
481 {
482  const auto itEnd = m_parentDirs.constEnd();
483  for (auto it = m_parentDirs.constBegin(); it != itEnd; ++it) {
485  }
486 }
487 
488 void DeleteJobPrivate::currentSourceStated(bool isDir, bool isLink)
489 {
490  Q_Q(DeleteJob);
491  const QUrl url = (*m_currentStat);
492  if (isDir && !isLink) {
493  // Add toplevel dir in list of dirs
494  dirs.append(url);
495  if (url.isLocalFile()) {
496  // We are about to delete this dir, no need to watch it
497  // Maybe we should ask kdirwatch to remove all watches recursively?
498  // But then there would be no feedback (things disappearing progressively) during huge deletions
500  }
502  // qDebug() << url << "is a directory, let's list it";
504 #if KIOCORE_BUILD_DEPRECATED_SINCE(5, 69)
505  // TODO KF6: remove legacy details code path
506  newjob->addMetaData(QStringLiteral("details"), QStringLiteral("0"));
507 #endif
508  newjob->addMetaData(QStringLiteral("statDetails"), QString::number(KIO::StatBasic));
509  newjob->setUnrestricted(true); // No KIOSK restrictions
510  QObject::connect(newjob, &KIO::ListJob::entries, q, [this](KIO::Job *job, const KIO::UDSEntryList &list) {
511  slotEntries(job, list);
512  });
513  q->addSubjob(newjob);
514  // Note that this listing job will happen in parallel with other stat jobs.
515  }
516  } else {
517  if (isLink) {
518  // qDebug() << "Target is a symlink";
519  symlinks.append(url);
520  } else {
521  // qDebug() << "Target is a file";
522  files.append(url);
523  }
524  }
525  if (url.isLocalFile()) {
527  m_parentDirs.insert(parentDir);
528  }
529 }
530 
531 void DeleteJob::slotResult(KJob *job)
532 {
533  Q_D(DeleteJob);
534  switch (d->state) {
535  case DELETEJOB_STATE_STATING:
536  removeSubjob(job);
537 
538  // Was this a stat job or a list job? We do both in parallel.
539  if (StatJob *statJob = qobject_cast<StatJob *>(job)) {
540  // Was there an error while stating ?
541  if (job->error()) {
542  // Probably : doesn't exist
543  Job::slotResult(job); // will set the error and emit result(this)
544  d->restoreDirWatch();
545  return;
546  }
547 
548  const UDSEntry &entry = statJob->statResult();
549  // Is it a file or a dir ?
550  const bool isLink = entry.isLink();
551  const bool isDir = entry.isDir();
552  d->currentSourceStated(isDir, isLink);
553 
554  ++d->m_currentStat;
555  d->statNextSrc();
556  } else {
557  if (job->error()) {
558  // Try deleting nonetheless, it may be empty (and non-listable)
559  }
560  if (!hasSubjobs()) {
561  d->finishedStatPhase();
562  }
563  }
564  break;
565  case DELETEJOB_STATE_DELETING_FILES:
566  // Propagate the subjob's metadata (a SimpleJob) to the real DeleteJob
567  // FIXME: setMetaData() in the KIO API only allows access to outgoing metadata,
568  // but we need to alter the incoming one
569  d->m_incomingMetaData = dynamic_cast<KIO::Job *>(job)->metaData();
570 
571  if (job->error()) {
572  Job::slotResult(job); // will set the error and emit result(this)
573  d->restoreDirWatch();
574  return;
575  }
576  removeSubjob(job);
577  Q_ASSERT(!hasSubjobs());
578  d->m_processedFiles++;
579 
580  d->deleteNextFile();
581  break;
582  case DELETEJOB_STATE_DELETING_DIRS:
583  if (job->error()) {
584  Job::slotResult(job); // will set the error and emit result(this)
585  d->restoreDirWatch();
586  return;
587  }
588  removeSubjob(job);
589  Q_ASSERT(!hasSubjobs());
590  d->m_processedDirs++;
591  // emit processedAmount( this, KJob::Directories, d->m_processedDirs );
592  // emitPercent( d->m_processedFiles + d->m_processedDirs, d->m_totalFilesDirs );
593 
594  d->deleteNextDir();
595  break;
596  default:
597  Q_ASSERT(0);
598  }
599 }
600 
601 DeleteJob *KIO::del(const QUrl &src, JobFlags flags)
602 {
603  QList<QUrl> srcList;
604  srcList.append(src);
605  DeleteJob *job = DeleteJobPrivate::newJob(srcList, flags);
606  if (job->uiDelegateExtension()) {
607  job->uiDelegateExtension()->createClipboardUpdater(job, JobUiDelegateExtension::RemoveContent);
608  }
609  return job;
610 }
611 
613 {
614  DeleteJob *job = DeleteJobPrivate::newJob(src, flags);
615  if (job->uiDelegateExtension()) {
616  job->uiDelegateExtension()->createClipboardUpdater(job, JobUiDelegateExtension::RemoveContent);
617  }
618  return job;
619 }
620 
621 #include "deletejob.moc"
622 #include "moc_deletejob.cpp"
static KFileItem cachedItemForUrl(const QUrl &url)
Return the KFileItem for the given URL, if it was listed recently and it's still in the cache,...
Q_OBJECTQ_OBJECT
void append(const T &value)
bool stopDirScan(const QString &path)
virtual ClipboardUpdater * createClipboardUpdater(Job *job, ClipboardUpdaterMode mode)
Creates a clipboard updater as a child of the given job.
KIOCORE_EXPORT TransferJob * http_delete(const QUrl &url, JobFlags flags=DefaultFlags)
HTTP DELETE.
virtual void registerJob(KJob *job)
KIOCORE_EXPORT SimpleJob * file_delete(const QUrl &src, JobFlags flags=DefaultFlags)
Delete a single file.
Definition: job.cpp:380
QString number(int n, int base)
CaseInsensitive
Q_SLOTSQ_SLOTS
bool remove()
Q_EMITQ_EMIT
QString scheme() const const
int count(const T &value) const const
@ NoPrivilegeExecution
When set, notifies the worker that application/job does not want privilege execution.
Definition: job_base.h:300
bool isDir() const
Definition: udsentry.cpp:386
void addMetaData(const QString &key, const QString &value)
Add key/value pair to the meta data that is sent to the worker.
Definition: job.cpp:228
static bool canDeleteRecursive(const QUrl &url)
Returns whether the protocol can recursively delete directories by itself.
bool wait(QDeadlineTimer deadline)
void finished()
void entries(KIO::Job *job, const KIO::UDSEntryList &list)
This signal emits the entry found by the job while listing.
bool restartDirScan(const QString &path)
KIOFILEWIDGETS_EXPORT QStringList list(const QString &fileClass)
Returns a list of directories associated with this file-class.
Definition: krecentdirs.cpp:39
const QList< QKeySequence > & begin()
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
@ UDS_NAME
Filename - as displayed in directory listings etc.
Definition: udsentry.h:249
void setParentJob(Job *parentJob)
Set the parent Job.
Definition: job.cpp:199
KIOCORE_EXPORT KJobTrackerInterface * getJobTracker()
Returns the job tracker to be used by all KIO jobs (in which HideProgressInfo is not set)
Definition: jobtracker.cpp:14
void quit()
QString stringValue(uint field) const
Definition: udsentry.cpp:376
void deleteLater()
KIOCORE_EXPORT ListJob * listRecursive(const QUrl &url, JobFlags flags=DefaultFlags, bool includeHidden=true)
The same as the previous method, but recurses subdirectories.
Definition: listjob.cpp:248
KIOCORE_EXPORT QString buildErrorString(int errorCode, const QString &errorText)
Returns a translated error message for errorCode using the additional error information provided by e...
Definition: job_error.cpp:27
KIOCORE_EXPORT DeleteJob * del(const QUrl &src, JobFlags flags=DefaultFlags)
Delete a file or directory.
Definition: deletejob.cpp:601
MetaData metaData() const
Get meta data received from the worker.
Definition: job.cpp:212
bool isNull() const
Return true if default-constructed.
Definition: kfileitem.cpp:1700
@ UDS_URL
An alternative URL (If different from the caption).
Definition: udsentry.h:276
StripTrailingSlash
QSet::const_iterator constBegin() const const
void start(QThread::Priority priority)
void timeout()
bool isEmpty() const const
void removeFirst()
QString toDisplayString(QUrl::FormattingOptions options) const const
QSet::const_iterator constEnd() const const
KIOCORE_EXPORT KJobUiDelegate * createDefaultJobUiDelegate()
Convenience method: use default factory, if there's one, to create a delegate and return it.
QueuedConnection
bool isEmpty() const const
QString toLocalFile() const const
@ StatBasic
Filename, access, type, size, linkdest.
Definition: global.h:369
void setUnrestricted(bool unrestricted)
Do not apply any KIOSK restrictions to this job.
Definition: listjob.cpp:253
static KDirWatch * self()
AKONADI_CALENDAR_EXPORT QString displayName(Akonadi::ETMCalendar *calendar, const Akonadi::Collection &collection)
Q_SIGNALSQ_SIGNALS
bool startsWith(const QString &s, Qt::CaseSensitivity cs) const const
bool isLink() const
Definition: udsentry.cpp:391
static bool supportsDeleting(const QUrl &url)
Returns whether the protocol can delete files/objects.
QString path(QUrl::ComponentFormattingOptions options) const const
QList< QUrl > urls() const
Returns the list of URLs.
Definition: deletejob.cpp:177
void stop()
void setPath(const QString &path, QUrl::ParsingMode mode)
KStandardDirs * dirs()
bool isLocalFile() const const
bool invokeMethod(QObject *obj, const char *member, Qt::ConnectionType type, QGenericReturnArgument ret, QGenericArgument val0, QGenericArgument val1, QGenericArgument val2, QGenericArgument val3, QGenericArgument val4, QGenericArgument val5, QGenericArgument val6, QGenericArgument val7, QGenericArgument val8, QGenericArgument val9)
void setUiDelegate(KJobUiDelegate *delegate)
QUrl adjusted(QUrl::FormattingOptions options) const const
KIOCORE_EXPORT StatJob * statDetails(const QUrl &url, KIO::StatJob::StatSide side, KIO::StatDetails details=KIO::StatDefaultDetails, JobFlags flags=DefaultFlags)
Find all details for one file or directory.
Definition: statjob.cpp:263
A namespace for KIO globals.
virtual void slotResult(KJob *job)
KIOCORE_EXPORT SimpleJob * rmdir(const QUrl &url)
Removes a single directory.
Definition: simplejob.cpp:336
QSet::iterator insert(const T &value)
QList::iterator begin()
@ HideProgressInfo
Hide progress information dialog, i.e. don't show a GUI.
Definition: job_base.h:275
JobUiDelegateExtension * uiDelegateExtension() const
Retrieves the UI delegate extension used by this job.
Definition: job.cpp:51
int error() const
bool hasSubjobs() const
QList::iterator end()
bool removeSubjob(KJob *job) override
Mark a sub job as being done.
Definition: job.cpp:87
const QList< QKeySequence > & end()
Q_D(Todo)
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Sun Dec 3 2023 03:53:22 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.