|
1 # -*- coding: utf-8 -*- |
|
2 |
|
3 # Copyright (c) 2009 - 2022 Detlev Offenbach <detlev@die-offenbachs.de> |
|
4 # |
|
5 |
|
6 """ |
|
7 Class implementing a specialized application class. |
|
8 """ |
|
9 |
|
10 import os |
|
11 |
|
12 from PyQt6.QtCore import Qt, QCoreApplication |
|
13 from PyQt6.QtGui import QColor, QPalette |
|
14 from PyQt6.QtWidgets import QApplication |
|
15 |
|
16 QCoreApplication.setAttribute( |
|
17 Qt.ApplicationAttribute.AA_ShareOpenGLContexts, True) |
|
18 |
|
19 from . import EricMessageBox |
|
20 |
|
21 |
|
22 class EricApplication(QApplication): |
|
23 """ |
|
24 Eric application class with an object registry. |
|
25 """ |
|
26 PaletteRoleMapping = { |
|
27 "alternate-base": QPalette.ColorRole.AlternateBase, |
|
28 "base": QPalette.ColorRole.Base, |
|
29 "text": QPalette.ColorRole.Text, |
|
30 "bright-text": QPalette.ColorRole.BrightText, |
|
31 "placeholder-text": QPalette.ColorRole.PlaceholderText, |
|
32 "window": QPalette.ColorRole.Window, |
|
33 " window-text": QPalette.ColorRole.WindowText, |
|
34 "tooltip-base": QPalette.ColorRole.ToolTipBase, |
|
35 "tooltip-text": QPalette.ColorRole.ToolTipText, |
|
36 "button": QPalette.ColorRole.Button, |
|
37 "button-text": QPalette.ColorRole.ButtonText, |
|
38 "highlight": QPalette.ColorRole.Highlight, |
|
39 "highlighted-text": QPalette.ColorRole.HighlightedText, |
|
40 "link": QPalette.ColorRole.Link, |
|
41 "link-visited": QPalette.ColorRole.LinkVisited, |
|
42 } |
|
43 |
|
44 def __init__(self, argv): |
|
45 """ |
|
46 Constructor |
|
47 |
|
48 @param argv command line arguments |
|
49 @type list |
|
50 """ |
|
51 super().__init__(argv) |
|
52 |
|
53 QCoreApplication.setAttribute( |
|
54 Qt.ApplicationAttribute.AA_DontCreateNativeWidgetSiblings, True) |
|
55 |
|
56 self.__objectRegistry = {} |
|
57 self.__pluginObjectRegistry = {} |
|
58 |
|
59 self.__smallScreen = False |
|
60 if "--small-screen" in argv: |
|
61 self.__smallScreen = True |
|
62 argv.remove("--small-screen") |
|
63 if not self.__smallScreen: |
|
64 primaryScreenSize = self.primaryScreen().size() |
|
65 self.__smallScreen = ( |
|
66 primaryScreenSize.width() < 1920 or |
|
67 primaryScreenSize.height() < 1080 |
|
68 ) |
|
69 |
|
70 def usesSmallScreen(self): |
|
71 """ |
|
72 Public method to determine, if the application is used on a small |
|
73 screen. |
|
74 |
|
75 @return flag indicating the use of a small screen |
|
76 @rtype bool |
|
77 """ |
|
78 return self.__smallScreen |
|
79 |
|
80 def registerObject(self, name, objectRef): |
|
81 """ |
|
82 Public method to register an object in the object registry. |
|
83 |
|
84 @param name name of the object |
|
85 @type str |
|
86 @param objectRef reference to the object |
|
87 @type any |
|
88 @exception KeyError raised when the given name is already in use |
|
89 """ |
|
90 if name in self.__objectRegistry: |
|
91 raise KeyError('Object "{0}" already registered.'.format(name)) |
|
92 else: |
|
93 self.__objectRegistry[name] = objectRef |
|
94 |
|
95 def getObject(self, name): |
|
96 """ |
|
97 Public method to get a reference to a registered object. |
|
98 |
|
99 @param name name of the object |
|
100 @type str |
|
101 @return reference to the registered object |
|
102 @rtype any |
|
103 @exception KeyError raised when the given name is not known |
|
104 """ |
|
105 if name not in self.__objectRegistry: |
|
106 raise KeyError('Object "{0}" is not registered.'.format(name)) |
|
107 |
|
108 return self.__objectRegistry[name] |
|
109 |
|
110 def registerPluginObject(self, name, objectRef, pluginType=None): |
|
111 """ |
|
112 Public method to register a plugin object in the object registry. |
|
113 |
|
114 @param name name of the plugin object |
|
115 @type str |
|
116 @param objectRef reference to the plugin object |
|
117 @type any |
|
118 @param pluginType type of the plugin object |
|
119 @type str |
|
120 @exception KeyError raised when the given name is already in use |
|
121 """ |
|
122 if name in self.__pluginObjectRegistry: |
|
123 raise KeyError( |
|
124 'Pluginobject "{0}" already registered.'.format(name)) |
|
125 else: |
|
126 self.__pluginObjectRegistry[name] = (objectRef, pluginType) |
|
127 |
|
128 def unregisterPluginObject(self, name): |
|
129 """ |
|
130 Public method to unregister a plugin object in the object registry. |
|
131 |
|
132 @param name name of the plugin object |
|
133 @type str |
|
134 """ |
|
135 if name in self.__pluginObjectRegistry: |
|
136 del self.__pluginObjectRegistry[name] |
|
137 |
|
138 def getPluginObject(self, name): |
|
139 """ |
|
140 Public method to get a reference to a registered plugin object. |
|
141 |
|
142 @param name name of the plugin object |
|
143 @type str |
|
144 @return reference to the registered plugin object |
|
145 @rtype any |
|
146 @exception KeyError raised when the given name is not known |
|
147 """ |
|
148 if name not in self.__pluginObjectRegistry: |
|
149 raise KeyError( |
|
150 'Pluginobject "{0}" is not registered.'.format(name)) |
|
151 |
|
152 return self.__pluginObjectRegistry[name][0] |
|
153 |
|
154 def getPluginObjects(self): |
|
155 """ |
|
156 Public method to get a list of (name, reference) pairs of all |
|
157 registered plugin objects. |
|
158 |
|
159 @return list of (name, reference) pairs |
|
160 @rtype list of (str, any) |
|
161 """ |
|
162 objects = [] |
|
163 for name in self.__pluginObjectRegistry: |
|
164 objects.append((name, self.__pluginObjectRegistry[name][0])) |
|
165 return objects |
|
166 |
|
167 def getPluginObjectType(self, name): |
|
168 """ |
|
169 Public method to get the type of a registered plugin object. |
|
170 |
|
171 @param name name of the plugin object |
|
172 @type str |
|
173 @return type of the plugin object |
|
174 @rtype str |
|
175 @exception KeyError raised when the given name is not known |
|
176 """ |
|
177 if name not in self.__pluginObjectRegistry: |
|
178 raise KeyError( |
|
179 'Pluginobject "{0}" is not registered.'.format(name)) |
|
180 |
|
181 return self.__pluginObjectRegistry[name][1] |
|
182 |
|
183 def getStyleIconsPath(self, universal=False): |
|
184 """ |
|
185 Public method to get the path for the style icons. |
|
186 |
|
187 @param universal flag indicating a universal file path (defaults to |
|
188 False) |
|
189 @type bool (optional) |
|
190 @return directory path containing the style icons |
|
191 @rtype str |
|
192 """ |
|
193 import Preferences |
|
194 import Utilities |
|
195 from eric7config import getConfig |
|
196 |
|
197 styleIconsPath = Preferences.getUI("StyleIconsPath") |
|
198 if not styleIconsPath: |
|
199 # default is the 'StyleIcons' sub-directory of the icons |
|
200 # directory |
|
201 styleIconsPath = os.path.join( |
|
202 getConfig('ericIconDir'), "StyleIcons") |
|
203 |
|
204 if universal: |
|
205 return Utilities.fromNativeSeparators(styleIconsPath) |
|
206 else: |
|
207 return styleIconsPath |
|
208 |
|
209 def setStyleSheetFile(self, filename): |
|
210 """ |
|
211 Public method to read a QSS style sheet file and set the application |
|
212 style sheet based on its contents. |
|
213 |
|
214 @param filename name of the QSS style sheet file |
|
215 @type str |
|
216 """ |
|
217 if filename: |
|
218 try: |
|
219 with open(filename, "r", encoding="utf-8") as f: |
|
220 styleSheet = f.read() |
|
221 except OSError as msg: |
|
222 EricMessageBox.warning( |
|
223 None, |
|
224 QCoreApplication.translate( |
|
225 "EricApplication", "Loading Style Sheet"), |
|
226 QCoreApplication.translate( |
|
227 "EricApplication", |
|
228 """<p>The Qt Style Sheet file <b>{0}</b> could""" |
|
229 """ not be read.<br>Reason: {1}</p>""") |
|
230 .format(filename, str(msg))) |
|
231 return |
|
232 else: |
|
233 styleSheet = "" |
|
234 |
|
235 if styleSheet: |
|
236 # pre-process the style sheet to replace the placeholder for the |
|
237 # path to the icons |
|
238 styleIconsPath = self.getStyleIconsPath(universal=True) |
|
239 styleSheet = styleSheet.replace("${path}", styleIconsPath) |
|
240 |
|
241 if "QPalette {" in styleSheet: |
|
242 self.__setPaletteFromStyleSheet(styleSheet) |
|
243 |
|
244 ericApp().setStyleSheet(styleSheet) |
|
245 |
|
246 def __setPaletteFromStyleSheet(self, styleSheet): |
|
247 """ |
|
248 Private method to set the palette from a style sheet. |
|
249 |
|
250 @param styleSheet style sheet |
|
251 @type str |
|
252 """ |
|
253 palette = self.palette() |
|
254 |
|
255 paletteStr = styleSheet.split("QPalette {")[1].split("}")[0] |
|
256 paletteLines = paletteStr.strip().splitlines() |
|
257 for line in paletteLines: |
|
258 role, value = line.strip().split() |
|
259 role = role.strip("\t :").lower() |
|
260 value = value.strip("\t ;") |
|
261 if role in self.PaletteRoleMapping and value.startswith("#"): |
|
262 palette.setColor(self.PaletteRoleMapping[role], QColor(value)) |
|
263 |
|
264 self.setPalette(palette) |
|
265 |
|
266 def usesDarkPalette(self): |
|
267 """ |
|
268 Public method to check, if the application uses a palette with a dark |
|
269 background. |
|
270 |
|
271 @return flag indicating the use of a palette with a dark background |
|
272 @rtype bool |
|
273 """ |
|
274 palette = self.palette() |
|
275 lightness = palette.color(QPalette.ColorRole.Window).lightness() |
|
276 return lightness <= 128 |
|
277 |
|
278 ericApp = QCoreApplication.instance |