File indexing completed on 2025-02-16 04:48:49
0001 /* 0002 * fileresourceconfigmanager.cpp - config manager for resources accessed via file system 0003 * Program: kalarm 0004 * SPDX-FileCopyrightText: 2020-2023 David Jarvie <djarvie@kde.org> 0005 * 0006 * SPDX-License-Identifier: GPL-2.0-or-later 0007 */ 0008 0009 #include "fileresourceconfigmanager.h" 0010 0011 #include "resources.h" 0012 #include "singlefileresource.h" 0013 #include "fileresourcecalendarupdater.h" 0014 #include "kalarm_debug.h" 0015 0016 #include <KConfig> 0017 #include <KConfigGroup> 0018 0019 #include <QRegularExpression> 0020 0021 namespace 0022 { 0023 // Config file keys 0024 const QLatin1String GENERAL_GROUP("General"); 0025 const char* KEY_LASTID = "LastId"; 0026 } 0027 0028 FileResourceConfigManager* FileResourceConfigManager::mInstance {nullptr}; 0029 0030 /****************************************************************************** 0031 * Creates and returns the unique instance. 0032 */ 0033 FileResourceConfigManager* FileResourceConfigManager::instance() 0034 { 0035 if (!mInstance) 0036 mInstance = new FileResourceConfigManager; 0037 return mInstance; 0038 } 0039 0040 /****************************************************************************** 0041 * Constructor. Reads the current config and creates all resources. 0042 */ 0043 FileResourceConfigManager::FileResourceConfigManager() 0044 { 0045 mConfig = new KConfig(QStringLiteral("kalarmresources")); 0046 } 0047 0048 /****************************************************************************** 0049 * Read the current config and create all resources. 0050 */ 0051 void FileResourceConfigManager::createResources(QObject* parent) 0052 { 0053 FileResourceConfigManager* manager = instance(); 0054 if (manager->mCreated) 0055 return; 0056 manager->mCreated = 1; 0057 0058 static const QRegularExpression re(QStringLiteral("^Resource_\\d+$")); 0059 QStringList resourceGroups = manager->mConfig->groupList().filter(re); 0060 if (!resourceGroups.isEmpty()) 0061 { 0062 std::sort(resourceGroups.begin(), resourceGroups.end(), 0063 [](const QString& g1, const QString& g2) 0064 { 0065 return QStringView(g1).mid(9).toInt() < QStringView(g2).mid(9).toInt(); 0066 }); 0067 0068 KConfigGroup general(manager->mConfig, GENERAL_GROUP); 0069 manager->mLastId = general.readEntry(KEY_LASTID, 0) | ResourceType::IdFlag; 0070 0071 for (const QString& resourceGroup : std::as_const(resourceGroups)) 0072 { 0073 const int groupIndex = QStringView(resourceGroup).mid(9).toInt(); 0074 FileResourceSettings::Ptr settings(new FileResourceSettings(manager->mConfig, resourceGroup)); 0075 if (!settings->isValid()) 0076 { 0077 qCWarning(KALARM_LOG) << "FileResourceConfigManager: Invalid config for" << resourceGroup; 0078 manager->mConfig->deleteGroup(resourceGroup); // invalid config for this resource 0079 } 0080 else 0081 { 0082 // Check for and remove duplicate URL or 'standard' setting 0083 for (auto it = manager->mResources.constBegin(); it != manager->mResources.constEnd(); ++it) 0084 { 0085 const ResourceData& data = it.value(); 0086 if (settings->url() == data.resource.location()) 0087 { 0088 qCWarning(KALARM_LOG) << "FileResourceConfigManager: Duplicate URL in config for" << resourceGroup; 0089 manager->mConfig->deleteGroup(resourceGroup); // invalid config for this resource 0090 qCWarning(KALARM_LOG) << "FileResourceConfigManager: Deleted duplicate resource" << settings->displayName(); 0091 settings.clear(); 0092 break; 0093 } 0094 const CalEvent::Types std = settings->standardTypes() & data.settings->standardTypes(); 0095 if (std) 0096 { 0097 qCWarning(KALARM_LOG) << "FileResourceConfigManager: Duplicate 'standard' setting in config for" << resourceGroup; 0098 settings->setStandard(settings->standardTypes() ^ std); 0099 } 0100 } 0101 if (settings) 0102 { 0103 Resource resource(createResource(settings)); 0104 manager->mResources[settings->id()] = ResourceData(resource, settings); 0105 manager->mConfigGroups[groupIndex] = settings->id(); 0106 0107 Resources::notifyNewResourceInitialised(resource); 0108 0109 // Update the calendar to the current KAlarm format if necessary, and 0110 // if the user agrees. 0111 FileResourceCalendarUpdater::updateToCurrentFormat(resource, false, parent); 0112 } 0113 } 0114 } 0115 manager->mConfig->sync(); 0116 0117 // Allow any calendar updater instances to complete and auto-delete. 0118 FileResourceCalendarUpdater::waitForCompletion(); 0119 } 0120 manager->mCreated = 2; 0121 } 0122 0123 /****************************************************************************** 0124 * Destructor. Writes the current config. 0125 */ 0126 FileResourceConfigManager::~FileResourceConfigManager() 0127 { 0128 writeConfig(); 0129 delete mConfig; 0130 mInstance = nullptr; 0131 } 0132 0133 /****************************************************************************** 0134 * Writes the 'kalarmresources' config file. 0135 */ 0136 void FileResourceConfigManager::writeConfig() 0137 { 0138 // No point in writing unless the config has already been read! 0139 if (mInstance) 0140 mInstance->mConfig->sync(); 0141 } 0142 0143 /****************************************************************************** 0144 * Return the IDs of all calendar resources. 0145 */ 0146 QList<ResourceId> FileResourceConfigManager::resourceIds() 0147 { 0148 return instance()->mResources.keys(); 0149 } 0150 0151 /****************************************************************************** 0152 * Create a new calendar resource with the given settings. 0153 */ 0154 Resource FileResourceConfigManager::addResource(FileResourceSettings::Ptr& settings) 0155 { 0156 // Find the first unused config group name index. 0157 FileResourceConfigManager* manager = instance(); 0158 int lastIndex = 0; 0159 for (auto it = manager->mConfigGroups.constBegin(); it != manager->mConfigGroups.constEnd(); ++it) 0160 { 0161 const int index = it.key(); 0162 if (index > lastIndex + 1) 0163 break; 0164 lastIndex = index; 0165 } 0166 const int groupIndex = lastIndex + 1; 0167 0168 // Get a unique ID. 0169 const int id = ++manager->mLastId; 0170 settings->setId(id); 0171 // Save the new last-used ID, but strip out IdFlag to make it more legible. 0172 KConfigGroup general(manager->mConfig, GENERAL_GROUP); 0173 general.writeEntry(KEY_LASTID, id & ~ResourceType::IdFlag); 0174 0175 const QString configGroup = groupName(groupIndex); 0176 settings->createConfig(manager->mConfig, configGroup); 0177 manager->mConfigGroups[groupIndex] = id; 0178 Resource resource(createResource(settings)); 0179 manager->mResources[id] = ResourceData(resource, settings); 0180 0181 Resources::notifyNewResourceInitialised(resource); 0182 return resource; 0183 } 0184 0185 /****************************************************************************** 0186 * Delete a calendar resource and its settings. 0187 */ 0188 bool FileResourceConfigManager::removeResource(Resource& resource) 0189 { 0190 if (resource.isValid()) 0191 { 0192 FileResourceConfigManager* manager = instance(); 0193 const ResourceId id = resource.id(); 0194 const int groupIndex = manager->findResourceGroup(id); 0195 if (groupIndex >= 0) 0196 { 0197 const QString configGroup = groupName(groupIndex); 0198 manager->mConfig->deleteGroup(configGroup); 0199 manager->mConfig->sync(); 0200 manager->mConfigGroups.remove(groupIndex); 0201 Resources::notifySettingsDestroyed(id); // removing from mResources will destroy settings instance 0202 manager->mResources.remove(id); 0203 return true; 0204 } 0205 } 0206 return false; 0207 } 0208 0209 /****************************************************************************** 0210 * Return the available file system resource types handled by the manager. 0211 */ 0212 QList<ResourceType::Storage> FileResourceConfigManager::storageTypes() 0213 { 0214 return { ResourceType::Storage::File 0215 // , ResourceType::Storage::Directory // not currently intended to be implemented 0216 }; 0217 } 0218 0219 /****************************************************************************** 0220 * Find the config group for a resource ID. 0221 */ 0222 int FileResourceConfigManager::findResourceGroup(ResourceId id) const 0223 { 0224 for (auto it = mConfigGroups.constBegin(); it != mConfigGroups.constEnd(); ++it) 0225 if (it.value() == id) 0226 return it.key(); 0227 return -1; 0228 } 0229 0230 /****************************************************************************** 0231 * Return the config group name for a given config group index. 0232 */ 0233 QString FileResourceConfigManager::groupName(int groupIndex) 0234 { 0235 return QStringLiteral("Resource_%1").arg(groupIndex); 0236 } 0237 0238 /****************************************************************************** 0239 * Create a new resource with the given settings. 0240 */ 0241 Resource FileResourceConfigManager::createResource(FileResourceSettings::Ptr& settings) 0242 { 0243 switch (settings->storageType()) 0244 { 0245 case FileResourceSettings::File: 0246 return SingleFileResource::create(settings); 0247 case FileResourceSettings::Directory: // not currently intended to be implemented 0248 default: 0249 return Resource::null(); 0250 } 0251 } 0252 0253 // vim: et sw=4: