1// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
2//
3// SPDX-License-Identifier: GPL-3.0-or-later
4
5#include "actionmanager.h"
6#include "util/shortcututil.h"
7#include "util/custompaths.h"
8
9#include <QAction>
10#include <QDir>
11
12static ActionManager *kActionManagerInstance = nullptr;
13
14class ActionManagerPrivate final
15{
16public:
17 using IdCmdMap = QHash<QString, Action *>;
18
19 ActionManagerPrivate();
20 Action *addOverrideAction(QString id, QAction *action);
21 Action *removeOverrideAction(QString id);
22 Command *command(QString id);
23 QList<Command *> commands();
24
25 void addSetting(QString id, Action *action);
26 void removeSetting(QString id);
27 void saveAllSetting();
28 void readUserSetting();
29
30private:
31 IdCmdMap idCmdMap;
32 QString configFilePath;
33};
34
35ActionManagerPrivate::ActionManagerPrivate()
36 : configFilePath(CustomPaths::user(CustomPaths::Flags::Configures) + QDir::separator() + QString("shortcut.support"))
37{
38
39}
40
41Action *ActionManagerPrivate::addOverrideAction(QString id, QAction *action)
42{
43 Action *a = idCmdMap.value(id, nullptr);
44 if (!a) {
45 a = new Action(id, action);
46 idCmdMap.insert(id, a);
47 }
48
49 return a;
50}
51
52Action *ActionManagerPrivate::removeOverrideAction(QString id)
53{
54 Action *a = idCmdMap.value(id, nullptr);
55 if (a) {
56 idCmdMap.remove(id);
57 }
58
59 return a;
60}
61
62Command *ActionManagerPrivate::command(QString id)
63{
64 return idCmdMap.value(id, nullptr);
65}
66
67QList<Command *> ActionManagerPrivate::commands()
68{
69 QList<Command *> result;
70 foreach (Command *cmd, idCmdMap) {
71 result << cmd;
72 }
73
74 return result;
75}
76
77void ActionManagerPrivate::addSetting(QString id, Action *action)
78{
79 QString shortcut = action->keySequence().toString();
80 QString description = action->description();
81
82 QMap<QString, QStringList> shortcutItemMap;
83 ShortcutUtil::readFromJson(configFilePath, shortcutItemMap);
84 QStringList valueList = {description, shortcut};
85 shortcutItemMap[id] = valueList;
86 ShortcutUtil::writeToJson(configFilePath, shortcutItemMap);
87}
88
89void ActionManagerPrivate::removeSetting(QString id)
90{
91 QMap<QString, QStringList> shortcutItemMap;
92 ShortcutUtil::readFromJson(configFilePath, shortcutItemMap);
93 if (shortcutItemMap.contains(id)) {
94 shortcutItemMap.remove(id);
95 }
96 ShortcutUtil::writeToJson(configFilePath, shortcutItemMap);
97}
98
99void ActionManagerPrivate::saveAllSetting()
100{
101 QMap<QString, QStringList> shortcutItemMap;
102 IdCmdMap::const_iterator iter = idCmdMap.begin();
103 for (; iter != idCmdMap.end(); ++iter)
104 {
105 QStringList valueList = {iter.value()->description(), iter.value()->keySequence().toString()};
106 shortcutItemMap.insert(iter.key(), valueList);
107 }
108
109 ShortcutUtil::writeToJson(configFilePath, shortcutItemMap);
110}
111
112void ActionManagerPrivate::readUserSetting()
113{
114 QMap<QString, QStringList> shortcutItemMap;
115 ShortcutUtil::readFromJson(configFilePath, shortcutItemMap);
116
117 IdCmdMap::const_iterator iter = idCmdMap.begin();
118 for (; iter != idCmdMap.end(); ++iter)
119 {
120 QString id = iter.key();
121 if (shortcutItemMap.contains(id) && iter.value()->action()) {
122 QString shortcut = shortcutItemMap.value(id).last();
123 iter.value()->action()->setShortcut(QKeySequence(shortcut));
124 }
125 }
126}
127
128ActionManager::ActionManager(QObject *parent)
129 : QObject(parent)
130 , d(new ActionManagerPrivate())
131{
132
133}
134
135ActionManager::~ActionManager()
136{
137 if (d) {
138 delete d;
139 }
140}
141
142ActionManager *ActionManager::getInstance()
143{
144 if (!kActionManagerInstance) {
145 kActionManagerInstance = new ActionManager();
146 }
147 return kActionManagerInstance;
148}
149
150/*!
151 \fn Command *ActionManager::registerAction(QAction *action, const QString id,
152 const QString description,
153 const QKeySequence defaultShortcut)
154
155 Makes an action known to the system under the specified action, id, description, default shortcut.
156 New a command and insert to map, set the keysequence and description to action, and save info to config file.
157
158 Returns a Command instance that represents the action in the application
159 and is owned by the ActionManager.
160
161 Usage: ActionManager::getInstance->registerAction(...);
162*/
163Command *ActionManager::registerAction(QAction *action, const QString &id,
164 const QString &description/* = nullptr*/,
165 const QKeySequence defaultShortcut/* = QKeySequence()*/,
166 const QString &iconFileName/* = nullptr*/)
167{
168 if(!action || id.isEmpty())
169 return nullptr;
170
171 const QIcon icon = QIcon(iconFileName);
172 if (!icon.isNull())
173 action->setIcon(icon);
174
175 connect(action, &QAction::destroyed, [=] {
176 unregisterAction(id);
177 });
178
179 Action *a = d->addOverrideAction(id, action);
180 if (a) {
181 a->setKeySequence(defaultShortcut);
182 a->setDescription(description);
183 }
184
185 return a;
186}
187
188/*!
189 \fn void ActionManager::unregisterAction(QString id)
190
191 Removes the knowledge about an action under the specified id.
192 Remove from map, set action shortcut to null, and save info to config file.
193
194 Usage: ActionManager::getInstance->unregisterAction(...);
195*/
196void ActionManager::unregisterAction(QString id)
197{
198 Action *a = d->removeOverrideAction(id);
199 if (a) {
200 a->setKeySequence(QKeySequence());
201 }
202}
203
204Command *ActionManager::command(QString id)
205{
206 return d->command(id);
207}
208
209QList<Command *> ActionManager::commands()
210{
211 return d->commands();
212}
213
214void ActionManager::readUserSetting()
215{
216 return d->readUserSetting();
217}
218
219void ActionManager::saveSetting()
220{
221 return d->saveAllSetting();
222}
223
224