#! /usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Copyright 2022 , Nils Hilbricht , Germany ( https : / / www . hilbricht . net )
This file is part of the Laborejo Software Suite ( https : / / www . laborejo . org ) ,
This is free software : you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation , either version 3 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program . If not , see < http : / / www . gnu . org / licenses / > .
"""
import logging ; logger = logging . getLogger ( __name__ ) ; logger . info ( " import " )
#Third Party
from PyQt5 import QtCore , QtGui , QtWidgets
#Engine
import engine . api as api #This loads the engine and starts a session.
#QtGui
from . addclientprompt import askForExecutable
from . resources import *
class SystemTray ( QtWidgets . QSystemTrayIcon ) :
def __init__ ( self , mainWindow ) :
super ( ) . __init__ ( QtGui . QIcon ( " :icon.png " ) )
self . mainWindow = mainWindow
self . available = self . isSystemTrayAvailable ( )
self . show ( )
#self.showMessage("Title", "Helllo!", QtWidgets.QSystemTrayIcon.Information) #title, message, icon, timeout. #has messageClicked() signal.
#Don't build the context menu here. The engine is not ready to provide us with session information. Let the callbacks do it.
#self.messageClicked.connect(self._reactSignal_messageClicked)
self . activated . connect ( self . _reactSignal_activated )
#Connect to api callbacks to rebuild context menu when session changes
api . callbacks . sessionClosed . append ( self . buildContextMenu )
api . callbacks . sessionOpenReady . append ( self . buildContextMenu )
api . callbacks . sessionsChanged . append ( self . buildContextMenu )
#api.callbacks.clientStatusChanged.append(self.buildContextMenu) #too much. We deal with the client list separately.
self . toggleVisMenu = None
def updateToggleVisMenu ( self ) :
if not self . toggleVisMenu or not api . currentSession ( ) : return #program start or not in a session
for a in self . toggleVisMenu . findChildren ( QtWidgets . QAction ) :
if not a . menu ( ) :
self . toggleVisMenu . removeAction ( a )
del a
for clientItem in self . mainWindow . sessionController . openSessionController . allSessionItems ( ) :
if clientItem . clientDict [ " hasOptionalGUI " ] :
a = QtWidgets . QAction ( clientItem . clientDict [ " reportedName " ] , self . toggleVisMenu )
self . toggleVisMenu . addAction ( a )
def createToggleLambda ( clientId ) :
return lambda : api . clientToggleVisible ( clientId )
command = createToggleLambda ( clientItem . clientDict [ " clientId " ] )
a . triggered . connect ( command )
def buildContextMenu ( self , * args ) :
""" In a function for readability.
It gets rebuild everytime a session is opened or closed or the session list changed
"""
menu = QtWidgets . QMenu ( )
def _add ( text , function ) :
a = QtWidgets . QAction ( text , menu )
menu . addAction ( a )
a . triggered . connect ( function )
nsmSessionName = api . currentSession ( )
_add ( QtCore . QCoreApplication . translate ( " TrayIcon " , " Hide/Show Agordejo " ) , lambda : self . mainWindow . toggleVisible ( force = None ) ) #explicit force=None because the qt signal is sending a bool
menu . addSeparator ( )
#Add other pre-defined actions
if nsmSessionName : #We are in a loaded session
menu . addAction ( self . mainWindow . ui . actionShow_All_Clients )
_add ( QtCore . QCoreApplication . translate ( " TrayIcon " , " Add Client (Prompt) " ) , lambda : askForExecutable ( self . mainWindow . qtApp . desktop ( ) ) )
menu . addSeparator ( )
menu . addAction ( self . mainWindow . ui . actionShow_All_Clients )
menu . addAction ( self . mainWindow . ui . actionHide_All_Clients )
#Create a submenu to toggle visibility for all supported clients.
self . toggleVisMenu = menu . addMenu ( QtCore . QCoreApplication . translate ( " TrayIcon " , " Toggle Client Visibility " ) )
#Updated on each trayIcon show event with updateToggleVisMenu
menu . addSeparator ( )
_add ( QtCore . QCoreApplication . translate ( " TrayIcon " , " Save {} " . format ( nsmSessionName ) ) , api . sessionSave )
_add ( QtCore . QCoreApplication . translate ( " TrayIcon " , " Save && Close {} " . format ( nsmSessionName ) ) , api . sessionClose )
_add ( QtCore . QCoreApplication . translate ( " TrayIcon " , " Close without Saving {} " . format ( nsmSessionName ) ) , api . sessionAbort )
menu . addSeparator ( )
_add ( QtCore . QCoreApplication . translate ( " TrayIcon " , " Save && Quit Agordejo " ) , self . mainWindow . closeAndQuit )
_add ( QtCore . QCoreApplication . translate ( " TrayIcon " , " Close without Saving && Quit Agordejo " ) , self . mainWindow . abortAndQuit )
menu . addSeparator ( )
else :
for recentName in self . mainWindow . recentlyOpenedSessions . get ( ) :
_add ( f " Session: { recentName } " , lambda : api . sessionOpen ( recentName ) )
_add ( QtCore . QCoreApplication . translate ( " TrayIcon " , " Quit " ) , self . mainWindow . menuRealQuit )
self . setContextMenu ( menu )
def _reactSignal_activated ( self , qActivationReason ) :
"""
QtWidgets . QSystemTrayIcon . Unknown
QtWidgets . QSystemTrayIcon . Context
QtWidgets . QSystemTrayIcon . DoubleClick
QtWidgets . QSystemTrayIcon . Trigger
QtWidgets . QSystemTrayIcon . MiddleClick
"""
logger . info ( f " System tray activated with reason { qActivationReason } " )
self . updateToggleVisMenu ( )
if qActivationReason == QtWidgets . QSystemTrayIcon . Trigger :
self . mainWindow . toggleVisible ( )
#def _reactSignal_messageClicked(self):
# """this signal is emitted when the message displayed using
# showMessage() was clicked by the user."""
# print ("clicky")