eric7/Tools/TrayStarter.py

branch
eric7
changeset 8312
800c432b34c8
parent 8265
0090cfa83159
child 8314
e3642a6a1e71
equal deleted inserted replaced
8311:4e8b98454baa 8312:800c432b34c8
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2006 - 2021 Detlev Offenbach <detlev@die-offenbachs.de>
4 #
5
6 """
7 Module implementing a starter for the system tray.
8 """
9
10 import sys
11 import os
12 import contextlib
13
14 from PyQt5.QtCore import QProcess, QSettings, QFileInfo
15 from PyQt5.QtGui import QCursor
16 from PyQt5.QtWidgets import QSystemTrayIcon, QMenu, QDialog, QApplication
17
18 from E5Gui import E5MessageBox
19 from E5Gui.E5Application import e5App
20
21 import Globals
22 import UI.PixmapCache
23 from UI.Info import Version, Program
24
25 import Utilities
26 import Preferences
27
28 from eric6config import getConfig
29
30
31 class TrayStarter(QSystemTrayIcon):
32 """
33 Class implementing a starter for the system tray.
34 """
35 def __init__(self, settingsDir):
36 """
37 Constructor
38
39 @param settingsDir directory to be used for the settings files
40 @type str
41 """
42 super().__init__(
43 UI.PixmapCache.getIcon(
44 Preferences.getTrayStarter("TrayStarterIcon")))
45
46 self.settingsDir = settingsDir
47
48 self.maxMenuFilePathLen = 75
49
50 self.rsettings = QSettings(
51 QSettings.Format.IniFormat,
52 QSettings.Scope.UserScope,
53 Globals.settingsNameOrganization,
54 Globals.settingsNameRecent)
55
56 self.recentProjects = []
57 self.__loadRecentProjects()
58 self.recentMultiProjects = []
59 self.__loadRecentMultiProjects()
60 self.recentFiles = []
61 self.__loadRecentFiles()
62
63 self.activated.connect(self.__activated)
64
65 self.__menu = QMenu(self.tr("eric tray starter"))
66
67 self.recentProjectsMenu = QMenu(
68 self.tr('Recent Projects'), self.__menu)
69 self.recentProjectsMenu.aboutToShow.connect(
70 self.__showRecentProjectsMenu)
71 self.recentProjectsMenu.triggered.connect(self.__openRecent)
72
73 self.recentMultiProjectsMenu = QMenu(
74 self.tr('Recent Multiprojects'), self.__menu)
75 self.recentMultiProjectsMenu.aboutToShow.connect(
76 self.__showRecentMultiProjectsMenu)
77 self.recentMultiProjectsMenu.triggered.connect(self.__openRecent)
78
79 self.recentFilesMenu = QMenu(self.tr('Recent Files'), self.__menu)
80 self.recentFilesMenu.aboutToShow.connect(self.__showRecentFilesMenu)
81 self.recentFilesMenu.triggered.connect(self.__openRecent)
82
83 act = self.__menu.addAction(
84 self.tr("eric tray starter"), self.__about)
85 font = act.font()
86 font.setBold(True)
87 act.setFont(font)
88 self.__menu.addSeparator()
89
90 self.__menu.addAction(
91 self.tr("Show Versions"), self.__showVersions)
92 self.__menu.addSeparator()
93
94 self.__menu.addAction(
95 self.tr("QRegularExpression editor"),
96 self.__startQRegularExpression)
97 self.__menu.addAction(
98 self.tr("Python re editor"), self.__startPyRe)
99 self.__menu.addSeparator()
100
101 self.__menu.addAction(
102 UI.PixmapCache.getIcon("uiPreviewer"),
103 self.tr("UI Previewer"), self.__startUIPreviewer)
104 self.__menu.addAction(
105 UI.PixmapCache.getIcon("trPreviewer"),
106 self.tr("Translations Previewer"), self.__startTRPreviewer)
107 self.__menu.addAction(
108 UI.PixmapCache.getIcon("unittest"),
109 self.tr("Unittest"), self.__startUnittest)
110 self.__menu.addSeparator()
111
112 self.__menu.addAction(
113 UI.PixmapCache.getIcon("diffFiles"),
114 self.tr("Compare Files"), self.__startDiff)
115 self.__menu.addAction(
116 UI.PixmapCache.getIcon("compareFiles"),
117 self.tr("Compare Files side by side"), self.__startCompare)
118 self.__menu.addSeparator()
119
120 self.__menu.addAction(
121 UI.PixmapCache.getIcon("sqlBrowser"),
122 self.tr("SQL Browser"), self.__startSqlBrowser)
123 self.__menu.addSeparator()
124
125 self.__menu.addAction(
126 UI.PixmapCache.getIcon("ericSnap"),
127 self.tr("Snapshot"), self.__startSnapshot)
128 self.__menu.addAction(
129 UI.PixmapCache.getIcon("iconEditor"),
130 self.tr("Icon Editor"), self.__startIconEditor)
131 self.__menu.addSeparator()
132
133 self.__menu.addAction(
134 UI.PixmapCache.getIcon("pluginInstall"),
135 self.tr("Install Plugin"), self.__startPluginInstall)
136 self.__menu.addAction(
137 UI.PixmapCache.getIcon("pluginUninstall"),
138 self.tr("Uninstall Plugin"), self.__startPluginUninstall)
139 self.__menu.addAction(
140 UI.PixmapCache.getIcon("pluginRepository"),
141 self.tr("Plugin Repository"), self.__startPluginRepository)
142 self.__menu.addSeparator()
143
144 self.__menu.addAction(
145 UI.PixmapCache.getIcon("configure"),
146 self.tr('Preferences'), self.__startPreferences)
147 self.__menu.addSeparator()
148
149 self.__menu.addAction(
150 UI.PixmapCache.getIcon("editor"),
151 self.tr("eric Mini Editor"), self.__startMiniEditor)
152 self.__menu.addAction(
153 UI.PixmapCache.getIcon("hexEditor"),
154 self.tr("eric Hex Editor"), self.__startHexEditor)
155 self.__menu.addAction(
156 UI.PixmapCache.getIcon("shell"),
157 self.tr("eric Shell Window"), self.__startShell)
158 self.__menu.addSeparator()
159
160 self.__menu.addAction(
161 UI.PixmapCache.getIcon("ericWeb"),
162 self.tr("eric Web Browser"), self.__startWebBrowser)
163 self.__menu.addAction(
164 UI.PixmapCache.getIcon("ericWeb"),
165 self.tr("eric Web Browser (with QtHelp)"),
166 self.__startWebBrowserQtHelp)
167 self.__menu.addAction(
168 UI.PixmapCache.getIcon("ericWeb"),
169 self.tr("eric Web Browser (Private Mode)"),
170 self.__startWebBrowserPrivate)
171 self.__menu.addSeparator()
172
173 # recent files
174 self.menuRecentFilesAct = self.__menu.addMenu(self.recentFilesMenu)
175 # recent multi projects
176 self.menuRecentMultiProjectsAct = self.__menu.addMenu(
177 self.recentMultiProjectsMenu)
178 # recent projects
179 self.menuRecentProjectsAct = self.__menu.addMenu(
180 self.recentProjectsMenu)
181 self.__menu.addSeparator()
182
183 self.__menu.addAction(
184 UI.PixmapCache.getIcon("erict"),
185 self.tr("eric IDE"), self.__startEric)
186 self.__menu.addSeparator()
187
188 self.__menu.addAction(
189 UI.PixmapCache.getIcon("configure"),
190 self.tr('Configure Tray Starter'), self.__showPreferences)
191 self.__menu.addSeparator()
192
193 self.__menu.addAction(
194 UI.PixmapCache.getIcon("exit"),
195 self.tr('Quit'), e5App().quit)
196
197 def __loadRecentProjects(self):
198 """
199 Private method to load the recently opened project filenames.
200 """
201 rp = self.rsettings.value(Globals.recentNameProject)
202 if rp is not None:
203 for f in rp:
204 if QFileInfo(f).exists():
205 self.recentProjects.append(f)
206
207 def __loadRecentMultiProjects(self):
208 """
209 Private method to load the recently opened multi project filenames.
210 """
211 rmp = self.rsettings.value(Globals.recentNameMultiProject)
212 if rmp is not None:
213 for f in rmp:
214 if QFileInfo(f).exists():
215 self.recentMultiProjects.append(f)
216
217 def __loadRecentFiles(self):
218 """
219 Private method to load the recently opened filenames.
220 """
221 rf = self.rsettings.value(Globals.recentNameFiles)
222 if rf is not None:
223 for f in rf:
224 if QFileInfo(f).exists():
225 self.recentFiles.append(f)
226
227 def __activated(self, reason):
228 """
229 Private slot to handle the activated signal.
230
231 @param reason reason code of the signal
232 (QSystemTrayIcon.ActivationReason)
233 """
234 if reason in (
235 QSystemTrayIcon.ActivationReason.Context,
236 QSystemTrayIcon.ActivationReason.MiddleClick
237 ):
238 self.__showContextMenu()
239 elif reason == QSystemTrayIcon.ActivationReason.DoubleClick:
240 self.__startEric()
241
242 def __showContextMenu(self):
243 """
244 Private slot to show the context menu.
245 """
246 self.menuRecentProjectsAct.setEnabled(len(self.recentProjects) > 0)
247 self.menuRecentMultiProjectsAct.setEnabled(
248 len(self.recentMultiProjects) > 0)
249 self.menuRecentFilesAct.setEnabled(len(self.recentFiles) > 0)
250
251 pos = QCursor.pos()
252 x = pos.x() - self.__menu.sizeHint().width()
253 pos.setX(x > 0 and x or 0)
254 y = pos.y() - self.__menu.sizeHint().height()
255 pos.setY(y > 0 and y or 0)
256 self.__menu.popup(pos)
257
258 def __startProc(self, applName, *applArgs):
259 """
260 Private method to start an eric application.
261
262 @param applName name of the eric application script (string)
263 @param *applArgs variable list of application arguments
264 """
265 proc = QProcess()
266 applPath = os.path.join(getConfig("ericDir"), applName)
267
268 args = []
269 args.append(applPath)
270 args.append("--config={0}".format(Utilities.getConfigDir()))
271 if self.settingsDir:
272 args.append("--settings={0}".format(self.settingsDir))
273 for arg in applArgs:
274 args.append(arg)
275
276 if (
277 not os.path.isfile(applPath) or
278 not proc.startDetached(sys.executable, args)
279 ):
280 E5MessageBox.critical(
281 self,
282 self.tr('Process Generation Error'),
283 self.tr(
284 '<p>Could not start the process.<br>'
285 'Ensure that it is available as <b>{0}</b>.</p>'
286 ).format(applPath),
287 self.tr('OK'))
288
289 def __startMiniEditor(self):
290 """
291 Private slot to start the eric Mini Editor.
292 """
293 self.__startProc("eric6_editor.py")
294
295 def __startEric(self):
296 """
297 Private slot to start the eric IDE.
298 """
299 self.__startProc("eric6.py")
300
301 def __startPreferences(self):
302 """
303 Private slot to start the eric configuration dialog.
304 """
305 self.__startProc("eric6_configure.py")
306
307 def __startPluginInstall(self):
308 """
309 Private slot to start the eric plugin installation dialog.
310 """
311 self.__startProc("eric6_plugininstall.py")
312
313 def __startPluginUninstall(self):
314 """
315 Private slot to start the eric plugin uninstallation dialog.
316 """
317 self.__startProc("eric6_pluginuninstall.py")
318
319 def __startPluginRepository(self):
320 """
321 Private slot to start the eric plugin repository dialog.
322 """
323 self.__startProc("eric6_pluginrepository.py")
324
325 def __startWebBrowser(self):
326 """
327 Private slot to start the eric web browser.
328 """
329 variant = Globals.getWebBrowserSupport()
330 if variant == "QtWebEngine":
331 self.__startProc("eric6_browser.py")
332
333 def __startWebBrowserQtHelp(self):
334 """
335 Private slot to start the eric web browser with QtHelp support.
336 """
337 variant = Globals.getWebBrowserSupport()
338 if variant == "QtWebEngine":
339 self.__startProc("eric6_browser.py", "--qthelp")
340
341 def __startWebBrowserPrivate(self):
342 """
343 Private slot to start the eric web browser in private mode.
344 """
345 variant = Globals.getWebBrowserSupport()
346 if variant == "QtWebEngine":
347 self.__startProc("eric6_browser.py", "--private")
348
349 def __startUIPreviewer(self):
350 """
351 Private slot to start the eric UI previewer.
352 """
353 self.__startProc("eric6_uipreviewer.py")
354
355 def __startTRPreviewer(self):
356 """
357 Private slot to start the eric translations previewer.
358 """
359 self.__startProc("eric6_trpreviewer.py")
360
361 def __startUnittest(self):
362 """
363 Private slot to start the eric unittest dialog.
364 """
365 self.__startProc("eric6_unittest.py")
366
367 def __startDiff(self):
368 """
369 Private slot to start the eric diff dialog.
370 """
371 self.__startProc("eric6_diff.py")
372
373 def __startCompare(self):
374 """
375 Private slot to start the eric compare dialog.
376 """
377 self.__startProc("eric6_compare.py")
378
379 def __startSqlBrowser(self):
380 """
381 Private slot to start the eric sql browser dialog.
382 """
383 self.__startProc("eric6_sqlbrowser.py")
384
385 def __startIconEditor(self):
386 """
387 Private slot to start the eric icon editor dialog.
388 """
389 self.__startProc("eric6_iconeditor.py")
390
391 def __startSnapshot(self):
392 """
393 Private slot to start the eric snapshot dialog.
394 """
395 self.__startProc("eric6_snap.py")
396
397 def __startQRegularExpression(self):
398 """
399 Private slot to start the eric QRegularExpression editor dialog.
400 """
401 self.__startProc("eric6_qregularexpression.py")
402
403 def __startPyRe(self):
404 """
405 Private slot to start the eric Python re editor dialog.
406 """
407 self.__startProc("eric6_re.py")
408
409 def __startHexEditor(self):
410 """
411 Private slot to start the eric hex editor dialog.
412 """
413 self.__startProc("eric6_hexeditor.py")
414
415 def __startShell(self):
416 """
417 Private slot to start the eric Shell window.
418 """
419 self.__startProc("eric6_shell.py")
420
421 def __showRecentProjectsMenu(self):
422 """
423 Private method to set up the recent projects menu.
424 """
425 self.recentProjects = []
426 self.rsettings.sync()
427 self.__loadRecentProjects()
428
429 self.recentProjectsMenu.clear()
430
431 for idx, rp in enumerate(self.recentProjects, start=1):
432 formatStr = '&{0:d}. {1}' if idx < 10 else '{0:d}. {1}'
433 act = self.recentProjectsMenu.addAction(
434 formatStr.format(
435 idx, Utilities.compactPath(rp, self.maxMenuFilePathLen)))
436 act.setData(rp)
437
438 def __showRecentMultiProjectsMenu(self):
439 """
440 Private method to set up the recent multi projects menu.
441 """
442 self.recentMultiProjects = []
443 self.rsettings.sync()
444 self.__loadRecentMultiProjects()
445
446 self.recentMultiProjectsMenu.clear()
447
448 for idx, rmp in enumerate(self.recentMultiProjects, start=1):
449 formatStr = '&{0:d}. {1}' if idx < 10 else '{0:d}. {1}'
450 act = self.recentMultiProjectsMenu.addAction(
451 formatStr.format(
452 idx, Utilities.compactPath(rmp, self.maxMenuFilePathLen)))
453 act.setData(rmp)
454
455 def __showRecentFilesMenu(self):
456 """
457 Private method to set up the recent files menu.
458 """
459 self.recentFiles = []
460 self.rsettings.sync()
461 self.__loadRecentFiles()
462
463 self.recentFilesMenu.clear()
464
465 for idx, rf in enumerate(self.recentFiles, start=1):
466 formatStr = '&{0:d}. {1}' if idx < 10 else '{0:d}. {1}'
467 act = self.recentFilesMenu.addAction(
468 formatStr.format(
469 idx, Utilities.compactPath(rf, self.maxMenuFilePathLen)))
470 act.setData(rf)
471
472 def __openRecent(self, act):
473 """
474 Private method to open a project or file from the list of recently
475 opened projects or files.
476
477 @param act reference to the action that triggered (QAction)
478 """
479 filename = act.data()
480 if filename:
481 self.__startProc(
482 "eric6.py",
483 filename)
484
485 def __showPreferences(self):
486 """
487 Private slot to set the preferences.
488 """
489 from Preferences.ConfigurationDialog import (
490 ConfigurationDialog, ConfigurationMode
491 )
492 dlg = ConfigurationDialog(
493 None, 'Configuration', True, fromEric=True,
494 displayMode=ConfigurationMode.TRAYSTARTERMODE)
495 dlg.preferencesChanged.connect(self.preferencesChanged)
496 dlg.show()
497 dlg.showConfigurationPageByName("trayStarterPage")
498 dlg.exec()
499 QApplication.processEvents()
500 if dlg.result() == QDialog.DialogCode.Accepted:
501 dlg.setPreferences()
502 Preferences.syncPreferences()
503 self.preferencesChanged()
504
505 def preferencesChanged(self):
506 """
507 Public slot to handle a change of preferences.
508 """
509 self.setIcon(
510 UI.PixmapCache.getIcon(
511 Preferences.getTrayStarter("TrayStarterIcon")))
512
513 def __about(self):
514 """
515 Private slot to handle the About dialog.
516 """
517 from Plugins.AboutPlugin.AboutDialog import AboutDialog
518 dlg = AboutDialog()
519 dlg.exec()
520
521 def __showVersions(self):
522 """
523 Private slot to handle the Versions dialog.
524 """
525 from PyQt5.QtCore import qVersion, PYQT_VERSION_STR
526 from PyQt5.Qsci import QSCINTILLA_VERSION_STR
527
528 try:
529 try:
530 from PyQt5 import sip
531 except ImportError:
532 import sip
533 sip_version_str = sip.SIP_VERSION_STR
534 except (ImportError, AttributeError):
535 sip_version_str = "sip version not available"
536
537 versionText = self.tr(
538 """<h3>Version Numbers</h3>"""
539 """<table>""")
540 versionText += (
541 """<tr><td><b>Python</b></td><td>{0}</td></tr>"""
542 .format(sys.version.split()[0])
543 )
544 versionText += (
545 """<tr><td><b>Qt</b></td><td>{0}</td></tr>"""
546 .format(qVersion())
547 )
548 versionText += (
549 """<tr><td><b>PyQt</b></td><td>{0}</td></tr>"""
550 .format(PYQT_VERSION_STR)
551 )
552 versionText += (
553 """<tr><td><b>sip</b></td><td>{0}</td></tr>"""
554 .format(sip_version_str)
555 )
556 versionText += (
557 """<tr><td><b>QScintilla</b></td><td>{0}</td></tr>"""
558 .format(QSCINTILLA_VERSION_STR)
559 )
560 with contextlib.suppress(ImportError):
561 from WebBrowser.Tools import WebBrowserTools
562 chromeVersion = WebBrowserTools.getWebEngineVersions()[0]
563 versionText += (
564 """<tr><td><b>WebEngine</b></td><td>{0}</td></tr>"""
565 .format(chromeVersion)
566 )
567 versionText += (
568 """<tr><td><b>{0}</b></td><td>{1}</td></tr>"""
569 .format(Program, Version)
570 )
571 versionText += self.tr("""</table>""")
572
573 E5MessageBox.about(None, Program, versionText)

eric ide

mercurial