You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
calculate-utils-3-console-gui/pym/consolegui/application/TrayIcon.py

371 lines
14 KiB

#-*- coding: utf-8 -*-
# Copyright 2012-2013 Calculate Ltd. http://www.calculate-linux.org
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from PySide import QtGui, QtCore
import time, urllib2
from calculate.core.client.function import create_obj
try:
from calculate.update.update_info import UpdateInfo
except ImportError:
UpdateInfo = None
import dbus
from ReturnMessage import ReturnedMessage
from calculate.consolegui.application.pid_information import client_pid_info, \
client_list_pid
from more import show_msg, get_sid, _print
#class MySignal(QtCore.QObject):
# sig = QtCore.Signal(str, str)
class TrayUpdateSystem(QtCore.QThread):
mes_sig = QtCore.Signal(str, str)
started_sig = QtCore.Signal(str)
def __init__(self, target, parent = None):
QtCore.QThread.__init__(self, parent)
self._parent = target
def run(self):
self.close_flag = False
if not hasattr(self._parent, 'localhost_ClientObj'):
self.mes_sig.emit(_('Connection Error'), \
_('You are not connected to the localhost server'))
return 1
if not self._parent.localhost_ClientObj.client:
self.mes_sig.emit(_('Connection Error'), \
_('You are not connected to the localhost server'))
return 1
sid = get_sid(self._parent.localhost_ClientObj.client)
try:
param_object = create_obj(self._parent.localhost_ClientObj.client,
"update")
meth_result_temp = \
self._parent.localhost_ClientObj.client.service.update(
sid, param_object)
except Exception, e:
msg = e.message
if type (e.message) == tuple:
msg = ' '.join( map(lambda x:str(x), list(e.message)))
self.mes_sig.emit(msg, 'cl-client-console Exception')
return 1
meth_result = []
method_name = 'System update tray'
error = False
for res in meth_result_temp[0]:
meth_result.append(ReturnedMessage(res.type, res.field, \
res.message, res.expert))
if res.type == 'error':
error = True
if error:
return 1
if meth_result[0].type == "pid":
# create process dict
self._parent.localhost_ClientObj.process_dict \
[meth_result[0].message] = {}
self._parent.localhost_ClientObj.process_dict \
[meth_result[0].message]['result'] = meth_result[0]
self._parent.localhost_ClientObj.process_dict \
[meth_result[0].message]['name'] = method_name
self._parent.localhost_ClientObj.process_dict \
[meth_result[0].message]['layout'] = QtGui.QVBoxLayout()
self._parent.localhost_ClientObj.process_dict \
[meth_result[0].message]['layout'].setAlignment \
(QtCore.Qt.AlignTop)
else:
return 1
#self.mes_sig.emit('', _('Update running'))
mess = meth_result[0]
pid = mess.message
self._parent.sys_update_pid = int(pid)
self.started_sig.emit(pid)
#self.get_update_status(sid, pid)
def get_update_status(self, sid, pid):
end_frame = True
try:
current_frame = self._parent.localhost_ClientObj.client.\
service.get_entire_frame(sid, pid)
except urllib2.URLError:
_print ('get_entire_frame in TrayIcon Exception')
current_frame = None
while end_frame:
while current_frame in [None, [], ""]:
for i in range(5):
time.sleep(0.1)
if self.close_flag:
#self.mes_sig.emit('', _('Update aborted'))
return 0
try:
client = self._parent.localhost_ClientObj.client
current_frame = client.service.get_frame(sid, pid,"gui")
except urllib2.URLError:
_print ('client.service.get_entire_frame in'
' TrayIcon Exception')
current_frame = None
for item in range(len(current_frame[0])):
if current_frame[0][item].type == 'error':
#self.mes_sig.emit(_("Failed to update!"), \
# current_frame[0][item].message)
end_frame = False
return 1
elif current_frame[0][item].type == 'endFrame':
if current_frame[0][item].message:
message = current_frame[0][item].message
else:
message = ''
#self.mes_sig.emit(_('Update successfully completed'), \
# message)
end_frame = False
current_frame = None
def close(self):
self.close_flag = True
class TrayIcon (QtGui.QSystemTrayIcon):
default_theme_name = 'Tango'
def __init__(self, parent):
super(TrayIcon, self).__init__(parent)
self._parent = parent
self.actions = []
self.setIcon(QtGui.QIcon(
'/usr/share/pixmaps/calculate-console-offline.png'))
self.generation_actions()
self.right_menu = self.create_menu('help', 'bug_report', None, 'tools',
'update_system', None, 'exit')
self.activated.connect(self.activ)
self.setToolTip('cl-console-gui - '+ _('System control'))
self.setContextMenu(self.right_menu)
self.update_thread = TrayUpdateSystem(parent)
self.update_thread.mes_sig.connect(self.showMessage)
self.update_thread.started_sig.connect(self.showUpdate)
def select_icon(self, icons):
old_theme_name = QtGui.QIcon.themeName()
try:
for theme_name in (old_theme_name, self.default_theme_name):
QtGui.QIcon.setThemeName(theme_name)
for image in icons:
if QtGui.QIcon.hasThemeIcon(image):
return QtGui.QIcon.fromTheme(image)
return QtGui.QIcon()
finally:
QtGui.QIcon.setThemeName(old_theme_name)
def generation_actions(self):
_("About")
_("Report a Bug")
_("Program settings")
_("Update System")
_("Exit Program")
self.actions = {
'help': {
'icons': ['help-about', 'help-browser'],
'label': "About",
'trigger': self.help},
'bug_report': {
'icons': ['tools-report-bug', 'system-help',
'help-browser'],
'label': "Report a Bug",
'trigger': self.bug_report},
'tools': {
'icons': ['preferences-other', 'preferences-system'],
'label': "Program settings",
'trigger': self.tools},
'update_system': {
'icons': ['system-software-update'],
'label': "Update System",
'trigger': self.start_update_system},
'exit': {
'icons': ["application-exit", "system-log-out"],
'label': "Exit Program",
'trigger': self.exit},
'show_hide': {
'icons': ['preferences-system-windows'],
'label': "Show/Hide Window",
'trigger': self.windowVisible}
}
for action_name, action_data in self.actions.items():
setattr(self, '%s_action' % action_name,
QtGui.QAction(self.select_icon(action_data['icons']),
_(action_data['label']), self,
triggered=action_data['trigger']))
def create_menu(self, *actions):
menu = QtGui.QMenu()
for action in actions:
if action:
menu.addAction(getattr(self, "%s_action" % action))
else:
menu.addSeparator()
return menu
def check_for_update(self):
if self._parent.localhost_ClientObj:
if UpdateInfo:
uinfo = UpdateInfo(self._parent.localhost_ClientObj.VarsApi)
return (uinfo.need_update() and
not uinfo.update_already_run() and
not self.get_update_pid() and
not self.update_thread.isRunning())
return False
def set_icon(self, online, has_update=None):
if has_update is None:
if self.check_for_update():
has_update = True
else:
has_update = False
if online:
if has_update:
self.setIcon(QtGui.QIcon \
('/usr/share/pixmaps/calculate-console-update.png'))
else:
self.setIcon(QtGui.QIcon \
('/usr/share/pixmaps/calculate-console-online.png'))
else:
self.setIcon(QtGui.QIcon \
('/usr/share/pixmaps/calculate-console-offline.png'))
def translate(self):
for action_name, action_data in self.actions.items():
getattr(self, '%s_action' % action_name).setText(
_(action_data['label']))
def help(self):
self._parent.currentWidget().help()
def bug_report(self):
self._parent.currentWidget().bug_report()
def tools(self):
self._parent.currentWidget().tools()
def get_update_pid(self):
"""
Получить pid процесса выполняющего update для этой сессии
"""
pid = str(self._parent.sys_update_pid)
client_obj = self._parent.localhost_ClientObj
pids = map(str, client_pid_info(client_obj, client_obj.client, 0))
if self._parent.localhost_ClientObj:
if pid and pid in client_obj.process_dict and pid in pids:
return pid
else:
for pid in pids:
d = client_obj.process_dict[pid]
if (d['method_name'] == 'update'
and d.get('status', '0') == '1'):
return pid
def show_update(self):
pid = self.get_update_pid()
if pid:
client_obj = self._parent.localhost_ClientObj
client_pid_info(client_obj, client_obj.client, 0)
client_obj._parent.setWindowTitle \
("Calculate console" + ' - ' + _('System Update'))
result = client_obj.process_dict[pid]['result']
client_obj.MainWidget.main_view_process('update', result, pid)
client_obj.app.processEvents()
vsb = client_obj.MainWidget.main_frame.verticalScrollBar()
vsb.setValue(vsb.maximum())
self._parent.hide()
self._parent.show()
self._parent.showNormal()
else:
self._parent.show()
self._parent.move(self._parent.cur_pos)
self._parent.show()
def exit(self):
#if self.update_thread.isRunning():
# text = _('The system is updated')
# informative_text = _('Stop updating and exit?')
# reply = show_question(self._parent, text, informative_text)
# if reply == QtGui.QMessageBox.No:
# return 0
# elif reply == QtGui.QMessageBox.Yes:
# self.update_thread.close()
# self.update_thread.wait()
self._parent._closeEvent()
def activ(self, reason):
if reason == QtGui.QSystemTrayIcon.Trigger:
if self.check_for_update():
self.start_update_system()
return
else:
self.windowVisible()
if reason == QtGui.QSystemTrayIcon.DoubleClick:
self.windowVisible()
def showMessage(self, title, message, icon = 'dialog-warning'):
# This uses the session bus because it's session-specific.
bus = dbus.SessionBus()
proxy = bus.get_object('org.freedesktop.Notifications', \
'/org/freedesktop/Notifications')
interface = dbus.Interface(proxy,dbus_interface= \
'org.freedesktop.Notifications')
interface.Notify('cl-console-gui', 1, icon, title, message, [], {}, -1)
# KDE KNotify
#bus = dbus.SessionBus()
#knotify = bus.get_object('org.kde.knotify', '/Notify')
#knotify.event("warning", "kde", [], 'title', 'text', [], [], 0, 0,
# dbus_interface="org.kde.KNotify")
def windowVisible(self):
if self._parent.isVisible():
self._parent.cur_pos = self._parent.pos()
self._parent.hide()
else:
self._parent.show()
self._parent.move(self._parent.cur_pos)
def start_update_system(self):
self.set_icon(True, False)
if self.get_update_pid():
self.show_update()
else:
self.update_thread.start()
#if not self.update_thread.isRunning():
def showUpdate(self, message):
self.show_update()