33// SPDX-License-Identifier: LGPL-3.0-or-later
44
55#include " configloader.h"
6- #include " core/shortcutconfig.h"
76
87#include < algorithm>
98
@@ -24,6 +23,12 @@ const QString CONFIG_SUBPATH_DIR = "/usr/share/deepin/org.deepin.dde.keybinding/
2423
2524DCORE_USE_NAMESPACE
2625
26+ static DConfig *createDConfig (const QString &name, const QString &subPath, QObject *parent)
27+ {
28+ const QString normalized = CustomShortcutStore::normalizeSubPath (subPath);
29+ return DConfig::create (APP_ID , name, QStringLiteral (" /" ) + normalized, parent);
30+ }
31+
2732ConfigLoader::ConfigLoader (QObject *parent)
2833 : QObject(parent)
2934{
@@ -106,22 +111,36 @@ void ConfigLoader::resetHotkeys(const QStringList &ids)
106111 }
107112}
108113
109- void ConfigLoader::updateValue (const QString &id, const QString &key, const QVariant &value)
114+ bool ConfigLoader::updateValue (const QString &id, const QString &key, const QVariant &value)
110115{
111116 if (!m_configs.contains (id)) {
112117 qWarning () << " ConfigLoader: config not found or can not be changed:" << id << key << value;
113- return ;
118+ return false ;
114119 }
115120
116121 m_configs[id]->setValue (key, value);
122+ return true ;
123+ }
124+
125+ bool ConfigLoader::canUpdateValue (const QString &id) const
126+ {
127+ return m_configs.contains (id);
117128}
118129
119130QSet<QString> ConfigLoader::discoverSubPaths ()
120131{
121- // Accumulate all found subpaths
122132 QSet<QString> foundSubPaths;
133+ foundSubPaths.unite (scanIniSubPaths (CONFIG_SUBPATH_DIR ));
134+ foundSubPaths.unite (m_customStore.discoverSubPaths ());
123135
124- QDir regDir (CONFIG_SUBPATH_DIR );
136+ return foundSubPaths;
137+ }
138+
139+ QSet<QString> ConfigLoader::scanIniSubPaths (const QString &dirPath)
140+ {
141+ QSet<QString> foundSubPaths;
142+
143+ QDir regDir (dirPath);
125144 if (!regDir.exists ()) {
126145 return foundSubPaths;
127146 }
@@ -132,7 +151,7 @@ QSet<QString> ConfigLoader::discoverSubPaths()
132151 static const QRegularExpression reContinuation (QStringLiteral (" \\\\\\ s*\\ n" ));
133152 QStringList iniFiles = regDir.entryList (QStringList () << " *.ini" , QDir::Files | QDir::NoDotAndDotDot);
134153 for (const QString &iniFile : iniFiles) {
135- QString fullPath = QDir ( CONFIG_SUBPATH_DIR ) .absoluteFilePath (iniFile);
154+ QString fullPath = regDir .absoluteFilePath (iniFile);
136155 QFile file (fullPath);
137156 if (!file.open (QIODevice::ReadOnly | QIODevice::Text)) {
138157 qWarning () << " ConfigLoader: Failed to open" << fullPath;
@@ -182,6 +201,122 @@ QSet<QString> ConfigLoader::discoverSubPaths()
182201 return foundSubPaths;
183202}
184203
204+ bool ConfigLoader::saveCustomShortcut (const KeyConfig &config)
205+ {
206+ const QString subPath = CustomShortcutStore::normalizeSubPath (config.subPath );
207+ DConfig *customDconfig = m_configs.value (subPath);
208+ const bool existingDConfig = customDconfig;
209+ if (!customDconfig) {
210+ customDconfig = m_customStore.createConfig (subPath, this );
211+ if (!customDconfig)
212+ return false ;
213+ if (!customDconfig->isValid ()) {
214+ qWarning () << " ConfigLoader: failed to create custom shortcut DConfig:" << subPath;
215+ delete customDconfig;
216+ return false ;
217+ }
218+ }
219+
220+ KeyConfig storedConfig = config;
221+ storedConfig.subPath = subPath;
222+ if (!m_customStore.save (storedConfig, customDconfig)) {
223+ if (!existingDConfig) {
224+ m_customStore.reset (customDconfig, subPath);
225+ customDconfig->deleteLater ();
226+ }
227+ return false ;
228+ }
229+
230+ auto existing = std::find_if (m_keys.begin (), m_keys.end (),
231+ [&](const KeyConfig &item) { return item.subPath == subPath; });
232+ if (existing != m_keys.end ())
233+ *existing = storedConfig;
234+ else
235+ m_keys.append (storedConfig);
236+
237+ m_loadedSubPaths.insert (subPath);
238+ if (!m_configs.contains (subPath)) {
239+ connect (customDconfig, &DConfig::valueChanged, this , [this , subPath, customDconfig](const QString &key) {
240+ if (!customDconfig->isValid () || !m_configs.contains (subPath)) {
241+ qWarning () << " DConfig invalid or not found:" << subPath;
242+ return ;
243+ }
244+
245+ KeyConfig updatedConfig = parseKeyConfig (customDconfig);
246+ qDebug () << " DConfig value changed:" << subPath << key;
247+ auto existing = std::find_if (m_keys.begin (), m_keys.end (),
248+ [&](const KeyConfig &item) { return item.subPath == subPath; });
249+ if (existing != m_keys.end ()) {
250+ *existing = updatedConfig;
251+ } else {
252+ m_keys.append (updatedConfig);
253+ }
254+ emit keyConfigChanged (updatedConfig);
255+ });
256+ m_configs.insert (subPath, customDconfig);
257+ }
258+
259+ return true ;
260+ }
261+
262+ bool ConfigLoader::updateCustomShortcut (const KeyConfig &config)
263+ {
264+ const QString subPath = CustomShortcutStore::normalizeSubPath (config.subPath );
265+ DConfig *customDconfig = m_configs.value (subPath);
266+ if (!customDconfig) {
267+ qWarning () << " ConfigLoader: custom shortcut config not found for update:" << subPath;
268+ return false ;
269+ }
270+
271+ KeyConfig storedConfig = config;
272+ storedConfig.subPath = subPath;
273+ if (!m_customStore.updateCustomShortcutFields (storedConfig, customDconfig))
274+ return false ;
275+
276+ auto existing = std::find_if (m_keys.begin (), m_keys.end (),
277+ [&](const KeyConfig &item) { return item.subPath == subPath; });
278+ if (existing != m_keys.end ())
279+ *existing = storedConfig;
280+ else
281+ m_keys.append (storedConfig);
282+
283+ m_loadedSubPaths.insert (subPath);
284+ return true ;
285+ }
286+
287+ bool ConfigLoader::removeCustomShortcut (const QString &subPath)
288+ {
289+ const QString normalized = CustomShortcutStore::normalizeSubPath (subPath);
290+ if (normalized.isEmpty ()) {
291+ return false ;
292+ }
293+
294+ DConfig *config = m_configs.take (normalized);
295+ if (!config || !config->isValid ()) {
296+ qWarning () << " ConfigLoader: custom shortcut config not found for removal:" << subPath;
297+ if (config) config->deleteLater ();
298+ return false ;
299+ } else {
300+ disconnect (config, nullptr , this , nullptr );
301+ }
302+
303+ m_customStore.reset (config, normalized);
304+ if (!m_customStore.removeSubPath (normalized)) {
305+ qWarning () << " ConfigLoader: failed to remove custom shortcut subPath after reset,"
306+ << " leaving a stale ini entry:" << normalized;
307+ }
308+
309+ m_loadedSubPaths.remove (normalized);
310+ m_keys.erase (std::remove_if (m_keys.begin (), m_keys.end (),
311+ [&](const KeyConfig &config) { return config.subPath == normalized; }),
312+ m_keys.end ());
313+
314+ if (config)
315+ config->deleteLater ();
316+
317+ return true ;
318+ }
319+
185320void ConfigLoader::loadConfig (const QString &subPath, bool newOne)
186321{
187322 qDebug () << " Loading config from:" << subPath;
@@ -199,9 +334,8 @@ void ConfigLoader::loadConfig(const QString &subPath, bool newOne)
199334 return ;
200335 }
201336
202- DConfig *config = DConfig::create (APP_ID ,
203- isKey ? CONFIG_NAME_SHORTCUT : CONFIG_NAME_GESTURE ,
204- " /" + subPath, this );
337+ DConfig *config = createDConfig (isKey ? CONFIG_NAME_SHORTCUT : CONFIG_NAME_GESTURE ,
338+ subPath, this );
205339 if (!config->isValid ()) {
206340 qWarning () << " Failed to create DConfig for" << subPath;
207341 delete config;
@@ -272,20 +406,22 @@ void ConfigLoader::loadConfig(const QString &subPath, bool newOne)
272406 qDebug () << " DConfig value changed:" << subPath << key;
273407 if (isKey) {
274408 KeyConfig updatedConfig = parseKeyConfig (config);
275- for (auto &existing : m_keys) {
276- if (existing.subPath == subPath) {
277- existing = updatedConfig;
278- break ;
279- }
409+ auto existing = std::find_if (m_keys.begin (), m_keys.end (),
410+ [&](const KeyConfig &item) { return item.subPath == subPath; });
411+ if (existing != m_keys.end ()) {
412+ *existing = updatedConfig;
413+ } else {
414+ m_keys.append (updatedConfig);
280415 }
281416 emit keyConfigChanged (updatedConfig);
282417 } else {
283418 GestureConfig updatedConfig = parseGestureConfig (config);
284- for (auto &existing : m_gestures) {
285- if (existing.subPath == subPath) {
286- existing = updatedConfig;
287- break ;
288- }
419+ auto existing = std::find_if (m_gestures.begin (), m_gestures.end (),
420+ [&](const GestureConfig &item) { return item.subPath == subPath; });
421+ if (existing != m_gestures.end ()) {
422+ *existing = updatedConfig;
423+ } else {
424+ m_gestures.append (updatedConfig);
289425 }
290426 emit gestureConfigChanged (updatedConfig);
291427 }
@@ -295,15 +431,10 @@ void ConfigLoader::loadConfig(const QString &subPath, bool newOne)
295431 }
296432}
297433
298- static QString normalizedSubpath (const QString &raw)
299- {
300- return raw.startsWith (QLatin1Char (' /' )) ? raw.mid (1 ) : raw;
301- }
302-
303434KeyConfig ConfigLoader::parseKeyConfig (DConfig *config)
304435{
305436 KeyConfig keyConfig;
306- keyConfig.subPath = normalizedSubpath (config->subpath ());
437+ keyConfig.subPath = CustomShortcutStore::normalizeSubPath (config->subpath ());
307438 keyConfig.appId = config->value (" appId" ).toString ();
308439 keyConfig.displayName = config->value (" displayName" ).toString ();
309440 keyConfig.enabled = config->value (" enabled" ).toBool ();
@@ -324,7 +455,7 @@ KeyConfig ConfigLoader::parseKeyConfig(DConfig *config)
324455GestureConfig ConfigLoader::parseGestureConfig (DConfig *config)
325456{
326457 GestureConfig gestureConfig;
327- gestureConfig.subPath = normalizedSubpath (config->subpath ());
458+ gestureConfig.subPath = CustomShortcutStore::normalizeSubPath (config->subpath ());
328459 gestureConfig.appId = config->value (" appId" ).toString ();
329460 gestureConfig.displayName = config->value (" displayName" ).toString ();
330461 gestureConfig.enabled = config->value (" enabled" ).toBool ();
0 commit comments