KService

kbuildsycoca.cpp
1/*
2 This file is part of the KDE libraries
3 SPDX-FileCopyrightText: 1999 David Faure <faure@kde.org>
4 SPDX-FileCopyrightText: 2002-2003 Waldo Bastian <bastian@kde.org>
5
6 SPDX-License-Identifier: LGPL-2.0-only
7*/
8
9#include "kbuildsycoca_p.h"
10#include "ksycoca_p.h"
11#include "ksycocaresourcelist_p.h"
12#include "ksycocautils_p.h"
13#include "sycocadebug.h"
14#include "vfolder_menu_p.h"
15
16#include "kbuildmimetypefactory_p.h"
17#include "kbuildservicefactory_p.h"
18#include "kbuildservicegroupfactory_p.h"
19#include "kctimefactory_p.h"
20#include <QDataStream>
21#include <QDateTime>
22#include <QDebug>
23#include <QDir>
24#include <QDirIterator>
25#include <QEventLoop>
26#include <QFile>
27#include <QLocale>
28#include <QSaveFile>
29#include <QTimer>
30#include <config-ksycoca.h>
31#include <kservice.h>
32#include <kservicegroup.h>
33
34#include <kmemfile_p.h>
35
36#include <QLockFile>
37#include <QStandardPaths>
38#include <qplatformdefs.h>
39
40static const char *s_cSycocaPath = nullptr;
41
42KBuildSycocaInterface::~KBuildSycocaInterface()
43{
44}
45
46KBuildSycoca::KBuildSycoca()
47 : KSycoca(true)
48 , m_allEntries(nullptr)
49 , m_ctimeFactory(nullptr)
50 , m_ctimeDict(nullptr)
51 , m_currentEntryDict(nullptr)
52 , m_serviceGroupEntryDict(nullptr)
53 , m_vfolder(nullptr)
54 , m_newTimestamp(0)
55 , m_menuTest(false)
56 , m_changed(false)
57{
58}
59
60KBuildSycoca::~KBuildSycoca()
61{
62 // Delete the factories while we exist, so that the virtual isBuilding() still works
63 qDeleteAll(*factories());
64 factories()->clear();
65}
66
67KSycocaEntry::Ptr KBuildSycoca::createEntry(KSycocaFactory *currentFactory, const QString &file)
68{
69 quint32 timeStamp = m_ctimeFactory->dict()->ctime(file, m_resource);
70 if (!timeStamp) {
71 timeStamp = calcResourceHash(m_resourceSubdir, file);
72 if (!timeStamp) { // file disappeared meanwhile
73 return {};
74 }
75 }
77 if (m_allEntries) {
78 Q_ASSERT(m_ctimeDict);
79 quint32 oldTimestamp = m_ctimeDict->ctime(file, m_resource);
80 if (file.contains(QLatin1String("fake"))) {
81 qCDebug(SYCOCA) << "m_ctimeDict->ctime(" << file << ") = " << oldTimestamp << "compared with" << timeStamp;
82 }
83
84 if (timeStamp && (timeStamp == oldTimestamp)) {
85 // Re-use old entry
86 if (currentFactory == d->m_serviceFactory) { // Strip .directory from service-group entries
87 entry = m_currentEntryDict->value(file.left(file.length() - 10));
88 } else {
89 entry = m_currentEntryDict->value(file);
90 }
91 // remove from m_ctimeDict; if m_ctimeDict is not empty
92 // after all files have been processed, it means
93 // some files were removed since last time
94 if (file.contains(QLatin1String("fake"))) {
95 qCDebug(SYCOCA) << "reusing (and removing) old entry for:" << file << "entry=" << entry;
96 }
97 m_ctimeDict->remove(file, m_resource);
98 } else if (oldTimestamp) {
99 m_changed = true;
100 m_ctimeDict->remove(file, m_resource);
101 qCDebug(SYCOCA) << "modified:" << file;
102 } else {
103 m_changed = true;
104 qCDebug(SYCOCA) << "new:" << file;
105 }
106 }
107 m_ctimeFactory->dict()->addCTime(file, m_resource, timeStamp);
108 if (!entry) {
109 // Create a new entry
110 entry = currentFactory->createEntry(file);
111 }
112 if (entry && entry->isValid()) {
113 return entry;
114 }
115 return KSycocaEntry::Ptr();
116}
117
118KService::Ptr KBuildSycoca::createService(const QString &path)
119{
120 KSycocaEntry::Ptr entry = createEntry(d->m_serviceFactory, path);
121 if (entry) {
122 m_tempStorage.append(entry);
123 }
124 return KService::Ptr(static_cast<KService *>(entry.data()));
125}
126
127// returns false if the database is up to date, true if it needs to be saved
128bool KBuildSycoca::build()
129{
130 using KBSEntryDictList = QList<KBSEntryDict *>;
131 KBSEntryDictList entryDictList;
132 KBSEntryDict *serviceEntryDict = nullptr;
133
134 // Convert for each factory the entryList to a Dict.
135 entryDictList.reserve(factories()->size());
136 int i = 0;
137 // For each factory
138 const auto &factoryList = *factories();
139 for (KSycocaFactory *factory : factoryList) {
140 KBSEntryDict *entryDict = new KBSEntryDict;
141 if (m_allEntries) { // incremental build
142 for (const KSycocaEntry::Ptr &entry : std::as_const((*m_allEntries).at(i++))) {
143 // if (entry->entryPath().contains("fake"))
144 // qCDebug(SYCOCA) << "inserting into entryDict:" << entry->entryPath() << entry;
145 entryDict->insert(entry->entryPath(), entry);
146 }
147 }
148 if (factory == d->m_serviceFactory) {
149 serviceEntryDict = entryDict;
150 } else if (factory == m_buildServiceGroupFactory) {
151 m_serviceGroupEntryDict = entryDict;
152 }
153 entryDictList.append(entryDict);
154 }
155
156 // Save the mtime of each dir, just before we list them
157 // ## should we convert to UTC to avoid surprises when summer time kicks in?
158 const auto lstDirs = factoryResourceDirs();
159 for (const QString &dir : lstDirs) {
160 qint64 stamp = 0;
161 KSycocaUtilsPrivate::visitResourceDirectory(dir, [&stamp](const QFileInfo &info) {
162 stamp = qMax(stamp, info.lastModified().toMSecsSinceEpoch());
163 return true;
164 });
165 m_allResourceDirs.insert(dir, stamp);
166 }
167
168 const auto lstFiles = factoryExtraFiles();
169 for (const QString &file : lstFiles) {
170 m_extraFiles.insert(file, QFileInfo(file).lastModified().toMSecsSinceEpoch());
171 }
172
173 QMap<QString, QByteArray> allResourcesSubDirs; // dirs, kstandarddirs-resource-name
174 // For each factory
175 for (KSycocaFactory *factory : factoryList) {
176 // For each resource the factory deals with
177 const KSycocaResourceList resourceList = factory->resourceList();
178 for (const KSycocaResource &res : resourceList) {
179 // With this we would get dirs, but not a unique list of relative files (for global+local merging to work)
180 // const QStringList dirs = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, res.subdir, QStandardPaths::LocateDirectory);
181 // allResourcesSubDirs[res.resource] += dirs;
182 allResourcesSubDirs.insert(res.subdir, res.resource);
183 }
184 }
185
186 m_ctimeFactory = new KCTimeFactory(this); // This is a build factory too, don't delete!!
187 for (auto it1 = allResourcesSubDirs.cbegin(); it1 != allResourcesSubDirs.cend(); ++it1) {
188 m_changed = false;
189 m_resourceSubdir = it1.key();
190 m_resource = it1.value();
191
192 QSet<QString> relFiles;
194 qCDebug(SYCOCA) << "Looking for subdir" << m_resourceSubdir << "=>" << dirs;
195 for (const QString &dir : dirs) {
197 while (it.hasNext()) {
198 const QString filePath = it.next();
199 Q_ASSERT(filePath.startsWith(dir)); // due to the line below...
200 const QString relPath = filePath.mid(dir.length() + 1);
201 relFiles.insert(relPath);
202 }
203 }
204 // Now find all factories that use this resource....
205 // For each factory -- and its corresponding entryDict (iterate over both lists in parallel)
206 for (int f = 0; f < factoryList.count(); ++f) {
207 KSycocaFactory *currentFactory = factoryList.at(f);
208 // m_ctimeInfo gets created after the initial loop, so it has no entryDict.
209 m_currentEntryDict = f == entryDictList.size() ? nullptr : entryDictList.at(f);
210 // For each resource the factory deals with
211 const KSycocaResourceList &resourceList = currentFactory->resourceList();
212 for (const KSycocaResource &res : resourceList) {
213 if (res.resource != m_resource) {
214 continue;
215 }
216
217 // For each file in the resource
218 for (const QString &entryPath : std::as_const(relFiles)) {
219 // Check if file matches filter
220 if (entryPath.endsWith(res.extension)) {
221 KSycocaEntry::Ptr entry = createEntry(currentFactory, entryPath);
222 if (entry) {
223 currentFactory->addEntry(entry);
224 }
225 }
226 }
227 }
228 }
229 }
230
231 bool result = true;
232 const bool createVFolder = true; // we need to always run the VFolderMenu code
233 if (createVFolder || m_menuTest) {
234 m_resource = "apps";
235 m_resourceSubdir = QStringLiteral("applications");
236 m_currentEntryDict = serviceEntryDict;
237 m_changed = false;
238
239 m_vfolder = new VFolderMenu(d->m_serviceFactory, this);
240 if (!m_trackId.isEmpty()) {
241 m_vfolder->setTrackId(m_trackId);
242 }
243
244 VFolderMenu::SubMenu *kdeMenu = m_vfolder->parseMenu(QStringLiteral("applications.menu"));
245
246 KServiceGroup::Ptr entry = m_buildServiceGroupFactory->addNew(QStringLiteral("/"), kdeMenu->directoryFile, KServiceGroup::Ptr(), false);
247 entry->setLayoutInfo(kdeMenu->layoutList);
248 createMenu(QString(), QString(), kdeMenu);
249
250 // Storing the mtime *after* looking at these dirs is a tiny race condition,
251 // but I'm not sure how to get the vfolder dirs upfront...
252 const auto allDirectories = m_vfolder->allDirectories();
253 for (QString dir : allDirectories) {
254 if (dir.endsWith(QLatin1Char('/'))) {
255 dir.chop(1); // remove trailing slash, to avoid having ~/.local/share/applications twice
256 }
257 if (!m_allResourceDirs.contains(dir)) {
258 qint64 stamp = 0;
259 KSycocaUtilsPrivate::visitResourceDirectory(dir, [&stamp](const QFileInfo &info) {
260 stamp = qMax(stamp, info.lastModified().toMSecsSinceEpoch());
261 return true;
262 });
263 m_allResourceDirs.insert(dir, stamp);
264 }
265 }
266
267 if (m_menuTest) {
268 result = false;
269 }
270 }
271
272 if (m_ctimeDict && !m_ctimeDict->isEmpty()) {
273 qCDebug(SYCOCA) << "Still in time dict:";
274 m_ctimeDict->dump();
275 }
276
277 qDeleteAll(entryDictList);
278 return result;
279}
280
281void KBuildSycoca::createMenu(const QString &caption_, const QString &name_, VFolderMenu::SubMenu *menu)
282{
283 QString caption = caption_;
284 QString name = name_;
285 for (VFolderMenu::SubMenu *subMenu : std::as_const(menu->subMenus)) {
286 QString subName = name + subMenu->name + QLatin1Char('/');
287
288 QString directoryFile = subMenu->directoryFile;
289 if (directoryFile.isEmpty()) {
290 directoryFile = subName + QLatin1String(".directory");
291 }
292 quint32 timeStamp = m_ctimeFactory->dict()->ctime(directoryFile, m_resource);
293 if (!timeStamp) {
294 timeStamp = calcResourceHash(m_resourceSubdir, directoryFile);
295 }
296
297 KServiceGroup::Ptr entry;
298 if (m_allEntries) {
299 const quint32 oldTimestamp = m_ctimeDict->ctime(directoryFile, m_resource);
300
301 if (timeStamp && (timeStamp == oldTimestamp)) {
302 KSycocaEntry::Ptr group = m_serviceGroupEntryDict->value(subName);
303 if (group) {
304 entry = KServiceGroup::Ptr(static_cast<KServiceGroup *>(group.data()));
305 if (entry->directoryEntryPath() != directoryFile) {
306 entry = nullptr; // Can't reuse this one!
307 }
308 }
309 }
310 }
311 if (timeStamp) { // bug? (see calcResourceHash). There might not be a .directory file...
312 m_ctimeFactory->dict()->addCTime(directoryFile, m_resource, timeStamp);
313 }
314
315 entry = m_buildServiceGroupFactory->addNew(subName, subMenu->directoryFile, entry, subMenu->isDeleted);
316 entry->setLayoutInfo(subMenu->layoutList);
317 if (!(m_menuTest && entry->noDisplay())) {
318 createMenu(caption + entry->caption() + QLatin1Char('/'), subName, subMenu);
319 }
320 }
321 if (caption.isEmpty()) {
322 caption += QLatin1Char('/');
323 }
324 if (name.isEmpty()) {
325 name += QLatin1Char('/');
326 }
327 for (const KService::Ptr &p : std::as_const(menu->items)) {
328 if (m_menuTest) {
329 if (!menu->isDeleted && !p->noDisplay()) {
330 printf("%s\t%s\t%s\n",
331 qPrintable(caption),
332 qPrintable(p->menuId()),
334 }
335 } else {
336 m_buildServiceGroupFactory->addNewEntryTo(name, p);
337 }
338 }
339}
340
341bool KBuildSycoca::recreate(bool incremental)
342{
344 if (!QDir().mkpath(fi.absolutePath())) {
345 qCWarning(SYCOCA) << "Couldn't create" << fi.absolutePath();
346 return false;
347 }
348 QString path(fi.absoluteFilePath());
349
350 QLockFile lockFile(path + QLatin1String(".lock"));
351 if (!lockFile.tryLock()) {
352 qCDebug(SYCOCA) << "Waiting for already running" << KBUILDSYCOCA_EXENAME << "to finish.";
353 if (!lockFile.lock()) {
354 qCWarning(SYCOCA) << "Couldn't lock" << path + QLatin1String(".lock");
355 return false;
356 }
357 if (!needsRebuild()) {
358 // qCDebug(SYCOCA) << "Up-to-date, skipping.";
359 return true;
360 }
361 }
362
363 QByteArray qSycocaPath = QFile::encodeName(path);
364 s_cSycocaPath = qSycocaPath.data();
365
366 m_allEntries = nullptr;
367 m_ctimeDict = nullptr;
368 if (incremental && checkGlobalHeader()) {
369 qCDebug(SYCOCA) << "Reusing existing ksycoca";
370 KSycoca *oldSycoca = KSycoca::self();
371 m_allEntries = new KSycocaEntryListList;
372 m_ctimeDict = new KCTimeDict;
373
374 // Must be in same order as in KBuildSycoca::recreate()!
375 m_allEntries->append(KSycocaPrivate::self()->mimeTypeFactory()->allEntries());
376 m_allEntries->append(KSycocaPrivate::self()->serviceGroupFactory()->allEntries());
377 m_allEntries->append(KSycocaPrivate::self()->serviceFactory()->allEntries());
378
379 KCTimeFactory *ctimeInfo = new KCTimeFactory(oldSycoca);
380 *m_ctimeDict = ctimeInfo->loadDict();
381 }
382 s_cSycocaPath = nullptr;
383
384 QSaveFile database(path);
385 bool openedOK = database.open(QIODevice::WriteOnly);
386
387 if (!openedOK && database.error() == QFile::WriteError && QFile::exists(path)) {
388 QFile::remove(path);
389 openedOK = database.open(QIODevice::WriteOnly);
390 }
391 if (!openedOK) {
392 qCWarning(SYCOCA) << "ERROR creating database" << path << ":" << database.errorString();
393 return false;
394 }
395
396 QDataStream *str = new QDataStream(&database);
398
399 m_newTimestamp = QDateTime::currentMSecsSinceEpoch();
400 qCDebug(SYCOCA).nospace() << "Recreating ksycoca file (" << path << ", version " << KSycoca::version() << ")";
401
402 KBuildMimeTypeFactory *buildMimeTypeFactory = new KBuildMimeTypeFactory(this);
403 d->m_mimeTypeFactory = buildMimeTypeFactory;
404 m_buildServiceGroupFactory = new KBuildServiceGroupFactory(this);
405 d->m_serviceGroupFactory = m_buildServiceGroupFactory;
406 d->m_serviceFactory = new KBuildServiceFactory(buildMimeTypeFactory);
407
408 if (build()) { // Parse dirs
409 save(str); // Save database
410 if (str->status() != QDataStream::Ok) { // Probably unnecessary now in Qt5, since QSaveFile detects write errors
411 database.cancelWriting(); // Error
412 }
413 delete str;
414 str = nullptr;
415
416 // if we are currently via sudo, preserve the original owner
417 // as $HOME may also be that of another user rather than /root
418#ifdef Q_OS_UNIX
419 if (qEnvironmentVariableIsSet("SUDO_UID")) {
420 const int uid = qEnvironmentVariableIntValue("SUDO_UID");
421 const int gid = qEnvironmentVariableIntValue("SUDO_GID");
422 if (uid && gid) {
423 fchown(database.handle(), uid, gid);
424 }
425 }
426#endif
427
428 if (!database.commit()) {
429 qCWarning(SYCOCA) << "ERROR writing database" << database.fileName() << database.errorString();
430 return false;
431 }
432 } else {
433 delete str;
434 str = nullptr;
435 database.cancelWriting();
436 if (m_menuTest) {
437 return true;
438 }
439 qCDebug(SYCOCA) << "Database is up to date";
440 }
441
442#ifndef QT_NO_SHAREDMEMORY
443 if (d->m_sycocaStrategy == KSycocaPrivate::StrategyMemFile) {
444 KMemFile::fileContentsChanged(path);
445 }
446#endif
447
448 delete m_ctimeDict;
449 delete m_allEntries;
450 delete m_vfolder;
451
452 return true;
453}
454
455void KBuildSycoca::save(QDataStream *str)
456{
457 // Write header (#pass 1)
458 str->device()->seek(0);
459
460 (*str) << qint32(KSycoca::version());
461 // KSycocaFactory * servicetypeFactory = 0;
462 // KBuildMimeTypeFactory * mimeTypeFactory = 0;
463 KBuildServiceFactory *serviceFactory = nullptr;
464 auto lst = *factories();
465 for (KSycocaFactory *factory : std::as_const(lst)) {
466 qint32 aId;
467 qint32 aOffset;
468 aId = factory->factoryId();
469 // if ( aId == KST_KServiceTypeFactory )
470 // servicetypeFactory = factory;
471 // else if ( aId == KST_KMimeTypeFactory )
472 // mimeTypeFactory = static_cast<KBuildMimeTypeFactory *>( factory );
473 if (aId == KST_KServiceFactory) {
474 serviceFactory = static_cast<KBuildServiceFactory *>(factory);
475 }
476 aOffset = factory->offset(); // not set yet, so always 0
477 (*str) << aId;
478 (*str) << aOffset;
479 }
480 (*str) << qint32(0); // No more factories.
481 // Write XDG_DATA_DIRS
483 (*str) << m_newTimestamp;
484 (*str) << QLocale().bcp47Name();
485 // This makes it possible to trigger a ksycoca update for all users (KIOSK feature)
486 (*str) << calcResourceHash(QStringLiteral("kservices6"), QStringLiteral("update_ksycoca"));
487 (*str) << m_allResourceDirs.keys();
488 for (auto it = m_allResourceDirs.constBegin(); it != m_allResourceDirs.constEnd(); ++it) {
489 (*str) << it.value();
490 }
491 (*str) << m_extraFiles.keys();
492 for (auto it = m_extraFiles.constBegin(); it != m_extraFiles.constEnd(); ++it) {
493 (*str) << it.value();
494 }
495
496 // Calculate per-servicetype/MIME type data
497 if (serviceFactory) {
498 serviceFactory->postProcessServices();
499 }
500
501 // Here so that it's the last debug message
502 qCDebug(SYCOCA) << "Saving";
503
504 // Write factory data....
505 lst = *factories();
506 for (KSycocaFactory *factory : std::as_const(lst)) {
507 factory->save(*str);
508 if (str->status() != QDataStream::Ok) { // ######## TODO: does this detect write errors, e.g. disk full?
509 return; // error
510 }
511 }
512
513 qint64 endOfData = str->device()->pos();
514
515 // Write header (#pass 2)
516 str->device()->seek(0);
517
518 (*str) << qint32(KSycoca::version());
519 lst = *factories();
520 for (KSycocaFactory *factory : std::as_const(lst)) {
521 qint32 aId;
522 qint32 aOffset;
523 aId = factory->factoryId();
524 aOffset = factory->offset();
525 (*str) << aId;
526 (*str) << aOffset;
527 }
528 (*str) << qint32(0); // No more factories.
529
530 // Jump to end of database
531 str->device()->seek(endOfData);
532}
533
534QStringList KBuildSycoca::factoryResourceDirs()
535{
536 static QStringList *dirs = nullptr;
537 if (dirs != nullptr) {
538 return *dirs;
539 }
540 dirs = new QStringList;
541 // these are all resource dirs cached by ksycoca
542 *dirs += KMimeTypeFactory::resourceDirs();
543 *dirs += KServiceFactory::resourceDirs();
544
545 return *dirs;
546}
547
548QStringList KBuildSycoca::factoryExtraFiles()
549{
550 QStringList files;
551 // these are the extra files cached by ksycoca
552 // and whose timestamps are checked
553 files += KMimeAssociations::mimeAppsFiles();
554
555 return files;
556}
557
558QStringList KBuildSycoca::existingResourceDirs()
559{
560 static QStringList *dirs = nullptr;
561 if (dirs != nullptr) {
562 return *dirs;
563 }
564 dirs = new QStringList(factoryResourceDirs());
565
566 auto checkDir = [](const QString &str) {
567 QFileInfo info(str);
568 return !info.exists() || !info.isReadable();
569 };
570 dirs->erase(std::remove_if(dirs->begin(), dirs->end(), checkDir), dirs->end());
571
572 return *dirs;
573}
574
575static quint32 updateHash(const QString &file, quint32 hash)
576{
577 QFileInfo fi(file);
578 if (fi.isReadable() && fi.isFile()) {
579 // This was using buff.st_ctime (in Waldo's initial commit to kstandarddirs.cpp in 2001), but that looks wrong?
580 // Surely we want to catch manual editing, while a chmod doesn't matter much?
581 qint64 timestamp = fi.lastModified().toSecsSinceEpoch();
582 // On some systems (i.e. Fedora Kinoite), all files in /usr have a last
583 // modified timestamp of 0 (UNIX Epoch). In this case, always assume
584 // the file as been changed.
585 if (timestamp == 0) {
586 static qint64 now = QDateTime::currentDateTimeUtc().toSecsSinceEpoch();
587 timestamp = now;
588 }
589 hash += timestamp;
590 }
591 return hash;
592}
593
594quint32 KBuildSycoca::calcResourceHash(const QString &resourceSubDir, const QString &filename)
595{
596 quint32 hash = 0;
597 if (!QDir::isRelativePath(filename)) {
598 return updateHash(filename, hash);
599 }
600 const QString filePath = resourceSubDir + QLatin1Char('/') + filename;
601 const QString qrcFilePath = QStringLiteral(":/") + filePath;
602 const QStringList files =
604 for (const QString &file : files) {
605 hash = updateHash(file, hash);
606 }
607 if (hash == 0 && !filename.endsWith(QLatin1String("update_ksycoca"))
608 && !filename.endsWith(QLatin1String(".directory")) // bug? needs investigation from someone who understands the VFolder spec
609 ) {
610 if (files.isEmpty()) {
611 // This can happen if the file was deleted between directory listing and the above locateAll
612 qCDebug(SYCOCA) << "File not found anymore:" << filename << " -- probably deleted meanwhile";
613 } else {
614 // This can happen if the file was deleted between locateAll and QFileInfo
615 qCDebug(SYCOCA) << "File(s) found but not readable (or disappeared meanwhile)" << files;
616 }
617 }
618 return hash;
619}
620
621bool KBuildSycoca::checkGlobalHeader()
622{
623 // Since it's part of the filename, we are 99% sure that the locale and prefixes will match.
624 const QString current_language = QLocale().bcp47Name();
625 const quint32 current_update_sig = KBuildSycoca::calcResourceHash(QStringLiteral("kservices6"), QStringLiteral("update_ksycoca"));
627
628 const KSycocaHeader header = KSycocaPrivate::self()->readSycocaHeader();
629 Q_ASSERT(!header.prefixes.split(QLatin1Char(':')).contains(QDir::homePath()));
630
631 return (current_update_sig == header.updateSignature) //
632 && (current_language == header.language) //
633 && (current_prefixes == header.prefixes) //
634 && (header.timeStamp != 0);
635}
636
637const char *KBuildSycoca::sycocaPath()
638{
639 return s_cSycocaPath;
640}
641
642#include "moc_kbuildsycoca_p.cpp"
KServiceGroup represents a group of service, for example screensavers.
QExplicitlySharedDataPointer< KServiceGroup > Ptr
A shared data pointer for KServiceGroup.
Represents an installed application.
Definition kservice.h:44
QExplicitlySharedDataPointer< KService > Ptr
A shared data pointer for KService.
Definition kservice.h:49
QExplicitlySharedDataPointer< KSycocaEntry > Ptr
A shared data pointer for KSycocaEntry.
static int version()
Definition ksycoca.cpp:151
static KSycoca * self()
Get or create the only instance of KSycoca (read-only)
Definition ksycoca.cpp:357
static QString absoluteFilePath()
Definition ksycoca.cpp:683
KActionMenu * createMenu(KColorSchemeManager *manager, QObject *parent=nullptr)
KIOCORE_EXPORT MkpathJob * mkpath(const QUrl &url, const QUrl &baseUrl=QUrl(), JobFlags flags=DefaultFlags)
QString path(const QString &relativePath)
KIOCORE_EXPORT QString dir(const QString &fileClass)
QString name(StandardAction id)
QAction * save(const QObject *recvr, const char *slot, QObject *parent)
char * data()
QIODevice * device() const const
void setVersion(int v)
Status status() const const
QDateTime currentDateTimeUtc()
qint64 currentMSecsSinceEpoch()
qint64 toMSecsSinceEpoch() const const
qint64 toSecsSinceEpoch() const const
QString homePath()
bool isRelativePath(const QString &path)
QByteArray encodeName(const QString &fileName)
bool exists() const const
bool remove()
bool exists() const const
bool exists(const QString &path)
bool isReadable() const const
QDateTime lastModified() const const
virtual qint64 pos() const const
virtual bool seek(qint64 pos)
iterator begin()
iterator end()
iterator erase(const_iterator begin, const_iterator end)
void reserve(qsizetype size)
QString bcp47Name() const const
const_iterator cbegin() const const
const_iterator cend() const const
iterator insert(const Key &key, const T &value)
iterator insert(const T &value)
QString locate(StandardLocation type, const QString &fileName, LocateOptions options)
QStringList locateAll(StandardLocation type, const QString &fileName, LocateOptions options)
QStringList standardLocations(StandardLocation type)
void chop(qsizetype n)
bool contains(QChar ch, Qt::CaseSensitivity cs) const const
bool endsWith(QChar c, Qt::CaseSensitivity cs) const const
bool isEmpty() const const
QString left(qsizetype n) const const
qsizetype length() const const
QString mid(qsizetype position, qsizetype n) const const
bool startsWith(QChar c, Qt::CaseSensitivity cs) const const
QString join(QChar separator) const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri Dec 13 2024 11:51:32 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.