1 /*
2 This file is part of the KDE libraries
3 SPDX-FileCopyrightText: 2000 Waldo Bastian <bastian@kde.org>
4
5 SPDX-License-Identifier: LGPL-2.0-only
6 */
7
8 #include "kservicegroup.h"
9 #include "kservice.h"
10 #include "kservicefactory_p.h"
11 #include "kservicegroup_p.h"
12 #include "kservicegroupfactory_p.h"
13 #include "ksycoca_p.h"
14 #include "servicesdebug.h"
15 #include <KConfigGroup>
16 #include <KDesktopFile>
17 #include <ksycoca.h>
18
KServiceGroup(const QString & name)19 KServiceGroup::KServiceGroup(const QString &name)
20 : KSycocaEntry(*new KServiceGroupPrivate(name))
21 {
22 }
23
KServiceGroup(const QString & configFile,const QString & _relpath)24 KServiceGroup::KServiceGroup(const QString &configFile, const QString &_relpath)
25 : KSycocaEntry(*new KServiceGroupPrivate(_relpath))
26 {
27 Q_D(KServiceGroup);
28
29 QString cfg = configFile;
30 if (cfg.isEmpty()) {
31 cfg = _relpath + QLatin1String(".directory");
32 }
33
34 d->load(cfg);
35 }
36
load(const QString & cfg)37 void KServiceGroupPrivate::load(const QString &cfg)
38 {
39 directoryEntryPath = cfg;
40
41 const KDesktopFile desktopFile(cfg);
42
43 const KConfigGroup config = desktopFile.desktopGroup();
44
45 m_strCaption = config.readEntry("Name");
46 m_strIcon = config.readEntry("Icon");
47 m_strComment = config.readEntry("Comment");
48 deleted = config.readEntry("Hidden", false);
49 m_bNoDisplay = desktopFile.noDisplay();
50 m_strBaseGroupName = config.readEntry("X-KDE-BaseGroup");
51 suppressGenericNames = config.readEntry("X-KDE-SuppressGenericNames", QStringList());
52
53 // Fill in defaults.
54 if (m_strCaption.isEmpty()) {
55 m_strCaption = path;
56 if (m_strCaption.endsWith(QLatin1Char('/'))) {
57 m_strCaption.chop(1);
58 }
59 int i = m_strCaption.lastIndexOf(QLatin1Char('/'));
60 if (i > 0) {
61 m_strCaption.remove(0, i + 1);
62 }
63 }
64 if (m_strIcon.isEmpty()) {
65 m_strIcon = QStringLiteral("folder");
66 }
67 }
68
KServiceGroup(QDataStream & _str,int offset,bool deep)69 KServiceGroup::KServiceGroup(QDataStream &_str, int offset, bool deep)
70 : KSycocaEntry(*new KServiceGroupPrivate(_str, offset))
71 {
72 Q_D(KServiceGroup);
73 d->m_bDeep = deep;
74 d->load(_str);
75 }
76
~KServiceGroup()77 KServiceGroup::~KServiceGroup()
78 {
79 }
80
relPath() const81 QString KServiceGroup::relPath() const
82 {
83 return entryPath();
84 }
85
caption() const86 QString KServiceGroup::caption() const
87 {
88 Q_D(const KServiceGroup);
89 return d->m_strCaption;
90 }
91
icon() const92 QString KServiceGroup::icon() const
93 {
94 Q_D(const KServiceGroup);
95 return d->m_strIcon;
96 }
97
comment() const98 QString KServiceGroup::comment() const
99 {
100 Q_D(const KServiceGroup);
101 return d->m_strComment;
102 }
103
childCount() const104 int KServiceGroup::childCount() const
105 {
106 Q_D(const KServiceGroup);
107 return d->childCount();
108 }
109
childCount() const110 int KServiceGroupPrivate::childCount() const
111 {
112 if (m_childCount == -1) {
113 m_childCount = 0;
114
115 for (KServiceGroup::List::ConstIterator it = m_serviceList.begin(); it != m_serviceList.end(); ++it) {
116 KSycocaEntry::Ptr p = *it;
117 if (p->isType(KST_KService)) {
118 KService::Ptr service(static_cast<KService *>(p.data()));
119 if (!service->noDisplay()) {
120 m_childCount++;
121 }
122 } else if (p->isType(KST_KServiceGroup)) {
123 KServiceGroup::Ptr serviceGroup(static_cast<KServiceGroup *>(p.data()));
124 m_childCount += serviceGroup->childCount();
125 }
126 }
127 }
128 return m_childCount;
129 }
130
showInlineHeader() const131 bool KServiceGroup::showInlineHeader() const
132 {
133 Q_D(const KServiceGroup);
134 return d->m_bShowInlineHeader;
135 }
136
showEmptyMenu() const137 bool KServiceGroup::showEmptyMenu() const
138 {
139 Q_D(const KServiceGroup);
140 return d->m_bShowEmptyMenu;
141 }
142
inlineAlias() const143 bool KServiceGroup::inlineAlias() const
144 {
145 Q_D(const KServiceGroup);
146 return d->m_bInlineAlias;
147 }
148
setInlineAlias(bool _b)149 void KServiceGroup::setInlineAlias(bool _b)
150 {
151 Q_D(KServiceGroup);
152 d->m_bInlineAlias = _b;
153 }
154
setShowEmptyMenu(bool _b)155 void KServiceGroup::setShowEmptyMenu(bool _b)
156 {
157 Q_D(KServiceGroup);
158 d->m_bShowEmptyMenu = _b;
159 }
160
setShowInlineHeader(bool _b)161 void KServiceGroup::setShowInlineHeader(bool _b)
162 {
163 Q_D(KServiceGroup);
164 d->m_bShowInlineHeader = _b;
165 }
166
inlineValue() const167 int KServiceGroup::inlineValue() const
168 {
169 Q_D(const KServiceGroup);
170 return d->m_inlineValue;
171 }
172
setInlineValue(int _val)173 void KServiceGroup::setInlineValue(int _val)
174 {
175 Q_D(KServiceGroup);
176 d->m_inlineValue = _val;
177 }
178
allowInline() const179 bool KServiceGroup::allowInline() const
180 {
181 Q_D(const KServiceGroup);
182 return d->m_bAllowInline;
183 }
184
setAllowInline(bool _b)185 void KServiceGroup::setAllowInline(bool _b)
186 {
187 Q_D(KServiceGroup);
188 d->m_bAllowInline = _b;
189 }
190
noDisplay() const191 bool KServiceGroup::noDisplay() const
192 {
193 Q_D(const KServiceGroup);
194 return d->m_bNoDisplay || d->m_strCaption.startsWith(QLatin1Char('.'));
195 }
196
suppressGenericNames() const197 QStringList KServiceGroup::suppressGenericNames() const
198 {
199 Q_D(const KServiceGroup);
200 return d->suppressGenericNames;
201 }
202
load(QDataStream & s)203 void KServiceGroupPrivate::load(QDataStream &s)
204 {
205 QStringList groupList;
206 qint8 noDisplay;
207 qint8 _showEmptyMenu;
208 qint8 inlineHeader;
209 qint8 _inlineAlias;
210 qint8 _allowInline;
211 s >> m_strCaption >> m_strIcon >> m_strComment >> groupList >> m_strBaseGroupName >> m_childCount >> noDisplay >> suppressGenericNames >> directoryEntryPath
212 >> sortOrder >> _showEmptyMenu >> inlineHeader >> _inlineAlias >> _allowInline;
213
214 m_bNoDisplay = (noDisplay != 0);
215 m_bShowEmptyMenu = (_showEmptyMenu != 0);
216 m_bShowInlineHeader = (inlineHeader != 0);
217 m_bInlineAlias = (_inlineAlias != 0);
218 m_bAllowInline = (_allowInline != 0);
219
220 if (m_bDeep) {
221 for (const QString &path : std::as_const(groupList)) {
222 if (path.endsWith(QLatin1Char('/'))) {
223 KServiceGroup::Ptr serviceGroup;
224 serviceGroup = KSycocaPrivate::self()->serviceGroupFactory()->findGroupByDesktopPath(path, false);
225 if (serviceGroup) {
226 m_serviceList.append(KServiceGroup::SPtr(serviceGroup));
227 }
228 } else {
229 KService::Ptr service;
230 service = KSycocaPrivate::self()->serviceFactory()->findServiceByDesktopPath(path);
231 if (service) {
232 m_serviceList.append(KServiceGroup::SPtr(service));
233 }
234 }
235 }
236 }
237 }
238
addEntry(const KSycocaEntry::Ptr & entry)239 void KServiceGroup::addEntry(const KSycocaEntry::Ptr &entry)
240 {
241 Q_D(KServiceGroup);
242 d->m_serviceList.append(entry);
243 }
244
save(QDataStream & s)245 void KServiceGroupPrivate::save(QDataStream &s)
246 {
247 KSycocaEntryPrivate::save(s);
248
249 QStringList groupList;
250 for (const KSycocaEntry::Ptr &p : std::as_const(m_serviceList)) {
251 if (p->isType(KST_KService)) {
252 KService::Ptr service(static_cast<KService *>(p.data()));
253 groupList.append(service->entryPath());
254 } else if (p->isType(KST_KServiceGroup)) {
255 KServiceGroup::Ptr serviceGroup(static_cast<KServiceGroup *>(p.data()));
256 groupList.append(serviceGroup->relPath());
257 } else {
258 // fprintf(stderr, "KServiceGroup: Unexpected object in list!\n");
259 }
260 }
261
262 (void)childCount();
263
264 qint8 noDisplay = m_bNoDisplay ? 1 : 0;
265 qint8 _showEmptyMenu = m_bShowEmptyMenu ? 1 : 0;
266 qint8 inlineHeader = m_bShowInlineHeader ? 1 : 0;
267 qint8 _inlineAlias = m_bInlineAlias ? 1 : 0;
268 qint8 _allowInline = m_bAllowInline ? 1 : 0;
269 s << m_strCaption << m_strIcon << m_strComment << groupList << m_strBaseGroupName << m_childCount << noDisplay << suppressGenericNames << directoryEntryPath
270 << sortOrder << _showEmptyMenu << inlineHeader << _inlineAlias << _allowInline;
271 }
272
groupEntries(EntriesOptions options)273 QList<KServiceGroup::Ptr> KServiceGroup::groupEntries(EntriesOptions options)
274 {
275 Q_D(KServiceGroup);
276 bool sort = options & SortEntries || options & AllowSeparators;
277 QList<KServiceGroup::Ptr> list;
278 const List tmp = d->entries(this, sort, options & ExcludeNoDisplay, options & AllowSeparators, options & SortByGenericName);
279 for (const SPtr &ptr : tmp) {
280 if (ptr->isType(KST_KServiceGroup)) {
281 KServiceGroup::Ptr serviceGroup(static_cast<KServiceGroup *>(ptr.data()));
282 list.append(serviceGroup);
283 } else if (ptr->isType(KST_KServiceSeparator)) {
284 list.append(KServiceGroup::Ptr(static_cast<KServiceGroup *>(new KSycocaEntry())));
285 } else if (sort && ptr->isType(KST_KService)) {
286 break;
287 }
288 }
289 return list;
290 }
291
serviceEntries(EntriesOptions options)292 KService::List KServiceGroup::serviceEntries(EntriesOptions options)
293 {
294 Q_D(KServiceGroup);
295 bool sort = options & SortEntries || options & AllowSeparators;
296 QList<KService::Ptr> list;
297 const List tmp = d->entries(this, sort, options & ExcludeNoDisplay, options & AllowSeparators, options & SortByGenericName);
298 bool foundService = false;
299 for (const SPtr &ptr : tmp) {
300 if (ptr->isType(KST_KService)) {
301 list.append(KService::Ptr(static_cast<KService *>(ptr.data())));
302 foundService = true;
303 } else if (ptr->isType(KST_KServiceSeparator) && foundService) {
304 list.append(KService::Ptr(static_cast<KService *>(new KSycocaEntry())));
305 }
306 }
307 return list;
308 }
309
entries(bool sort)310 KServiceGroup::List KServiceGroup::entries(bool sort)
311 {
312 Q_D(KServiceGroup);
313 return d->entries(this, sort, true, false, false);
314 }
315
entries(bool sort,bool excludeNoDisplay)316 KServiceGroup::List KServiceGroup::entries(bool sort, bool excludeNoDisplay)
317 {
318 Q_D(KServiceGroup);
319 return d->entries(this, sort, excludeNoDisplay, false, false);
320 }
321
entries(bool sort,bool excludeNoDisplay,bool allowSeparators,bool sortByGenericName)322 KServiceGroup::List KServiceGroup::entries(bool sort, bool excludeNoDisplay, bool allowSeparators, bool sortByGenericName)
323 {
324 Q_D(KServiceGroup);
325 return d->entries(this, sort, excludeNoDisplay, allowSeparators, sortByGenericName);
326 }
327
addItem(KServiceGroup::List & sorted,const KSycocaEntry::Ptr & p,bool & addSeparator)328 static void addItem(KServiceGroup::List &sorted, const KSycocaEntry::Ptr &p, bool &addSeparator)
329 {
330 if (addSeparator && !sorted.isEmpty()) {
331 sorted.append(KSycocaEntry::Ptr(new KServiceSeparator()));
332 }
333 sorted.append(p);
334 addSeparator = false;
335 }
336
entries(KServiceGroup * group,bool sort,bool excludeNoDisplay,bool allowSeparators,bool sortByGenericName)337 KServiceGroup::List KServiceGroupPrivate::entries(KServiceGroup *group, bool sort, bool excludeNoDisplay, bool allowSeparators, bool sortByGenericName)
338 {
339 KSycoca::self()->ensureCacheValid();
340
341 // If the entries haven't been loaded yet, we have to reload ourselves
342 // together with the entries. We can't only load the entries afterwards
343 // since the offsets could have been changed if the database has changed.
344
345 KServiceGroup::Ptr grp;
346 if (!m_bDeep) {
347 grp = KSycocaPrivate::self()->serviceGroupFactory()->findGroupByDesktopPath(path, true);
348
349 group = grp.data();
350 if (nullptr == group) { // No guarantee that we still exist!
351 return KServiceGroup::List();
352 }
353 }
354
355 if (!sort) {
356 return group->d_func()->m_serviceList;
357 }
358
359 // Sort the list alphabetically, according to locale.
360 // Groups come first, then services.
361
362 // We use a QMap, for sorting using a stored temporary key.
363 typedef QMap<QByteArray, KServiceGroup::SPtr> SortedContainer;
364 SortedContainer slist;
365 SortedContainer glist;
366 const auto listService = group->d_func()->m_serviceList;
367 for (const KSycocaEntry::Ptr &p : listService) {
368 bool noDisplay = p->isType(KST_KServiceGroup) ? static_cast<KServiceGroup *>(p.data())->noDisplay() : static_cast<KService *>(p.data())->noDisplay();
369 if (excludeNoDisplay && noDisplay) {
370 continue;
371 }
372 // Choose the right list
373 SortedContainer &list = p->isType(KST_KServiceGroup) ? glist : slist;
374 QString name;
375 if (p->isType(KST_KServiceGroup)) {
376 name = static_cast<KServiceGroup *>(p.data())->caption();
377 } else if (sortByGenericName) {
378 name = static_cast<KService *>(p.data())->genericName() + QLatin1Char(' ') + p->name();
379 } else {
380 name = p->name() + QLatin1Char(' ') + static_cast<KService *>(p.data())->genericName();
381 }
382
383 const QByteArray nameStr = name.toLocal8Bit();
384
385 QByteArray key;
386 // strxfrm() crashes on Solaris and strxfrm is not defined under wince
387 #if !defined(USE_SOLARIS) && !defined(_WIN32_WCE)
388 // maybe it'd be better to use wcsxfrm() where available
389 key.resize(name.length() * 4 + 1);
390 size_t ln = strxfrm(key.data(), nameStr.constData(), key.size());
391 if (ln != size_t(-1)) {
392 key.resize(ln);
393 if (int(ln) >= key.size()) {
394 // didn't fit?
395 ln = strxfrm(key.data(), nameStr.constData(), key.size());
396 if (ln == size_t(-1)) {
397 key = nameStr;
398 }
399 }
400 } else
401 #endif
402 {
403 key = nameStr;
404 }
405 list.insert(key, KServiceGroup::SPtr(p));
406 }
407
408 if (sortOrder.isEmpty()) {
409 sortOrder << QStringLiteral(":M");
410 sortOrder << QStringLiteral(":F");
411 sortOrder << QStringLiteral(":OIH IL[4]"); // just inline header
412 }
413
414 QString rp = path;
415 if (rp == QLatin1String("/")) {
416 rp.clear();
417 }
418
419 // Iterate through the sort spec list.
420 // If an entry gets mentioned explicitly, we remove it from the sorted list
421 for (const QString &item : std::as_const(sortOrder)) {
422 if (item.isEmpty()) {
423 continue;
424 }
425 if (item[0] == QLatin1Char('/')) {
426 QString groupPath = rp + QStringView(item).mid(1) + QLatin1Char('/');
427 // Remove entry from sorted list of services.
428 for (SortedContainer::iterator it2 = glist.begin(); it2 != glist.end(); ++it2) {
429 const KServiceGroup::Ptr group(static_cast<KServiceGroup *>(it2.value().data()));
430 if (group->relPath() == groupPath) {
431 glist.erase(it2);
432 break;
433 }
434 }
435 } else if (item[0] != QLatin1Char(':')) {
436 // Remove entry from sorted list of services.
437 // TODO: Remove item from sortOrder-list if not found
438 // TODO: This prevents duplicates
439 for (SortedContainer::iterator it2 = slist.begin(); it2 != slist.end(); ++it2) {
440 const KService::Ptr service(static_cast<KService *>(it2.value().data()));
441 if (service->menuId() == item) {
442 slist.erase(it2);
443 break;
444 }
445 }
446 }
447 }
448
449 KServiceGroup::List sorted;
450
451 bool needSeparator = false;
452 // Iterate through the sort spec list.
453 // Add the entries to the list according to the sort spec.
454 for (QStringList::ConstIterator it(sortOrder.constBegin()); it != sortOrder.constEnd(); ++it) {
455 const QString &item = *it;
456 if (item.isEmpty()) {
457 continue;
458 }
459 if (item[0] == QLatin1Char(':')) {
460 // Special condition...
461 if (item == QLatin1String(":S")) {
462 if (allowSeparators) {
463 needSeparator = true;
464 }
465 } else if (item.contains(QLatin1String(":O"))) {
466 // todo parse attribute:
467 QString tmp(item);
468 tmp.remove(QStringLiteral(":O"));
469 QStringList optionAttribute = tmp.split(QLatin1Char(' '), Qt::SkipEmptyParts);
470 if (optionAttribute.isEmpty()) {
471 optionAttribute.append(tmp);
472 }
473 bool showEmptyMenu = false;
474 bool showInline = false;
475 bool showInlineHeader = false;
476 bool showInlineAlias = false;
477 int inlineValue = -1;
478
479 for (QStringList::Iterator it3 = optionAttribute.begin(); it3 != optionAttribute.end(); ++it3) {
480 parseAttribute(*it3, showEmptyMenu, showInline, showInlineHeader, showInlineAlias, inlineValue);
481 }
482 for (SortedContainer::Iterator it2 = glist.begin(); it2 != glist.end(); ++it2) {
483 KServiceGroup::Ptr group(static_cast<KServiceGroup *>(it2.value().data()));
484 group->setShowEmptyMenu(showEmptyMenu);
485 group->setAllowInline(showInline);
486 group->setShowInlineHeader(showInlineHeader);
487 group->setInlineAlias(showInlineAlias);
488 group->setInlineValue(inlineValue);
489 }
490
491 } else if (item == QLatin1String(":M")) {
492 // Add sorted list of sub-menus
493 for (SortedContainer::const_iterator it2 = glist.constBegin(); it2 != glist.constEnd(); ++it2) {
494 addItem(sorted, it2.value(), needSeparator);
495 }
496 } else if (item == QLatin1String(":F")) {
497 // Add sorted list of services
498 for (SortedContainer::const_iterator it2 = slist.constBegin(); it2 != slist.constEnd(); ++it2) {
499 addItem(sorted, it2.value(), needSeparator);
500 }
501 } else if (item == QLatin1String(":A")) {
502 // Add sorted lists of services and submenus
503 SortedContainer::Iterator it_s = slist.begin();
504 SortedContainer::Iterator it_g = glist.begin();
505
506 while (true) {
507 if (it_s == slist.end()) {
508 if (it_g == glist.end()) {
509 break; // Done
510 }
511
512 // Insert remaining sub-menu
513 addItem(sorted, it_g.value(), needSeparator);
514 it_g++;
515 } else if (it_g == glist.end()) {
516 // Insert remaining service
517 addItem(sorted, it_s.value(), needSeparator);
518 it_s++;
519 } else if (it_g.key() < it_s.key()) {
520 // Insert sub-menu first
521 addItem(sorted, it_g.value(), needSeparator);
522 it_g++;
523 } else {
524 // Insert service first
525 addItem(sorted, it_s.value(), needSeparator);
526 it_s++;
527 }
528 }
529 }
530 } else if (item[0] == QLatin1Char('/')) {
531 QString groupPath = rp + QStringView(item).mid(1) + QLatin1Char('/');
532
533 for (KServiceGroup::List::ConstIterator it2(group->d_func()->m_serviceList.constBegin()); it2 != group->d_func()->m_serviceList.constEnd(); ++it2) {
534 if (!(*it2)->isType(KST_KServiceGroup)) {
535 continue;
536 }
537 KServiceGroup::Ptr group(static_cast<KServiceGroup *>((*it2).data()));
538 if (group->relPath() == groupPath) {
539 if (!excludeNoDisplay || !group->noDisplay()) {
540 ++it;
541 const QString &nextItem = (it == sortOrder.constEnd()) ? QString() : *it;
542
543 if (nextItem.startsWith(QLatin1String(":O"))) {
544 QString tmp(nextItem);
545 tmp.remove(QStringLiteral(":O"));
546 QStringList optionAttribute = tmp.split(QLatin1Char(' '), Qt::SkipEmptyParts);
547 if (optionAttribute.isEmpty()) {
548 optionAttribute.append(tmp);
549 }
550 bool bShowEmptyMenu = false;
551 bool bShowInline = false;
552 bool bShowInlineHeader = false;
553 bool bShowInlineAlias = false;
554 int inlineValue = -1;
555 for (const QString &opt_attr : std::as_const(optionAttribute)) {
556 parseAttribute(opt_attr, bShowEmptyMenu, bShowInline, bShowInlineHeader, bShowInlineAlias, inlineValue);
557 group->setShowEmptyMenu(bShowEmptyMenu);
558 group->setAllowInline(bShowInline);
559 group->setShowInlineHeader(bShowInlineHeader);
560 group->setInlineAlias(bShowInlineAlias);
561 group->setInlineValue(inlineValue);
562 }
563 } else {
564 it--;
565 }
566
567 addItem(sorted, KServiceGroup::SPtr(group), needSeparator);
568 }
569 break;
570 }
571 }
572 } else {
573 for (KServiceGroup::List::ConstIterator it2(group->d_func()->m_serviceList.constBegin()); it2 != group->d_func()->m_serviceList.constEnd(); ++it2) {
574 if (!(*it2)->isType(KST_KService)) {
575 continue;
576 }
577 const KService::Ptr service(static_cast<KService *>((*it2).data()));
578 if (service->menuId() == item) {
579 if (!excludeNoDisplay || !service->noDisplay()) {
580 addItem(sorted, (*it2), needSeparator);
581 }
582 break;
583 }
584 }
585 }
586 }
587
588 return sorted;
589 }
590
parseAttribute(const QString & item,bool & showEmptyMenu,bool & showInline,bool & showInlineHeader,bool & showInlineAlias,int & inlineValue)591 void KServiceGroupPrivate::parseAttribute(const QString &item,
592 bool &showEmptyMenu,
593 bool &showInline,
594 bool &showInlineHeader,
595 bool &showInlineAlias,
596 int &inlineValue)
597 {
598 if (item == QLatin1String("ME")) { // menu empty
599 showEmptyMenu = true;
600 } else if (item == QLatin1String("NME")) { // not menu empty
601 showEmptyMenu = false;
602 } else if (item == QLatin1String("I")) { // inline menu !
603 showInline = true;
604 } else if (item == QLatin1String("NI")) { // not inline menu!
605 showInline = false;
606 } else if (item == QLatin1String("IH")) { // inline header!
607 showInlineHeader = true;
608 } else if (item == QLatin1String("NIH")) { // not inline header!
609 showInlineHeader = false;
610 } else if (item == QLatin1String("IA")) { // inline alias!
611 showInlineAlias = true;
612 } else if (item == QLatin1String("NIA")) { // not inline alias!
613 showInlineAlias = false;
614 } else if ((item).contains(QLatin1String("IL"))) { // inline limit!
615 QString tmp(item);
616 tmp.remove(QStringLiteral("IL["));
617 tmp.remove(QLatin1Char(']'));
618 bool ok;
619 int _inlineValue = tmp.toInt(&ok);
620 if (!ok) { // error
621 _inlineValue = -1;
622 }
623 inlineValue = _inlineValue;
624 } else {
625 qCDebug(SERVICES) << "This attribute is not supported:" << item;
626 }
627 }
628
setLayoutInfo(const QStringList & layout)629 void KServiceGroup::setLayoutInfo(const QStringList &layout)
630 {
631 Q_D(KServiceGroup);
632 d->sortOrder = layout;
633 }
634
layoutInfo() const635 QStringList KServiceGroup::layoutInfo() const
636 {
637 Q_D(const KServiceGroup);
638 return d->sortOrder;
639 }
640
root()641 KServiceGroup::Ptr KServiceGroup::root()
642 {
643 KSycoca::self()->ensureCacheValid();
644 return KSycocaPrivate::self()->serviceGroupFactory()->findGroupByDesktopPath(QStringLiteral("/"), true);
645 }
646
group(const QString & relPath)647 KServiceGroup::Ptr KServiceGroup::group(const QString &relPath)
648 {
649 if (relPath.isEmpty()) {
650 return root();
651 }
652 KSycoca::self()->ensureCacheValid();
653 return KSycocaPrivate::self()->serviceGroupFactory()->findGroupByDesktopPath(relPath, true);
654 }
655
childGroup(const QString & parent)656 KServiceGroup::Ptr KServiceGroup::childGroup(const QString &parent)
657 {
658 KSycoca::self()->ensureCacheValid();
659 return KSycocaPrivate::self()->serviceGroupFactory()->findGroupByDesktopPath(QLatin1String("#parent#") + parent, true);
660 }
661
baseGroupName() const662 QString KServiceGroup::baseGroupName() const
663 {
664 return d_func()->m_strBaseGroupName;
665 }
666
directoryEntryPath() const667 QString KServiceGroup::directoryEntryPath() const
668 {
669 Q_D(const KServiceGroup);
670 return d->directoryEntryPath;
671 }
672
673 class KServiceSeparatorPrivate : public KSycocaEntryPrivate
674 {
675 public:
K_SYCOCATYPE(KST_KServiceSeparator,KSycocaEntryPrivate)676 K_SYCOCATYPE(KST_KServiceSeparator, KSycocaEntryPrivate)
677
678 KServiceSeparatorPrivate(const QString &name)
679 : KSycocaEntryPrivate(name)
680 {
681 }
682
683 QString name() const override;
684 };
685
name() const686 QString KServiceSeparatorPrivate::name() const
687 {
688 return QStringLiteral("separator");
689 }
690
KServiceSeparator()691 KServiceSeparator::KServiceSeparator()
692 : KSycocaEntry(*new KServiceSeparatorPrivate(QStringLiteral("separator")))
693 {
694 }
695
~KServiceSeparator()696 KServiceSeparator::~KServiceSeparator()
697 {
698 }
699