File indexing completed on 2024-04-21 04:58:10
0001 /* 0002 SPDX-FileCopyrightText: 2009 David Faure <faure@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL 0005 */ 0006 0007 #include "module_manager.h" 0008 #include <kdesktopfile.h> 0009 #include <kio/deletejob.h> 0010 #include <kconfig.h> 0011 #include <kconfiggroup.h> 0012 #include <QDir> 0013 #include <QUrl> 0014 #include <QStandardPaths> 0015 #include <KSharedConfig> 0016 0017 #include "sidebar_debug.h" 0018 0019 // Input data: 0020 // Global dir: list of desktop files. 0021 // Local dir: list of desktop files, for modules added or modified 0022 // (When the user modifies something, we make a local copy) 0023 // Local KConfig file: config file with list (per profile) of "added" and "removed" desktop files 0024 0025 // Algorithm: 0026 // Then we create buttons: 0027 // * desktop files from the most-global directory (pre-installed modules), 0028 // skipping those listed as "removed" 0029 // * desktop files from other (more local) directories, if listed as "added" (for the current profile). 0030 // 0031 // (module not present globally and not "added" are either modified copies of 0032 // not-installed-anymore modules, or modules that were only added for another profile). 0033 0034 ModuleManager::ModuleManager(KConfigGroup *config) 0035 : m_config(config) 0036 { 0037 m_localPath = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1Char('/') + relativeDataPath(); 0038 } 0039 0040 QStringList ModuleManager::modules() const 0041 { 0042 QStringList fileNames; 0043 const QStringList addedModules = m_config->readEntry("AddedModules", QStringList()); 0044 const QStringList deletedModules = m_config->readEntry("DeletedModules", QStringList()); 0045 0046 const QStringList entries_dirs = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, relativeDataPath(), QStandardPaths::LocateDirectory); 0047 if (entries_dirs.isEmpty()) { // Ooops 0048 qCWarning(SIDEBAR_LOG) << "No global directory found for" << relativeDataPath() << "Installation problem!"; 0049 return QStringList(); 0050 } 0051 // We only list the most-global dir. Other levels use AddedModules. 0052 QDir globalDir(entries_dirs.last()); 0053 //qCDebug(SIDEBAR_LOG) << "Listing" << entries_dirs.last(); 0054 const QStringList globalDirEntries = globalDir.entryList(QDir::Files | QDir::NoDotAndDotDot); 0055 for (const QString &globalEntry: globalDirEntries) { 0056 //qCDebug(SIDEBAR_LOG) << " found" << globalEntry; 0057 if (!deletedModules.contains(globalEntry)) { 0058 fileNames.append(globalEntry); 0059 } 0060 } 0061 sortGlobalEntries(fileNames); 0062 //qCDebug(SIDEBAR_LOG) << "Adding local modules:" << addedModules; 0063 for (const QString &module: addedModules) { 0064 if (!fileNames.contains(module)) { 0065 fileNames.append(module); 0066 } 0067 } 0068 0069 return fileNames; 0070 } 0071 0072 QVector<KPluginMetaData> ModuleManager::availablePlugins() const 0073 { 0074 return KPluginMetaData::findPlugins(pluginDirectory()); 0075 } 0076 0077 QString ModuleManager::moduleDataPath(const QString &fileName) const 0078 { 0079 return relativeDataPath() + fileName; 0080 } 0081 0082 QString ModuleManager::moduleFullPath(const QString &fileName) const 0083 { 0084 return QStandardPaths::locate(QStandardPaths::GenericDataLocation, moduleDataPath(fileName)); 0085 } 0086 0087 void ModuleManager::saveOpenViews(const QStringList &fileName) 0088 { 0089 // TODO: this would be best stored per-window, in the session file 0090 0091 m_config->writeEntry("OpenViews", fileName); 0092 m_config->sync(); 0093 } 0094 0095 void ModuleManager::restoreDeletedButtons() 0096 { 0097 m_config->writeEntry("DeletedModules", QStringList()); 0098 m_config->sync(); 0099 } 0100 0101 void ModuleManager::rollbackToDefault() 0102 { 0103 const QString loc = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + "/konqsidebartng/"; 0104 QDir dir(loc); 0105 const QStringList dirEntries = dir.entryList(QDir::Dirs | QDir::NoSymLinks | QDir::NoDotAndDotDot); 0106 for (const QString &subdir: dirEntries) { 0107 if (subdir != "add") { 0108 qCDebug(SIDEBAR_LOG) << "Deleting" << (loc + subdir); 0109 KIO::Job *job = KIO::del(QUrl::fromLocalFile(loc + subdir), KIO::HideProgressInfo); 0110 job->exec(); 0111 } 0112 } 0113 m_config->writeEntry("DeletedModules", QStringList()); 0114 m_config->writeEntry("AddedModules", QStringList()); 0115 m_config->sync(); 0116 } 0117 0118 void ModuleManager::setModuleName(const QString &fileName, const QString &moduleName) 0119 { 0120 // Write the name in the .desktop file of this button. 0121 KConfig desktopFile(m_localPath + fileName, KConfig::SimpleConfig); 0122 KConfigGroup ksc(&desktopFile, "Desktop Entry"); 0123 ksc.writeEntry("Name", moduleName); 0124 ksc.writeEntry("Name", moduleName, KConfigBase::Persistent | KConfigBase::Localized); 0125 ksc.sync(); 0126 } 0127 0128 void ModuleManager::setModuleUrl(const QString &fileName, const QUrl &url) 0129 { 0130 KConfig desktopFile(m_localPath + fileName, KConfig::SimpleConfig); 0131 KConfigGroup ksc(&desktopFile, "Desktop Entry"); 0132 ksc.writePathEntry("URL", url.toDisplayString()); 0133 ksc.sync(); 0134 } 0135 0136 void ModuleManager::setModuleIcon(const QString &fileName, const QString &icon) 0137 { 0138 KConfig desktopFile(m_localPath + fileName, KConfig::SimpleConfig); 0139 KConfigGroup ksc(&desktopFile, "Desktop Entry"); 0140 ksc.writePathEntry("Icon", icon); 0141 ksc.sync(); 0142 } 0143 0144 void ModuleManager::setShowHiddenFolders(const QString &fileName, const bool &newState) 0145 { 0146 KConfig desktopFile(m_localPath + fileName, KConfig::SimpleConfig); 0147 KConfigGroup ksc(&desktopFile, "Desktop Entry"); 0148 ksc.writeEntry("ShowHiddenFolders", newState); 0149 ksc.sync(); 0150 } 0151 0152 int ModuleManager::getMaxKDEWeight() 0153 { 0154 int curMax = 1; // 0 is reserved for the treeModule 0155 for (const QString &fileName : modules()) { 0156 const QString path = moduleDataPath(fileName); 0157 if (! QStandardPaths::locate(QStandardPaths::GenericDataLocation, path).isEmpty()) { 0158 KSharedConfig::Ptr config = KSharedConfig::openConfig(path, 0159 KConfig::NoGlobals, 0160 QStandardPaths::GenericDataLocation); 0161 KConfigGroup configGroup(config, "Desktop Entry"); 0162 const int weight = configGroup.readEntry("X-KDE-Weight", 0); 0163 if (curMax < weight) { 0164 curMax = weight; 0165 } 0166 } 0167 } 0168 return curMax; 0169 } 0170 0171 int ModuleManager::getNextAvailableKDEWeight() 0172 { 0173 return getMaxKDEWeight() + 1; 0174 } 0175 0176 void ModuleManager::removeModule(const QString &fileName) 0177 { 0178 // Remove the local file (if it exists) 0179 QFile f(m_localPath + fileName); 0180 f.remove(); 0181 0182 // Mark module as deleted (so that we skip global file, if there's one) 0183 QStringList deletedModules = m_config->readEntry("DeletedModules", QStringList()); 0184 QStringList addedModules = m_config->readEntry("AddedModules", QStringList()); 0185 if ( !addedModules.contains(fileName) && !deletedModules.contains(fileName)) { // only add it to the "deletedModules" list if it is a global module 0186 deletedModules.append(fileName); 0187 } 0188 0189 addedModules.removeAll(fileName); 0190 m_config->writeEntry("DeletedModules", deletedModules); 0191 m_config->writeEntry("AddedModules", addedModules); 0192 m_config->sync(); 0193 } 0194 0195 void ModuleManager::moduleAdded(const QString &fileName) 0196 { 0197 qCDebug(SIDEBAR_LOG) << fileName; 0198 QStringList deletedModules = m_config->readEntry("DeletedModules", QStringList()); 0199 QStringList addedModules = m_config->readEntry("AddedModules", QStringList()); 0200 if (!addedModules.contains(fileName)) { 0201 addedModules.append(fileName); 0202 } 0203 deletedModules.removeAll(fileName); 0204 m_config->writeEntry("DeletedModules", deletedModules); 0205 m_config->writeEntry("AddedModules", addedModules); 0206 m_config->sync(); 0207 } 0208 0209 QString ModuleManager::addModuleFromTemplate(QString &templ) 0210 { 0211 if (!templ.contains("%1")) { 0212 qCWarning(SIDEBAR_LOG) << "Template filename should contain %1"; 0213 } 0214 0215 QString filename = templ.arg(QString()); 0216 QString myFile = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1Char('/') + moduleDataPath(filename); 0217 0218 if (QFile::exists(myFile)) { 0219 for (ulong l = 1; l < ULONG_MAX; l++) { 0220 filename = templ.arg(l); 0221 myFile = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1Char('/') + moduleDataPath(filename); 0222 if (!QFile::exists(myFile)) { 0223 break; 0224 } else { 0225 filename.clear(); 0226 myFile.clear(); 0227 } 0228 } 0229 } 0230 templ = filename; 0231 return myFile; 0232 } 0233 0234 QStringList ModuleManager::localModulePaths(const QString &filter) const 0235 { 0236 return QDir(m_localPath).entryList(QStringList() << filter); 0237 } 0238 0239 void ModuleManager::sortGlobalEntries(QStringList &fileNames) const 0240 { 0241 QMap<int, QString> sorter; 0242 for (const QString &fileName: fileNames) { 0243 const QString path = moduleDataPath(fileName); 0244 if (QStandardPaths::locate(QStandardPaths::GenericDataLocation, path).isEmpty()) { 0245 // doesn't exist anymore, skip it 0246 qCDebug(SIDEBAR_LOG) << "Skipping" << path; 0247 } else { 0248 KSharedConfig::Ptr config = KSharedConfig::openConfig(path, 0249 KConfig::NoGlobals, 0250 QStandardPaths::GenericDataLocation); 0251 KConfigGroup configGroup(config, "Desktop Entry"); 0252 const int weight = configGroup.readEntry("X-KDE-Weight", 0); 0253 sorter.insert(weight, fileName); 0254 0255 // While we have the config file open, fix migration issue between old and new history sidebar 0256 if (configGroup.readEntry("X-KDE-TreeModule") == "History") { 0257 // Old local file still there; remove it 0258 const QString localFile = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1Char('/') + path; 0259 QFile::rename(localFile, localFile + ".orig"); 0260 qCDebug(SIDEBAR_LOG) << "Migration: moving" << localFile << "out of the way"; 0261 } 0262 } 0263 } 0264 fileNames = sorter.values(); 0265 qCDebug(SIDEBAR_LOG) << fileNames; 0266 }