2 # -*- coding: utf-8 -*-
8 from subprocess import *
11 from threading import *
14 class pHelpDialog(gtk.Dialog):
15 def __init__(self, heading, text):
16 gtk.Dialog.__init__(self, heading, None,
17 gtk.DIALOG_DESTROY_WITH_PARENT | gtk.DIALOG_NO_SEPARATOR,
18 ("OK", gtk.RESPONSE_OK))
19 self.vbox.add(gtk.Label(text))
23 class UssdConfigDialog(gtk.Dialog):
24 def __init__(self, config):
25 gtk.Dialog.__init__(self, "USSD widget", None,
26 gtk.DIALOG_DESTROY_WITH_PARENT | gtk.DIALOG_NO_SEPARATOR,
27 ("Save", gtk.RESPONSE_OK))
28 self.ussdNumber = hildon.Entry(gtk.HILDON_SIZE_AUTO)
29 self.ussdNumber.set_text(config[0])
30 self.parser = hildon.Entry(gtk.HILDON_SIZE_AUTO)
31 self.parser.set_text(config[1])
32 self.chain = hildon.Entry(gtk.HILDON_SIZE_AUTO)
33 self.chain.set_text(config[2])
34 self.update_interval = hildon.Entry(gtk.HILDON_SIZE_AUTO)
35 self.update_interval.set_text(config[3])
36 self.regexp = hildon.Entry(gtk.HILDON_SIZE_AUTO)
37 self.regexp.set_text(config[4])
39 phelp = gtk.Button("?")
40 phelp.connect("clicked", on_show_phelp)
42 chelp = gtk.Button("?")
43 chelp.connect("clicked", on_show_chelp)
45 reghelp = gtk.Button("?")
46 reghelp.connect("clicked", on_show_reghelp)
48 numberBox = gtk.HBox()
49 numberBox.add(gtk.Label("USSD number"))
50 numberBox.add(self.ussdNumber)
51 self.vbox.add(numberBox)
53 parserBox = gtk.HBox()
54 parserBox.add(gtk.Label("Parser"))
56 parserBox.add(self.parser)
57 self.vbox.add(parserBox)
60 chainBox.add(gtk.Label("Chain"))
62 chainBox.add(self.chain)
63 self.vbox.add(chainBox)
65 updateBox = gtk.HBox()
66 updateBox.add(gtk.Label("Update every "))
67 updateBox.add(self.update_interval)
68 updateBox.add(gtk.Label(" minutes (BROKEN)"))
69 self.vbox.add(updateBox)
71 regexpBox = gtk.HBox()
72 regexpBox.add(gtk.Label("RegExp"))
73 regexpBox.add(reghelp)
74 regexpBox.add(self.regexp)
75 self.vbox.add(regexpBox)
80 def smart_split_string (str, query) :
83 # Is simbol backslashed?
85 # Quotes: 1 - ", 2 - ', 0 - no quotes
87 for i in range(len(str)) :
88 if bs == 0 and (str[i] == '"' and qs == 1 or str[i] == "'" and qs == 2) :
90 elif bs == 0 and qs == 0 and (str[i] == '"' or str[i] == "'") :
95 elif bs == 0 and str[i] == '\\' :
97 elif bs == 0 and str[i] == '%' :
101 if bs == 1 and str[i] != '\\' and str[i] != '"' and str[i] != "'" :
103 if qs == 0 and (str[i] == " " or str[i] == "\t") :
116 config = open(os.getenv("HOME")+"/.ussdWidget.conf","r")
119 number = config.readline().strip()
121 parser = config.readline().strip()
123 chain = config.readline().strip()
125 interval = config.readline().strip()
127 regexp = config.readline().strip()
129 return [number, parser, chain, interval, regexp]
133 def set_config(config):
134 fconfig = open(os.getenv("HOME")+"/.ussdWidget.conf","w")
135 fconfig.writelines(["# Parameters are taken by line number, do not move them\n", "# USSD query to be run by widget\n", config[0], "\n"])
136 fconfig.writelines(["Parser command\n", config[1], "\n"])
137 fconfig.writelines(["Chain command\n", config[2], "\n"])
138 fconfig.writelines(["Update interval in minutes\n", config[3], "\n"])
139 fconfig.writelines(["RegExp pattern\n", config[4], "\n"])
142 def check_regexp(regexp):
146 on_error_regexp( str( e ) )
150 #def timed_renewer(Thread):
151 # def __init__ (self, widget, period):
152 # self.widget = widget
153 # self.period = period
154 # self.version = widget.timerversion
157 # while widget.timerversion == version:
158 # ussd_renew(widget, None)
161 def ussd_renew(widget, event):
162 if widget.process == None or widget.process.isAlive() == False :
163 widget.process = ussd_renewer (widget)
164 # See bug https://bugs.maemo.org/show_bug.cgi?id=7809
167 class ussd_renewer ():#Thread):
168 def __init__ (self, widget):
169 # Thread.__init__ (self)
173 # stub while thread but is not fixed
179 config = get_config()
180 widget.processing = 1
181 last_text = widget.label.get_text()
182 widget.label.set_text("Processing")
184 gtk.main_iteration ()
187 p = Popen(['/usr/bin/ussdquery.py', config[0]], stdout=PIPE)
188 reply = p.communicate()[0].strip()
192 # Show previous text in 5 seconds
193 widget.timer = gobject.timeout_add (5000, error_return, widget, last_text)
197 p = Popen(smart_split_string(config[1], reply), stdout=PIPE)
198 reply = p.communicate(reply+"\n")[0].strip()
200 p = Popen(smart_split_string(config[2], reply))
203 r = re.match( config[4], reply ).group( 1 )
205 r = "Regexp Error: " + str( e )
210 reply = " Bad config "
211 widget.processing = 0
212 widget.label.set_text(reply)
214 gtk.main_iteration ()
216 def error_return(widget, text) :
217 if widget.processing == 0 and widget.error == 1:
218 widget.label.set_text(text)
221 def on_show_settings(widget):
222 config = get_config()
224 config = ["", "", "", "", ""]
226 dialog = UssdConfigDialog(config)
229 if check_regexp( dialog.regexp.get_text() ) :
232 set_config ([dialog.ussdNumber.get_text(), dialog.parser.get_text(), dialog.chain.get_text(), dialog.update_interval.get_text(), dialog.regexp.get_text()])
234 # Doesn't work in hildon-home
235 # widget.timerversion += 1
236 # if dialog.update_interval.get_text() != "" :
237 # ussd_renewer (widget, 60000*int(dialog.update_interval.get_text()))
241 if config == ["", "", "", "", ""] :
242 widget.label.set_text("Click to update")
244 def on_show_phelp(widget):
245 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")
249 def on_show_chelp(widget):
250 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")
254 def on_show_reghelp(widget):
255 dialog = pHelpDialog("Format help", "standard python regexps")
259 def on_error_regexp(error):
260 dialog = pHelpDialog( "Regexp syntax error", error )
264 def get_color(logicalcolorname):
265 settings = gtk.settings_get_default()
266 color_style = gtk.rc_get_style_by_paths(settings, 'GtkButton', 'osso-logical-colors', gtk.Button)
267 return color_style.lookup_color(logicalcolorname)
269 class UssdWidgetPlugin(hildondesktop.HomePluginItem):
271 hildondesktop.HomePluginItem.__init__(self)
274 self.timerversion = 0 # Because threads in pyton are crap
278 colormap = self.get_screen().get_rgba_colormap()
279 self.set_colormap (colormap)
281 config = get_config()
283 self.connect("button-press-event", ussd_renew)
285 self.label = gtk.Label()
286 self.label.set_padding(15, 10)
287 self.label.set_size_request(-1,-1)
288 self.set_size_request(-1,-1)
290 self.vbox = gtk.HBox()
291 self.vbox.add(self.label)
294 self.set_settings(True)
295 self.connect("show-settings", on_show_settings)
300 self.label.set_label("Data not available")
301 # Should be uncommented only after thread bug fixed
302 # ussd_renew (self, None)
303 # Doesn't work in hildon-home
304 # if config[3] != "" :
305 # timed_renewer (self, 60000*int(config[3]))
307 self.label.set_label("Configure me")
309 def _expose(self, event):
310 cr = self.window.cairo_create()
313 width, height = self.allocation[2], self.allocation[3]
315 #/* a custom shape, that could be wrapped in a function */
316 x0 = 0 #/*< parameters like cairo_rectangle */
319 radius = min(15, width/2, height/2) #/*< and an approximate curvature radius */
324 cr.move_to (x0, y0 + radius)
325 cr.arc (x0 + radius, y0 + radius, radius, 3.14, 1.5 * 3.14)
326 cr.line_to (x1 - radius, y0)
327 cr.arc (x1 - radius, y0 + radius, radius, 1.5 * 3.14, 0.0)
328 cr.line_to (x1 , y1 - radius)
329 cr.arc (x1 - radius, y1 - radius, radius, 0.0, 0.5 * 3.14)
330 cr.line_to (x0 + radius, y1)
331 cr.arc (x0 + radius, y1 - radius, radius, 0.5 * 3.14, 3.14)
335 fg_color = get_color("ActiveTextColor")
340 bg_color=gtk.gdk.color_parse('#000000')
342 cr.set_source_rgba (bg_color.red / 65535.0, bg_color.green/65535.0, bg_color.blue/65535.0, 0.7)
346 cr.set_source_rgba (1.0, 0.0, 0.0, 0.5)
348 cr.set_source_rgba (fg_color.red / 65535.0, fg_color.green / 65535.0, fg_color.blue / 65535.0, 0.7)
351 def do_expose_event(self, event):
354 self.vbox.do_expose_event (self, event)
356 hd_plugin_type = UssdWidgetPlugin
357 gtk.gdk.threads_init()
359 # The code below is just for testing purposes.
360 # It allows to run the widget as a standalone process.
361 if __name__ == "__main__":
362 gobject.type_register(hd_plugin_type)
363 obj = gobject.new(hd_plugin_type, plugin_id="plugin_id")
365 gtk.gdk.threads_init()