From 149f87da3465bef5f792e221953fbdcc74716492 Mon Sep 17 00:00:00 2001 From: kibergus Date: Fri, 22 Jan 2010 18:45:14 +0000 Subject: [PATCH] * Non-blocking queries, hildon-home doesn't hang any more * Regexp support * Automatically shrinks width (not height) * Word wrap * Timed renew * Localization support (russian localization available) git-svn-id: file:///svnroot/ussd-widget/trunk@17 d197f4d6-dc93-42ad-8354-0da1f58e353f --- ussd-widget/build_ussd-widget.py | 6 +- .../src/usr/lib/hildon-desktop/ussd-widget.py | 800 ++++++++++++-------- 2 files changed, 470 insertions(+), 336 deletions(-) diff --git a/ussd-widget/build_ussd-widget.py b/ussd-widget/build_ussd-widget.py index 7df6871..d2748c8 100644 --- a/ussd-widget/build_ussd-widget.py +++ b/ussd-widget/build_ussd-widget.py @@ -34,11 +34,11 @@ if __name__ == "__main__": # p.postinstall="""#!/bin/sh #""" #Set here your post install script - version = "0.0.3" + version = "0.0.4" build = "0" - changeloginformation = "Perl regexp from irmin. Code adoped for threads." + changeloginformation = "Non blocking queries, code cleanup, better interface." - dir_name = "src" + dir_name = "src" #Thanks to DareTheHair from talk.maemo.org for this snippet that recursively builds the file list for root, dirs, files in os.walk(dir_name): diff --git a/ussd-widget/src/usr/lib/hildon-desktop/ussd-widget.py b/ussd-widget/src/usr/lib/hildon-desktop/ussd-widget.py index ec501bb..8bc65b6 100755 --- a/ussd-widget/src/usr/lib/hildon-desktop/ussd-widget.py +++ b/ussd-widget/src/usr/lib/hildon-desktop/ussd-widget.py @@ -8,359 +8,493 @@ import os from subprocess import * import cairo import time -from threading import * import re +import gettext + +try : + t = gettext.translation('ussd-widget', '/usr/share/locale') + _ = t.ugettext +except IOError: + print "Translation file for your language not found" + def retme(arg): + return arg + _ = retme + +# TODO Cutt off too long messages and show them in separate dialog +# how TODO widget vertical minimum size policy +# TODO make multiple widgets coexist on desktop + +class USSD_Controller: + def __init__( self, widget ) : + self.widget = widget + self.default_config = ["", "", "", "", "", ""] + self.config = self.default_config + self.timeout_version = 0 + + def save_config( self ) : + fconfig = open(os.getenv("HOME")+"/.ussdWidget.conf","w") + fconfig.writelines(["# Parameters are taken by line number, do not move them\n", "# USSD query to be run by widget\n", "number="+self.config[0], "\n"]) + fconfig.writelines(["#Parser command\n", "parser="+self.config[1], "\n"]) + fconfig.writelines(["#Chain command\n", "chain="+self.config[2], "\n"]) + fconfig.writelines(["#Update interval in minutes\n", "interval="+self.config[3], "\n"]) + fconfig.writelines(["#RegExp pattern\n", "regexp="+self.config[4], "\n"]) + fconfig.writelines(["#Widget width\n", "width="+self.config[5], "\n"]) + fconfig.close() + + def get_config( self ): + try : + config = open(os.getenv("HOME")+"/.ussdWidget.conf","r") + + error = False + i = 0 + for line in config : + i += 1 + if line[0] == '#': + continue + line=line.split('=', 2) + + if len(line) != 2 : + error = True + print _("Error reading config on line %(line)d. = or # expected.")%{"line":i} + continue + if line[0] == "number" : + self.config[0] = line[1].strip() + elif line[0] == "parser" : + self.config[1] = line[1].strip() + elif line[0] == "chain" : + self.config[2] = line[1].strip() + elif line[0] == "interval" : + self.config[3] = line[1].strip() + elif line[0] == "regexp" : + self.config[4] = line[1].strip() + elif line[0] == "width" : + self.config[5] = line[1].strip() + else : + error = True + print _("Error reading config on line %(line)d. Unexpected variable: ")%{"line":i}+line[0] + continue + + config.close() + + if error : + self.widget.error = 1 + self.widget.set_text (_("Config error"), 5000) + + return self.config + except IOError: + self.widget.error = 1 + self.widget.set_text (_("Config error"), 0) + print _("IO error while reading config") + + return self.default.config + + def on_show_settings( self, widget ) : + dialog = UssdConfigDialog(self.config) + dialog.run() + + if check_regexp( dialog.regexp.get_text() ) : + return + +# TODO Check, that we have ussd number + #if dialog.ussdNumber +# TODO check, that width and interval are integers + self.config = [ + dialog.ussdNumber.get_text(), + dialog.parser.get_text(), + dialog.chain.get_text(), + dialog.update_interval.get_text(), + dialog.regexp.get_text(), + dialog.widthEdit.get_text() + ] + + self.save_config() + + if self.config[5] != "" : +# FIXME use methods instead of accessing properties, move to widget, execute on startup + self.widget.label.set_width_chars (int(self.config[5])) + else : + self.widget.label.set_width_chars(-1) + + self.reset_timed_renew() + + dialog.destroy() + + # Before running this function widget wasn't configured + if self.config == self.default_config: + self.widget.set_text(_("Click to update")) + return + + def callback_ussd_data( self, source, condition ): + if condition == gobject.IO_IN or condition == gobject.IO_PRI : + data = source.read( ) + if len( data ) > 0 : + self.cb_reply += data + return True + else : + self.cb_ready = 1 + return False + + elif condition == gobject.IO_HUP or condition == gobject.IO_ERR : + self.cb_ready = 1 + self.process_reply() + return False + + print (_("serious problems in program logic")) + return False + + + def call_external_script( self, ussd_code ): + self.cb_ready = 0 + self.cb_reply = ""; + p = Popen(['/usr/bin/ussdquery.py', ussd_code], stdout=PIPE) + gobject.io_add_watch( p.stdout, gobject.IO_IN | gobject.IO_PRI | gobject.IO_HUP | gobject.IO_ERR , self.callback_ussd_data ) + + def ussd_renew(self, widget, event): + if self.widget.processing == 0: + if self.config : + widget.processing = 1 + widget.set_text(_("Processing"), 0) + self.call_external_script( self.config[0] ) + else : + widget.processing = 0 + widget.error = 1 + widget.set_text(_("No config"), 0) + + def process_reply( self ): + reply = self.cb_reply.strip() + + if reply == "" : + self.widget.error = 1 + self.widget.set_text (_("Error"), 5000) + else : + self.widget.error = 0 + # Pass to parser + if self.config[1] != "": + p = Popen(smart_split_string(self.config[1], reply), stdout=PIPE) + reply = p.communicate(reply+"\n")[0].strip() + # Pass to chain + if self.config[2] != "": + p = Popen(smart_split_string(self.config[2], reply)) + # Apply regexp + if self.config[4] != "": + try : + r = re.match( self.config[4], reply ).group( 1 ) + except Exception, e: + r = _("Regexp Error: ") + str( e ) + "\n" + reply + + if r : + reply = r + self.widget.set_text(reply) + self.widget.processing = 0 + + def timed_renew(self, version): + if version < self.timeout_version : + return False + self.ussd_renew(self.widget, None) + return True + + def reset_timed_renew (self) : + self.timeout_version += 1 + if self.config[3] != "" : + self.timer = gobject.timeout_add (60000*int(self.config[3]), self.timed_renew, self.timeout_version) class pHelpDialog(gtk.Dialog): - def __init__(self, heading, text): - gtk.Dialog.__init__(self, heading, None, - gtk.DIALOG_DESTROY_WITH_PARENT | gtk.DIALOG_NO_SEPARATOR, - ("OK", gtk.RESPONSE_OK)) - self.vbox.add(gtk.Label(text)) - self.show_all() - self.parent + def __init__(self, heading, text): + gtk.Dialog.__init__(self, heading, None, + gtk.DIALOG_DESTROY_WITH_PARENT | gtk.DIALOG_NO_SEPARATOR, + (_("OK").encode("utf-8"), gtk.RESPONSE_OK)) + label = gtk.Label(text) + label.set_line_wrap (True) + self.vbox.add(label) + self.show_all() + self.parent class UssdConfigDialog(gtk.Dialog): - def __init__(self, config): - gtk.Dialog.__init__(self, "USSD widget", None, - gtk.DIALOG_DESTROY_WITH_PARENT | gtk.DIALOG_NO_SEPARATOR, - ("Save", gtk.RESPONSE_OK)) - self.ussdNumber = hildon.Entry(gtk.HILDON_SIZE_AUTO) - self.ussdNumber.set_text(config[0]) - self.parser = hildon.Entry(gtk.HILDON_SIZE_AUTO) - self.parser.set_text(config[1]) - self.chain = hildon.Entry(gtk.HILDON_SIZE_AUTO) - self.chain.set_text(config[2]) - self.update_interval = hildon.Entry(gtk.HILDON_SIZE_AUTO) - self.update_interval.set_text(config[3]) - self.regexp = hildon.Entry(gtk.HILDON_SIZE_AUTO) - self.regexp.set_text(config[4]) - - phelp = gtk.Button("?") - phelp.connect("clicked", on_show_phelp) - - chelp = gtk.Button("?") - chelp.connect("clicked", on_show_chelp) - - reghelp = gtk.Button("?") - reghelp.connect("clicked", on_show_reghelp) - - numberBox = gtk.HBox() - numberBox.add(gtk.Label("USSD number")) - numberBox.add(self.ussdNumber) - self.vbox.add(numberBox) - - parserBox = gtk.HBox() - parserBox.add(gtk.Label("Parser")) - parserBox.add(phelp) - parserBox.add(self.parser) - self.vbox.add(parserBox) - - chainBox = gtk.HBox() - chainBox.add(gtk.Label("Chain")) - chainBox.add(chelp) - chainBox.add(self.chain) - self.vbox.add(chainBox) - - updateBox = gtk.HBox() - updateBox.add(gtk.Label("Update every ")) - updateBox.add(self.update_interval) - updateBox.add(gtk.Label(" minutes (BROKEN)")) - self.vbox.add(updateBox) - - regexpBox = gtk.HBox() - regexpBox.add(gtk.Label("RegExp")) - regexpBox.add(reghelp) - regexpBox.add(self.regexp) - self.vbox.add(regexpBox) - - self.show_all() - self.parent + def __init__(self, config): + gtk.Dialog.__init__(self, _("USSD widget"), None, + gtk.DIALOG_DESTROY_WITH_PARENT | gtk.DIALOG_NO_SEPARATOR, + (_("Save").encode("utf-8"), gtk.RESPONSE_OK)) + self.set_size_request(-1, 400) + self.ussdNumber = hildon.Entry(gtk.HILDON_SIZE_AUTO) + self.ussdNumber.set_text(config[0]) + self.parser = hildon.Entry(gtk.HILDON_SIZE_AUTO) + self.parser.set_text(config[1]) + self.chain = hildon.Entry(gtk.HILDON_SIZE_AUTO) + self.chain.set_text(config[2]) + self.update_interval = hildon.Entry(gtk.HILDON_SIZE_AUTO) + self.update_interval.set_text(config[3]) + self.regexp = hildon.Entry(gtk.HILDON_SIZE_AUTO) + self.regexp.set_text(config[4]) + self.widthEdit = hildon.Entry(gtk.HILDON_SIZE_AUTO) + self.widthEdit.set_text(config[5]) + + phelp = gtk.Button("?") + phelp.connect("clicked", self.on_show_phelp) + + chelp = gtk.Button("?") + chelp.connect("clicked", self.on_show_chelp) + + reghelp = gtk.Button("?") + reghelp.connect("clicked", self.on_show_reghelp) + + area = hildon.PannableArea() + self.vbox.add(area) + vbox = gtk.VBox() + area.add_with_viewport(vbox) + + numberBox = gtk.HBox() + numberLabel = gtk.Label(_("USSD number")) + numberLabel.set_alignment(0,0) + numberLabel.set_size_request(100, -1) + self.ussdNumber.set_size_request(200, -1) + numberBox.add(numberLabel) + numberBox.add(self.ussdNumber) + vbox.add(numberBox) + + parserBox = gtk.HBox() + parserLabel = gtk.Label(_("Parser")) + parserLabel.set_alignment(0,0) + parserLabel.set_size_request(200, -1) + phelp.set_size_request(10, -1) + parserBox.add(parserLabel) + parserBox.add(phelp) + vbox.add(parserBox) + vbox.add(self.parser) + + chainBox = gtk.HBox() + chainLabel = gtk.Label(_("Chain")) + chainLabel.set_alignment(0,0) + chainLabel.set_size_request(200, -1) + chelp.set_size_request(10, -1) + chainBox.add(chainLabel) + chainBox.add(chelp) + vbox.add(chainBox) + vbox.add(self.chain) + + regexpBox = gtk.HBox() + regexpLabel = gtk.Label(_("RegExp")) + regexpLabel.set_alignment(0,0) + regexpLabel.set_size_request(200, -1) + reghelp.set_size_request(10, -1) + regexpBox.add(regexpLabel) + regexpBox.add(reghelp) + vbox.add(regexpBox) + vbox.add(self.regexp) + + widthBox = gtk.HBox() + widthLabel = gtk.Label(_("Max. width")) + widthLabel.set_alignment(0,0) + symbolsLabel = gtk.Label(_("symbols")) + widthLabel.set_size_request(150, -1) + self.widthEdit.set_size_request(30, -1) + symbolsLabel.set_size_request(40,-1) + widthBox.add(widthLabel) + widthBox.add(self.widthEdit) + widthBox.add(symbolsLabel) + vbox.add(widthBox) + + updateBox = gtk.HBox() + updateLabel = gtk.Label(_("Update every")) + updateLabel.set_alignment(0,0) + minutesLabel = gtk.Label(_("minutes")) + updateLabel.set_size_request(150, -1) + self.update_interval.set_size_request(30, -1) + minutesLabel.set_size_request(40, -1) + updateBox.add(updateLabel) + updateBox.add(self.update_interval) + updateBox.add(minutesLabel) + vbox.add(updateBox) + + self.show_all() + self.parent + + #============ Dialog helper functions ============= + def on_show_phelp(self, widget): + dialog = pHelpDialog(_("Format help"), _("Reply would be passed to specified utility, output of utility would be shown to you.\n Format:\n% would be replaced by reply\n\\ invalidates special meaming of following symbol\n\" and ' work as usual\nspace delimits command line parameters of utility")) + dialog.run() + dialog.destroy() + + def on_show_chelp(self, widget): + dialog = pHelpDialog(_("Format help"), _("Reply would be passed to specified utility after parser utility. May be used for logging, statistics etc.\n Format:\n% would be replaced by reply\n\\ invalidates special meaning of following symbol\n\" and ' work as usual\nspace delimits command line parameters of utility")) + dialog.run() + dialog.destroy() + + def on_show_reghelp(self, widget): + dialog = pHelpDialog(_("Format help"), _("standard python regexps")) + dialog.run() + dialog.destroy() + + def on_error_regexp(self, error): + dialog = pHelpDialog(_("Regexp syntax error"), error ) + dialog.run() + dialog.destroy() + + # TODO Use this for reporting error on wrong ussd number + def on_error_ussd_number(self, error): + dialog = pHelpDialog(_("Incorrect USSD number"), error ) + dialog.run() + dialog.destroy() + def smart_split_string (str, query) : - word = "" - result = [] - # Is simbol backslashed? - bs = 0 - # Quotes: 1 - ", 2 - ', 0 - no quotes - qs = 0 - for i in range(len(str)) : - if bs == 0 and (str[i] == '"' and qs == 1 or str[i] == "'" and qs == 2) : - qs = 0 - elif bs == 0 and qs == 0 and (str[i] == '"' or str[i] == "'") : - if str[i] == '"': - qs = 1 - else : - qs = 2 - elif bs == 0 and str[i] == '\\' : - bs = 1 - elif bs == 0 and str[i] == '%' : - word += query - ws = 0 - else : - if bs == 1 and str[i] != '\\' and str[i] != '"' and str[i] != "'" : - word += "\\" - if qs == 0 and (str[i] == " " or str[i] == "\t") : - if word != "" : - result.append(word) - word = "" - else : - word += str[i] - bs = 0 - if word != "" : - result.append(word) - return result - -def get_config(): - try : - config = open(os.getenv("HOME")+"/.ussdWidget.conf","r") - config.readline() - config.readline() - number = config.readline().strip() - config.readline() - parser = config.readline().strip() - config.readline() - chain = config.readline().strip() - config.readline() - interval = config.readline().strip() - config.readline() - regexp = config.readline().strip() - config.close() - return [number, parser, chain, interval, regexp] - except IOError: - return None - -def set_config(config): - fconfig = open(os.getenv("HOME")+"/.ussdWidget.conf","w") - fconfig.writelines(["# Parameters are taken by line number, do not move them\n", "# USSD query to be run by widget\n", config[0], "\n"]) - fconfig.writelines(["Parser command\n", config[1], "\n"]) - fconfig.writelines(["Chain command\n", config[2], "\n"]) - fconfig.writelines(["Update interval in minutes\n", config[3], "\n"]) - fconfig.writelines(["RegExp pattern\n", config[4], "\n"]) - fconfig.close() + word = "" + result = [] + # Is simbol backslashed? + bs = 0 + # Quotes: 1 - ", 2 - ', 0 - no quotes + qs = 0 + for i in range(len(str)) : + if bs == 0 and (str[i] == '"' and qs == 1 or str[i] == "'" and qs == 2) : + qs = 0 + elif bs == 0 and qs == 0 and (str[i] == '"' or str[i] == "'") : + if str[i] == '"': + qs = 1 + else : + qs = 2 + elif bs == 0 and str[i] == '\\' : + bs = 1 + elif bs == 0 and str[i] == '%' : + word += query + ws = 0 + else : + if bs == 1 and str[i] != '\\' and str[i] != '"' and str[i] != "'" : + word += "\\" + if qs == 0 and (str[i] == " " or str[i] == "\t") : + if word != "" : + result.append(word) + word = "" + else : + word += str[i] + bs = 0 + if word != "" : + result.append(word) + return result def check_regexp(regexp): try : - re.compile( regexp ) + re.compile( regexp ) except Exception, e: - on_error_regexp( str( e ) ) - return 1 + on_error_regexp( str( e ) ) + return 1 return 0 -#def timed_renewer(Thread): -# def __init__ (self, widget, period): -# self.widget = widget -# self.period = period -# self.version = widget.timerversion -# -# def run (self): -# while widget.timerversion == version: -# ussd_renew(widget, None) -# time.sleep(period) - -def ussd_renew(widget, event): - if widget.process == None or widget.process.isAlive() == False : - widget.process = ussd_renewer (widget) - # See bug https://bugs.maemo.org/show_bug.cgi?id=7809 - widget.process.run() - -class ussd_renewer ():#Thread): - def __init__ (self, widget): -# Thread.__init__ (self) - self.widget = widget - self.daemon = True - -# stub while thread but is not fixed - def isAlive(self): - return False - - def run(self): - widget = self.widget - config = get_config() - widget.processing = 1 - last_text = widget.label.get_text() - widget.label.set_text("Processing") - widget.queue_draw() - gtk.main_iteration () - - if config : - p = Popen(['/usr/bin/ussdquery.py', config[0]], stdout=PIPE) - reply = p.communicate()[0].strip() - if reply == "" : - reply = " Error " - widget.error = 1 - # Show previous text in 5 seconds - widget.timer = gobject.timeout_add (5000, error_return, widget, last_text) - else : - widget.error = 0 - if config[1] != "": - p = Popen(smart_split_string(config[1], reply), stdout=PIPE) - reply = p.communicate(reply+"\n")[0].strip() - if config[2] != "": - p = Popen(smart_split_string(config[2], reply)) - if config[4] != "": - try : - r = re.match( config[4], reply ).group( 1 ) - except Exception, e: - r = "Regexp Error: " + str( e ) - - if r : - reply = r - else : - reply = " Bad config " - widget.processing = 0 - widget.label.set_text(reply) - widget.queue_draw() - gtk.main_iteration () - -def error_return(widget, text) : - if widget.processing == 0 and widget.error == 1: - widget.label.set_text(text) - return False - -def on_show_settings(widget): - config = get_config() - if config == None : - config = ["", "", "", "", ""] - - dialog = UssdConfigDialog(config) - dialog.run() - - if check_regexp( dialog.regexp.get_text() ) : - return - - set_config ([dialog.ussdNumber.get_text(), dialog.parser.get_text(), dialog.chain.get_text(), dialog.update_interval.get_text(), dialog.regexp.get_text()]) - -# Doesn't work in hildon-home -# widget.timerversion += 1 -# if dialog.update_interval.get_text() != "" : -# ussd_renewer (widget, 60000*int(dialog.update_interval.get_text())) - - dialog.destroy() - - if config == ["", "", "", "", ""] : - widget.label.set_text("Click to update") - -def on_show_phelp(widget): - dialog = pHelpDialog("Format help", "Reply would be passed to specified utility, output\n of utility would be shown to you.\n Format:\n% would be replaced by reply\n\\ invalidates special meaming of following symbol\n\" and ' work as usual\nspace delimits command line parameters of utility") - dialog.run() - dialog.destroy() - -def on_show_chelp(widget): - dialog = pHelpDialog("Format help", "Reply would be passed to specified utility after\nparser utility. May be used for logging, statistics etc.\n Format:\n% would be replaced by reply\n\\ invalidates special meaming of following symbol\n\" and ' work as usual\nspace delimits command line parameters of utility") - dialog.run() - dialog.destroy() - -def on_show_reghelp(widget): - dialog = pHelpDialog("Format help", "standard python regexps") - dialog.run() - dialog.destroy() - -def on_error_regexp(error): - dialog = pHelpDialog( "Regexp syntax error", error ) - dialog.run() - dialog.destroy() +#=============== The widget itself ================ def get_color(logicalcolorname): - settings = gtk.settings_get_default() - color_style = gtk.rc_get_style_by_paths(settings, 'GtkButton', 'osso-logical-colors', gtk.Button) - return color_style.lookup_color(logicalcolorname) + settings = gtk.settings_get_default() + color_style = gtk.rc_get_style_by_paths(settings, 'GtkButton', 'osso-logical-colors', gtk.Button) + return color_style.lookup_color(logicalcolorname) class UssdWidgetPlugin(hildondesktop.HomePluginItem): - def __init__(self): - hildondesktop.HomePluginItem.__init__(self) - - self.process = None - self.timerversion = 0 # Because threads in pyton are crap - self.processing = 0 - self.error = 0 - - colormap = self.get_screen().get_rgba_colormap() - self.set_colormap (colormap) - - config = get_config() - - self.connect("button-press-event", ussd_renew) - - self.label = gtk.Label() - self.label.set_padding(15, 10) - self.label.set_size_request(-1,-1) - self.set_size_request(-1,-1) - - self.vbox = gtk.HBox() - self.vbox.add(self.label) - self.add(self.vbox) - - self.set_settings(True) - self.connect("show-settings", on_show_settings) - - self.vbox.show_all() - - if config : - self.label.set_label("Data not available") -# Should be uncommented only after thread bug fixed -# ussd_renew (self, None) -# Doesn't work in hildon-home -# if config[3] != "" : -# timed_renewer (self, 60000*int(config[3])) - else : - self.label.set_label("Configure me") - - def _expose(self, event): - cr = self.window.cairo_create() - - # draw rounded rect - width, height = self.allocation[2], self.allocation[3] - - #/* a custom shape, that could be wrapped in a function */ - x0 = 0 #/*< parameters like cairo_rectangle */ - y0 = 0 - - radius = min(15, width/2, height/2) #/*< and an approximate curvature radius */ - - x1 = x0 + width - y1 = y0 + height - - cr.move_to (x0, y0 + radius) - cr.arc (x0 + radius, y0 + radius, radius, 3.14, 1.5 * 3.14) - cr.line_to (x1 - radius, y0) - cr.arc (x1 - radius, y0 + radius, radius, 1.5 * 3.14, 0.0) - cr.line_to (x1 , y1 - radius) - cr.arc (x1 - radius, y1 - radius, radius, 0.0, 0.5 * 3.14) - cr.line_to (x0 + radius, y1) - cr.arc (x0 + radius, y1 - radius, radius, 0.5 * 3.14, 3.14) - - cr.close_path () - - fg_color = get_color("ActiveTextColor") - - if self.processing : - bg_color=fg_color - else : - bg_color=gtk.gdk.color_parse('#000000') - - cr.set_source_rgba (bg_color.red / 65535.0, bg_color.green/65535.0, bg_color.blue/65535.0, 0.7) - cr.fill_preserve () - - if self.error : - cr.set_source_rgba (1.0, 0.0, 0.0, 0.5) - else : - cr.set_source_rgba (fg_color.red / 65535.0, fg_color.green / 65535.0, fg_color.blue / 65535.0, 0.7) - cr.stroke () - - def do_expose_event(self, event): - self.chain(event) - self._expose (event) - self.vbox.do_expose_event (self, event) + def __init__(self): + hildondesktop.HomePluginItem.__init__(self) + + self.processing = 0 + self.error = 0 + self.timeout_version = 0 + + colormap = self.get_screen().get_rgba_colormap() + self.set_colormap (colormap) + + self.controller = USSD_Controller(self) + +# TODO Click event would be better + self.connect("button-press-event", self.controller.ussd_renew) + + self.vbox = gtk.HBox() + self.add(self.vbox) + + self.set_settings(True) + self.connect("show-settings", self.controller.on_show_settings) + self.label = gtk.Label("") + self.set_text(_("Click to update")) + + self.vbox.add(self.label) + self.vbox.set_child_packing(self.label, False, False, 0, gtk.PACK_START) + self.label.set_padding(15, 10) + self.label.set_size_request(-1,-1) + self.set_size_request(-1,-1) + self.label.set_line_wrap (True) + + self.vbox.show_all() + self.controller.get_config() + self.controller.reset_timed_renew() + + def error_return (self): + if self.error == 1 and self.processing == 0: + self.set_text(self.text) + return False + + # showfor = + # -1 - This is a permanent text message + # 0 - This is service message, but it shouldn't be hidden automatically + # >0 - This is service message, show permament message after showfor milliseconds + def set_text(self, text, showfor=-1): + if showfor > 0 : + # Show previous text after 5 seconds + gobject.timeout_add (showfor, self.error_return) + else : + if showfor == -1 : + self.text = text + self.label.set_text(text) + + def get_text(self): + return self.text + + def _expose(self, event): + cr = self.window.cairo_create() + + # draw rounded rect + width, height = self.label.allocation[2], self.label.allocation[3] + + #/* a custom shape, that could be wrapped in a function */ + x0 = 0 #/*< parameters like cairo_rectangle */ + y0 = 0 + + radius = min(15, width/2, height/2) #/*< and an approximate curvature radius */ + + x1 = x0 + width + y1 = y0 + height + + cr.move_to (x0, y0 + radius) + cr.arc (x0 + radius, y0 + radius, radius, 3.14, 1.5 * 3.14) + cr.line_to (x1 - radius, y0) + cr.arc (x1 - radius, y0 + radius, radius, 1.5 * 3.14, 0.0) + cr.line_to (x1 , y1 - radius) + cr.arc (x1 - radius, y1 - radius, radius, 0.0, 0.5 * 3.14) + cr.line_to (x0 + radius, y1) + cr.arc (x0 + radius, y1 - radius, radius, 0.5 * 3.14, 3.14) + + cr.close_path () + + fg_color = get_color("ActiveTextColor") + + if self.processing : + bg_color=fg_color + else : + bg_color=gtk.gdk.color_parse('#000000') + + cr.set_source_rgba (bg_color.red / 65535.0, bg_color.green/65535.0, bg_color.blue/65535.0, 0.7) + cr.fill_preserve () + + if self.error : + cr.set_source_rgba (1.0, 0.0, 0.0, 0.5) + else : + cr.set_source_rgba (fg_color.red / 65535.0, fg_color.green / 65535.0, fg_color.blue / 65535.0, 0.7) + cr.stroke () + + def do_expose_event(self, event): + self.chain(event) + self._expose (event) + self.vbox.do_expose_event (self, event) hd_plugin_type = UssdWidgetPlugin -gtk.gdk.threads_init() # The code below is just for testing purposes. # It allows to run the widget as a standalone process. if __name__ == "__main__": - gobject.type_register(hd_plugin_type) - obj = gobject.new(hd_plugin_type, plugin_id="plugin_id") - obj.show_all() - gtk.gdk.threads_init() - gtk.main() + import gobject + gobject.type_register(hd_plugin_type) + obj = gobject.new(hd_plugin_type, plugin_id="plugin_id") + obj.show_all() + gtk.main() -- 1.7.9.5