1 // SPDX-License-Identifier: GPL-3.0-or-later 2 // SPDX-FileCopyrightText: 2017-2019 Alejandro Sirgo Rica & Contributors 3 4 #include "desktopfileparse.h" 5 #include <QDir> 6 #include <QFile> 7 #include <QLocale> 8 #include <QString> 9 #include <QTextStream> 10 DesktopFileParser()11DesktopFileParser::DesktopFileParser() 12 { 13 QString locale = QLocale().name(); 14 QString localeShort = QLocale().name().left(2); 15 m_localeName = QStringLiteral("Name[%1]").arg(locale); 16 m_localeDescription = QStringLiteral("Comment[%1]").arg(locale); 17 m_localeNameShort = QStringLiteral("Name[%1]").arg(localeShort); 18 m_localeDescriptionShort = QStringLiteral("Comment[%1]").arg(localeShort); 19 m_defaultIcon = 20 QIcon::fromTheme(QStringLiteral("application-x-executable")); 21 } 22 parseDesktopFile(const QString & fileName,bool & ok) const23DesktopAppData DesktopFileParser::parseDesktopFile(const QString& fileName, 24 bool& ok) const 25 { 26 DesktopAppData res; 27 ok = true; 28 QFile file(fileName); 29 if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { 30 ok = false; 31 return res; 32 } 33 bool nameLocaleSet = false; 34 bool descriptionLocaleSet = false; 35 bool isApplication = false; 36 QTextStream in(&file); 37 // enter the desktop entry definition 38 while (!in.atEnd() && in.readLine() != QLatin1String("[Desktop Entry]")) { 39 } 40 // start parsing 41 while (!in.atEnd()) { 42 QString line = in.readLine(); 43 if (line.startsWith(QLatin1String("Icon"))) { 44 res.icon = QIcon::fromTheme( 45 line.mid(line.indexOf(QLatin1String("=")) + 1).trimmed(), 46 m_defaultIcon); 47 } else if (!nameLocaleSet && line.startsWith(QLatin1String("Name"))) { 48 if (line.startsWith(m_localeName) || 49 line.startsWith(m_localeNameShort)) { 50 res.name = 51 line.mid(line.indexOf(QLatin1String("=")) + 1).trimmed(); 52 nameLocaleSet = true; 53 } else if (line.startsWith(QLatin1String("Name="))) { 54 res.name = 55 line.mid(line.indexOf(QLatin1String("=")) + 1).trimmed(); 56 } 57 } else if (!descriptionLocaleSet && 58 line.startsWith(QLatin1String("Comment"))) { 59 if (line.startsWith(m_localeDescription) || 60 line.startsWith(m_localeDescriptionShort)) { 61 res.description = 62 line.mid(line.indexOf(QLatin1String("=")) + 1).trimmed(); 63 descriptionLocaleSet = true; 64 } else if (line.startsWith(QLatin1String("Comment="))) { 65 res.description = 66 line.mid(line.indexOf(QLatin1String("=")) + 1).trimmed(); 67 } 68 } else if (line.startsWith(QLatin1String("Exec"))) { 69 if (line.contains(QLatin1String("%"))) { 70 res.exec = 71 line.mid(line.indexOf(QLatin1String("=")) + 1).trimmed(); 72 } else { 73 ok = false; 74 break; 75 } 76 } else if (line.startsWith(QLatin1String("Type"))) { 77 if (line.contains(QLatin1String("Application"))) { 78 isApplication = true; 79 } 80 } else if (line.startsWith(QLatin1String("Categories"))) { 81 res.categories = line.mid(line.indexOf(QLatin1String("=")) + 1) 82 .split(QStringLiteral(";")); 83 } else if (line == QLatin1String("NoDisplay=true")) { 84 ok = false; 85 break; 86 } else if (line == QLatin1String("Terminal=true")) { 87 res.showInTerminal = true; 88 } 89 // ignore the other entries 90 else if (line.startsWith(QLatin1String("["))) { 91 break; 92 } 93 } 94 file.close(); 95 if (res.exec.isEmpty() || res.name.isEmpty() || !isApplication) { 96 ok = false; 97 } 98 return res; 99 } 100 processDirectory(const QDir & dir)101int DesktopFileParser::processDirectory(const QDir& dir) 102 { 103 QStringList entries = dir.entryList(QDir::NoDotAndDotDot | QDir::Files); 104 bool ok; 105 int length = m_appList.length(); 106 for (QString file : entries) { 107 DesktopAppData app = parseDesktopFile(dir.absoluteFilePath(file), ok); 108 if (ok) { 109 m_appList.append(app); 110 } 111 } 112 return m_appList.length() - length; 113 } 114 getAppsByCategory(const QString & category)115QVector<DesktopAppData> DesktopFileParser::getAppsByCategory( 116 const QString& category) 117 { 118 QVector<DesktopAppData> res; 119 for (const DesktopAppData& app : m_appList) { 120 if (app.categories.contains(category)) { 121 res.append(app); 122 } 123 } 124 return res; 125 } 126 getAppsByCategory(const QStringList & categories)127QMap<QString, QVector<DesktopAppData>> DesktopFileParser::getAppsByCategory( 128 const QStringList& categories) 129 { 130 QMap<QString, QVector<DesktopAppData>> res; 131 for (const DesktopAppData& app : m_appList) { 132 for (const QString& category : categories) { 133 if (app.categories.contains(category)) { 134 res[category].append(app); 135 } 136 } 137 } 138 return res; 139 } 140