src/eric7/Tools/TrayStarter.py

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

eric ide

mercurial