Index: kded/kbuildsycoca.cpp =================================================================== --- kded/kbuildsycoca.cpp (Revision 921137) +++ kded/kbuildsycoca.cpp (Revision 921138) @@ -514,7 +514,7 @@ // Calculate per-servicetype/mimetype data mimeTypeFactory->parseSubclasses(); - serviceFactory->populateServiceTypes(); + serviceFactory->postProcessServices(); // Write factory data.... for(KSycocaFactoryList::Iterator factory = factories()->begin(); Index: kded/kbuildservicefactory.cpp =================================================================== --- kded/kbuildservicefactory.cpp (Revision 921137) +++ kded/kbuildservicefactory.cpp (Revision 921138) @@ -193,13 +193,50 @@ } } +void KBuildServiceFactory::postProcessServices() +{ + // By doing all this here rather than in addEntry (and removing when replacing + // with local override), we only do it for the final applications. + // For every service... + KSycocaEntryDict::Iterator itserv = m_entryDict->begin(); + const KSycocaEntryDict::Iterator endserv = m_entryDict->end(); + for( ; itserv != endserv ; ++itserv ) { + + KSycocaEntry::Ptr entry = *itserv; + KService::Ptr service = KService::Ptr::staticCast(entry); + + if (!service->isDeleted()) { + const QString parent = service->parentApp(); + if (!parent.isEmpty()) + m_serviceGroupFactory->addNewChild(parent, KSycocaEntry::Ptr::staticCast(service)); + } + + const QString name = service->desktopEntryName(); + m_nameDict->add(name, entry); + m_nameMemoryHash.insert(name, service); + + const QString relName = service->entryPath(); + //kDebug(7021) << "adding service" << service.data() << service->menuId() << "name=" << name << "relName=" << relName; + m_relNameDict->add(relName, entry); + m_relNameMemoryHash.insert(relName, service); // for KMimeAssociations + + const QString menuId = service->menuId(); + if (!menuId.isEmpty()) { // empty for services, non-empty for applications + m_menuIdDict->add(menuId, entry); + m_menuIdMemoryHash.insert(menuId, service); // for KMimeAssociations + } + } + populateServiceTypes(); +} + void KBuildServiceFactory::populateServiceTypes() { // For every service... KSycocaEntryDict::Iterator itserv = m_entryDict->begin(); const KSycocaEntryDict::Iterator endserv = m_entryDict->end(); for( ; itserv != endserv ; ++itserv ) { + KService::Ptr service = KService::Ptr::staticCast(*itserv); QVector serviceTypeList = service->_k_accessServiceTypes(); //bool hasAllAll = false; @@ -336,30 +373,18 @@ if (m_dupeDict.contains(newEntry)) return; - KSycocaFactory::addEntry(newEntry); - const KService::Ptr service = KService::Ptr::staticCast( newEntry ); m_dupeDict.insert(newEntry); - if (!service->isDeleted()) { - const QString parent = service->parentApp(); - if (!parent.isEmpty()) - m_serviceGroupFactory->addNewChild(parent, KSycocaEntry::Ptr::staticCast(service)); + KSycocaEntry::Ptr oldEntry = m_entryDict->value(newEntry->storageId()); + if (oldEntry) { + // Already exists -> replace + //KService::Ptr oldService = KService::Ptr::staticCast(oldEntry); + // We found a more-local override, e.g. ~/.local/share/applications/kde4/foo.desktop + // So forget about the more global file. + //kDebug(7021) << "removing" << oldService.data() << oldService->entryPath() << "because of" << service->entryPath(); + KSycocaFactory::removeEntry(newEntry->storageId()); } - const QString name = service->desktopEntryName(); - m_nameDict->add( name, newEntry ); - m_nameMemoryHash.insert(name, service); - - const QString relName = service->entryPath(); - //kDebug(7021) << "adding service" << service->menuId() << "name=" << name << "relName=" << relName; - m_relNameDict->add( relName, newEntry ); - m_relNameMemoryHash.insert(relName, service); // for KMimeAssociations - - const QString menuId = service->menuId(); - if (!menuId.isEmpty()) { - m_menuIdDict->add( menuId, newEntry ); - m_menuIdMemoryHash.insert(menuId, service); // for KMimeAssociations - } + KSycocaFactory::addEntry(newEntry); } - Index: kded/vfolder_menu.cpp =================================================================== --- kded/vfolder_menu.cpp (Revision 921137) +++ kded/vfolder_menu.cpp (Revision 921138) @@ -349,7 +349,7 @@ VFolderMenu::addApplication(const QString &id, KService::Ptr service) { service->setMenuId(id); - m_appsInfo->applications.insert(id, service); + m_appsInfo->applications.insert(id, service); // replaces, if already there m_serviceFactory->addEntry(KSycocaEntry::Ptr::staticCast(service)); } @@ -1029,7 +1029,7 @@ void VFolderMenu::processKDELegacyDirs() { -kDebug(7021) << "processKDELegacyDirs()"; + kDebug(7021); QHash items; QString prefix = "kde4-"; @@ -1091,7 +1091,7 @@ void VFolderMenu::processLegacyDir(const QString &dir, const QString &relDir, const QString &prefix) { -kDebug(7021).nospace() << "processLegacyDir(" << dir << ", " << relDir << ", " << prefix << ")"; + kDebug(7021).nospace() << "processLegacyDir(" << dir << ", " << relDir << ", " << prefix << ")"; QHash items; // We look for a set of files. Index: kded/kbuildservicefactory.h =================================================================== --- kded/kbuildservicefactory.h (Revision 921137) +++ kded/kbuildservicefactory.h (Revision 921138) @@ -83,9 +83,10 @@ */ static QStringList resourceTypes(); - void populateServiceTypes(); + void postProcessServices(); private: + void populateServiceTypes(); void saveOfferList(QDataStream &str); void collectInheritedServices(); void collectInheritedServices(KMimeType::Ptr mime, QSet& visitedMimes); Index: kdecore/sycoca/ksycocaentry_p.h =================================================================== --- kdecore/sycoca/ksycocaentry_p.h (Revision 921137) +++ kdecore/sycoca/ksycocaentry_p.h (Revision 921138) @@ -23,7 +23,7 @@ #define K_SYCOCATYPE( type, baseclass ) \ virtual bool isType(KSycocaType t) const { if (t == type) return true; return baseclass::isType(t);} \ - virtual KSycocaType sycocaType() const { return type; } + virtual KSycocaType sycocaType() const { return type; } class KSycocaEntryPrivate @@ -68,6 +68,8 @@ virtual QString name() const = 0; + virtual QString storageId() const { return name(); } + int offset; bool deleted; QString path; Index: kdecore/sycoca/ksycocaentry.cpp =================================================================== --- kdecore/sycoca/ksycocaentry.cpp (Revision 921137) +++ kdecore/sycoca/ksycocaentry.cpp (Revision 921138) @@ -106,6 +106,12 @@ return d->path; } +QString KSycocaEntry::storageId() const +{ + Q_D(const KSycocaEntry); + return d->storageId(); +} + bool KSycocaEntry::isDeleted() const { Q_D(const KSycocaEntry); @@ -164,5 +170,3 @@ Q_D(const KSycocaEntry); return d->property(name); } - - Index: kdecore/sycoca/ksycocaentry.h =================================================================== --- kdecore/sycoca/ksycocaentry.h (Revision 921137) +++ kdecore/sycoca/ksycocaentry.h (Revision 921138) @@ -86,6 +86,13 @@ QString entryPath() const; /** + * @return the unique ID for this entry + * In practice, this is storageId() for KService and name() for everything else. + * \since 4.2.1 + */ + QString storageId() const; + + /** * @return true if valid */ bool isValid() const; @@ -117,7 +124,7 @@ */ void setDeleted( bool deleted ); - + /* * @returns true, if this is a separator */ Index: kdecore/sycoca/ksycocafactory.cpp =================================================================== --- kdecore/sycoca/ksycocafactory.cpp (Revision 921137) +++ kdecore/sycoca/ksycocafactory.cpp (Revision 921138) @@ -150,12 +150,8 @@ if (!d->m_sycocaDict) return; // Error! - // Note that we use a QMultiHash since there can be several entries - // with the same name (e.g. kfmclient.desktop and konqbrowser.desktop both - // have Name=Konqueror). - - const QString name = newEntry->name(); - m_entryDict->insertMulti( name, newEntry ); + const QString name = newEntry->storageId(); + m_entryDict->insert( name, newEntry ); d->m_sycocaDict->add( name, newEntry ); } Index: kdecore/sycoca/ksycoca.cpp =================================================================== --- kdecore/sycoca/ksycoca.cpp (Revision 921137) +++ kdecore/sycoca/ksycoca.cpp (Revision 921138) @@ -43,7 +43,7 @@ * If the existing file is outdated, it will not get read * but instead we'll ask kded to regenerate a new one... */ -#define KSYCOCA_VERSION 130 +#define KSYCOCA_VERSION 131 /** * Sycoca file name, used internally (by kbuildsycoca) Index: kdecore/services/kservice_p.h =================================================================== --- kdecore/services/kservice_p.h (Revision 921137) +++ kdecore/services/kservice_p.h (Revision 921138) @@ -51,6 +51,13 @@ return m_strName; } + virtual QString storageId() const + { + if (!menuId.isEmpty()) + return menuId; + return path; + } + virtual bool isValid() const { return m_bValid; Index: kdecore/services/kservice.cpp =================================================================== --- kdecore/services/kservice.cpp (Revision 921137) +++ kdecore/services/kservice.cpp (Revision 921138) @@ -704,7 +704,7 @@ return QString(); } } - + return it->toString(); } @@ -736,9 +736,7 @@ QString KService::storageId() const { Q_D(const KService); - if (!d->menuId.isEmpty()) - return d->menuId; - return entryPath(); + return d->storageId(); } QString KService::locateLocal() const