File indexing completed on 2024-04-28 07:45:43

0001 /*
0002     This file is part of the KDE libraries
0003     SPDX-FileCopyrightText: 2000 Waldo Bastian <bastian@kde.org>
0004 
0005     SPDX-License-Identifier: LGPL-2.0-only
0006 */
0007 
0008 #include "kservicegroup.h"
0009 #include "kservice.h"
0010 #include "kservicefactory_p.h"
0011 #include "kservicegroup_p.h"
0012 #include "kservicegroupfactory_p.h"
0013 #include "ksycoca_p.h"
0014 #include "servicesdebug.h"
0015 #include <KConfigGroup>
0016 #include <KDesktopFile>
0017 #include <ksycoca.h>
0018 
0019 KServiceGroup::KServiceGroup(const QString &name)
0020     : KSycocaEntry(*new KServiceGroupPrivate(name))
0021 {
0022 }
0023 
0024 KServiceGroup::KServiceGroup(const QString &configFile, const QString &_relpath)
0025     : KSycocaEntry(*new KServiceGroupPrivate(_relpath))
0026 {
0027     Q_D(KServiceGroup);
0028 
0029     QString cfg = configFile;
0030     if (cfg.isEmpty()) {
0031         cfg = _relpath + QLatin1String(".directory");
0032     }
0033 
0034     d->load(cfg);
0035 }
0036 
0037 void KServiceGroupPrivate::load(const QString &cfg)
0038 {
0039     directoryEntryPath = cfg;
0040 
0041     const KDesktopFile desktopFile(cfg);
0042 
0043     const KConfigGroup config = desktopFile.desktopGroup();
0044 
0045     m_strCaption = config.readEntry("Name");
0046     m_strIcon = config.readEntry("Icon");
0047     m_strComment = config.readEntry("Comment");
0048     deleted = config.readEntry("Hidden", false);
0049     m_bNoDisplay = desktopFile.noDisplay();
0050     m_strBaseGroupName = config.readEntry("X-KDE-BaseGroup");
0051     suppressGenericNames = config.readEntry("X-KDE-SuppressGenericNames", QStringList());
0052 
0053     // Fill in defaults.
0054     if (m_strCaption.isEmpty()) {
0055         m_strCaption = path;
0056         if (m_strCaption.endsWith(QLatin1Char('/'))) {
0057             m_strCaption.chop(1);
0058         }
0059         int i = m_strCaption.lastIndexOf(QLatin1Char('/'));
0060         if (i > 0) {
0061             m_strCaption.remove(0, i + 1);
0062         }
0063     }
0064     if (m_strIcon.isEmpty()) {
0065         m_strIcon = QStringLiteral("folder");
0066     }
0067 }
0068 
0069 KServiceGroup::KServiceGroup(QDataStream &_str, int offset, bool deep)
0070     : KSycocaEntry(*new KServiceGroupPrivate(_str, offset))
0071 {
0072     Q_D(KServiceGroup);
0073     d->m_bDeep = deep;
0074     d->load(_str);
0075 }
0076 
0077 KServiceGroup::~KServiceGroup()
0078 {
0079 }
0080 
0081 QString KServiceGroup::relPath() const
0082 {
0083     return entryPath();
0084 }
0085 
0086 QString KServiceGroup::caption() const
0087 {
0088     Q_D(const KServiceGroup);
0089     return d->m_strCaption;
0090 }
0091 
0092 QString KServiceGroup::icon() const
0093 {
0094     Q_D(const KServiceGroup);
0095     return d->m_strIcon;
0096 }
0097 
0098 QString KServiceGroup::comment() const
0099 {
0100     Q_D(const KServiceGroup);
0101     return d->m_strComment;
0102 }
0103 
0104 int KServiceGroup::childCount() const
0105 {
0106     Q_D(const KServiceGroup);
0107     return d->childCount();
0108 }
0109 
0110 int KServiceGroupPrivate::childCount() const
0111 {
0112     if (m_childCount == -1) {
0113         m_childCount = 0;
0114 
0115         for (const KSycocaEntry::Ptr &entryPtr : m_serviceList) {
0116             if (entryPtr->isType(KST_KService)) {
0117                 KService::Ptr service(static_cast<KService *>(entryPtr.data()));
0118                 if (!service->noDisplay()) {
0119                     m_childCount++;
0120                 }
0121             } else if (entryPtr->isType(KST_KServiceGroup)) {
0122                 KServiceGroup::Ptr serviceGroup(static_cast<KServiceGroup *>(entryPtr.data()));
0123                 m_childCount += serviceGroup->childCount();
0124             }
0125         }
0126     }
0127     return m_childCount;
0128 }
0129 
0130 bool KServiceGroup::showInlineHeader() const
0131 {
0132     Q_D(const KServiceGroup);
0133     return d->m_bShowInlineHeader;
0134 }
0135 
0136 bool KServiceGroup::showEmptyMenu() const
0137 {
0138     Q_D(const KServiceGroup);
0139     return d->m_bShowEmptyMenu;
0140 }
0141 
0142 bool KServiceGroup::inlineAlias() const
0143 {
0144     Q_D(const KServiceGroup);
0145     return d->m_bInlineAlias;
0146 }
0147 
0148 void KServiceGroup::setInlineAlias(bool _b)
0149 {
0150     Q_D(KServiceGroup);
0151     d->m_bInlineAlias = _b;
0152 }
0153 
0154 void KServiceGroup::setShowEmptyMenu(bool _b)
0155 {
0156     Q_D(KServiceGroup);
0157     d->m_bShowEmptyMenu = _b;
0158 }
0159 
0160 void KServiceGroup::setShowInlineHeader(bool _b)
0161 {
0162     Q_D(KServiceGroup);
0163     d->m_bShowInlineHeader = _b;
0164 }
0165 
0166 int KServiceGroup::inlineValue() const
0167 {
0168     Q_D(const KServiceGroup);
0169     return d->m_inlineValue;
0170 }
0171 
0172 void KServiceGroup::setInlineValue(int _val)
0173 {
0174     Q_D(KServiceGroup);
0175     d->m_inlineValue = _val;
0176 }
0177 
0178 bool KServiceGroup::allowInline() const
0179 {
0180     Q_D(const KServiceGroup);
0181     return d->m_bAllowInline;
0182 }
0183 
0184 void KServiceGroup::setAllowInline(bool _b)
0185 {
0186     Q_D(KServiceGroup);
0187     d->m_bAllowInline = _b;
0188 }
0189 
0190 bool KServiceGroup::noDisplay() const
0191 {
0192     Q_D(const KServiceGroup);
0193     return d->m_bNoDisplay || d->m_strCaption.startsWith(QLatin1Char('.'));
0194 }
0195 
0196 QStringList KServiceGroup::suppressGenericNames() const
0197 {
0198     Q_D(const KServiceGroup);
0199     return d->suppressGenericNames;
0200 }
0201 
0202 void KServiceGroupPrivate::load(QDataStream &s)
0203 {
0204     QStringList groupList;
0205     qint8 noDisplay;
0206     qint8 _showEmptyMenu;
0207     qint8 inlineHeader;
0208     qint8 _inlineAlias;
0209     qint8 _allowInline;
0210     s >> m_strCaption >> m_strIcon >> m_strComment >> groupList >> m_strBaseGroupName >> m_childCount >> noDisplay >> suppressGenericNames >> directoryEntryPath
0211         >> sortOrder >> _showEmptyMenu >> inlineHeader >> _inlineAlias >> _allowInline;
0212 
0213     m_bNoDisplay = (noDisplay != 0);
0214     m_bShowEmptyMenu = (_showEmptyMenu != 0);
0215     m_bShowInlineHeader = (inlineHeader != 0);
0216     m_bInlineAlias = (_inlineAlias != 0);
0217     m_bAllowInline = (_allowInline != 0);
0218 
0219     if (m_bDeep) {
0220         for (const QString &path : std::as_const(groupList)) {
0221             if (path.endsWith(QLatin1Char('/'))) {
0222                 KServiceGroup::Ptr serviceGroup;
0223                 serviceGroup = KSycocaPrivate::self()->serviceGroupFactory()->findGroupByDesktopPath(path, false);
0224                 if (serviceGroup) {
0225                     m_serviceList.append(KServiceGroup::SPtr(serviceGroup));
0226                 }
0227             } else {
0228                 KService::Ptr service;
0229                 service = KSycocaPrivate::self()->serviceFactory()->findServiceByDesktopPath(path);
0230                 if (service) {
0231                     m_serviceList.append(KServiceGroup::SPtr(service));
0232                 }
0233             }
0234         }
0235     }
0236 }
0237 
0238 void KServiceGroup::addEntry(const KSycocaEntry::Ptr &entry)
0239 {
0240     Q_D(KServiceGroup);
0241     d->m_serviceList.append(entry);
0242 }
0243 
0244 void KServiceGroupPrivate::save(QDataStream &s)
0245 {
0246     KSycocaEntryPrivate::save(s);
0247 
0248     QStringList groupList;
0249     for (const KSycocaEntry::Ptr &p : std::as_const(m_serviceList)) {
0250         if (p->isType(KST_KService)) {
0251             KService::Ptr service(static_cast<KService *>(p.data()));
0252             groupList.append(service->entryPath());
0253         } else if (p->isType(KST_KServiceGroup)) {
0254             KServiceGroup::Ptr serviceGroup(static_cast<KServiceGroup *>(p.data()));
0255             groupList.append(serviceGroup->relPath());
0256         } else {
0257             // fprintf(stderr, "KServiceGroup: Unexpected object in list!\n");
0258         }
0259     }
0260 
0261     (void)childCount();
0262 
0263     qint8 noDisplay = m_bNoDisplay ? 1 : 0;
0264     qint8 _showEmptyMenu = m_bShowEmptyMenu ? 1 : 0;
0265     qint8 inlineHeader = m_bShowInlineHeader ? 1 : 0;
0266     qint8 _inlineAlias = m_bInlineAlias ? 1 : 0;
0267     qint8 _allowInline = m_bAllowInline ? 1 : 0;
0268     s << m_strCaption << m_strIcon << m_strComment << groupList << m_strBaseGroupName << m_childCount << noDisplay << suppressGenericNames << directoryEntryPath
0269       << sortOrder << _showEmptyMenu << inlineHeader << _inlineAlias << _allowInline;
0270 }
0271 
0272 QList<KServiceGroup::Ptr> KServiceGroup::groupEntries(EntriesOptions options)
0273 {
0274     Q_D(KServiceGroup);
0275     bool sort = options & SortEntries || options & AllowSeparators;
0276     QList<KServiceGroup::Ptr> list;
0277     const List tmp = d->entries(this, sort, options & ExcludeNoDisplay, options & AllowSeparators, options & SortByGenericName);
0278     for (const SPtr &ptr : tmp) {
0279         if (ptr->isType(KST_KServiceGroup)) {
0280             KServiceGroup::Ptr serviceGroup(static_cast<KServiceGroup *>(ptr.data()));
0281             list.append(serviceGroup);
0282         } else if (ptr->isType(KST_KServiceSeparator)) {
0283             list.append(KServiceGroup::Ptr(static_cast<KServiceGroup *>(new KSycocaEntry())));
0284         } else if (sort && ptr->isType(KST_KService)) {
0285             break;
0286         }
0287     }
0288     return list;
0289 }
0290 
0291 KService::List KServiceGroup::serviceEntries(EntriesOptions options)
0292 {
0293     Q_D(KServiceGroup);
0294     bool sort = options & SortEntries || options & AllowSeparators;
0295     QList<KService::Ptr> list;
0296     const List tmp = d->entries(this, sort, options & ExcludeNoDisplay, options & AllowSeparators, options & SortByGenericName);
0297     bool foundService = false;
0298     for (const SPtr &ptr : tmp) {
0299         if (ptr->isType(KST_KService)) {
0300             list.append(KService::Ptr(static_cast<KService *>(ptr.data())));
0301             foundService = true;
0302         } else if (ptr->isType(KST_KServiceSeparator) && foundService) {
0303             list.append(KService::Ptr(static_cast<KService *>(new KSycocaEntry())));
0304         }
0305     }
0306     return list;
0307 }
0308 
0309 KServiceGroup::List KServiceGroup::entries(bool sort)
0310 {
0311     Q_D(KServiceGroup);
0312     return d->entries(this, sort, true, false, false);
0313 }
0314 
0315 KServiceGroup::List KServiceGroup::entries(bool sort, bool excludeNoDisplay)
0316 {
0317     Q_D(KServiceGroup);
0318     return d->entries(this, sort, excludeNoDisplay, false, false);
0319 }
0320 
0321 KServiceGroup::List KServiceGroup::entries(bool sort, bool excludeNoDisplay, bool allowSeparators, bool sortByGenericName)
0322 {
0323     Q_D(KServiceGroup);
0324     return d->entries(this, sort, excludeNoDisplay, allowSeparators, sortByGenericName);
0325 }
0326 
0327 static void addItem(KServiceGroup::List &sorted, const KSycocaEntry::Ptr &p, bool &addSeparator)
0328 {
0329     if (addSeparator && !sorted.isEmpty()) {
0330         sorted.append(KSycocaEntry::Ptr(new KServiceSeparator()));
0331     }
0332     sorted.append(p);
0333     addSeparator = false;
0334 }
0335 
0336 KServiceGroup::List KServiceGroupPrivate::entries(KServiceGroup *group, bool sort, bool excludeNoDisplay, bool allowSeparators, bool sortByGenericName)
0337 {
0338     KSycoca::self()->ensureCacheValid();
0339 
0340     // If the entries haven't been loaded yet, we have to reload ourselves
0341     // together with the entries. We can't only load the entries afterwards
0342     // since the offsets could have been changed if the database has changed.
0343 
0344     KServiceGroup::Ptr grp;
0345     if (!m_bDeep) {
0346         grp = KSycocaPrivate::self()->serviceGroupFactory()->findGroupByDesktopPath(path, true);
0347 
0348         group = grp.data();
0349         if (nullptr == group) { // No guarantee that we still exist!
0350             return KServiceGroup::List();
0351         }
0352     }
0353 
0354     if (!sort) {
0355         return group->d_func()->m_serviceList;
0356     }
0357 
0358     // Sort the list alphabetically, according to locale.
0359     // Groups come first, then services.
0360 
0361     // We use a QMap, for sorting using a stored temporary key.
0362     typedef QMap<QByteArray, KServiceGroup::SPtr> SortedContainer;
0363     SortedContainer slist;
0364     SortedContainer glist;
0365     const auto listService = group->d_func()->m_serviceList;
0366     for (const KSycocaEntry::Ptr &p : listService) {
0367         bool noDisplay = p->isType(KST_KServiceGroup) ? static_cast<KServiceGroup *>(p.data())->noDisplay() : static_cast<KService *>(p.data())->noDisplay();
0368         if (excludeNoDisplay && noDisplay) {
0369             continue;
0370         }
0371         // Choose the right list
0372         SortedContainer &list = p->isType(KST_KServiceGroup) ? glist : slist;
0373         QString name;
0374         if (p->isType(KST_KServiceGroup)) {
0375             name = static_cast<KServiceGroup *>(p.data())->caption();
0376         } else if (sortByGenericName) {
0377             name = static_cast<KService *>(p.data())->genericName() + QLatin1Char(' ') + p->name();
0378         } else {
0379             name = p->name() + QLatin1Char(' ') + static_cast<KService *>(p.data())->genericName();
0380         }
0381 
0382         const QByteArray nameStr = name.toLocal8Bit();
0383 
0384         QByteArray key;
0385         // strxfrm() crashes on Solaris and strxfrm is not defined under wince
0386 #if !defined(USE_SOLARIS) && !defined(_WIN32_WCE)
0387         // maybe it'd be better to use wcsxfrm() where available
0388         key.resize(name.length() * 4 + 1);
0389         size_t ln = strxfrm(key.data(), nameStr.constData(), key.size());
0390         if (ln != size_t(-1)) {
0391             key.resize(ln);
0392             if (int(ln) >= key.size()) {
0393                 // didn't fit?
0394                 ln = strxfrm(key.data(), nameStr.constData(), key.size());
0395                 if (ln == size_t(-1)) {
0396                     key = nameStr;
0397                 }
0398             }
0399         } else
0400 #endif
0401         {
0402             key = nameStr;
0403         }
0404         list.insert(key, KServiceGroup::SPtr(p));
0405     }
0406 
0407     if (sortOrder.isEmpty()) {
0408         sortOrder << QStringLiteral(":M");
0409         sortOrder << QStringLiteral(":F");
0410         sortOrder << QStringLiteral(":OIH IL[4]"); // just inline header
0411     }
0412 
0413     QString rp = path;
0414     if (rp == QLatin1String("/")) {
0415         rp.clear();
0416     }
0417 
0418     // Iterate through the sort spec list.
0419     // If an entry gets mentioned explicitly, we remove it from the sorted list
0420     for (const QString &item : std::as_const(sortOrder)) {
0421         if (item.isEmpty()) {
0422             continue;
0423         }
0424         if (item[0] == QLatin1Char('/')) {
0425             QString groupPath = rp + QStringView(item).mid(1) + QLatin1Char('/');
0426             // Remove entry from sorted list of services.
0427             for (SortedContainer::iterator it2 = glist.begin(); it2 != glist.end(); ++it2) {
0428                 const KServiceGroup::Ptr group(static_cast<KServiceGroup *>(it2.value().data()));
0429                 if (group->relPath() == groupPath) {
0430                     glist.erase(it2);
0431                     break;
0432                 }
0433             }
0434         } else if (item[0] != QLatin1Char(':')) {
0435             // Remove entry from sorted list of services.
0436             // TODO: Remove item from sortOrder-list if not found
0437             // TODO: This prevents duplicates
0438             for (SortedContainer::iterator it2 = slist.begin(); it2 != slist.end(); ++it2) {
0439                 const KService::Ptr service(static_cast<KService *>(it2.value().data()));
0440                 if (service->menuId() == item) {
0441                     slist.erase(it2);
0442                     break;
0443                 }
0444             }
0445         }
0446     }
0447 
0448     KServiceGroup::List sorted;
0449 
0450     bool needSeparator = false;
0451     // Iterate through the sort spec list.
0452     // Add the entries to the list according to the sort spec.
0453     for (QStringList::ConstIterator it(sortOrder.constBegin()); it != sortOrder.constEnd(); ++it) {
0454         const QString &item = *it;
0455         if (item.isEmpty()) {
0456             continue;
0457         }
0458         if (item[0] == QLatin1Char(':')) {
0459             // Special condition...
0460             if (item == QLatin1String(":S")) {
0461                 if (allowSeparators) {
0462                     needSeparator = true;
0463                 }
0464             } else if (item.contains(QLatin1String(":O"))) {
0465                 // todo parse attribute:
0466                 QString tmp(item);
0467                 tmp.remove(QStringLiteral(":O"));
0468                 QStringList optionAttribute = tmp.split(QLatin1Char(' '), Qt::SkipEmptyParts);
0469                 if (optionAttribute.isEmpty()) {
0470                     optionAttribute.append(tmp);
0471                 }
0472                 bool showEmptyMenu = false;
0473                 bool showInline = false;
0474                 bool showInlineHeader = false;
0475                 bool showInlineAlias = false;
0476                 int inlineValue = -1;
0477 
0478                 for (QStringList::Iterator it3 = optionAttribute.begin(); it3 != optionAttribute.end(); ++it3) {
0479                     parseAttribute(*it3, showEmptyMenu, showInline, showInlineHeader, showInlineAlias, inlineValue);
0480                 }
0481                 for (SortedContainer::Iterator it2 = glist.begin(); it2 != glist.end(); ++it2) {
0482                     KServiceGroup::Ptr group(static_cast<KServiceGroup *>(it2.value().data()));
0483                     group->setShowEmptyMenu(showEmptyMenu);
0484                     group->setAllowInline(showInline);
0485                     group->setShowInlineHeader(showInlineHeader);
0486                     group->setInlineAlias(showInlineAlias);
0487                     group->setInlineValue(inlineValue);
0488                 }
0489 
0490             } else if (item == QLatin1String(":M")) {
0491                 // Add sorted list of sub-menus
0492                 for (SortedContainer::const_iterator it2 = glist.constBegin(); it2 != glist.constEnd(); ++it2) {
0493                     addItem(sorted, it2.value(), needSeparator);
0494                 }
0495             } else if (item == QLatin1String(":F")) {
0496                 // Add sorted list of services
0497                 for (SortedContainer::const_iterator it2 = slist.constBegin(); it2 != slist.constEnd(); ++it2) {
0498                     addItem(sorted, it2.value(), needSeparator);
0499                 }
0500             } else if (item == QLatin1String(":A")) {
0501                 // Add sorted lists of services and submenus
0502                 SortedContainer::Iterator it_s = slist.begin();
0503                 SortedContainer::Iterator it_g = glist.begin();
0504 
0505                 while (true) {
0506                     if (it_s == slist.end()) {
0507                         if (it_g == glist.end()) {
0508                             break; // Done
0509                         }
0510 
0511                         // Insert remaining sub-menu
0512                         addItem(sorted, it_g.value(), needSeparator);
0513                         it_g++;
0514                     } else if (it_g == glist.end()) {
0515                         // Insert remaining service
0516                         addItem(sorted, it_s.value(), needSeparator);
0517                         it_s++;
0518                     } else if (it_g.key() < it_s.key()) {
0519                         // Insert sub-menu first
0520                         addItem(sorted, it_g.value(), needSeparator);
0521                         it_g++;
0522                     } else {
0523                         // Insert service first
0524                         addItem(sorted, it_s.value(), needSeparator);
0525                         it_s++;
0526                     }
0527                 }
0528             }
0529         } else if (item[0] == QLatin1Char('/')) {
0530             QString groupPath = rp + QStringView(item).mid(1) + QLatin1Char('/');
0531 
0532             for (KServiceGroup::List::ConstIterator it2(group->d_func()->m_serviceList.constBegin()); it2 != group->d_func()->m_serviceList.constEnd(); ++it2) {
0533                 if (!(*it2)->isType(KST_KServiceGroup)) {
0534                     continue;
0535                 }
0536                 KServiceGroup::Ptr group(static_cast<KServiceGroup *>((*it2).data()));
0537                 if (group->relPath() == groupPath) {
0538                     if (!excludeNoDisplay || !group->noDisplay()) {
0539                         ++it;
0540                         const QString &nextItem = (it == sortOrder.constEnd()) ? QString() : *it;
0541 
0542                         if (nextItem.startsWith(QLatin1String(":O"))) {
0543                             QString tmp(nextItem);
0544                             tmp.remove(QStringLiteral(":O"));
0545                             QStringList optionAttribute = tmp.split(QLatin1Char(' '), Qt::SkipEmptyParts);
0546                             if (optionAttribute.isEmpty()) {
0547                                 optionAttribute.append(tmp);
0548                             }
0549                             bool bShowEmptyMenu = false;
0550                             bool bShowInline = false;
0551                             bool bShowInlineHeader = false;
0552                             bool bShowInlineAlias = false;
0553                             int inlineValue = -1;
0554                             for (const QString &opt_attr : std::as_const(optionAttribute)) {
0555                                 parseAttribute(opt_attr, bShowEmptyMenu, bShowInline, bShowInlineHeader, bShowInlineAlias, inlineValue);
0556                                 group->setShowEmptyMenu(bShowEmptyMenu);
0557                                 group->setAllowInline(bShowInline);
0558                                 group->setShowInlineHeader(bShowInlineHeader);
0559                                 group->setInlineAlias(bShowInlineAlias);
0560                                 group->setInlineValue(inlineValue);
0561                             }
0562                         } else {
0563                             it--;
0564                         }
0565 
0566                         addItem(sorted, KServiceGroup::SPtr(group), needSeparator);
0567                     }
0568                     break;
0569                 }
0570             }
0571         } else {
0572             for (KServiceGroup::List::ConstIterator it2(group->d_func()->m_serviceList.constBegin()); it2 != group->d_func()->m_serviceList.constEnd(); ++it2) {
0573                 if (!(*it2)->isType(KST_KService)) {
0574                     continue;
0575                 }
0576                 const KService::Ptr service(static_cast<KService *>((*it2).data()));
0577                 if (service->menuId() == item) {
0578                     if (!excludeNoDisplay || !service->noDisplay()) {
0579                         addItem(sorted, (*it2), needSeparator);
0580                     }
0581                     break;
0582                 }
0583             }
0584         }
0585     }
0586 
0587     return sorted;
0588 }
0589 
0590 void KServiceGroupPrivate::parseAttribute(const QString &item,
0591                                           bool &showEmptyMenu,
0592                                           bool &showInline,
0593                                           bool &showInlineHeader,
0594                                           bool &showInlineAlias,
0595                                           int &inlineValue)
0596 {
0597     if (item == QLatin1String("ME")) { // menu empty
0598         showEmptyMenu = true;
0599     } else if (item == QLatin1String("NME")) { // not menu empty
0600         showEmptyMenu = false;
0601     } else if (item == QLatin1String("I")) { // inline menu !
0602         showInline = true;
0603     } else if (item == QLatin1String("NI")) { // not inline menu!
0604         showInline = false;
0605     } else if (item == QLatin1String("IH")) { // inline  header!
0606         showInlineHeader = true;
0607     } else if (item == QLatin1String("NIH")) { // not inline  header!
0608         showInlineHeader = false;
0609     } else if (item == QLatin1String("IA")) { // inline alias!
0610         showInlineAlias = true;
0611     } else if (item == QLatin1String("NIA")) { // not inline alias!
0612         showInlineAlias = false;
0613     } else if ((item).contains(QLatin1String("IL"))) { // inline limit!
0614         QString tmp(item);
0615         tmp.remove(QStringLiteral("IL["));
0616         tmp.remove(QLatin1Char(']'));
0617         bool ok;
0618         int _inlineValue = tmp.toInt(&ok);
0619         if (!ok) { // error
0620             _inlineValue = -1;
0621         }
0622         inlineValue = _inlineValue;
0623     } else {
0624         qCDebug(SERVICES) << "This attribute is not supported:" << item;
0625     }
0626 }
0627 
0628 void KServiceGroup::setLayoutInfo(const QStringList &layout)
0629 {
0630     Q_D(KServiceGroup);
0631     d->sortOrder = layout;
0632 }
0633 
0634 QStringList KServiceGroup::layoutInfo() const
0635 {
0636     Q_D(const KServiceGroup);
0637     return d->sortOrder;
0638 }
0639 
0640 KServiceGroup::Ptr KServiceGroup::root()
0641 {
0642     KSycoca::self()->ensureCacheValid();
0643     return KSycocaPrivate::self()->serviceGroupFactory()->findGroupByDesktopPath(QStringLiteral("/"), true);
0644 }
0645 
0646 KServiceGroup::Ptr KServiceGroup::group(const QString &relPath)
0647 {
0648     if (relPath.isEmpty()) {
0649         return root();
0650     }
0651     KSycoca::self()->ensureCacheValid();
0652     return KSycocaPrivate::self()->serviceGroupFactory()->findGroupByDesktopPath(relPath, true);
0653 }
0654 
0655 KServiceGroup::Ptr KServiceGroup::childGroup(const QString &parent)
0656 {
0657     KSycoca::self()->ensureCacheValid();
0658     return KSycocaPrivate::self()->serviceGroupFactory()->findGroupByDesktopPath(QLatin1String("#parent#") + parent, true);
0659 }
0660 
0661 QString KServiceGroup::baseGroupName() const
0662 {
0663     return d_func()->m_strBaseGroupName;
0664 }
0665 
0666 QString KServiceGroup::directoryEntryPath() const
0667 {
0668     Q_D(const KServiceGroup);
0669     return d->directoryEntryPath;
0670 }
0671 
0672 class KServiceSeparatorPrivate : public KSycocaEntryPrivate
0673 {
0674 public:
0675     K_SYCOCATYPE(KST_KServiceSeparator, KSycocaEntryPrivate)
0676 
0677     KServiceSeparatorPrivate(const QString &name)
0678         : KSycocaEntryPrivate(name)
0679     {
0680     }
0681 
0682     QString name() const override;
0683 };
0684 
0685 QString KServiceSeparatorPrivate::name() const
0686 {
0687     return QStringLiteral("separator");
0688 }
0689 
0690 KServiceSeparator::KServiceSeparator()
0691     : KSycocaEntry(*new KServiceSeparatorPrivate(QStringLiteral("separator")))
0692 {
0693 }
0694 
0695 KServiceSeparator::~KServiceSeparator()
0696 {
0697 }