|
1 # -*- coding: utf-8 -*- |
|
2 |
|
3 # Copyright (c) 2021 Detlev Offenbach <detlev@die-offenbachs.de> |
|
4 # |
|
5 |
|
6 """ |
|
7 Module implementing a class representing the shortcuts JSON file. |
|
8 """ |
|
9 |
|
10 import json |
|
11 import time |
|
12 import typing |
|
13 |
|
14 from PyQt5.QtCore import QObject |
|
15 |
|
16 from E5Gui import E5MessageBox |
|
17 from E5Gui.E5OverrideCursor import E5OverridenCursor |
|
18 from E5Gui.E5Application import e5App |
|
19 |
|
20 import Preferences |
|
21 |
|
22 HelpViewer = typing.TypeVar("WebBrowserWindow") |
|
23 |
|
24 |
|
25 class ShortcutsFile(QObject): |
|
26 """ |
|
27 Class representing the shortcuts JSON file. |
|
28 """ |
|
29 def __init__(self: "ShortcutsFile", parent: QObject = None) -> None: |
|
30 """ |
|
31 Constructor |
|
32 |
|
33 @param parent reference to the parent object (defaults to None) |
|
34 @type QObject (optional) |
|
35 """ |
|
36 super().__init__(parent) |
|
37 |
|
38 def __addActionsToDict(self: "ShortcutsFile", category: str, actions: list, |
|
39 actionsDict: dict) -> None: |
|
40 """ |
|
41 Private method to add a list of actions to the actions dictionary. |
|
42 |
|
43 @param category category of the actions |
|
44 @type str |
|
45 @param actions list of actions |
|
46 @type list of QAction |
|
47 @param actionsDict reference to the actions dictionary to be modified |
|
48 @type dict |
|
49 """ |
|
50 if actions: |
|
51 if category not in actionsDict: |
|
52 actionsDict[category] = {} |
|
53 for act in actions: |
|
54 if act.objectName(): |
|
55 # shortcuts are only exported, if their objectName is set |
|
56 actionsDict[category][act.objectName()] = ( |
|
57 act.shortcut().toString(), |
|
58 act.alternateShortcut().toString() |
|
59 ) |
|
60 |
|
61 def writeFile(self: "ShortcutsFile", filename: str, |
|
62 helpViewer: HelpViewer = None) -> bool: |
|
63 """ |
|
64 Public method to write the shortcuts data to a shortcuts JSON file. |
|
65 |
|
66 @param filename name of the shortcuts file |
|
67 @type str |
|
68 @param helpViewer reference to the help window object |
|
69 @type WebBrowserWindow |
|
70 @return flag indicating a successful write |
|
71 @rtype bool |
|
72 """ |
|
73 actionsDict = {} |
|
74 |
|
75 # step 1: collect all the shortcuts |
|
76 if helpViewer is None: |
|
77 self.__addActionsToDict( |
|
78 "Project", |
|
79 e5App().getObject("Project").getActions(), |
|
80 actionsDict |
|
81 ) |
|
82 self.__addActionsToDict( |
|
83 "General", |
|
84 e5App().getObject("UserInterface").getActions('ui'), |
|
85 actionsDict |
|
86 ) |
|
87 self.__addActionsToDict( |
|
88 "Wizards", |
|
89 e5App().getObject("UserInterface").getActions('wizards'), |
|
90 actionsDict |
|
91 ) |
|
92 self.__addActionsToDict( |
|
93 "Debug", |
|
94 e5App().getObject("DebugUI").getActions(), |
|
95 actionsDict |
|
96 ) |
|
97 self.__addActionsToDict( |
|
98 "Edit", |
|
99 e5App().getObject("ViewManager").getActions('edit'), |
|
100 actionsDict |
|
101 ) |
|
102 self.__addActionsToDict( |
|
103 "File", |
|
104 e5App().getObject("ViewManager").getActions('file'), |
|
105 actionsDict |
|
106 ) |
|
107 self.__addActionsToDict( |
|
108 "Search", |
|
109 e5App().getObject("ViewManager").getActions('search'), |
|
110 actionsDict |
|
111 ) |
|
112 self.__addActionsToDict( |
|
113 "View", |
|
114 e5App().getObject("ViewManager").getActions('view'), |
|
115 actionsDict |
|
116 ) |
|
117 self.__addActionsToDict( |
|
118 "Macro", |
|
119 e5App().getObject("ViewManager").getActions('macro'), |
|
120 actionsDict |
|
121 ) |
|
122 self.__addActionsToDict( |
|
123 "Bookmarks", |
|
124 e5App().getObject("ViewManager").getActions('bookmark'), |
|
125 actionsDict |
|
126 ) |
|
127 self.__addActionsToDict( |
|
128 "Spelling", |
|
129 e5App().getObject("ViewManager").getActions('spelling'), |
|
130 actionsDict |
|
131 ) |
|
132 self.__addActionsToDict( |
|
133 "Window", |
|
134 e5App().getObject("ViewManager").getActions('window'), |
|
135 actionsDict |
|
136 ) |
|
137 |
|
138 for category, ref in e5App().getPluginObjects(): |
|
139 if hasattr(ref, "getActions"): |
|
140 self.__addActionsToDict( |
|
141 category, ref.getActions(), actionsDict |
|
142 ) |
|
143 |
|
144 else: |
|
145 self.__addActionsToDict( |
|
146 helpViewer.getActionsCategory(), |
|
147 helpViewer.getActions(), |
|
148 actionsDict |
|
149 ) |
|
150 |
|
151 # step 2: assemble the data structure to be written |
|
152 shortcutsDict = {} |
|
153 # step 2.0: header |
|
154 shortcutsDict["header"] = { |
|
155 "comment": "eric keyboard shortcuts file", |
|
156 "saved": time.strftime('%Y-%m-%d, %H:%M:%S'), |
|
157 "author": Preferences.getUser("Email"), |
|
158 } |
|
159 # step 2.1: keyboard shortcuts |
|
160 shortcutsDict["shortcuts"] = actionsDict |
|
161 |
|
162 try: |
|
163 jsonString = json.dumps(shortcutsDict, indent=2) |
|
164 with open(filename, "w") as f: |
|
165 f.write(jsonString) |
|
166 except (TypeError, OSError) as err: |
|
167 with E5OverridenCursor(): |
|
168 E5MessageBox.critical( |
|
169 None, |
|
170 self.tr("Export Keyboard Shortcuts"), |
|
171 self.tr( |
|
172 "<p>The keyboard shortcuts file <b>{0}</b> could not" |
|
173 " be written.</p><p>Reason: {1}</p>" |
|
174 ).format(filename, str(err)) |
|
175 ) |
|
176 return False |
|
177 |
|
178 return True |
|
179 |
|
180 def readFile(self: "ShortcutsFile", filename: str) -> bool: |
|
181 """ |
|
182 Public method to read the shortcuts data from a shortcuts JSON file. |
|
183 |
|
184 @param filename name of the shortcuts file |
|
185 @type str |
|
186 @return Dictionary of dictionaries of shortcuts. The keys of the |
|
187 dictionary are the shortcuts categories, the values are |
|
188 dictionaries. These dictionaries have the shortcut name as their |
|
189 key and a tuple of accelerators as their value. |
|
190 @rtype dict |
|
191 """ |
|
192 try: |
|
193 with open(filename, "r") as f: |
|
194 jsonString = f.read() |
|
195 shortcutsDict = json.loads(jsonString) |
|
196 except (OSError, json.JSONDecodeError) as err: |
|
197 E5MessageBox.critical( |
|
198 None, |
|
199 self.tr("Import Keyboard Shortcuts"), |
|
200 self.tr( |
|
201 "<p>The keyboard shortcuts file <b>{0}</b> could not be" |
|
202 " read.</p><p>Reason: {1}</p>" |
|
203 ).format(filename, str(err)) |
|
204 ) |
|
205 return {} |
|
206 |
|
207 return shortcutsDict["shortcuts"] |