|
1 # -*- coding: utf-8 -*- |
|
2 |
|
3 # Copyright (c) 2006 - 2019 Detlev Offenbach <detlev@die-offenbachs.de> |
|
4 # |
|
5 |
|
6 """ |
|
7 Module defining common data to be used by all modules. |
|
8 """ |
|
9 |
|
10 # |
|
11 # Note: Do not import any eric stuff in here!!!!!!! |
|
12 # |
|
13 |
|
14 from __future__ import unicode_literals |
|
15 try: |
|
16 str = unicode # __IGNORE_EXCEPTION__ |
|
17 except NameError: |
|
18 pass |
|
19 |
|
20 import sys |
|
21 import os |
|
22 import re |
|
23 import shutil |
|
24 |
|
25 from PyQt5.QtCore import QDir, QLibraryInfo, QByteArray, QCoreApplication, \ |
|
26 QT_VERSION_STR, QT_VERSION, QProcess, qVersion |
|
27 |
|
28 # names of the various settings objects |
|
29 settingsNameOrganization = "Eric6" |
|
30 settingsNameGlobal = "eric6" |
|
31 settingsNameRecent = "eric6recent" |
|
32 |
|
33 # key names of the various recent entries |
|
34 recentNameMultiProject = "MultiProjects" |
|
35 recentNameProject = "Projects" |
|
36 recentNameFiles = "Files" |
|
37 recentNameHexFiles = "HexFiles" |
|
38 recentNameHosts = "Hosts6" |
|
39 recentNameBreakpointFiles = "BreakPointFiles" |
|
40 recentNameBreakpointConditions = "BreakPointConditions" |
|
41 |
|
42 configDir = None |
|
43 |
|
44 |
|
45 def isWindowsPlatform(): |
|
46 """ |
|
47 Function to check, if this is a Windows platform. |
|
48 |
|
49 @return flag indicating Windows platform (boolean) |
|
50 """ |
|
51 return sys.platform.startswith(("win", "cygwin")) |
|
52 |
|
53 |
|
54 def isMacPlatform(): |
|
55 """ |
|
56 Function to check, if this is a Mac platform. |
|
57 |
|
58 @return flag indicating Mac platform (boolean) |
|
59 """ |
|
60 return sys.platform == "darwin" |
|
61 |
|
62 |
|
63 def isLinuxPlatform(): |
|
64 """ |
|
65 Function to check, if this is a Linux platform. |
|
66 |
|
67 @return flag indicating Linux platform (boolean) |
|
68 """ |
|
69 return sys.platform.startswith("linux") |
|
70 |
|
71 |
|
72 def desktopName(): |
|
73 """ |
|
74 Function to determine the name of the desktop environment used |
|
75 (Linux only). |
|
76 |
|
77 @return name of the desktop environment |
|
78 @rtype str |
|
79 """ |
|
80 if not isLinuxPlatform(): |
|
81 return "" |
|
82 |
|
83 currDesktop = os.environ.get("XDG_CURRENT_DESKTOP", "") |
|
84 if currDesktop: |
|
85 return currDesktop |
|
86 |
|
87 currDesktop = os.environ.get("XDG_SESSION_DESKTOP", "") |
|
88 if currDesktop: |
|
89 return currDesktop |
|
90 |
|
91 currDesktop = os.environ.get("GDMSESSION", "") |
|
92 if currDesktop: |
|
93 return currDesktop |
|
94 |
|
95 currDesktop = os.environ.get("GNOME_DESKTOP_SESSION_ID", "") |
|
96 if currDesktop: |
|
97 return currDesktop |
|
98 |
|
99 currDesktop = os.environ.get("KDE_FULL_SESSION", "") |
|
100 if currDesktop: |
|
101 return currDesktop |
|
102 |
|
103 currDesktop = os.environ.get("DESKTOP_SESSION", "") |
|
104 if currDesktop: |
|
105 return currDesktop |
|
106 |
|
107 return "" |
|
108 |
|
109 |
|
110 def isKdeDesktop(): |
|
111 """ |
|
112 Function to check, if the current session is a KDE desktop (Linux only). |
|
113 |
|
114 @return flag indicating a KDE desktop |
|
115 @rtype bool |
|
116 """ |
|
117 if not isLinuxPlatform(): |
|
118 return False |
|
119 |
|
120 isKDE = False |
|
121 |
|
122 desktop = os.environ.get("XDG_CURRENT_DESKTOP", "").lower() or \ |
|
123 os.environ.get("XDG_SESSION_DESKTOP", "").lower() or \ |
|
124 os.environ.get("DESKTOP_SESSION", "").lower() |
|
125 if desktop: |
|
126 isKDE = "kde" in desktop or "plasma" in desktop |
|
127 else: |
|
128 isKDE = bool(os.environ.get("KDE_FULL_SESSION", "")) |
|
129 |
|
130 return isKDE |
|
131 |
|
132 |
|
133 def isGnomeDesktop(): |
|
134 """ |
|
135 Function to check, if the current session is a Gnome desktop (Linux only). |
|
136 |
|
137 @return flag indicating a Gnome desktop |
|
138 @rtype bool |
|
139 """ |
|
140 if not isLinuxPlatform(): |
|
141 return False |
|
142 |
|
143 isGnome = False |
|
144 |
|
145 desktop = os.environ.get("XDG_CURRENT_DESKTOP", "").lower() or \ |
|
146 os.environ.get("XDG_SESSION_DESKTOP", "").lower() or \ |
|
147 os.environ.get("GDMSESSION", "").lower() |
|
148 if desktop: |
|
149 isGnome = "gnome" in desktop |
|
150 else: |
|
151 isGnome = bool(os.environ.get("GNOME_DESKTOP_SESSION_ID", "")) |
|
152 |
|
153 return isGnome |
|
154 |
|
155 |
|
156 def sessionType(): |
|
157 """ |
|
158 Function to determine the name of the running session (Linux only). |
|
159 |
|
160 @return name of the desktop environment |
|
161 @rtype str |
|
162 """ |
|
163 if not isLinuxPlatform(): |
|
164 return "" |
|
165 |
|
166 sessionType = os.environ.get("XDG_SESSION_TYPE").lower() |
|
167 if "x11" in sessionType: |
|
168 return "X11" |
|
169 elif "wayland" in sessionType: |
|
170 return "Wayland" |
|
171 |
|
172 sessionType = os.environ.get("WAYLAND_DISPLAY", "").lower() |
|
173 if "wayland" in sessionType: |
|
174 return "Wayland" |
|
175 |
|
176 return "" |
|
177 |
|
178 |
|
179 def isWaylandSession(): |
|
180 """ |
|
181 Function to check, if the current session is a wayland session. |
|
182 |
|
183 @return flag indicating a wayland session |
|
184 @rtype bool |
|
185 """ |
|
186 return sessionType() == "Wayland" |
|
187 |
|
188 |
|
189 def getConfigDir(): |
|
190 """ |
|
191 Module function to get the name of the directory storing the config data. |
|
192 |
|
193 @return directory name of the config dir (string) |
|
194 """ |
|
195 if configDir is not None and os.path.exists(configDir): |
|
196 hp = configDir |
|
197 else: |
|
198 cdn = ".eric6" |
|
199 if isWindowsPlatform(): |
|
200 # migrate the old config directory (< v18.06) |
|
201 cdnOld = "_eric6" |
|
202 hpOld = os.path.join(os.path.expanduser("~"), cdnOld) |
|
203 if os.path.exists(hpOld): |
|
204 hpNew = os.path.join(os.path.expanduser("~"), cdn) |
|
205 if os.path.exists(hpNew): |
|
206 # simply delete the old config directory |
|
207 shutil.rmtree(hpOld, True) |
|
208 else: |
|
209 os.rename(hpOld, hpNew) |
|
210 |
|
211 hp = os.path.join(os.path.expanduser("~"), cdn) |
|
212 if not os.path.exists(hp): |
|
213 os.mkdir(hp) |
|
214 return hp |
|
215 |
|
216 |
|
217 def setConfigDir(d): |
|
218 """ |
|
219 Module function to set the name of the directory storing the config data. |
|
220 |
|
221 @param d name of an existing directory (string) |
|
222 """ |
|
223 global configDir |
|
224 configDir = os.path.expanduser(d) |
|
225 |
|
226 |
|
227 def getPythonModulesDirectory(): |
|
228 """ |
|
229 Function to determine the path to Python's modules directory. |
|
230 |
|
231 @return path to the Python modules directory (string) |
|
232 """ |
|
233 import distutils.sysconfig |
|
234 return distutils.sysconfig.get_python_lib(True) |
|
235 |
|
236 |
|
237 def getPyQt5ModulesDirectory(): |
|
238 """ |
|
239 Function to determine the path to PyQt5's (or PyQt4's) modules directory. |
|
240 |
|
241 @return path to the PyQt5/PyQt4 modules directory (string) |
|
242 """ |
|
243 import distutils.sysconfig |
|
244 for pyqt in ["PyQt5", "PyQt4"]: |
|
245 pyqtPath = os.path.join(distutils.sysconfig.get_python_lib(True), pyqt) |
|
246 if os.path.exists(pyqtPath): |
|
247 return pyqtPath |
|
248 |
|
249 return "" |
|
250 |
|
251 |
|
252 def getPyQtToolsPath(version=5): |
|
253 """ |
|
254 Module function to get the path of the PyQt tools. |
|
255 |
|
256 @param version PyQt major version |
|
257 @type int |
|
258 @return path to the PyQt tools |
|
259 @rtype str |
|
260 """ |
|
261 import Preferences |
|
262 |
|
263 path = "" |
|
264 |
|
265 # step 1: check, if the user has configured a tools path |
|
266 path = Preferences.getQt("PyQtToolsDir") |
|
267 |
|
268 # step 2: determine from used Python interpreter (pyrcc is test object) |
|
269 if not path: |
|
270 program = "pyrcc{0}".format(version) |
|
271 if isWindowsPlatform(): |
|
272 program += ".exe" |
|
273 dirName = os.path.dirname(sys.executable) |
|
274 if os.path.exists(os.path.join(dirName, program)): |
|
275 path = dirName |
|
276 elif os.path.exists(os.path.join(dirName, "Scripts", program)): |
|
277 path = os.path.join(dirName, "Scripts") |
|
278 else: |
|
279 dirName = os.path.dirname(sys.executable) |
|
280 if os.path.exists(os.path.join(dirName, program)): |
|
281 path = dirName |
|
282 |
|
283 return path |
|
284 |
|
285 |
|
286 def getQtBinariesPath(): |
|
287 """ |
|
288 Module function to get the path of the Qt binaries. |
|
289 |
|
290 @return path of the Qt binaries (string) |
|
291 """ |
|
292 import Preferences |
|
293 |
|
294 path = "" |
|
295 |
|
296 # step 1: check, if the user has configured a tools path |
|
297 path = Preferences.getQt("QtToolsDir") |
|
298 |
|
299 if not path and isWindowsPlatform(): |
|
300 # step 2.1: check for PyQt5 Windows installer (designer is test object) |
|
301 modDir = getPyQt5ModulesDirectory() |
|
302 if os.path.exists(os.path.join(modDir, "bin", "designer.exe")): |
|
303 path = os.path.join(modDir, "bin") |
|
304 elif os.path.exists(os.path.join(modDir, "designer.exe")): |
|
305 path = modDir |
|
306 |
|
307 if not path: |
|
308 import distutils.sysconfig |
|
309 # step 2.2.1: check for the pyqt5-tools wheel (new variant) |
|
310 # (Windows only) |
|
311 pyqt5ToolsPath = os.path.join( |
|
312 distutils.sysconfig.get_python_lib(True), "pyqt5_tools") |
|
313 if os.path.exists(os.path.join(pyqt5ToolsPath, "designer.exe")): |
|
314 path = pyqt5ToolsPath |
|
315 if not path: |
|
316 # step 2.2.2: check for the pyqt5-tools wheel (old variant) |
|
317 # (Windows only) |
|
318 pyqt5ToolsPath = os.path.join( |
|
319 distutils.sysconfig.get_python_lib(True), "pyqt5-tools") |
|
320 if os.path.exists(os.path.join(pyqt5ToolsPath, |
|
321 "designer.exe")): |
|
322 path = pyqt5ToolsPath |
|
323 |
|
324 if not path: |
|
325 # step 3: get the path from Qt |
|
326 # Note: no Qt tools are to be found there for PyQt 5.7.0 |
|
327 path = QLibraryInfo.location(QLibraryInfo.BinariesPath) |
|
328 if not os.path.exists(path): |
|
329 path = "" |
|
330 |
|
331 return QDir.toNativeSeparators(path) |
|
332 |
|
333 |
|
334 def translate(*args): |
|
335 """ |
|
336 Module function to handle different PyQt 4/5 QCoreApplication.translate |
|
337 parameter. |
|
338 |
|
339 @param args tuple of arguments from QCoreApplication.translate (tuple) |
|
340 @return translated string (string) |
|
341 """ |
|
342 if QT_VERSION_STR.startswith('4.'): |
|
343 args = list(args) |
|
344 args.insert(3, QCoreApplication.CodecForTr) |
|
345 return QCoreApplication.translate(*args) |
|
346 |
|
347 |
|
348 ############################################################################### |
|
349 ## functions for version handling |
|
350 ############################################################################### |
|
351 |
|
352 |
|
353 def versionToTuple(version): |
|
354 """ |
|
355 Module function to convert a version string into a tuple. |
|
356 |
|
357 Note: A version string consists of non-negative decimals separated by "." |
|
358 optionally followed by a suffix. Suffix is everything after the last |
|
359 decimal. |
|
360 |
|
361 @param version version string |
|
362 @type str |
|
363 @return version tuple without the suffix |
|
364 @rtype tuple of int |
|
365 """ |
|
366 versionParts = [] |
|
367 |
|
368 # step 1: extract suffix |
|
369 version = re.split(r"[^\d.]", version)[0] |
|
370 for part in version.split("."): |
|
371 versionParts.append(int(part)) |
|
372 |
|
373 return tuple(versionParts) |
|
374 |
|
375 |
|
376 def qVersionTuple(): |
|
377 """ |
|
378 Module function to get the Qt version as a tuple. |
|
379 |
|
380 @return Qt version as a tuple |
|
381 @rtype tuple of int |
|
382 """ |
|
383 return ( |
|
384 (QT_VERSION & 0xff0000) >> 16, |
|
385 (QT_VERSION & 0xff00) >> 8, |
|
386 QT_VERSION & 0xff, |
|
387 ) |
|
388 |
|
389 |
|
390 ############################################################################### |
|
391 ## functions for extended string handling |
|
392 ############################################################################### |
|
393 |
|
394 |
|
395 def strGroup(txt, sep, groupLen=4): |
|
396 """ |
|
397 Module function to group a string into sub-strings separated by a |
|
398 separator. |
|
399 |
|
400 @param txt text to be grouped |
|
401 @type str |
|
402 @param sep separator string |
|
403 @type str |
|
404 @param groupLen length of each group |
|
405 @type int |
|
406 @return result string |
|
407 @rtype str |
|
408 """ |
|
409 groups = [] |
|
410 |
|
411 while len(txt) // groupLen != 0: |
|
412 groups.insert(0, txt[-groupLen:]) |
|
413 txt = txt[:-groupLen] |
|
414 if len(txt) > 0: |
|
415 groups.insert(0, txt) |
|
416 return sep.join(groups) |
|
417 |
|
418 |
|
419 def strToQByteArray(txt): |
|
420 """ |
|
421 Module function to convert a Python string into a QByteArray. |
|
422 |
|
423 @param txt Python string to be converted |
|
424 @type str, bytes, bytearray, unicode |
|
425 @return converted QByteArray |
|
426 @rtype QByteArray |
|
427 """ |
|
428 if sys.version_info[0] == 2: |
|
429 if isinstance(txt, unicode): # __IGNORE_WARNING__ |
|
430 txt = txt.encode("utf-8") |
|
431 else: |
|
432 if isinstance(txt, str): |
|
433 txt = txt.encode("utf-8") |
|
434 |
|
435 return QByteArray(txt) |
|
436 |
|
437 |
|
438 def dataString(size): |
|
439 """ |
|
440 Module function to generate a formatted size string. |
|
441 |
|
442 @param size size to be formatted |
|
443 @type int |
|
444 @return formatted data string |
|
445 @rtype str |
|
446 """ |
|
447 if size < 1024: |
|
448 return QCoreApplication.translate( |
|
449 "Globals", "{0:.1f} Bytes").format(size) |
|
450 elif size < 1024 * 1024: |
|
451 size /= 1024 |
|
452 return QCoreApplication.translate( |
|
453 "Globals", "{0:.1f} KiB").format(size) |
|
454 elif size < 1024 * 1024 * 1024: |
|
455 size /= 1024 * 1024 |
|
456 return QCoreApplication.translate( |
|
457 "Globals", "{0:.2f} MiB").format(size) |
|
458 else: |
|
459 size /= 1024 * 1024 * 1024 |
|
460 return QCoreApplication.translate( |
|
461 "Globals", "{0:.2f} GiB").format(size) |
|
462 |
|
463 |
|
464 ############################################################################### |
|
465 ## functions for converting QSetting return types to valid types |
|
466 ############################################################################### |
|
467 |
|
468 |
|
469 def toBool(value): |
|
470 """ |
|
471 Module function to convert a value to bool. |
|
472 |
|
473 @param value value to be converted |
|
474 @return converted data |
|
475 """ |
|
476 if value in ["true", "1", "True"]: |
|
477 return True |
|
478 elif value in ["false", "0", "False"]: |
|
479 return False |
|
480 else: |
|
481 return bool(value) |
|
482 |
|
483 |
|
484 def toList(value): |
|
485 """ |
|
486 Module function to convert a value to a list. |
|
487 |
|
488 @param value value to be converted |
|
489 @return converted data |
|
490 """ |
|
491 if value is None: |
|
492 return [] |
|
493 elif not isinstance(value, list): |
|
494 return [value] |
|
495 else: |
|
496 return value |
|
497 |
|
498 |
|
499 def toByteArray(value): |
|
500 """ |
|
501 Module function to convert a value to a byte array. |
|
502 |
|
503 @param value value to be converted |
|
504 @return converted data |
|
505 """ |
|
506 if value is None: |
|
507 return QByteArray() |
|
508 else: |
|
509 return value |
|
510 |
|
511 |
|
512 def toDict(value): |
|
513 """ |
|
514 Module function to convert a value to a dictionary. |
|
515 |
|
516 @param value value to be converted |
|
517 @return converted data |
|
518 """ |
|
519 if value is None: |
|
520 return {} |
|
521 else: |
|
522 return value |
|
523 |
|
524 |
|
525 ############################################################################### |
|
526 ## functions for web browser variant detection |
|
527 ############################################################################### |
|
528 |
|
529 |
|
530 def getWebBrowserSupport(): |
|
531 """ |
|
532 Module function to determine the supported web browser variant. |
|
533 |
|
534 @return string indicating the supported web browser variant ("QtWebEngine", |
|
535 "QtWebKit" or "None") |
|
536 @rtype str |
|
537 """ |
|
538 from eric6config import getConfig |
|
539 scriptPath = os.path.join(getConfig("ericDir"), "Tools", |
|
540 "webBrowserSupport.py") |
|
541 proc = QProcess() |
|
542 proc.start(sys.executable, [scriptPath, qVersion()]) |
|
543 if proc.waitForFinished(10000): |
|
544 variant = str(proc.readAllStandardOutput(), "utf-8", 'replace').strip() |
|
545 else: |
|
546 variant = "None" |
|
547 return variant |
|
548 # |
|
549 # eflag: noqa = M801 |