eric6/Tools/TrayStarter.py

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

eric ide

mercurial