From ccfb245419895875dbea7ba19ca00a4417d8d49d Mon Sep 17 00:00:00 2001 From: ComixHe Date: Fri, 25 Aug 2023 10:47:17 +0800 Subject: [PATCH] refact: Desktop file parsing process and Application methods to Properties Signed-off-by: ComixHe --- ...opspec.ApplicationManager1.Application.xml | 57 ++-- api/dbus/org.desktopspec.ObjectManager1.xml | 5 +- apps/dde-application-manager/src/main.cpp | 8 +- src/constant.h | 1 + src/dbus/applicationmanager1service.cpp | 6 +- src/dbus/applicationmanager1service.h | 2 +- src/dbus/applicationservice.cpp | 163 ++++-------- src/dbus/applicationservice.h | 14 +- src/desktopentry.cpp | 245 +++++++++++++----- src/desktopentry.h | 29 +-- src/global.h | 44 +++- 11 files changed, 329 insertions(+), 245 deletions(-) diff --git a/api/dbus/org.desktopspec.ApplicationManager1.Application.xml b/api/dbus/org.desktopspec.ApplicationManager1.Application.xml index af2b1e7..5eec181 100644 --- a/api/dbus/org.desktopspec.ApplicationManager1.Application.xml +++ b/api/dbus/org.desktopspec.ApplicationManager1.Application.xml @@ -61,6 +61,30 @@ + + + + + + + + + + + + + + + @@ -84,38 +108,5 @@ This option might request a polikit authentication." /> - - - - - - - - - - - - - - - - - - - diff --git a/api/dbus/org.desktopspec.ObjectManager1.xml b/api/dbus/org.desktopspec.ObjectManager1.xml index c1fbe2a..9c58842 100644 --- a/api/dbus/org.desktopspec.ObjectManager1.xml +++ b/api/dbus/org.desktopspec.ObjectManager1.xml @@ -2,13 +2,14 @@ - + - + + diff --git a/apps/dde-application-manager/src/main.cpp b/apps/dde-application-manager/src/main.cpp index 419a3ed..a5c33e4 100644 --- a/apps/dde-application-manager/src/main.cpp +++ b/apps/dde-application-manager/src/main.cpp @@ -19,7 +19,13 @@ void registerComplexDbusType() qDBusRegisterMetaType>(); qDBusRegisterMetaType>>(); qDBusRegisterMetaType(); + qRegisterMetaType(); + qDBusRegisterMetaType(); + qRegisterMetaType(); qDBusRegisterMetaType(); + qDBusRegisterMetaType>(); + qRegisterMetaType(); + qDBusRegisterMetaType(); } } // namespace @@ -48,7 +54,7 @@ int main(int argc, char *argv[]) return false; } if (!AMService.addApplication(std::move(ret).value())) { - qWarning() << "add Application failed:" << ret->sourcePath() << "skip..."; + qWarning() << "add Application failed, skip..."; } return false; // means to apply this function to the rest of the files }); diff --git a/src/constant.h b/src/constant.h index ccf5161..b85e92e 100644 --- a/src/constant.h +++ b/src/constant.h @@ -16,6 +16,7 @@ constexpr auto DDEApplicationManager1ServiceName = #endif constexpr auto DDEApplicationManager1ObjectPath = u8"/org/deepin/dde/ApplicationManager1"; +constexpr auto DDEAutoStartManager1ObjectPath = u8"/org/deepin/dde/AutoStartManager1"; constexpr auto DDEApplicationManager1JobManagerObjectPath = u8"/org/deepin/dde/ApplicationManager1/JobManager1"; constexpr auto DesktopFileEntryKey = u8"Desktop Entry"; constexpr auto DesktopFileActionKey = u8"Desktop Action "; diff --git a/src/dbus/applicationmanager1service.cpp b/src/dbus/applicationmanager1service.cpp index 0475795..57b6951 100644 --- a/src/dbus/applicationmanager1service.cpp +++ b/src/dbus/applicationmanager1service.cpp @@ -135,7 +135,7 @@ bool ApplicationManager1Service::addApplication(DesktopFile desktopFileSource) n return false; } m_applicationList.insert(application->applicationPath(), application); - emit InterfacesAdded(application->applicationPath(), getInterfacesListFromObject(ptr)); + emit InterfacesAdded(application->applicationPath(), getChildInterfacesAndPropertiesFromObject(ptr)); return true; } @@ -143,7 +143,7 @@ bool ApplicationManager1Service::addApplication(DesktopFile desktopFileSource) n void ApplicationManager1Service::removeOneApplication(const QDBusObjectPath &application) noexcept { if (auto it = m_applicationList.find(application); it != m_applicationList.cend()) { - emit InterfacesRemoved(application, getInterfacesListFromObject(it->data())); + emit InterfacesRemoved(application, getChildInterfacesFromObject(it->data())); unregisterObjectFromDBus(application.path()); m_applicationList.remove(application); } @@ -225,7 +225,7 @@ void ApplicationManager1Service::updateApplication(const QSharedPointerparse(destApp->desktopFileSource()); - if (err != DesktopErrorCode::NoError and err != DesktopErrorCode::EntryKeyInvalid) { + if (err != DesktopErrorCode::NoError) { qWarning() << "update desktop file failed:" << err << ", content wouldn't change."; return; } diff --git a/src/dbus/applicationmanager1service.h b/src/dbus/applicationmanager1service.h index 4154efd..69276f0 100644 --- a/src/dbus/applicationmanager1service.h +++ b/src/dbus/applicationmanager1service.h @@ -46,7 +46,7 @@ public Q_SLOTS: [[nodiscard]] ObjectMap GetManagedObjects() const; Q_SIGNALS: - void InterfacesAdded(const QDBusObjectPath &object_path, const QStringList &interfaces); + void InterfacesAdded(const QDBusObjectPath &object_path, const ObjectInterfaceMap &interfaces); void InterfacesRemoved(const QDBusObjectPath &object_path, const QStringList &interfaces); private: diff --git a/src/dbus/applicationservice.cpp b/src/dbus/applicationservice.cpp index 1ea2dfb..fcc17d9 100644 --- a/src/dbus/applicationservice.cpp +++ b/src/dbus/applicationservice.cpp @@ -63,10 +63,8 @@ QSharedPointer ApplicationService::createApplicationService( auto error = entry->parse(sourceStream); if (error != DesktopErrorCode::NoError) { - if (error != DesktopErrorCode::EntryKeyInvalid) { - qWarning() << "parse failed:" << error; - return nullptr; - } + qWarning() << "parse failed:" << error << app->desktopFileSource().sourcePath(); + return nullptr; } if (auto val = entry->value(DesktopFileEntryKey, "Hidden"); val.has_value()) { @@ -89,110 +87,6 @@ QSharedPointer ApplicationService::createApplicationService( return app; } -QString ApplicationService::GetActionName(const QString &identifier, const QStringList &env) const -{ - const auto &supportedActions = actions(); - if (supportedActions.isEmpty()) { - return {}; - } - if (auto index = supportedActions.indexOf(identifier); index == -1) { - qWarning() << "can't find " << identifier << " in supported actions List."; - return {}; - } - - const auto &actionHeader = QString{"%1%2"}.arg(DesktopFileActionKey, identifier); - const auto &actionName = m_entry->value(actionHeader, "Name"); - if (!actionName) { - return {}; - } - - QString locale{""}; - bool ok; - if (!env.isEmpty()) { - QString lcStr; - for (const auto &lc : env) { - if (lc.startsWith("LANG")) { - locale = lc.split('=').last(); - } - - if (lc.startsWith("LC_ALL")) { - locale = lc.split('=').last(); - break; - } - } - } - - QLocale lc = locale.isEmpty() ? getUserLocale() : QLocale{locale}; - - const auto &name = actionName->toLocaleString(lc, ok); - if (!ok) { - qWarning() << "convert to locale string failed, dest locale:" << lc; - return {}; - } - return name; -} - -QString ApplicationService::GetDisplayName(const QStringList &env) const -{ - const auto &displayName = m_entry->value(DesktopFileEntryKey, "Name"); - if (!displayName) { - return {}; - } - - QString locale{""}; - bool ok; - if (!env.isEmpty()) { - QString lcStr; - for (const auto &lc : env) { - if (lc.startsWith("LANG")) { - locale = lc.split('=').last(); - } - - if (lc.startsWith("LC_ALL")) { - locale = lc.split('=').last(); - break; - } - } - } - - QLocale lc = locale.isEmpty() ? getUserLocale() : QLocale{locale}; - - const auto &name = displayName->toLocaleString(lc, ok); - if (!ok) { - qWarning() << "convert to locale string failed, dest locale:" << lc; - return {}; - } - return name; -} - -QString ApplicationService::GetIconName(const QString &action) const -{ - std::optional iconName{std::nullopt}; - - if (action.isEmpty()) { - iconName = m_entry->value(DesktopFileEntryKey, "Icon"); - - } else { - const auto &supportedActions = actions(); - - if (auto index = supportedActions.indexOf(action); index == -1) { - qWarning() << "can't find " << action << " in supported actions List."; - return {}; - } - - const auto &actionHeader = QString{"%1%2"}.arg(DesktopFileActionKey, action); - iconName = m_entry->value(actionHeader, "Icon"); - } - - if (!iconName) { - return {}; - } - - bool ok{false}; - const auto &name = iconName->toIconString(ok); - return ok ? name : ""; -} - QDBusObjectPath ApplicationService::Launch(const QString &action, const QStringList &fields, const QVariantMap &options) { QString execStr; @@ -325,12 +219,55 @@ QStringList ApplicationService::actions() const noexcept return {}; } - auto actionList = str.split(";"); - actionList.removeAll(""); - + auto actionList = str.split(";", Qt::SkipEmptyParts); return actionList; } +PropMap ApplicationService::actionName() const noexcept +{ + PropMap ret; + auto actionList = actions(); + + for (auto &action : actionList) { + action.prepend(DesktopFileActionKey); + auto value = m_entry->value(action, "Name"); + if (!value.has_value()) { + continue; + } + ret.insert(action, {std::move(value).value()}); + } + + return ret; +} + +PropMap ApplicationService::displayName() const noexcept +{ + PropMap ret; + auto value = std::move(m_entry->value(DesktopFileEntryKey, "Name")).value(); + ret.insert(QString{"Name"}, {std::move(value)}); + return ret; +} + +PropMap ApplicationService::iconName() const noexcept +{ + PropMap ret; + auto actionList = actions(); + for (const auto &action : actionList) { + auto value = m_entry->value(QString{action}.prepend(DesktopFileActionKey), "Icon"); + if (!value.has_value()) { + continue; + } + ret.insert(action, {std::move(value).value()}); + } + + auto mainIcon = m_entry->value(DesktopFileEntryKey, "Icon"); + if (mainIcon.has_value()) { + ret.insert(defaultKeyStr, {std::move(mainIcon).value()}); + } + + return ret; +} + ObjectMap ApplicationService::GetManagedObjects() const { return dumpDBusObject(m_Instances); @@ -384,7 +321,7 @@ bool ApplicationService::addOneInstance(const QString &instanceId, const QString m_Instances.insert(QDBusObjectPath{objectPath}, QSharedPointer{service}); service->moveToThread(this->thread()); adaptor->moveToThread(this->thread()); - emit InterfacesAdded(QDBusObjectPath{objectPath}, getInterfacesListFromObject(service)); + emit InterfacesAdded(QDBusObjectPath{objectPath}, getChildInterfacesAndPropertiesFromObject(service)); return true; } @@ -396,7 +333,7 @@ bool ApplicationService::addOneInstance(const QString &instanceId, const QString void ApplicationService::removeOneInstance(const QDBusObjectPath &instance) noexcept { if (auto it = m_Instances.find(instance); it != m_Instances.cend()) { - emit InterfacesRemoved(instance, getInterfacesListFromObject(it->data())); + emit InterfacesRemoved(instance, getChildInterfacesFromObject(it->data())); unregisterObjectFromDBus(instance.path()); m_Instances.remove(instance); } diff --git a/src/dbus/applicationservice.h b/src/dbus/applicationservice.h index f49352a..c8f5a15 100644 --- a/src/dbus/applicationservice.h +++ b/src/dbus/applicationservice.h @@ -36,9 +36,18 @@ public: Q_PROPERTY(QStringList Actions READ actions) [[nodiscard]] QStringList actions() const noexcept; + Q_PROPERTY(PropMap ActionName READ actionName) + [[nodiscard]] PropMap actionName() const noexcept; + Q_PROPERTY(QString ID READ id CONSTANT) [[nodiscard]] QString id() const noexcept; + Q_PROPERTY(PropMap DisplayName READ displayName) + [[nodiscard]] PropMap displayName() const noexcept; + + Q_PROPERTY(PropMap IconName READ iconName) + [[nodiscard]] PropMap iconName() const noexcept; + Q_PROPERTY(qulonglong LastLaunchedTime READ lastLaunchedTime) [[nodiscard]] qulonglong lastLaunchedTime() const noexcept; @@ -71,14 +80,11 @@ public: void resetEntry(DesktopEntry *newEntry) noexcept; public Q_SLOTS: - [[nodiscard]] QString GetActionName(const QString &identifier, const QStringList &env) const; QDBusObjectPath Launch(const QString &action, const QStringList &fields, const QVariantMap &options); - [[nodiscard]] QString GetIconName(const QString &action) const; - [[nodiscard]] QString GetDisplayName(const QStringList &env) const; [[nodiscard]] ObjectMap GetManagedObjects() const; Q_SIGNALS: - void InterfacesAdded(const QDBusObjectPath &object_path, const QStringList &interfaces); + void InterfacesAdded(const QDBusObjectPath &object_path, const ObjectInterfaceMap &interfaces); void InterfacesRemoved(const QDBusObjectPath &object_path, const QStringList &interfaces); private: diff --git a/src/desktopentry.cpp b/src/desktopentry.cpp index 9a41816..199f2cc 100644 --- a/src/desktopentry.cpp +++ b/src/desktopentry.cpp @@ -17,26 +17,52 @@ auto DesktopEntry::parserGroupHeader(const QString &str) noexcept { - auto groupHeader = str.sliced(1, str.size() - 2); - auto it = m_entryMap.find(groupHeader); - if (it == m_entryMap.cend()) { - return m_entryMap.insert(groupHeader, {}); + auto groupHeader = str.sliced(1, str.size() - 2).trimmed(); + decltype(m_entryMap)::iterator it{m_entryMap.end()}; + + QRegularExpression re{R"([^\x20-\x5a-\x5e-\x7e\x5c])"}; + auto matcher = re.match(groupHeader); + if (matcher.hasMatch()) { + return it; } + + auto tmp = m_entryMap.find(groupHeader); + if (tmp == m_entryMap.end()) { + it = m_entryMap.insert(groupHeader, {}); + } + return it; } QString DesktopFile::sourcePath() const noexcept { + if (!m_fileSource) { + return ""; + } + QFileInfo info(*m_fileSource); return info.absoluteFilePath(); } -DesktopErrorCode DesktopEntry::parseEntry(const QString &str, decltype(m_entryMap)::iterator ¤tGroup) noexcept +bool DesktopEntry::isInvalidLocaleString(const QString &str) noexcept { - if (str.startsWith("#")) { - return DesktopErrorCode::NoError; - } + constexpr auto Language = R"((?:[a-z]+))"; // language of locale postfix. eg.(en, zh) + constexpr auto Country = R"((?:_[A-Z]+))"; // country of locale postfix. eg.(US, CN) + constexpr auto Encoding = R"((?:\.[0-9A-Z-]+))"; // encoding of locale postfix. eg.(UFT-8) + constexpr auto Modifier = R"((?:@[a-z=;]+))"; // modifier of locale postfix. eg.(euro;collation=traditional) + const static auto validKey = QString(R"(^%1%2?%3?%4?$)").arg(Language, Country, Encoding, Modifier); + // example: https://regex101.com/r/hylOay/2 + static QRegularExpression re = []() -> QRegularExpression { + QRegularExpression tmp{validKey}; + tmp.optimize(); + return tmp; + }(); + return re.match(str).hasMatch(); +} + +QPair DesktopEntry::processEntry(const QString &str) noexcept +{ auto splitCharIndex = str.indexOf(']'); if (splitCharIndex != -1) { for (; splitCharIndex < str.size(); ++splitCharIndex) { @@ -49,56 +75,97 @@ DesktopErrorCode DesktopEntry::parseEntry(const QString &str, decltype(m_entryMa } auto keyStr = str.first(splitCharIndex).trimmed(); auto valueStr = str.sliced(splitCharIndex + 1).trimmed(); + return qMakePair(std::move(keyStr), std::move(valueStr)); +} + +std::optional> DesktopEntry::processEntryKey(const QString &keyStr) noexcept +{ QString key; - QString valueKey{defaultKeyStr}; - - constexpr auto MainKey = R"re((?[0-9a-zA-Z-]+))re"; // main key. eg.(Name, X-CUSTOM-KEY). - constexpr auto Language = R"re((?:[a-z]+))re"; // language of locale postfix. eg.(en, zh) - constexpr auto Country = R"re((?:_[A-Z]+))re"; // country of locale postfix. eg.(US, CN) - constexpr auto Encoding = R"re((?:\.[0-9A-Z-]+))re"; // encoding of locale postfix. eg.(UFT-8) - constexpr auto Modifier = R"re((?:@[a-z=;]+))re"; // modifier of locale postfix. eg(euro;collation=traditional) - const static auto validKey = - QString("^%1(?:\\[(?%2%3?%4?%5?)\\])?$").arg(MainKey).arg(Language).arg(Country).arg(Encoding).arg(Modifier); - // example: https://regex101.com/r/hylOay/1 - static QRegularExpression re = []() -> QRegularExpression { - QRegularExpression tmp{validKey}; - tmp.optimize(); - return tmp; - }(); - - auto matcher = re.match(keyStr); - if (!matcher.hasMatch()) { -#ifdef DEBUG_MODE - qWarning() << "invalid key: " << keyStr; -#endif - return DesktopErrorCode::EntryKeyInvalid; + QString localeStr; + if (auto index = keyStr.indexOf('['); index != -1) { + key = keyStr.sliced(0, index); + localeStr = keyStr.sliced(index + 1, keyStr.length() - 1 - index - 1); // strip '[' and ']' + } else { + key = keyStr; } - key = matcher.captured("MainKey"); - - if (auto locale = matcher.captured("LOCALE"); !locale.isEmpty()) { - valueKey = locale; + QRegularExpression re{"R([^A-Za-z0-9-])"}; + if (re.match(key).hasMatch()) { + qWarning() << "keyName's format is invalid."; + return std::nullopt; } - auto cur = currentGroup->find(key); - if (cur == currentGroup->end()) { - currentGroup->insert(keyStr, {{valueKey, valueStr}}); + return qMakePair(std::move(key), std::move(localeStr)); +} + +DesktopErrorCode DesktopEntry::parseEntry(const QString &str, decltype(m_entryMap)::iterator ¤tGroup) noexcept +{ + auto [key, value] = processEntry(str); + auto keyPair = processEntryKey(key); + + if (!keyPair.has_value()) { + return DesktopErrorCode::InvalidFormat; + } + + auto [keyName, localeStr] = std::move(keyPair).value(); + if (localeStr.isEmpty()) { + localeStr = defaultKeyStr; + } + + auto valueIt = currentGroup->find(keyName); + if (valueIt == currentGroup->end()) { + currentGroup->insert(keyName, {{localeStr, value}}); return DesktopErrorCode::NoError; } - auto value = cur->find(valueKey); - if (value == cur->end()) { - cur->insert(valueKey, valueStr); + auto innerIt = valueIt->find(localeStr); + if (innerIt == valueIt->end()) { + valueIt->insert(localeStr, value); return DesktopErrorCode::NoError; } qWarning() << "duplicated postfix and this line will be aborted, maybe format is invalid.\n" - << "exist: " << value.key() << "[" << value.value() << "]" - << "current: " << str; + << "exist: " << innerIt.key() << "[" << innerIt.value() << "]" + << "current: " << keyName << "[" << localeStr << "]"; return DesktopErrorCode::NoError; } +bool DesktopEntry::checkMainEntryValidation() const noexcept +{ + auto it = m_entryMap.find(DesktopFileEntryKey); + if (it == m_entryMap.end()) { + return false; + } + + if (auto name = it->find("Name"); name == it->end()) { + qWarning() << "No Name."; + return false; + } + + auto type = it->find("Type"); + if (type == it->end()) { + qWarning() << "No Type."; + for (const auto &[k, v] : it->asKeyValueRange()) { + qInfo() << "keyName:" << k; + for (const auto &[key, value] : v.asKeyValueRange()) { + qInfo() << key << value; + } + } + return false; + } + + const auto &typeStr = *type->find(defaultKeyStr); + + if (typeStr == "Link") { + if (it->find("URL") == it->end()) { + return false; + } + } + + return true; +} + std::optional DesktopFile::createTemporaryDesktopFile(std::unique_ptr temporaryFile) noexcept { auto mtime = getFileModifiedTime(*temporaryFile); @@ -228,9 +295,17 @@ DesktopErrorCode DesktopEntry::parse(DesktopFile &file) noexcept return parse(stream); } +bool DesktopEntry::skipCheck(const QString &line) noexcept +{ + return line.startsWith('#') or line.isEmpty(); +} + DesktopErrorCode DesktopEntry::parse(QTextStream &stream) noexcept { if (stream.atEnd()) { + if (m_context == EntryContext::Done) { + return DesktopErrorCode::NoError; + } return DesktopErrorCode::OpenFailed; } @@ -238,28 +313,74 @@ DesktopErrorCode DesktopEntry::parse(QTextStream &stream) noexcept decltype(m_entryMap)::iterator currentGroup; DesktopErrorCode err{DesktopErrorCode::NoError}; + bool mainEntryParsed{false}; + QString line; + while (!stream.atEnd()) { - auto line = stream.readLine().trimmed(); + switch (m_context) { + case EntryContext::Unknown: { + qWarning() << "entry context is unknown,abort."; + err = DesktopErrorCode::InvalidFormat; + return err; + } break; + case EntryContext::EntryOuter: { + if (skipCheck(line)) { + line = stream.readLine().trimmed(); + continue; + } - if (line.isEmpty()) { - continue; - } + if (line.startsWith('[')) { + auto group = parserGroupHeader(line); - if (line[0] == '[') { - if (!(line[line.size() - 1] == ']')) { - return DesktopErrorCode::GroupHeaderInvalid; - } - currentGroup = parserGroupHeader(line); - continue; - } + if (group == m_entryMap.end()) { + qWarning() << "groupName format error or already exists:" << line; + return DesktopErrorCode::InvalidFormat; + } + currentGroup = group; + bool isMainEntry = (currentGroup.key() == DesktopFileEntryKey); - if (auto error = parseEntry(line, currentGroup); error != DesktopErrorCode::NoError) { - err = error; -#ifdef DEBUG_MODE - qWarning() << "an error occurred,this line will be skipped:" << line; -#endif + if ((!mainEntryParsed and isMainEntry) or (mainEntryParsed and !isMainEntry)) { + m_context = EntryContext::Entry; + continue; + } + } + qWarning() << "groupName format error:" << line; + err = DesktopErrorCode::InvalidFormat; + return err; + } break; + case EntryContext::Entry: { + line = stream.readLine().trimmed(); + + if (skipCheck(line)) { + continue; + } + + if (line.startsWith('[')) { + m_context = EntryContext::EntryOuter; + + if (currentGroup.key() == DesktopFileEntryKey) { + mainEntryParsed = true; + } + continue; + } + + err = parseEntry(line, currentGroup); + if (err != DesktopErrorCode::NoError) { + qWarning() << "Entry format error:" << line; + return err; + } + } break; + case EntryContext::Done: + break; } } + + m_context = EntryContext::Done; + if (!checkMainEntryValidation()) { + qWarning() << "invalid MainEntry, abort."; + err = DesktopErrorCode::MissingInfo; + } + return err; } @@ -425,12 +546,12 @@ QDebug operator<<(QDebug debug, const DesktopErrorCode &v) errMsg = "couldn't open the file."; break; } - case DesktopErrorCode::GroupHeaderInvalid: { - errMsg = "groupHead syntax is invalid."; + case DesktopErrorCode::InvalidFormat: { + errMsg = "the format of desktopEntry file is invalid."; break; } - case DesktopErrorCode::EntryKeyInvalid: { - errMsg = "key syntax is invalid."; + case DesktopErrorCode::MissingInfo: { + errMsg = "missing required infomation."; break; } } diff --git a/src/desktopentry.h b/src/desktopentry.h index b86f8e6..c3ffec5 100644 --- a/src/desktopentry.h +++ b/src/desktopentry.h @@ -15,15 +15,9 @@ constexpr static auto defaultKeyStr = "default"; -enum class DesktopErrorCode { - NoError, - NotFound, - MismatchedFile, - InvalidLocation, - OpenFailed, - GroupHeaderInvalid, - EntryKeyInvalid -}; +enum class DesktopErrorCode { NoError, NotFound, MismatchedFile, InvalidLocation, InvalidFormat, OpenFailed, MissingInfo }; + +enum class EntryContext { Unknown, EntryOuter, Entry, Done }; struct DesktopFileGuard; @@ -104,18 +98,10 @@ private: class DesktopEntry { public: - class Value final : private QMap + class Value final : public QMap { public: using QMap::QMap; - using QMap::find; - using QMap::insert; - using QMap::cbegin; - using QMap::cend; - using QMap::begin; - using QMap::end; - using QMap::asKeyValueRange; - QString toString(bool &ok) const noexcept; bool toBoolean(bool &ok) const noexcept; QString toIconString(bool &ok) const noexcept; @@ -138,11 +124,18 @@ public: [[nodiscard]] DesktopErrorCode parse(QTextStream &stream) noexcept; [[nodiscard]] std::optional> group(const QString &key) const noexcept; [[nodiscard]] std::optional value(const QString &key, const QString &valueKey) const noexcept; + static bool isInvalidLocaleString(const QString &str) noexcept; private: + EntryContext m_context{EntryContext::EntryOuter}; QMap> m_entryMap; + auto parserGroupHeader(const QString &str) noexcept; + [[nodiscard]] bool checkMainEntryValidation() const noexcept; + static bool skipCheck(const QString &line) noexcept; static DesktopErrorCode parseEntry(const QString &str, decltype(m_entryMap)::iterator ¤tGroup) noexcept; + static QPair processEntry(const QString &str) noexcept; + static std::optional> processEntryKey(const QString &keyStr) noexcept; }; QDebug operator<<(QDebug debug, const DesktopEntry::Value &v); diff --git a/src/global.h b/src/global.h index f118f9a..a955791 100644 --- a/src/global.h +++ b/src/global.h @@ -27,7 +27,13 @@ Q_DECLARE_LOGGING_CATEGORY(DDEAMProf) using IconMap = QMap>>; -using ObjectMap = QMap; +using ObjectInterfaceMap = QMap; +using ObjectMap = QMap; +using PropMap = QMap>; + +Q_DECLARE_METATYPE(ObjectInterfaceMap) +Q_DECLARE_METATYPE(ObjectMap) +Q_DECLARE_METATYPE(PropMap) inline QString getApplicationLauncherBinary() { @@ -200,17 +206,39 @@ inline QString getDBusInterface(const QMetaType &meta) return {}; } -inline QStringList getInterfacesListFromObject(QObject *o) +inline ObjectInterfaceMap getChildInterfacesAndPropertiesFromObject(QObject *o) { auto childs = o->children(); - QStringList interfaces; - std::for_each(childs.cbegin(), childs.cend(), [&interfaces](QObject *app) { + ObjectInterfaceMap ret; + + std::for_each(childs.cbegin(), childs.cend(), [&ret](QObject *app) { if (app->inherits("QDBusAbstractAdaptor")) { - interfaces.emplace_back(getDBusInterface(app->metaObject()->metaType())); + auto interface = getDBusInterface(app->metaObject()->metaType()); + QVariantMap properties; + const auto *mo = app->metaObject(); + for (int i = mo->propertyOffset(); i < mo->propertyCount(); ++i) { + auto prop = mo->property(i); + properties.insert(prop.name(), prop.read(app)); + } + ret.insert(interface, properties); } }); - return interfaces; + return ret; +} + +inline QStringList getChildInterfacesFromObject(QObject *o) +{ + auto childs = o->children(); + QStringList ret; + + std::for_each(childs.cbegin(), childs.cend(), [&ret](QObject *app) { + if (app->inherits("QDBusAbstractAdaptor")) { + ret.append(getDBusInterface(app->metaObject()->metaType())); + } + }); + + return ret; } inline uid_t getCurrentUID() @@ -399,8 +427,8 @@ ObjectMap dumpDBusObject(const QMap> &map) ObjectMap objs; for (const auto &[key, value] : map.asKeyValueRange()) { - auto interfaces = getInterfacesListFromObject(value.data()); - objs.insert(key, interfaces); + auto interAndProps = getChildInterfacesAndPropertiesFromObject(value.data()); + objs.insert(key, interAndProps); } return objs;