Baloo Widgets

filemetadataprovider.cpp
1 /*
2  SPDX-FileCopyrightText: 2010 Peter Penz <[email protected]>
3  SPDX-FileCopyrightText: 2012 Vishesh Handa <[email protected]>
4  SPDX-FileCopyrightText: 2021 Kai Uwe Broulik <[email protected]>
5 
6  SPDX-License-Identifier: LGPL-2.0-or-later
7 */
8 
9 #include "filemetadataprovider.h"
10 #include "filefetchjob.h"
11 
12 #include <KFileMetaData/PropertyInfo>
13 #include <KFormat>
14 #include <KLocalizedString>
15 #include <KProtocolInfo>
16 #include <KShell>
17 
18 #include <QDebug>
19 #include <QPair>
20 #include <QTimer>
21 
22 // Required includes for subDirectoriesCount():
23 #ifdef Q_OS_WIN
24 #include <QDir>
25 #else
26 #include <QFile>
27 #include <dirent.h>
28 #endif
29 
30 using namespace Baloo;
31 
32 namespace
33 {
34 QVariant intersect(const QVariant &v1, const QVariant &v2)
35 {
36  if (!v1.isValid() || !v2.isValid()) {
37  return {};
38  }
39 
40  // List and String
41  if (v1.type() == QVariant::StringList && v2.type() == QVariant::String) {
43  QString str = v2.toString();
44 
45  if (!list.contains(str)) {
46  list << str;
47  }
48 
49  return QVariant(list);
50  }
51 
52  // String and List
53  if (v1.type() == QVariant::String && v2.type() == QVariant::StringList) {
55  QString str = v1.toString();
56 
57  if (!list.contains(str)) {
58  list << str;
59  }
60 
61  return QVariant(list);
62  }
63 
64  // List and List
65  if (v1.type() == QVariant::StringList && v2.type() == QVariant::StringList) {
68 
69  return QVariant(s1.intersect(s2).values());
70  }
71 
72  if (v1 == v2) {
73  return v1;
74  }
75 
76  return {};
77 }
78 
79 /**
80  * The standard QMap::unite will contain the key multiple times if both \p v1 and \p v2
81  * contain the same key.
82  *
83  * This will only take the key from \p v2 into account
84  */
85 QVariantMap unite(const QVariantMap &v1, const QVariantMap &v2)
86 {
87  QVariantMap v(v1);
89  while (it.hasNext()) {
90  it.next();
91 
92  v[it.key()] = it.value();
93  }
94 
95  return v;
96 }
97 } // anonymous namespace
98 
99 void FileMetaDataProvider::totalPropertyAndInsert(const QString &prop, const QList<QVariantMap> &resources, QSet<QString> &allProperties)
100 {
101  if (allProperties.contains(prop)) {
102  int total = 0;
103  for (const QVariantMap &map : resources) {
104  QVariantMap::const_iterator it = map.constFind(prop);
105  if (it == map.constEnd()) {
106  total = 0;
107  break;
108  } else {
109  total += it.value().toInt();
110  }
111  }
112 
113  if (total) {
114  m_data.insert(prop, QVariant(total));
115  }
116  allProperties.remove(prop);
117  }
118 }
119 
120 void FileMetaDataProvider::slotFileFetchFinished(KJob *job)
121 {
122  auto fetchJob = static_cast<FileFetchJob *>(job);
123  QList<QVariantMap> files = fetchJob->data();
124 
125  Q_ASSERT(!files.isEmpty());
126 
127  if (files.size() > 1) {
128  insertCommonData(files);
129  } else {
130  m_data = unite(m_data, files.first());
131 
132  const auto width = m_data.value(QStringLiteral("width"));
133  const auto height = m_data.value(QStringLiteral("height"));
134  if ((width.type() == QVariant::Double || width.type() == QVariant::Int) && (height.type() == QVariant::Double || height.type() == QVariant::Int)) {
135  m_data.insert(QStringLiteral("dimensions"), i18nc("width × height", "%1 × %2", width.toInt(), height.toInt()));
136  }
137 
138  bool okLatitude;
139  const auto gpsLatitude = m_data.value(QStringLiteral("photoGpsLatitude")).toFloat(&okLatitude);
140  bool okLongitude;
141  const auto gpsLongitude = m_data.value(QStringLiteral("photoGpsLongitude")).toFloat(&okLongitude);
142 
143  if (okLatitude && okLongitude) {
144  m_data.insert(QStringLiteral("gpsLocation"), QVariant::fromValue(QPair<float, float>(gpsLatitude, gpsLongitude)));
145  }
146  }
147  m_readOnly = !fetchJob->canEditAll();
148 
149  insertEditableData();
151 }
152 
153 void FileMetaDataProvider::insertSingleFileBasicData()
154 {
155  // TODO: Handle case if remote URLs are used properly. isDir() does
156  // not work, the modification date needs also to be adjusted...
157  Q_ASSERT(m_fileItems.count() <= 1);
158  if (m_fileItems.count() == 1) {
159  const KFileItem &item = m_fileItems.first();
160 
161  KFormat format;
162  if (item.isDir()) {
163  bool isSizeUnknown = !item.isLocalFile() || item.isSlow();
164  if (!isSizeUnknown) {
165  const QPair<int, int> counts = subDirectoriesCount(item.url().path());
166  const int count = counts.first;
167  isSizeUnknown = count == -1;
168  if (!isSizeUnknown) {
169  QString itemCountString = i18ncp("@item:intable", "%1 item", "%1 items", count);
170  m_data.insert(QStringLiteral("kfileitem#size"), itemCountString);
171 
172  const int hiddenCount = counts.second;
173  if (hiddenCount > 0) {
174  // add hidden items count
175  QString hiddenCountString = i18ncp("@item:intable", "%1 item", "%1 items", hiddenCount);
176  m_data.insert(QStringLiteral("kfileitem#hiddenItems"), hiddenCountString);
177  }
178  }
179  } else if (item.entry().contains(KIO::UDSEntry::UDS_SIZE)) {
180  m_data.insert(QStringLiteral("kfileitem#size"), format.formatByteSize(item.size()));
181  }
183  m_data.insert(QStringLiteral("kfileitem#totalSize"), format.formatByteSize(item.recursiveSize()));
184  }
185  } else {
186  if (item.entry().contains(KIO::UDSEntry::UDS_SIZE)) {
187  m_data.insert(QStringLiteral("kfileitem#size"), format.formatByteSize(item.size()));
188  }
189  }
190 
191  m_data.insert(QStringLiteral("kfileitem#type"), item.mimeComment());
192  if (item.isLink()) {
193  m_data.insert(QStringLiteral("kfileitem#linkDest"), item.linkDest());
194  }
196  m_data.insert(QStringLiteral("kfileitem#targetUrl"), KShell::tildeCollapse(item.targetUrl().toDisplayString(QUrl::PreferLocalFile)));
197  }
198  QDateTime modificationTime = item.time(KFileItem::ModificationTime);
199  if (modificationTime.isValid()) {
200  m_data.insert(QStringLiteral("kfileitem#modified"), modificationTime);
201  }
202  QDateTime creationTime = item.time(KFileItem::CreationTime);
203  if (creationTime.isValid()) {
204  m_data.insert(QStringLiteral("kfileitem#created"), creationTime);
205  }
206  QDateTime accessTime = item.time(KFileItem::AccessTime);
207  if (accessTime.isValid()) {
208  m_data.insert(QStringLiteral("kfileitem#accessed"), accessTime);
209  }
210 
211  m_data.insert(QStringLiteral("kfileitem#owner"), item.user());
212  m_data.insert(QStringLiteral("kfileitem#group"), item.group());
213  m_data.insert(QStringLiteral("kfileitem#permissions"), item.permissionsString());
214 
215  const auto extraFields = KProtocolInfo::extraFields(item.url());
216  for (int i = 0; i < extraFields.count(); ++i) {
217  const auto &field = extraFields.at(i);
218  if (field.type == KProtocolInfo::ExtraField::Invalid) {
219  continue;
220  }
221 
222  const QString text = item.entry().stringValue(KIO::UDSEntry::UDS_EXTRA + i);
223  if (text.isEmpty()) {
224  continue;
225  }
226 
227  const QString key = QStringLiteral("kfileitem#extra_%1_%2").arg(item.url().scheme(), QString::number(i + 1));
228 
229  if (field.type == KProtocolInfo::ExtraField::DateTime) {
230  const QDateTime date = QDateTime::fromString(text, Qt::ISODate);
231  if (!date.isValid()) {
232  continue;
233  }
234 
235  m_data.insert(key, date);
236  } else {
237  m_data.insert(key, text);
238  }
239  }
240  }
241 }
242 
243 void FileMetaDataProvider::insertFilesListBasicData()
244 {
245  // If all directories
246  Q_ASSERT(m_fileItems.count() > 1);
247  bool allDirectories = true;
248  for (const KFileItem &item : std::as_const(m_fileItems)) {
249  allDirectories &= item.isDir();
250  if (!allDirectories) {
251  break;
252  }
253  }
254 
255  if (allDirectories) {
256  int count = 0;
257  int hiddenCount = 0;
258  bool isSizeKnown = true;
259  for (const KFileItem &item : std::as_const(m_fileItems)) {
260  isSizeKnown = item.isLocalFile() && !item.isSlow();
261  if (!isSizeKnown) {
262  return;
263  }
264  const QPair<int, int> counts = subDirectoriesCount(item.url().path());
265  const int subcount = counts.first;
266  isSizeKnown = subcount != -1;
267  if (!isSizeKnown) {
268  return;
269  }
270  count += subcount;
271  hiddenCount += counts.second;
272  }
273  QString itemCountString = i18ncp("@item:intable", "%1 item", "%1 items", count);
274  if (hiddenCount > 0) {
275  // add hidden items count
276  QString hiddenCountString = i18ncp("@item:intable", "%1 item", "%1 items", hiddenCount);
277  m_data.insert(QStringLiteral("kfileitem#hiddenItems"), hiddenCountString);
278  }
279  m_data.insert(QStringLiteral("kfileitem#totalSize"), itemCountString);
280 
281  } else {
282  // Calculate the size of all items
283  quint64 totalSize = 0;
284  for (const KFileItem &item : std::as_const(m_fileItems)) {
285  if (!item.isDir() && !item.isLink()) {
286  totalSize += item.size();
287  }
288  }
289  KFormat format;
290  m_data.insert(QStringLiteral("kfileitem#totalSize"), format.formatByteSize(totalSize));
291  }
292 }
293 
294 void FileMetaDataProvider::insertEditableData()
295 {
296  if (!m_readOnly) {
297  if (!m_data.contains(QStringLiteral("tags"))) {
298  m_data.insert(QStringLiteral("tags"), QVariant());
299  }
300  if (!m_data.contains(QStringLiteral("rating"))) {
301  m_data.insert(QStringLiteral("rating"), 0);
302  }
303  if (!m_data.contains(QStringLiteral("userComment"))) {
304  m_data.insert(QStringLiteral("userComment"), QVariant());
305  }
306  }
307 }
308 
309 void FileMetaDataProvider::insertCommonData(const QList<QVariantMap> &files)
310 {
311  //
312  // Only report the stuff that is common to all the files
313  //
314  QSet<QString> allProperties;
315  QList<QVariantMap> propertyList;
316  for (const QVariantMap &fileData : files) {
317  propertyList << fileData;
318  auto uniqueValues = fileData.keys();
319  uniqueValues.erase(std::unique(uniqueValues.begin(), uniqueValues.end()), uniqueValues.end());
320  allProperties += QSet<QString>(uniqueValues.begin(), uniqueValues.end());
321  }
322 
323  // Special handling for certain properties
324  totalPropertyAndInsert(QStringLiteral("duration"), propertyList, allProperties);
325  totalPropertyAndInsert(QStringLiteral("characterCount"), propertyList, allProperties);
326  totalPropertyAndInsert(QStringLiteral("wordCount"), propertyList, allProperties);
327  totalPropertyAndInsert(QStringLiteral("lineCount"), propertyList, allProperties);
328 
329  for (const QString &propUri : std::as_const(allProperties)) {
330  for (const QVariantMap &map : std::as_const(propertyList)) {
331  QVariantMap::const_iterator it = map.find(propUri);
332  if (it == map.constEnd()) {
333  m_data.remove(propUri);
334  break;
335  }
336 
337  QVariantMap::iterator dit = m_data.find(it.key());
338  if (dit == m_data.end()) {
339  m_data.insert(propUri, it.value());
340  } else {
341  QVariant finalValue = intersect(it.value(), dit.value());
342  if (finalValue.isValid()) {
343  m_data[propUri] = finalValue;
344  } else {
345  m_data.remove(propUri);
346  break;
347  }
348  }
349  }
350  }
351 }
352 
353 FileMetaDataProvider::FileMetaDataProvider(QObject *parent)
354  : QObject(parent)
355  , m_readOnly(false)
356  , m_realTimeIndexing(false)
357 {
358 }
359 
360 FileMetaDataProvider::~FileMetaDataProvider() = default;
361 
362 void FileMetaDataProvider::setFileItem()
363 {
364  // There are 3 code paths -
365  // Remote file
366  // Single local file -
367  // * Not Indexed
368  // * Indexed
369  //
370  insertSingleFileBasicData();
371  const QUrl url = m_fileItems.first().targetUrl();
372  if (!url.isLocalFile() || m_fileItems.first().isSlow()) {
373  // FIXME - are extended attributes supported for remote files?
374  m_readOnly = true;
376  return;
377  }
378 
379  const QString filePath = url.toLocalFile();
380  FileFetchJob *job;
381 
382  // Not indexed or only basic file indexing (no content)
383  if (!m_config.fileIndexingEnabled() || !m_config.shouldBeIndexed(filePath) || m_config.onlyBasicIndexing()) {
384  m_realTimeIndexing = true;
385 
386  job = new FileFetchJob(QStringList{filePath}, true, FileFetchJob::UseRealtimeIndexing::Only, this);
387 
388  // Fully indexed by Baloo
389  } else {
390  job = new FileFetchJob(QStringList{filePath}, true, FileFetchJob::UseRealtimeIndexing::Fallback, this);
391  }
392  connect(job, &FileFetchJob::finished, this, &FileMetaDataProvider::slotFileFetchFinished);
393  job->start();
394 }
395 
396 void FileMetaDataProvider::setFileItems()
397 {
398  // Multiple Files -
399  // * Not Indexed
400  // * Indexed
401 
402  QStringList urls;
403  urls.reserve(m_fileItems.size());
404  // Only extract data from indexed files,
405  // it would be too expensive otherwise.
406  for (const KFileItem &item : std::as_const(m_fileItems)) {
407  const QUrl url = item.targetUrl();
408  if (url.isLocalFile() && !item.isSlow()) {
409  urls << url.toLocalFile();
410  }
411  }
412 
413  insertFilesListBasicData();
414  if (!urls.isEmpty()) {
415  // Editing only if all URLs are local
416  bool canEdit = (urls.size() == m_fileItems.size());
417 
418  auto job = new FileFetchJob(urls, canEdit, FileFetchJob::UseRealtimeIndexing::Disabled, this);
419  connect(job, &FileFetchJob::finished, this, &FileMetaDataProvider::slotFileFetchFinished);
420  job->start();
421 
422  } else {
423  // FIXME - are extended attributes supported for remote files?
424  m_readOnly = true;
426  }
427 }
428 
430 {
431  m_fileItems = items;
432  m_data.clear();
433  m_realTimeIndexing = false;
434 
435  if (items.isEmpty()) {
437  } else if (items.size() == 1) {
438  setFileItem();
439  } else {
440  setFileItems();
441  }
442 }
443 
444 QString FileMetaDataProvider::label(const QString &metaDataLabel) const
445 {
446  static QHash<QString, QString> hash = {
447  {QStringLiteral("kfileitem#comment"), i18nc("@label", "Comment")},
448  {QStringLiteral("kfileitem#created"), i18nc("@label", "Created")},
449  {QStringLiteral("kfileitem#accessed"), i18nc("@label", "Accessed")},
450  {QStringLiteral("kfileitem#modified"), i18nc("@label", "Modified")},
451  {QStringLiteral("kfileitem#owner"), i18nc("@label", "Owner")},
452  {QStringLiteral("kfileitem#group"), i18nc("@label", "Group")},
453  {QStringLiteral("kfileitem#permissions"), i18nc("@label", "Permissions")},
454  {QStringLiteral("kfileitem#rating"), i18nc("@label", "Rating")},
455  {QStringLiteral("kfileitem#size"), i18nc("@label", "Size")},
456  {QStringLiteral("kfileitem#tags"), i18nc("@label", "Tags")},
457  {QStringLiteral("kfileitem#totalSize"), i18nc("@label", "Total Size")},
458  {QStringLiteral("kfileitem#hiddenItems"), i18nc("@label", "Hidden items")},
459  {QStringLiteral("kfileitem#type"), i18nc("@label", "Type")},
460  {QStringLiteral("kfileitem#linkDest"), i18nc("@label", "Link to")},
461  {QStringLiteral("kfileitem#targetUrl"), i18nc("@label", "Points to")},
462  {QStringLiteral("tags"), i18nc("@label", "Tags")},
463  {QStringLiteral("rating"), i18nc("@label", "Rating")},
464  {QStringLiteral("userComment"), i18nc("@label", "Comment")},
465  {QStringLiteral("originUrl"), i18nc("@label", "Downloaded From")},
466  {QStringLiteral("dimensions"), i18nc("@label", "Dimensions")},
467  {QStringLiteral("gpsLocation"), i18nc("@label", "GPS Location")},
468  };
469 
470  QString value = hash.value(metaDataLabel);
471  if (value.isEmpty()) {
472  static const auto extraPrefix = QStringLiteral("kfileitem#extra_");
473  if (metaDataLabel.startsWith(extraPrefix)) {
474 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
475  const auto parts = metaDataLabel.splitRef(QLatin1Char('_'));
476 #else
477  const auto parts = metaDataLabel.split(QLatin1Char('_'));
478 #endif
479  Q_ASSERT(parts.count() == 3);
480  const auto protocol = parts.at(1);
481  const int extraNumber = parts.at(2).toInt() - 1;
482 
483  // Have to construct a dummy URL for KProtocolInfo::extraFields...
484  QUrl url;
485 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
486  url.setScheme(protocol.toString());
487 #else
488  url.setScheme(protocol);
489 #endif
490  const auto extraFields = KProtocolInfo::extraFields(url);
491  auto field = extraFields.value(extraNumber);
492  if (field.type != KProtocolInfo::ExtraField::Invalid) {
493  value = field.name;
494  }
495  }
496  }
497 
498  if (value.isEmpty()) {
499  value = KFileMetaData::PropertyInfo::fromName(metaDataLabel).displayName();
500  }
501 
502  return value;
503 }
504 
506 {
507  static QHash<QString, QString> uriGrouper = {
508 
509  // KFileItem Data
510  {QStringLiteral("kfileitem#type"), QStringLiteral("0FileItemA")},
511  {QStringLiteral("kfileitem#linkDest"), QStringLiteral("0FileItemB")},
512  {QStringLiteral("kfileitem#size"), QStringLiteral("0FileItemC")},
513  {QStringLiteral("kfileitem#totalSize"), QStringLiteral("0FileItemC")},
514  {QStringLiteral("kfileitem#hiddenItems"), QStringLiteral("0FileItemD")},
515  {QStringLiteral("kfileitem#modified"), QStringLiteral("0FileItemE")},
516  {QStringLiteral("kfileitem#accessed"), QStringLiteral("0FileItemF")},
517  {QStringLiteral("kfileitem#created"), QStringLiteral("0FileItemG")},
518  {QStringLiteral("kfileitem#owner"), QStringLiteral("0FileItemH")},
519  {QStringLiteral("kfileitem#group"), QStringLiteral("0FileItemI")},
520  {QStringLiteral("kfileitem#permissions"), QStringLiteral("0FileItemJ")},
521 
522  // Editable Data
523  {QStringLiteral("tags"), QStringLiteral("1EditableDataA")},
524  {QStringLiteral("rating"), QStringLiteral("1EditableDataB")},
525  {QStringLiteral("userComment"), QStringLiteral("1EditableDataC")},
526 
527  // Image Data
528  {QStringLiteral("width"), QStringLiteral("2ImageA")},
529  {QStringLiteral("height"), QStringLiteral("2ImageB")},
530  {QStringLiteral("dimensions"), QStringLiteral("2ImageCA")},
531  {QStringLiteral("photoFNumber"), QStringLiteral("2ImageC")},
532  {QStringLiteral("photoExposureTime"), QStringLiteral("2ImageD")},
533  {QStringLiteral("photoExposureBiasValue"), QStringLiteral("2ImageE")},
534  {QStringLiteral("photoISOSpeedRatings"), QStringLiteral("2ImageF")},
535  {QStringLiteral("photoFocalLength"), QStringLiteral("2ImageG")},
536  {QStringLiteral("photoFocalLengthIn35mmFilm"), QStringLiteral("2ImageH")},
537  {QStringLiteral("photoFlash"), QStringLiteral("2ImageI")},
538  {QStringLiteral("imageOrientation"), QStringLiteral("2ImageJ")},
539  {QStringLiteral("photoGpsLocation"), QStringLiteral("2ImageK")},
540  {QStringLiteral("photoGpsLatitude"), QStringLiteral("2ImageL")},
541  {QStringLiteral("photoGpsLongitude"), QStringLiteral("2ImageM")},
542  {QStringLiteral("photoGpsAltitude"), QStringLiteral("2ImageN")},
543  {QStringLiteral("manufacturer"), QStringLiteral("2ImageO")},
544  {QStringLiteral("model"), QStringLiteral("2ImageP")},
545 
546  // Media Data
547  {QStringLiteral("title"), QStringLiteral("3MediaA")},
548  {QStringLiteral("artist"), QStringLiteral("3MediaB")},
549  {QStringLiteral("album"), QStringLiteral("3MediaC")},
550  {QStringLiteral("albumArtist"), QStringLiteral("3MediaD")},
551  {QStringLiteral("genre"), QStringLiteral("3MediaE")},
552  {QStringLiteral("trackNumber"), QStringLiteral("3MediaF")},
553  {QStringLiteral("discNumber"), QStringLiteral("3MediaG")},
554  {QStringLiteral("releaseYear"), QStringLiteral("3MediaH")},
555  {QStringLiteral("duration"), QStringLiteral("3MediaI")},
556  {QStringLiteral("sampleRate"), QStringLiteral("3MediaJ")},
557  {QStringLiteral("bitRate"), QStringLiteral("3MediaK")},
558 
559  // Miscellaneous Data
560  {QStringLiteral("originUrl"), QStringLiteral("4MiscA")},
561  };
562 
563  const QString val = uriGrouper.value(label);
564  if (val.isEmpty()) {
565  return QStringLiteral("lastGroup");
566  }
567  return val;
568 }
569 
570 KFileItemList FileMetaDataProvider::items() const
571 {
572  return m_fileItems;
573 }
574 
576 {
577  m_readOnly = readOnly;
578 }
579 
580 bool FileMetaDataProvider::isReadOnly() const
581 {
582  return m_readOnly;
583 }
584 
585 QVariantMap FileMetaDataProvider::data() const
586 {
587  return m_data;
588 }
589 
590 QPair<int, int> FileMetaDataProvider::subDirectoriesCount(const QString &path)
591 {
592 #ifdef Q_OS_WIN
593  QDir dir(path);
594  int count = dir.entryList(QDir::AllEntries | QDir::NoDotAndDotDot | QDir::System).count();
595  int hiddenCount = dir.entryList(QDir::AllEntries | QDir::NoDotAndDotDot | QDir::System | QDir::Hidden).count();
596  return QPair<int, int>(count, hiddenCount);
597 #else
598  // Taken from kdelibs/kio/kio/kdirmodel.cpp
599  // SPDX-FileCopyrightText: 2006 David Faure <[email protected]>
600 
601  int count = -1;
602  int hiddenCount = -1;
603  DIR *dir = ::opendir(QFile::encodeName(path).constData());
604  if (dir) {
605  count = 0;
606  hiddenCount = 0;
607  struct dirent *dirEntry = nullptr;
608  while ((dirEntry = ::readdir(dir))) { // krazy:exclude=syscalls
609  if (dirEntry->d_name[0] == '.') {
610  if (dirEntry->d_name[1] == '\0') {
611  // Skip "."
612  continue;
613  }
614  if (dirEntry->d_name[1] == '.' && dirEntry->d_name[2] == '\0') {
615  // Skip ".."
616  continue;
617  }
618  // hidden files
619  hiddenCount++;
620  } else {
621  ++count;
622  }
623  }
624  ::closedir(dir);
625  }
626  return QPair<int, int>(count, hiddenCount);
627 #endif
628 }
629 
631 {
632  return m_realTimeIndexing;
633 }
T & first()
void loadingFinished()
Emitted once per KFileMetaDataProvider::setItems() after data loading is finished.
const T value(const Key &key) const const
bool isValid() const const
QString formatByteSize(double size, int precision=1, KFormat::BinaryUnitDialect dialect=KFormat::DefaultBinaryDialect, KFormat::BinarySizeUnits units=KFormat::DefaultBinaryUnits) const
bool remove(const T &value)
Q_INVOKABLE QDateTime time(FileTimes which) const
QString number(int n, int base)
virtual QString label(const QString &metaDataLabel) const
QVariant fromValue(const T &value)
virtual QString group(const QString &label) const
Meta data items are sorted alphabetically by their translated label per default.
Q_EMITQ_EMIT
void setItems(const KFileItemList &items)
Sets the items, where the meta data should be requested.
QString scheme() const const
QStringList split(const QString &sep, QString::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
int count(const T &value) const const
QByteArray encodeName(const QString &fileName)
bool contains(const QString &str, Qt::CaseSensitivity cs) const const
bool isLocalFile() const
static ExtraFieldList extraFields(const QUrl &url)
KIOFILEWIDGETS_EXPORT QStringList list(const QString &fileClass)
QString permissionsString() const
bool isDir() const
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QString mimeComment() const
QString displayName() const
QString i18ncp(const char *context, const char *singular, const char *plural, const TYPE &arg...)
void setScheme(const QString &scheme)
QUrl targetUrl() const
void reserve(int alloc)
QString stringValue(uint field) const
int size() const const
bool isLink() const
QString linkDest() const
QVariant::Type type() const const
PreferLocalFile
bool isEmpty() const const
QVector< QStringRef > splitRef(const QString &sep, QString::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
QString toDisplayString(QUrl::FormattingOptions options) const const
bool isEmpty() const const
QString toLocalFile() const const
QList::const_iterator cend() const const
QDateTime fromString(const QString &string, Qt::DateFormat format)
static PropertyInfo fromName(const QString &name)
QString user() const
KIO::filesize_t recursiveSize() const
KIO::UDSEntry entry() const
bool contains(const T &value) const const
KCOREADDONS_EXPORT QString tildeCollapse(const QString &path)
bool startsWith(const QString &s, Qt::CaseSensitivity cs) const const
QUrl url() const
KIO::filesize_t size() const
QString path(QUrl::ComponentFormattingOptions options) const const
QList::iterator erase(QList::iterator pos)
int count() const const
QString arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const const
bool isLocalFile() const const
QList::const_iterator cbegin() const const
bool isValid() const const
QString i18nc(const char *context, const char *text, const TYPE &arg...)
QStringList toStringList() const const
bool realTimeIndexing()
Returns true if the items do not exist in the database and have just been indexed.
bool isSlow() const
QFuture< void > map(Sequence &sequence, MapFunctor function)
QString group() const
bool contains(uint field) const
void setReadOnly(bool readOnly)
If set to true, data such as the comment, tag or rating cannot be changed by the user.
QString toString() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2022 The KDE developers.
Generated on Thu Aug 11 2022 04:13:42 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.