From 581480d60665d2f556c2036dbda48fa3bc8f0ce1 Mon Sep 17 00:00:00 2001 From: kibergus Date: Mon, 11 Jan 2010 22:06:11 +0000 Subject: [PATCH 1/1] Perl regexp from irmin. Code adoped for threads. git-svn-id: file:///svnroot/ussd-widget/trunk@15 d197f4d6-dc93-42ad-8354-0da1f58e353f --- ussd-widget/build_ussd-widget.py | 6 +- .../src/usr/lib/hildon-desktop/ussd-widget.py | 269 +++++++++++++++++--- 2 files changed, 235 insertions(+), 40 deletions(-) diff --git a/ussd-widget/build_ussd-widget.py b/ussd-widget/build_ussd-widget.py index 9b33a52..7df6871 100644 --- a/ussd-widget/build_ussd-widget.py +++ b/ussd-widget/build_ussd-widget.py @@ -23,7 +23,7 @@ if __name__ == "__main__": p.description="Widget, that executes USSD query and displays response text\nThe main purpose is viewing your balance. In Russia all operators provide balace information via USSD queries andmost part of contracts are prepaid. Ability to see your balance on desktop can be useful in such case.\nAnyway, you can configure widget to any other USSD query." p.author="Alexey Guseynov" p.mail="kibergus@gmail.com" - p.depends = "python2.5, ussd-common, python-hildondesktop, hildon-desktop-python-loader, python-gtk2, python-gobject, python-hildon, python-cairo" + p.depends = "python2.5, ussd-common, python-hildondesktop (>=0.1.0-1maemo2), hildon-desktop-python-loader (>=0.1.0-1maemo2), python-gtk2, python-gobject, python-hildon, python-cairo" p.section="user/desktop" p.icon = "./ussd-widget.png" p.arch="all" #should be all for python, any for all arch @@ -34,9 +34,9 @@ if __name__ == "__main__": # p.postinstall="""#!/bin/sh #""" #Set here your post install script - version = "0.0.1" + version = "0.0.3" build = "0" - changeloginformation = "Transpared widget, more debug support, initial parser support" + changeloginformation = "Perl regexp from irmin. Code adoped for threads." dir_name = "src" 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 23fc4fd..ec501bb 100755 --- a/ussd-widget/src/usr/lib/hildon-desktop/ussd-widget.py +++ b/ussd-widget/src/usr/lib/hildon-desktop/ussd-widget.py @@ -1,13 +1,24 @@ #!/usr/bin/python # -*- coding: utf-8 -*- +import gobject import gtk import hildon import hildondesktop import os from subprocess import * import cairo +import time +from threading import * +import re -supports_alpha = False +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 class UssdConfigDialog(gtk.Dialog): def __init__(self, config): @@ -18,13 +29,88 @@ class UssdConfigDialog(gtk.Dialog): self.ussdNumber.set_text(config[0]) self.parser = hildon.Entry(gtk.HILDON_SIZE_AUTO) self.parser.set_text(config[1]) - self.vbox.add(gtk.Label("USSD number")) - self.vbox.add(self.ussdNumber) - self.vbox.add(gtk.Label("Parser")) - self.vbox.add(self.parser) + 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 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") @@ -33,8 +119,14 @@ def get_config(): 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] + return [number, parser, chain, interval, regexp] except IOError: return None @@ -42,44 +134,133 @@ 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() +def check_regexp(regexp): + try : + re.compile( regexp ) + except Exception, e: + 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): - config = get_config() - widget.processing = 1 - widget.label.set_text("Processing") - widget.queue_draw() - gtk.main_iteration () -# widget.send_expose(gtk.gdk.EXPOSE) - if config : - p = Popen(['python', '/usr/bin/ussdquery.py', config[0]], stdout=PIPE) - reply = p.communicate()[0].strip() - if reply == "" : - reply = " Error " -# else : -# if config[1] != "": -# p = Popen([config[1]], stdout=PIPE) -# reply = p.communicate(reply)[0].strip() - else : - reply = " Bad config " - widget.processing = 0 - widget.label.set_text(reply) + 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 = ["", ""] + config = ["", "", "", "", ""] dialog = UssdConfigDialog(config) dialog.run() - set_config ([dialog.ussdNumber.get_text(), dialog.parser.get_text()]) - + 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 == ["", ""] : + 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() + def get_color(logicalcolorname): settings = gtk.settings_get_default() color_style = gtk.rc_get_style_by_paths(settings, 'GtkButton', 'osso-logical-colors', gtk.Button) @@ -89,19 +270,19 @@ 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) - query = get_config() - if query : - self.label = gtk.Label("Click to update") - else : - self.label = gtk.Label("Configure me") - + 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) @@ -115,6 +296,16 @@ class UssdWidgetPlugin(hildondesktop.HomePluginItem): 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() @@ -151,7 +342,10 @@ class UssdWidgetPlugin(hildondesktop.HomePluginItem): cr.set_source_rgba (bg_color.red / 65535.0, bg_color.green/65535.0, bg_color.blue/65535.0, 0.7) cr.fill_preserve () - cr.set_source_rgba (fg_color.red / 65535.0, fg_color.green / 65535.0, fg_color.blue / 65535.0, 0.5) + 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): @@ -160,12 +354,13 @@ class UssdWidgetPlugin(hildondesktop.HomePluginItem): 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__": - import gobject 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() -- 1.7.9.5