Merge branch 'stable'
[pedometerwidget] / src / usr / lib / hildon-desktop / pedometer_widget_home.py
1 #Pedometer Home Widget
2 #Author: Mirestean Andrei < andrei.mirestean at gmail.com >
3 #
4 #This program is free software: you can redistribute it and/or modify
5 #it under the terms of the GNU General Public License as published by
6 #the Free Software Foundation, either version 3 of the License, or
7 #(at your option) any later version.
8 #
9 #This program is distributed in the hope that it will be useful,
10 #but WITHOUT ANY WARRANTY; without even the implied warranty of
11 #MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 #GNU General Public License for more details.
13 #
14 #You should have received a copy of the GNU General Public License
15 #along with this program.  If not, see <http://www.gnu.org/licenses/>.
16
17 import os
18 import time
19 import pickle
20 from datetime import date, timedelta
21 from xml.dom.minidom import getDOMImplementation, parseString
22
23 import gobject
24 import gconf
25 import gtk
26 import cairo
27 import locale
28 import gettext
29
30 import pygst
31 pygst.require("0.10")
32 import gst
33
34 import hildondesktop
35 import hildon
36
37 APP_NAME = "pedometer"
38
39 PATH = "/apps/pedometerhomewidget"
40 MODE = PATH + "/mode"
41 HEIGHT = PATH + "/height"
42 STEP_LENGTH = PATH + "/step_length"
43 WEIGHT = PATH + "/weight"
44 UNIT = PATH + "/unit"
45 SENSITIVITY = PATH + "/sensitivity"
46 ASPECT = PATH + "/aspect"
47 SECONDVIEW = PATH + "/secondview"
48 GRAPHVIEW = PATH + "/graphview"
49 NOIDLETIME = PATH + "/noidletime"
50 LOGGING = PATH + "/logging"
51
52 ALARM_PATH = PATH + "/alarm"
53 ALARM_ENABLE = ALARM_PATH + "/enable"
54 ALARM_FNAME = ALARM_PATH + "/fname"
55 ALARM_TYPE = ALARM_PATH + "/type"
56 ALARM_INTERVAL = ALARM_PATH + "/interval"
57
58 ICONSPATH = "/opt/pedometerhomewidget/"
59
60 unit = 0
61
62 class Singleton(object):
63     _instance = None
64     _references = 0
65     def __new__(cls, *args, **kwargs):
66         cls._references+=1
67         if not cls._instance:
68             cls._instance = super(Singleton, cls).__new__(
69                                 cls, *args, **kwargs)
70         return cls._instance
71
72 class Translate(Singleton):
73
74     def __init__(self):
75         if self._references > 1:
76             return
77         #Get the local directory since we are not installing anything
78         #self.local_path = os.path.realpath(os.path.dirname(sys.argv[0]))
79         self.local_path = os.path.join(os.path.expanduser("~"), "pedometer-widget-0.1", "locale")
80         # Init the list of languages to support
81         langs = []
82         #Check the default locale
83         lc, encoding = locale.getdefaultlocale()
84         if (lc):
85             #If we have a default, it's the first in the list
86             langs = [lc]
87         # Now lets get all of the supported languages on the system
88         language = os.environ.get('LANGUAGE', None)
89         if (language):
90             """langage comes back something like en_CA:en_US:en_GB:en
91             on linuxy systems, on Win32 it's nothing, so we need to
92             split it up into a list"""
93             langs += language.split(":")
94         """Now add on to the back of the list the translations that we
95         know that we have, our defaults"""
96         langs += ["en_CA", "en_US", "ro_RO"]
97
98         """Now langs is a list of all of the languages that we are going
99         to try to use.  First we check the default, then what the system
100         told us, and finally the 'known' list"""
101
102         gettext.bindtextdomain(APP_NAME, self.local_path)
103         print self.local_path
104         print langs
105         gettext.textdomain(APP_NAME)
106         # Get the language to use
107         self.lang = gettext.translation(APP_NAME, self.local_path
108             , languages=langs, fallback = True)
109         """Install the language, map _() (which we marked our
110         strings to translate with) to self.lang.gettext() which will
111         translate them."""
112
113 _ = Translate().lang.gettext
114
115 class PedoIntervalCounter(Singleton):
116     MIN_THRESHOLD = 500
117     MIN_TIME_STEPS = 0.5
118     sensitivity = 100
119     mode = 0
120     x = []
121     y = []
122     z = []
123     t = []
124
125     #TODO: check if last detected step is at the end of the interval
126
127     def set_vals(self, coords, tval):
128         self.x = coords[0]
129         self.y = coords[1]
130         self.z = coords[2]
131         self.t = tval
132
133     def set_mode(self, mode):
134         #runnig, higher threshold to prevent fake steps
135         self.mode = mode
136         if mode == 1:
137             self.MIN_THRESHOLD = 650.0 * (200 - self.sensitivity) / 100
138             self.MIN_TIME_STEPS = 0.35
139         #walking
140         else:
141             self.MIN_THRESHOLD = 500.0 * (200 - self.sensitivity) / 100
142             self.MIN_TIME_STEPS = 0.5
143
144     def set_sensitivity(self, value):
145         self.sensitivity = value
146         self.set_mode(self.mode)
147
148     def calc_mean(self, vals):
149         sum = 0
150         for i in vals:
151             sum += i
152         if len(vals) > 0:
153             return sum / len(vals)
154         return 0
155
156     def calc_stdev(self, vals):
157         rez = 0
158         mean = self.calc_mean(vals)
159         for i in vals:
160             rez += pow(abs(mean - i), 2)
161         return math.sqrt(rez / len(vals))
162
163     def calc_threshold(self, vals):
164         vmax = max(vals)
165         vmin = min(vals)
166         mean = self.calc_mean(vals)
167         threshold = max (abs(mean - vmax), abs(mean - vmin))
168         return threshold
169
170     def count_steps(self, vals, t):
171         threshold = self.MIN_THRESHOLD
172         mean = self.calc_mean(vals)
173         cnt = 0
174         i = 0
175         while i < len(vals):
176             if abs(vals[i] - mean) > threshold:
177                 cnt += 1
178                 ntime = t[i] + self.MIN_TIME_STEPS
179                 while i < len(vals) and t[i] < ntime:
180                     i += 1
181             i += 1
182         return cnt
183
184     def get_best_values(self, x, y, z):
185         dev1 = self.calc_stdev(x)
186         dev2 = self.calc_stdev(y)
187         dev3 = self.calc_stdev(z)
188         dev_max = max(dev1, dev2, dev3)
189
190         if (abs(dev1 - dev_max) < 0.001):
191             logger.info("X chosen as best axis, stdev %f" % dev1)
192             return x
193         elif (abs(dev2 - dev_max) < 0.001):
194             logger.info("Y chosen as best axis, stdev %f" % dev2)
195             return y
196         else:
197             logger.info("Z chosen as best axis, stdev %f" % dev3)
198             return z
199
200     def number_steps(self):
201         vals = self.get_best_values(self.x, self.y, self.z)
202         return self.count_steps(vals, self.t)
203
204 class PedoValues():
205     def __init__(self, time=0, steps=0, dist=0, calories=0):
206         self.time = time
207         self.steps = steps
208         self.calories = calories
209         self.dist = dist
210
211     def __add__(self, other):
212         return PedoValues(self.time + other.time,
213                           self.steps + other.steps,
214                           self.dist + other.dist,
215                           self.calories + other.calories)
216
217     def __sub__(self, other):
218         return PedoValues(self.time - other.time,
219                           self.steps - other.steps,
220                           self.dist - other.dist,
221                           self.calories - other.calories)
222
223     def get_print_time(self):
224         tdelta = self.time
225         hours = int(tdelta / 3600)
226         tdelta -= 3600 * hours
227         mins = int(tdelta / 60)
228         tdelta -= 60 * mins
229         secs = int(tdelta)
230         strtime = "%.2d:%.2d:%.2d" % (hours, mins, secs)
231         return strtime
232
233     def get_print_distance(self):
234         global unit
235         if self.dist > 1000:
236             if unit == 0:
237                 return "%.2f km" % (self.dist / 1000)
238             else:
239                 return "%.2f mi" % (self.dist / 1609.344)
240         else:
241             if unit == 0:
242                 return "%d m" % self.dist
243             else:
244                 return "%d ft" % int(self.dist * 3.2808)
245
246     def get_avg_speed(self):
247         global unit
248         conv = 0
249         if unit:
250             conv = 2.23693629
251         else:
252             conv = 3.6
253
254         if self.time == 0:
255             return 0
256         speed = 1.0 * self.dist / self.time
257         return speed * conv
258
259     def get_print_avg_speed(self):
260         global unit
261         suffix = ""
262         conv = 0
263         if unit:
264             suffix = "mi/h"
265             conv = 2.23693629
266         else:
267             suffix = "km/h"
268             conv = 3.6
269
270         if self.time == 0:
271             return "N/A " + suffix
272         speed = 1.0 * self.dist / self.time
273         #convert from meters per second to km/h or mi/h
274         speed *= conv
275         return "%.2f %s" % (speed, suffix)
276
277     def get_print_steps(self):
278         return str(self.steps)
279
280     def get_print_calories(self):
281         return "%.2f" % self.calories
282
283 class PedoRepository(Singleton):
284     values = {}
285
286     def load(self):
287         raise NotImplementedError("Must be implemented by subclass")
288
289     def save(self):
290         raise NotImplementedError("Must be implemented by subclass")
291
292     def reset_values(self):
293         self.values = {}
294         self.save()
295
296     def get_history_count(self):
297         """return the number of days in the log"""
298         return len(values)
299
300     def get_values(self):
301         return self.values
302
303     def add_values(self, values, when=None):
304         if when is None:
305             when = date.today()
306         """add PedoValues values to repository """
307         try:
308             self.values[when] = self.values[when] + values
309         except KeyError:
310             self.values[when] = values
311
312     def get_last_7_days(self):
313         ret = []
314         day = date.today()
315         for i in range(7):
316             try:
317                 ret.append(self.values[day])
318             except KeyError:
319                 ret.append(PedoValues())
320             day = day - timedelta(days=1)
321         return ret
322
323     def get_last_weeks(self):
324         delta = timedelta(days=1)
325         day = date.today()
326         week = int(date.today().strftime("%W"))
327         val = PedoValues()
328         ret = []
329         for i in range(56):
330             try:
331                 val += self.values[day]
332             except KeyError:
333                 pass
334             w = int(day.strftime("%W"))
335             if w != week:
336                 ret.append(val)
337                 val = PedoValues()
338                 week = w
339                 if len(ret) == 7:
340                     break
341             day -= delta
342         return ret
343
344     def get_alltime_values(self):
345         ret = PedoValues()
346         for k, v in self.values.iteritems():
347             ret = ret + v
348         return ret
349
350     def get_today_values(self):
351         try:
352             return self.values[date.today()]
353         except KeyError:
354             return PedoValues()
355
356     def get_this_week_values(self):
357         day = date.today()
358         ret = PedoValues()
359         while True:
360             try:
361                 ret += self.values[day]
362             except:
363                 pass
364             if day.weekday() == 0:
365                 break
366             day = day - timedelta(days=1)
367
368         return ret
369
370 class PedoRepositoryXML(PedoRepository):
371     DIR = os.path.join(os.path.expanduser("~"), ".pedometer")
372     FILE = os.path.join(DIR, "data.xml")
373     FILE2 = os.path.join(DIR, "pickle.log")
374     def __init__(self):
375         if not os.path.exists(self.DIR):
376             os.makedirs(self.DIR)
377         PedoRepository.__init__(self)
378
379     def load(self):
380         try:
381             f = open(self.FILE, "r")
382             dom = parseString(f.read())
383             values = dom.getElementsByTagName("pedometer")[0]
384             for v in values.getElementsByTagName("date"):
385                 d = int(v.getAttribute("ordinal_day"))
386                 steps = int(v.getAttribute("steps"))
387                 calories = float(v.getAttribute("calories"))
388                 dist = float(v.getAttribute("dist"))
389                 time = float(v.getAttribute("time"))
390                 day = date.fromordinal(d)
391                 self.values[day] = PedoValues(time, steps, dist, calories)
392
393             f.close()
394         except Exception, e:
395             logger.error("Error while loading data from xml file: %s" % e)
396
397     def save(self):
398         try:
399             f = open(self.FILE, "w")
400
401             impl = getDOMImplementation()
402
403             newdoc = impl.createDocument(None, "pedometer", None)
404             top_element = newdoc.documentElement
405             for k, v in self.values.iteritems():
406                 d = newdoc.createElement('date')
407                 d.setAttribute("day", str(k.isoformat()))
408                 d.setAttribute("ordinal_day", str(k.toordinal()))
409                 d.setAttribute("steps", str(v.steps))
410                 d.setAttribute("time", str(v.time))
411                 d.setAttribute("dist", str(v.dist))
412                 d.setAttribute("calories", str(v.calories))
413                 top_element.appendChild(d)
414
415             newdoc.appendChild(top_element)
416             newdoc.writexml(f)
417             #f.write(newdoc.toprettyxml())
418             f.close()
419         except Exception, e:
420             logger.error("Error while saving data to xml file: %s" % e)
421
422 class PedoRepositoryPickle(PedoRepository):
423     DIR = os.path.join(os.path.expanduser("~"), ".pedometer")
424     FILE = os.path.join(DIR, "pickle.log")
425
426     def __init__(self):
427         if not os.path.exists(self.DIR):
428             os.makedirs(self.DIR)
429         PedoRepository.__init__(self)
430
431     def load(self):
432         try:
433             f = open(self.FILE, "rb")
434             self.values = pickle.load(f)
435             f.close()
436         except Exception, e:
437             logger.error("Error while loading pickle file: %s" % e)
438
439     def save(self):
440         try:
441             f = open(self.FILE, "wb")
442             pickle.dump(self.values, f)
443             f.close()
444         except Exception, e:
445             logger.error("Error while saving data to pickle: %s" % e)
446
447 class PedoController(Singleton):
448     mode = 0
449     unit = 0
450     weight = 70
451     height_interval = 0
452     sensitivity = 100
453     #what to display in second view - 0 - alltime, 1 - today, 2 - week
454     second_view = 0
455     callback_update_ui = None
456     no_idle_time = False
457
458     STEP_LENGTH = 0.7
459
460     #The interval(number of steps) between two file updates
461     BUFFER_STEPS_INTERVAL = 100
462     #values for the two views in the widget ( current and day/week/alltime)
463     #third value to count the steps that were not yet written to file
464     v = [PedoValues(), PedoValues(), PedoValues()]
465
466     last_time = 0
467     is_running = False
468
469     observers = []
470
471     midnight_set = False
472     midnight_source_id = None
473     midnight_before_source_id = None
474
475     def __init__(self):
476
477         self.pedometer = PedoCounter(self.steps_detected)
478         self.pedometerInterval = PedoIntervalCounter()
479         self.pedometerInterval.set_mode(self.mode)
480         self.repository = PedoRepositoryXML()
481         self.repository.load()
482
483         self.load_values()
484
485         if not self.midnight_set:
486             self.update_at_midnight()
487             self.midnight_set = True
488
489         self.config = Config()
490         self.config.add_observer(self.load_config)
491
492     def update_at_midnight(self):
493         next_day = date.today() + timedelta(days=1)
494         diff = int(time.mktime(next_day.timetuple()) - time.time())
495         diff_before = diff - 5
496         diff_after = diff + 5
497         self.midnight_source_id = gobject.timeout_add_seconds(diff_after, self.midnight_callback, True)
498         self.midnight_before_source_id = gobject.timeout_add_seconds(diff_before, self.midnight_before_callback, True)
499
500     def stop_midnight_callback(self):
501         if self.midnight_source_id is not None:
502             gobject.source_remove(self.midnight_source_id)
503         if self.midnight_before_source_id is not None:
504             gobject.source_remove(self.midnight_before_source_id)
505
506     def midnight_before_callback(self, first=False):
507         logger.info("Before midnight callback")
508         if self.is_running:
509             self.stop_pedometer()
510             self.start_pedometer()
511         if first:
512             self.midnight_before_source_id = gobject.timeout_add_seconds(24*3600, self.midnight_before_callback)
513             return False
514         else:
515             return True
516
517     def midnight_callback(self, first=False):
518         logger.info("Midnight callback")
519         self.load_values()
520         self.notify()
521         if first:
522             self.midnight_source_id = gobject.timeout_add_seconds(24*3600, self.midnight_callback)
523             return False
524         else:
525             return True
526
527     def load_config(self):
528         self.set_height(self.config.get_height(), self.config.get_step_length())
529         self.set_mode(self.config.get_mode())
530         self.set_unit(self.config.get_unit())
531         self.set_weight(self.config.get_weight())
532         self.set_second_view(self.config.get_secondview())
533         self.set_no_idle_time(self.config.get_noidletime())
534         self.set_sensitivity(self.config.get_sensitivity())
535
536     def load_values(self):
537         if self.second_view == 0:
538             self.v[1] = self.repository.get_alltime_values()
539         elif self.second_view == 1:
540             self.v[1] = self.repository.get_today_values()
541         else:
542             self.v[1] = self.repository.get_this_week_values()
543
544     def save_values(self):
545         logger.info("Saving values to file")
546         self.repository.add_values(self.v[2])
547         self.repository.save()
548         self.load_values()
549
550     def start_pedometer(self):
551         self.v[0] = PedoValues()
552         self.v[2] = PedoValues()
553         self.last_time = time.time()
554         self.is_running = True
555         self.pedometer.start()
556         self.notify(True)
557
558     def reset_all_values(self):
559         self.repository.reset_values()
560         self.v[0] = PedoValues()
561         self.v[1] = PedoValues()
562         self.v[2] = PedoValues()
563         self.notify()
564
565     def stop_pedometer(self):
566         self.is_running = False
567         self.pedometer.request_stop()
568
569     def get_first(self):
570         return self.v[0]
571
572     def get_second(self):
573         if self.is_running:
574             return self.v[2] + self.v[1]
575         else:
576             return self.v[1]
577
578     def update_current(self):
579         """
580         Update distance and calories for current values based on new height, mode values
581         """
582         self.v[0].dist = self.get_distance(self.v[0].steps)
583         self.v[0].calories = self.get_calories(self.v[0].steps)
584
585     def steps_detected(self, cnt, last_steps=False):
586         if not last_steps and cnt == 0 and self.no_idle_time:
587             logger.info("No steps detected, timer is paused")
588         else:
589             self.v[0].steps += cnt
590             self.v[0].dist += self.get_distance(cnt)
591             self.v[0].calories += self.get_calories(self.get_distance(cnt))
592             self.v[0].time += time.time() - self.last_time
593
594             self.v[2].steps += cnt
595             self.v[2].dist += self.get_distance(cnt)
596             self.v[2].calories += self.get_calories(self.get_distance(cnt))
597             self.v[2].time += time.time() - self.last_time
598
599             if not last_steps and self.v[2].steps > self.BUFFER_STEPS_INTERVAL:
600                 self.save_values()
601                 self.notify()
602                 self.v[2] = PedoValues()
603
604             if last_steps:
605                 self.save_values()
606                 self.notify()
607             else:
608                 self.notify(True)
609         self.last_time = time.time()
610
611     def get_calories(self, distance):
612         """calculate lost calories for the distance and weight given as parameters
613         """
614         #different coefficient for running and walking
615         if self.mode == 0:
616             coef = 0.53
617         else:
618             coef = 0.75
619
620         #convert distance from meters to miles
621         distance *= 0.000621371192
622
623         weight = self.weight
624         #convert weight from kg to pounds
625         if self.unit == 0:
626             weight *= 2.20462262
627         return weight * distance * coef
628
629     def set_mode(self, mode):
630         self.mode = mode
631         self.set_height(self.height_interval)
632         self.pedometerInterval.set_mode(self.mode)
633         self.notify()
634
635     def set_unit(self, new_unit):
636         self.unit = new_unit
637         global unit
638         unit = new_unit
639         self.notify()
640
641     def get_str_weight_unit(self, unit=None):
642         if unit is None:
643             unit = self.unit
644         if unit == 0:
645             return "kg"
646         else:
647             return "lb"
648
649     def set_weight(self, value):
650         self.weight = value
651         self.notify()
652
653     def get_weight(self):
654         return self.weight
655
656     def set_sensitivity(self, value):
657         self.sensitivity = value
658         self.pedometerInterval.set_sensitivity(value)
659
660     def get_sensitivity(self):
661         return self.sensitivity
662
663     def set_second_view(self, second_view):
664         self.second_view = second_view
665         self.load_values()
666         self.notify()
667
668     def set_callback_ui(self, func):
669         self.callback_update_ui = func
670
671     def set_height(self, height_interval, step_length=None):
672         self.height_interval = height_interval
673
674         if step_length is None:
675             step_length = self.STEP_LENGTH
676         #set height, will affect the distance
677         if height_interval == 0:
678             self.STEP_LENGTH = 0.59
679         elif height_interval == 1:
680             self.STEP_LENGTH = 0.64
681         elif height_interval == 2:
682             self.STEP_LENGTH = 0.71
683         elif height_interval == 3:
684             self.STEP_LENGTH = 0.77
685         elif height_interval == 4:
686             self.STEP_LENGTH = 0.83
687         elif height_interval == 5:
688             self.STEP_LENGTH = step_length
689         #increase step length if RUNNING
690         if self.mode == 1:
691             self.STEP_LENGTH *= 1.45
692         self.notify()
693
694     def set_no_idle_time(self, value):
695         self.no_idle_time = value
696
697     def get_distance(self, steps=None):
698         if steps == None:
699             steps = self.counter
700         return self.STEP_LENGTH * steps;
701
702     def add_observer(self, func):
703         try:
704             self.observers.index(func)
705         except:
706             self.observers.append(func)
707
708     def remove_observer(self, func):
709         self.observers.remove(func)
710
711     def notify(self, optional=False):
712         if self.callback_update_ui is not None:
713             self.callback_update_ui()
714
715         for func in self.observers:
716             func(optional)
717
718 class AlarmController(Singleton):
719     enable = False
720     fname = "/home/user/MyDocs/.sounds/Ringtones/Bicycle.aac"
721     interval = 5
722     type = 0
723
724     player = None
725     is_playing = False
726     pedo_controller = None
727
728     def __init__(self):
729         self.client = gconf.client_get_default()
730         self.config = Config()
731         self.config.add_observer(self.load_config)
732
733         self.pedo_controller = PedoController()
734         if self.enable:
735             self.init_player()
736             self.pedo_controller.add_observer(self.update)
737             self.start_value = self.pedo_controller.get_first()
738
739     def init_player(self):
740         self.player = gst.element_factory_make("playbin2", "player")
741         fakesink = gst.element_factory_make("fakesink", "fakesink")
742         self.player.set_property("video-sink", fakesink)
743
744         bus = self.player.get_bus()
745         bus.add_signal_watch()
746         bus.connect("message", self.on_message)
747
748     def on_message(self, bus, message):
749         t = message.type
750         if t == gst.MESSAGE_EOS:
751             self.player.set_state(gst.STATE_NULL)
752             self.is_playing = False
753         elif t == gst.MESSAGE_ERROR:
754             self.player.set_state(gst.STATE_NULL)
755             self.is_playing = False
756             err, debug = message.parse_error()
757             logger.error("ERROR: %s, %s" % (err, debug) )
758
759     def update(self, optional):
760         diff = self.pedo_controller.get_first() - self.start_value
761         if self.type == 0 and diff.time >= self.interval * 60 or \
762                    self.type == 1 and diff.steps >= self.interval or \
763                    self.type == 2 and diff.dist >= self.interval or \
764                    self.type == 3 and diff.calories >= self.interval:
765             self.play()
766             #get new instance of current values
767             self.start_value = PedoValues() + self.pedo_controller.get_first()
768             logger.info("Alarm!")
769
770     def play(self):
771         if self.player is None:
772             self.init_player()
773         if self.is_playing:
774             self.player.set_state(gst.STATE_NULL)
775             self.is_playing = False
776         else:
777             self.player.set_property("uri", "file://" + self.fname)
778             self.player.set_state(gst.STATE_PLAYING)
779             self.is_playing = True
780
781     def stop(self):
782         if self.player is not None:
783             self.player.set_state(gst.STATE_NULL)
784
785     def load_config(self):
786         self.enable  = self.config.get_alarm_enable()
787         self.set_alarm_file(self.config.get_alarm_fname())
788         self.set_interval(self.config.get_alarm_interval())
789         self.set_type(self.config.get_alarm_type())
790
791     def set_enable(self, value):
792        self.enable = value
793        if self.enable:
794            self.init_player()
795            self.pedo_controller.add_observer(self.update)
796            self.start_value = self.pedo_controller.get_first()
797        else:
798            self.stop()
799            self.player = None
800            self.pedo_controller.remove_observer(self.update)
801
802     def get_enable(self):
803         return self.enable
804
805     def set_alarm_file(self, fname):
806         self.fname = fname
807
808     def get_alarm_file(self):
809         if self.fname == None:
810             return ""
811         return self.fname
812
813     def set_interval(self, interval):
814         self.interval = interval
815
816     def get_interval(self):
817         return self.interval
818
819     def set_type(self, type):
820         self.type = type
821
822     def get_type(self):
823         return self.type
824
825 class PedoCounter(Singleton):
826     COORD_FNAME = "/sys/class/i2c-adapter/i2c-3/3-001d/coord"
827     COORD_FNAME_SDK = "/home/andrei/pedometer-widget-0.1/date.txt"
828     LOGFILE = "/home/user/log_pedometer"
829     #time in ms between two accelerometer data reads
830     COORD_GET_INTERVAL = 25
831
832     COUNT_INTERVAL = 5
833
834     interval_counter = None
835     stop_requested = False
836     update_function = None
837     logging = False
838     isRunning = False
839
840     def __init__(self, update_function=None):
841         if not os.path.exists(self.COORD_FNAME):
842             self.COORD_FNAME = self.COORD_FNAME_SDK
843
844         self.interval_counter = PedoIntervalCounter()
845         self.update_function = update_function
846
847     def set_logging(self, value):
848         self.logging = value
849
850     def get_rotation(self):
851         f = open(self.COORD_FNAME, 'r')
852         coords = [int(w) for w in f.readline().split()]
853         f.close()
854         return coords
855
856     def start(self):
857         logger.info("Counter started")
858         self.isRunning = True
859         self.stop_requested = False
860         if self.logging:
861             fname = "%d_%d_%d_%d_%d_%d" % time.localtime()[0:6]
862             self.file = open(self.LOGFILE + fname + ".txt", "w")
863         gobject.idle_add(self.run)
864
865     def run(self):
866         self.coords = [[], [], []]
867         self.stime = time.time()
868         self.t = []
869         gobject.timeout_add(self.COORD_GET_INTERVAL, self.read_coords)
870         return False
871
872     def read_coords(self):
873         x, y, z = self.get_rotation()
874         self.coords[0].append(int(x))
875         self.coords[1].append(int(y))
876         self.coords[2].append(int(z))
877         now = time.time() - self.stime
878         if self.logging:
879             self.file.write("%d %d %d %f\n" % (self.coords[0][-1], self.coords[1][-1], self.coords[2][-1], now))
880
881         self.t.append(now)
882         #call stop_interval
883         ret = True
884         if self.t[-1] > self.COUNT_INTERVAL or self.stop_requested:
885             ret = False
886             gobject.idle_add(self.stop_interval)
887         return ret
888
889     def stop_interval(self):
890         self.interval_counter.set_vals(self.coords, self.t)
891         cnt = self.interval_counter.number_steps()
892
893         logger.info("Number of steps detected for last interval %d, number of coords: %d" % (cnt, len(self.t)))
894
895         gobject.idle_add(self.update_function, cnt, self.stop_requested)
896
897         if self.stop_requested:
898             gobject.idle_add(self.stop)
899         else:
900             gobject.idle_add(self.run)
901         return False
902
903     def stop(self):
904         if self.logging:
905             self.file.close()
906         logger.info("Counter has finished")
907
908     def request_stop(self):
909         self.stop_requested = True
910         self.isRunning = False
911
912 class CustomButton(hildon.Button):
913     def __init__(self, icon):
914         hildon.Button.__init__(self, gtk.HILDON_SIZE_AUTO_WIDTH, hildon.BUTTON_ARRANGEMENT_VERTICAL)
915         self.icon = icon
916         self.set_size_request(int(32 * 1.4), int(30 * 1.0))
917         self.retval = self.connect("expose_event", self.expose)
918
919     def set_icon(self, icon):
920         self.icon = icon
921
922     def expose(self, widget, event):
923         self.context = widget.window.cairo_create()
924         self.context.rectangle(event.area.x, event.area.y,
925                             event.area.width, event.area.height)
926
927         self.context.clip()
928         rect = self.get_allocation()
929         self.context.rectangle(rect.x, rect.y, rect.width, rect.height)
930         self.context.set_source_rgba(1, 1, 1, 0)
931
932         style = self.rc_get_style()
933         color = style.lookup_color("DefaultBackgroundColor")
934         if self.state == gtk.STATE_ACTIVE:
935             style = self.rc_get_style()
936             color = style.lookup_color("SelectionColor")
937             self.context.set_source_rgba (color.red / 65535.0, color.green / 65335.0, color.blue / 65535.0, 0.75);
938         self.context.fill()
939
940         #img = cairo.ImageSurface.create_from_png(self.icon)
941
942         #self.context.set_source_surface(img)
943         #self.context.set_source_surface(img, rect.width/2 - img.get_width() /2, 0)
944         img = gtk.Image()
945         img.set_from_file(self.icon)
946         buf = img.get_pixbuf()
947         buf = buf.scale_simple(int(32 * 1.5), int(30 * 1.5), gtk.gdk.INTERP_BILINEAR)
948
949         self.context.set_source_pixbuf(buf, rect.x + (event.area.width / 2 - 15) - 8, rect.y + 1)
950         self.context.scale(200, 200)
951         self.context.paint()
952
953         return self.retval
954
955 class CustomEventBox(gtk.EventBox):
956
957     def __init__(self):
958         gtk.EventBox.__init__(self)
959
960     def do_expose_event(self, event):
961         self.context = self.window.cairo_create()
962         self.context.rectangle(event.area.x, event.area.y,
963                             event.area.width, event.area.height)
964
965         self.context.clip()
966         rect = self.get_allocation()
967         self.context.rectangle(rect.x, rect.y, rect.width, rect.height)
968
969         if self.state == gtk.STATE_ACTIVE:
970             style = self.rc_get_style()
971             color = style.lookup_color("SelectionColor")
972             self.context.set_source_rgba (color.red / 65535.0, color.green / 65335.0, color.blue / 65535.0, 0.75);
973         else:
974             self.context.set_source_rgba(1, 1, 1, 0)
975         self.context.fill()
976
977         gtk.EventBox.do_expose_event(self, event)
978
979 class GraphController(Singleton):
980     ytitles = [_("Steps"), _("Average Speed"), _("Distance"), _("Calories")]
981     xtitles = [_("Day"), _("Week")] # "Today"]
982     widget = None
983
984     config = None
985
986     def __init__(self):
987         self.repository = PedoRepositoryXML()
988         self.last_update = 0
989         PedoController().add_observer(self.update_ui)
990         self.config = Config()
991         self.config.add_observer(self.load_config)
992
993     def load_config(self):
994         self.set_current_view(self.config.get_graphview())
995
996     def set_graph(self, widget):
997         self.widget = widget
998         self.update_ui()
999
1000     def set_current_view(self, view):
1001         """
1002         current_view % len(ytitles) - gives the ytitle
1003         current_view / len(ytitles) - gives the xtitle
1004         """
1005         self.x_id = view / len(self.ytitles)
1006         self.y_id = view % len(self.ytitles)
1007         self.update_ui()
1008
1009     def next_view(self):
1010         current_view = self.config.get_graphview() + 1
1011         if current_view == len(self.ytitles) * len(self.xtitles):
1012             current_view = 0
1013         self.config.set_graphview(current_view)
1014
1015     def last_weeks_labels(self):
1016         d = date.today()
1017         delta = timedelta(days=7)
1018         ret = []
1019         for i in range(7):
1020             ret.append(_("Week") + d.strftime("%W"))
1021             d = d - delta
1022         return ret
1023
1024     def compute_values(self):
1025         labels = []
1026         if self.x_id == 0:
1027             values = self.repository.get_last_7_days()
1028             d = date.today()
1029             delta = timedelta(days=1)
1030             for i in range(7):
1031                 labels.append(d.ctime().split()[0])
1032                 d = d - delta
1033
1034         elif self.x_id == 1:
1035             values = self.repository.get_last_weeks()
1036             d = date.today()
1037             for i in range(7):
1038                 labels.append(_("Week") + " " + d.strftime("%W"))
1039                 d = d - timedelta(days=7)
1040         else:
1041             values = self.repository.get_today()
1042             #TODO get labels
1043
1044         if self.y_id == 0:
1045             yvalues = [line.steps for line in values]
1046         elif self.y_id == 1:
1047             yvalues = [line.get_avg_speed() for line in values]
1048         elif self.y_id == 2:
1049             yvalues = [line.dist for line in values]
1050         else:
1051             yvalues = [line.calories for line in values]
1052
1053         #determine values for y lines in graph
1054         diff = self.get_best_interval_value(max(yvalues))
1055         ytext = []
1056         for i in range(6):
1057             ytext.append(str(int(i*diff)))
1058
1059         if self.widget is not None:
1060             yvalues.reverse()
1061             labels.reverse()
1062             self.widget.values = yvalues
1063             self.widget.ytext = ytext
1064             self.widget.xtext = labels
1065             self.widget.max_value = diff * 5
1066             self.widget.text = self.xtitles[self.x_id] + " / " + self.ytitles[self.y_id]
1067             self.widget.queue_draw()
1068         else:
1069             logger.error("Widget not set in GraphController")
1070
1071     def get_best_interval_value(self, max_value):
1072         diff =  1.0 * max_value / 5
1073         l = len(str(int(diff)))
1074         d = math.pow(10, l/2)
1075         val = int(math.ceil(1.0 * diff / d)) * d
1076         if val == 0:
1077             val = 1
1078         return val
1079
1080     def update_ui(self, optional=False):
1081         """update graph values every x seconds"""
1082         if optional and self.last_update - time.time() < 600:
1083             return
1084         if self.widget is None:
1085             return
1086
1087         self.compute_values()
1088         self.last_update = time.time()
1089
1090 class GraphWidget(gtk.DrawingArea):
1091
1092     def __init__(self):
1093         gtk.DrawingArea.__init__(self)
1094         self.set_size_request(-1, 150)
1095         self.yvalues = 5
1096
1097         """sample values"""
1098         self.ytext = ["   0", "1000", "2000", "3000", "4000", "5000"]
1099         self.xtext = [_("Monday"), _("Tuesday"), _("Wednesday"), _("Thursday"), _("Friday"), _("Saturday"), _("Sunday")]
1100         self.values = [1500, 3400, 4000, 3600, 3200, 0, 4500]
1101         self.max_value = 5000
1102         self.text = _("All time steps")
1103
1104     def do_expose_event(self, event):
1105         context = self.window.cairo_create()
1106
1107         # set a clip region for the expose event
1108         context.rectangle(event.area.x, event.area.y,
1109                                event.area.width, event.area.height)
1110         context.clip()
1111
1112         context.save()
1113
1114         context.set_operator(cairo.OPERATOR_SOURCE)
1115         style = self.rc_get_style()
1116
1117         if self.state == gtk.STATE_ACTIVE:
1118             color = style.lookup_color("SelectionColor")
1119         else:
1120              color = style.lookup_color("DefaultBackgroundColor")
1121         context.set_source_rgba (color.red / 65535.0, color.green / 65335.0, color.blue / 65535.0, 0.75)
1122
1123         context.paint()
1124         context.restore();
1125         self.draw(context)
1126
1127     def draw(self, cr):
1128         space_below = 20
1129         space_above = 10
1130         border_right = 10
1131         border_left = 30
1132
1133         rect = self.get_allocation()
1134         x = rect.width
1135         y = rect.height
1136
1137         cr.select_font_face("Purisa", cairo.FONT_SLANT_NORMAL,
1138             cairo.FONT_WEIGHT_NORMAL)
1139         cr.set_font_size(13)
1140
1141         #check space needed to display ylabels
1142         te = cr.text_extents(self.ytext[-1])
1143         border_left = te[2] + 7
1144
1145         cr.set_source_rgb(1, 1, 1)
1146         cr.move_to(border_left, space_above)
1147         cr.line_to(border_left, y-space_below)
1148         cr.set_line_width(2)
1149         cr.stroke()
1150
1151         cr.move_to(border_left, y-space_below)
1152         cr.line_to(x-border_right, y-space_below)
1153         cr.set_line_width(2)
1154         cr.stroke()
1155
1156         ydiff = (y-space_above-space_below) / self.yvalues
1157         for i in range(self.yvalues):
1158             yy = y-space_below-ydiff*(i+1)
1159             cr.move_to(border_left, yy)
1160             cr.line_to(x-border_right, yy)
1161             cr.set_line_width(0.8)
1162             cr.stroke()
1163
1164
1165         for i in range(6):
1166             yy = y - space_below - ydiff*i + 5
1167             te = cr.text_extents(self.ytext[i])
1168
1169             cr.move_to(border_left-te[2]-2, yy)
1170             cr.show_text(self.ytext[i])
1171
1172         cr.set_font_size(15)
1173         te = cr.text_extents(self.text)
1174         cr.move_to((x-te[2])/2, y-5)
1175         cr.show_text(self.text)
1176
1177         graph_x_space = x - border_left - border_right
1178         graph_y_space = y - space_below - space_above
1179         bar_width = graph_x_space*0.75 / len(self.values)
1180         bar_distance = graph_x_space*0.25 / (1+len(self.values))
1181
1182         #set dummy max value to avoid exceptions
1183         if self.max_value == 0:
1184             self.max_value = 100
1185         for i in range(len(self.values)):
1186             xx = border_left + (i+1)*bar_distance + i * bar_width
1187             yy = y-space_below
1188             height = graph_y_space * (1.0 * self.values[i] / self.max_value)
1189             cr.set_source_rgba(1, 1, 1, 0.75)
1190             cr.rectangle(int(xx), int(yy-height), int(bar_width), int(height))
1191             cr.fill()
1192
1193         cr.set_source_rgba(1, 1, 1, 1)
1194         cr.select_font_face("Purisa", cairo.FONT_SLANT_NORMAL,
1195                             cairo.FONT_WEIGHT_NORMAL)
1196         cr.set_font_size(13)
1197
1198         cr.rotate(2*math.pi * (-45) / 180)
1199         for i in range(len(self.values)):
1200             xx = y - space_below - 10
1201             yy = border_left + (i+1)*bar_distance + i * bar_width
1202             cr.move_to(-xx, yy + bar_width*1.25 / 2)
1203             cr.show_text(self.xtext[i])
1204
1205 class Config(Singleton):
1206     mode = 0
1207     height = 0
1208     step_length = 0.7
1209     weight = 70
1210     sensitivity = 100
1211     unit = 0
1212     aspect = 0
1213     sensitivity = 100
1214     second_view = 0
1215     graph_view = 0
1216     no_idle_time = False
1217     logging = False
1218
1219     alarm_enable = False
1220     alarm_fname = "/home/user/MyDocs/.sounds/Ringtones/Bicycle.aac"
1221     alarm_interval = 5
1222     alarm_type = 0
1223
1224     observers = []
1225
1226     def __init__(self):
1227         if self._references > 1:
1228             return
1229         self.client = gconf.client_get_default()
1230         self.client.add_dir('/apps/pedometerhomewidget', gconf.CLIENT_PRELOAD_RECURSIVE)
1231         self.notify_id = self.client.notify_add('/apps/pedometerhomewidget', self.gconf_changed)
1232
1233     def add_observer(self, func):
1234         try:
1235             self.observers.index(func)
1236         except:
1237             self.observers.append(func)
1238             func()
1239
1240     def remove_observer(self, func):
1241         self.observers.remove(func)
1242
1243     def gconf_changed(self, client, *args, **kargs):
1244         self.notify()
1245
1246     def notify(self):
1247         t1 = time.time()
1248         for func in self.observers:
1249             func()
1250         t2 = time.time()
1251         logger.info("Update took: %f seconds" % (t2-t1))
1252
1253     def get_mode(self):
1254         return self.client.get_int(MODE)
1255
1256     def set_mode(self, value):
1257         self.client.set_int(MODE, value)
1258
1259     def get_height(self):
1260         return self.client.get_int(HEIGHT)
1261
1262     def set_height(self, value):
1263         self.client.set_int(HEIGHT, value)
1264
1265     def get_step_length(self):
1266         return self.client.get_float(STEP_LENGTH)
1267
1268     def set_step_length(self, value):
1269         self.client.set_float(STEP_LENGTH, value)
1270
1271     def get_weight(self):
1272         return self.client.get_int(WEIGHT)
1273
1274     def set_weight(self, value):
1275         self.client.set_int(WEIGHT, value)
1276
1277     def get_sensitivity(self):
1278         return self.client.get_int(SENSITIVITY)
1279
1280     def set_sensitivity(self, value):
1281         self.client.set_int(SENSITIVITY, value)
1282
1283     def get_unit(self):
1284         return self.client.get_int(UNIT)
1285
1286     def set_unit(self, value):
1287         self.client.set_int(UNIT, value)
1288
1289     def get_aspect(self):
1290         return self.client.get_int(ASPECT)
1291
1292     def set_aspect(self, value):
1293         self.client.set_int(ASPECT, value)
1294
1295     def get_secondview(self):
1296         value = self.client.get_int(SECONDVIEW)
1297         if value < 0 or value > 2:
1298             value = 0
1299             logger.error("Invalid secondview value read from Gconf. Using default value")
1300
1301         return value
1302
1303     def set_secondview(self, value):
1304         self.client.set_int(SECONDVIEW, value)
1305
1306     def get_graphview(self):
1307         return self.client.get_int(GRAPHVIEW)
1308
1309     def set_graphview(self, value):
1310         self.client.set_int(GRAPHVIEW, value)
1311
1312     def get_noidletime(self):
1313         return self.client.get_bool(NOIDLETIME)
1314
1315     def set_noidletime(self, value):
1316         self.client.set_bool(NOIDLETIME, value)
1317
1318     def get_logging(self):
1319         return self.client.get_bool(LOGGING)
1320
1321     def set_logging(self, value):
1322         self.client.set_bool(LOGGING, value)
1323
1324     def get_alarm_enable(self):
1325         return self.client.get_bool(ALARM_ENABLE)
1326
1327     def set_alarm_enable(self, value):
1328         self.client.set_bool(ALARM_ENABLE, value)
1329
1330     def get_alarm_fname(self):
1331         return self.client.get_string(ALARM_FNAME)
1332
1333     def set_alarm_fname(self, value):
1334         self.client.set_string(ALARM_FNAME, value)
1335
1336     def get_alarm_interval(self):
1337         return self.client.get_int(ALARM_INTERVAL)
1338
1339     def set_alarrm_interval(self, value):
1340         self.client.set_int(ALARM_INTERVAL, value)
1341
1342     def get_alarm_type(self):
1343         return self.client.get_int(ALARM_TYPE)
1344
1345     def set_alarm_type(self, value):
1346         self.client.set_int(ALARM_TYPE, value)
1347
1348
1349 class PedometerHomePlugin(hildondesktop.HomePluginItem):
1350     button = None
1351
1352     #labels to display
1353     labels = ["timer", "count", "dist", "avgSpeed", "calories"]
1354
1355     #current view
1356     labelsC = {}
1357
1358     #second view ( day / week/ alltime)
1359     labelsT = {}
1360
1361     second_view_labels = [_("All-time"), _("Today"), _("This week")]
1362
1363     controller = None
1364     graph_controller = None
1365
1366     config = None
1367
1368     def __init__(self):
1369         hildondesktop.HomePluginItem.__init__(self)
1370
1371         print "!!!!!!!!!!!!!!!Pedometer init"
1372         gobject.type_register(CustomEventBox)
1373         gobject.type_register(GraphWidget)
1374
1375         #global _
1376         #_ = Translate()._
1377
1378         self.config = Config()
1379
1380         self.button = CustomButton(ICONSPATH + "play.png")
1381         self.button.connect("clicked", self.button_clicked)
1382
1383         self.create_labels(self.labelsC)
1384         self.create_labels(self.labelsT)
1385         self.label_second_view = self.new_label_heading(self.second_view_labels[self.config.get_secondview()])
1386
1387         self.controller = PedoController()
1388         self.controller.set_callback_ui(self.update_values)
1389
1390         self.graph_controller = GraphController()
1391         self.alarm_controller = AlarmController()
1392
1393         self.update_current()
1394         self.update_total()
1395
1396         mainHBox = gtk.HBox(spacing=1)
1397
1398         descVBox = gtk.VBox(spacing=1)
1399         descVBox.add(self.new_label_heading())
1400         descVBox.add(self.new_label_heading(_("Time") + ":"))
1401         descVBox.add(self.new_label_heading(_("Steps") + ":"))
1402         descVBox.add(self.new_label_heading(_("Calories") + ":"))
1403         descVBox.add(self.new_label_heading(_("Distance") + ":"))
1404         descVBox.add(self.new_label_heading(_("Avg Speed") + ":"))
1405
1406         currentVBox = gtk.VBox(spacing=1)
1407         currentVBox.add(self.new_label_heading(_("Current")))
1408         currentVBox.add(self.labelsC["timer"])
1409         currentVBox.add(self.labelsC["count"])
1410         currentVBox.add(self.labelsC["calories"])
1411         currentVBox.add(self.labelsC["dist"])
1412         currentVBox.add(self.labelsC["avgSpeed"])
1413         self.currentBox = currentVBox
1414
1415         totalVBox = gtk.VBox(spacing=1)
1416         totalVBox.add(self.label_second_view)
1417         totalVBox.add(self.labelsT["timer"])
1418         totalVBox.add(self.labelsT["count"])
1419         totalVBox.add(self.labelsT["calories"])
1420         totalVBox.add(self.labelsT["dist"])
1421         totalVBox.add(self.labelsT["avgSpeed"])
1422         self.totalBox = totalVBox
1423
1424         buttonVBox = gtk.VBox(spacing=1)
1425         buttonVBox.add(self.new_label_heading(""))
1426         buttonVBox.add(self.button)
1427         buttonVBox.add(self.new_label_heading(""))
1428
1429         eventBox = CustomEventBox()
1430         eventBox.set_visible_window(False)
1431         eventBox.add(totalVBox)
1432         eventBox.connect("button-press-event", self.eventBox_clicked)
1433         eventBox.connect("button-release-event", self.eventBox_clicked_release)
1434
1435         mainHBox.add(buttonVBox)
1436         mainHBox.add(descVBox)
1437         mainHBox.add(currentVBox)
1438         mainHBox.add(eventBox)
1439         self.mainhbox = mainHBox
1440
1441         graph = GraphWidget()
1442         self.graph_controller.set_graph(graph)
1443
1444         eventBoxGraph = CustomEventBox()
1445         eventBoxGraph.set_visible_window(False)
1446         eventBoxGraph.add(graph)
1447         self.graph = graph
1448         eventBoxGraph.connect("button-press-event", self.eventBoxGraph_clicked)
1449         eventBoxGraph.connect("button-release-event", self.eventBoxGraph_clicked_release)
1450         self.graphBox = eventBoxGraph
1451
1452         self.mainvbox = gtk.VBox()
1453
1454         self.mainvbox.add(mainHBox)
1455         self.mainvbox.add(eventBoxGraph)
1456
1457         self.mainvbox.show_all()
1458         self.add(self.mainvbox)
1459
1460         self.connect("unrealize", self.close_requested)
1461         self.set_settings(True)
1462         self.connect("show-settings", self.show_settings)
1463
1464         self.config.add_observer(self.update_aspect)
1465
1466     def eventBoxGraph_clicked(self, widget, data=None):
1467         widget.set_state(gtk.STATE_ACTIVE)
1468
1469     def eventBoxGraph_clicked_release(self, widget, data=None):
1470         self.graph_controller.next_view()
1471         widget.set_state(gtk.STATE_NORMAL)
1472
1473     def eventBox_clicked(self, widget, data=None):
1474         widget.set_state(gtk.STATE_ACTIVE)
1475
1476     def eventBox_clicked_release(self, widget, data=None):
1477         widget.set_state(gtk.STATE_NORMAL)
1478
1479         second_view = self.config.get_secondview()
1480         second_view = (second_view + 1) % 3
1481         self.config.set_secondview(second_view)
1482
1483     def new_label_heading(self, title=""):
1484         l = gtk.Label(title)
1485         hildon.hildon_helper_set_logical_font(l, "SmallSystemFont")
1486         return l
1487
1488     def create_labels(self, new_labels):
1489         for label in self.labels:
1490             l = gtk.Label()
1491             hildon.hildon_helper_set_logical_font(l, "SmallSystemFont")
1492             hildon.hildon_helper_set_logical_color(l, gtk.RC_FG, gtk.STATE_NORMAL, "ActiveTextColor")
1493             new_labels[label] = l
1494
1495     def update_aspect(self):
1496         aspect = self.config.get_aspect()
1497         if aspect > 0:
1498             self.graphBox.hide_all()
1499         else:
1500             self.graphBox.show_all()
1501
1502         if aspect == 0 or aspect == 1:
1503             self.currentBox.show_all()
1504             self.totalBox.show_all()
1505         elif aspect == 2:
1506             self.currentBox.show_all()
1507             self.totalBox.hide_all()
1508         else:
1509             self.currentBox.hide_all()
1510             self.totalBox.show_all()
1511
1512         x,y = self.size_request()
1513         self.resize(x,y)
1514
1515     def update_ui_values(self, labels, values):
1516         labels["timer"].set_label(values.get_print_time())
1517         labels["count"].set_label(values.get_print_steps())
1518         labels["dist"].set_label(values.get_print_distance())
1519         labels["avgSpeed"].set_label(values.get_print_avg_speed())
1520         labels["calories"].set_label(values.get_print_calories())
1521
1522     def update_current(self):
1523         self.update_ui_values(self.labelsC, self.controller.get_first())
1524
1525     def update_total(self):
1526         self.update_ui_values(self.labelsT, self.controller.get_second())
1527
1528     def show_alarm_settings(self, main_button):
1529         def choose_file(widget):
1530             file = hildon.FileChooserDialog(self, gtk.FILE_CHOOSER_ACTION_OPEN, hildon.FileSystemModel() )
1531             file.show()
1532             if ( file.run() == gtk.RESPONSE_OK):
1533                 fname = file.get_filename()
1534                 widget.set_value(fname)
1535                 self.config.set_alarm_fname(fname)
1536             file.destroy()
1537
1538         def test_sound(button):
1539             try:
1540                 self.alarm_controller.play()
1541             except Exception, e:
1542                 logger.error("Could not play alarm sound: %s" % e)
1543                 hildon.hildon_banner_show_information(self, "None", "Could not play alarm sound")
1544
1545         def enableButton_changed(button):
1546             value = button.get_active()
1547             self.config.set_alarm_enable(value)
1548             if value:
1549                 main_button.set_value("Enabled")
1550             else:
1551                 main_button.set_value("Disabled")
1552
1553         def selectorType_changed(selector, data, labelEntry2):
1554             type = selector.get_active(0)
1555             self.config.set_alarm_type(type)
1556             labelEntry2.set_label(suffix[type])
1557
1558         dialog = gtk.Dialog()
1559         dialog.set_title(_("Alarm settings"))
1560         dialog.add_button(_("OK"), gtk.RESPONSE_OK)
1561
1562         enableButton = hildon.CheckButton(gtk.HILDON_SIZE_AUTO_WIDTH | gtk.HILDON_SIZE_FINGER_HEIGHT)
1563         enableButton.set_label(_("Enable alarm"))
1564         enableButton.set_active(self.alarm_controller.get_enable())
1565         enableButton.connect("toggled", enableButton_changed)
1566
1567         testButton = hildon.Button(gtk.HILDON_SIZE_AUTO_WIDTH | gtk.HILDON_SIZE_FINGER_HEIGHT, hildon.BUTTON_ARRANGEMENT_VERTICAL)
1568         testButton.set_alignment(0, 0.8, 1, 1)
1569         testButton.set_title(_("Test sound"))
1570         testButton.connect("pressed", test_sound)
1571
1572         fileButton = hildon.Button(gtk.HILDON_SIZE_AUTO_WIDTH | gtk.HILDON_SIZE_FINGER_HEIGHT, hildon.BUTTON_ARRANGEMENT_VERTICAL)
1573         fileButton.set_alignment(0, 0.8, 1, 1)
1574         fileButton.set_title(_("Alarm sound"))
1575         fileButton.set_value(self.alarm_controller.get_alarm_file())
1576         fileButton.connect("pressed", choose_file)
1577
1578         labelEntry = gtk.Label(_("Notify every") + ":")
1579         suffix = [_("mins"), _("steps"), _("m/ft"), _("calories")]
1580         labelEntry2 = gtk.Label(suffix[self.alarm_controller.get_type()])
1581         intervalEntry = hildon.Entry(gtk.HILDON_SIZE_AUTO_WIDTH)
1582         intervalEntry.set_text(str(self.alarm_controller.get_interval()))
1583
1584         selectorType = hildon.TouchSelector(text=True)
1585         selectorType.set_column_selection_mode(hildon.TOUCH_SELECTOR_SELECTION_MODE_SINGLE)
1586         selectorType.append_text(_("Time"))
1587         selectorType.append_text(_("Steps"))
1588         selectorType.append_text(_("Distance"))
1589         selectorType.append_text(_("Calories"))
1590         selectorType.connect("changed", selectorType_changed, labelEntry2)
1591
1592         typePicker = hildon.PickerButton(gtk.HILDON_SIZE_AUTO_WIDTH | gtk.HILDON_SIZE_FINGER_HEIGHT, hildon.BUTTON_ARRANGEMENT_VERTICAL)
1593         typePicker.set_alignment(0.0, 0.5, 1.0, 1.0)
1594         typePicker.set_title(_("Alarm type"))
1595         typePicker.set_selector(selectorType)
1596         typePicker.set_active(self.alarm_controller.get_type())
1597
1598         hbox = gtk.HBox()
1599         hbox.add(labelEntry)
1600         hbox.add(intervalEntry)
1601         hbox.add(labelEntry2)
1602
1603         dialog.vbox.add(enableButton)
1604         dialog.vbox.add(fileButton)
1605         dialog.vbox.add(testButton)
1606         dialog.vbox.add(typePicker)
1607         dialog.vbox.add(hbox)
1608         dialog.show_all()
1609         while 1:
1610             response = dialog.run()
1611             if response != gtk.RESPONSE_OK:
1612                 break
1613             try:
1614                 value = int(intervalEntry.get_text())
1615                 self.config.set_alarrm_interval(value)
1616                 break
1617             except:
1618                 hildon.hildon_banner_show_information(self, "None", _("Invalid interval"))
1619
1620         dialog.destroy()
1621
1622     def show_settings(self, widget):
1623         def reset_total_counter(arg):
1624             note = hildon.hildon_note_new_confirmation(self.dialog, _("Are you sure you want to delete all your pedometer history?"))
1625             ret = note.run()
1626             if ret == gtk.RESPONSE_OK:
1627                 self.controller.reset_all_values()
1628                 hildon.hildon_banner_show_information(self, "None", _("All history was deleted"))
1629             note.destroy()
1630
1631         def alarmButton_pressed(widget):
1632             self.show_alarm_settings(widget)
1633
1634         def selector_changed(selector, data):
1635             mode = selector.get_active(0)
1636             self.config.set_mode(mode)
1637
1638         def selectorUnit_changed(selector, data):
1639             unit = selector.get_active(0)
1640             self.config.set_unit(unit)
1641
1642             update_weight_button()
1643             stepLengthButton_value_update()
1644
1645         def selectorUI_changed(selector, data):
1646             aspect = selectorUI.get_active(0)
1647             self.config.set_aspect(aspect)
1648
1649         def logButton_changed(checkButton):
1650             logging = checkButton.get_active()
1651             self.config.set_logging(logging)
1652
1653         def idleButton_changed(idleButton):
1654             no_idle_time = idleButton.get_active()
1655             self.config.set_noidletime(no_idle_time)
1656
1657         def update_weight_button():
1658             weightButton.set_value(str(self.config.get_weight()) + \
1659                                            " " + self.controller.get_str_weight_unit(self.config.get_unit()) )
1660
1661         def weight_dialog(button):
1662             dialog = gtk.Dialog(_("Weight"), self.dialog)
1663             dialog.add_button(_("OK"), gtk.RESPONSE_OK)
1664
1665             label = gtk.Label(_("Weight") + ":")
1666             entry = gtk.Entry()
1667             entry.set_text(str(self.config.get_weight()))
1668
1669             suffixLabel = gtk.Label(self.controller.get_str_weight_unit(self.config.get_unit()))
1670
1671             hbox = gtk.HBox()
1672             hbox.add(label)
1673             hbox.add(entry)
1674             hbox.add(suffixLabel)
1675
1676             dialog.vbox.add(hbox)
1677             dialog.show_all()
1678             while 1:
1679                 response = dialog.run()
1680                 if response != gtk.RESPONSE_OK:
1681                     break
1682                 try:
1683                     value = int(entry.get_text())
1684                     if value <= 0:
1685                         raise ValueError
1686                     self.config.set_weight(value)
1687                     update_weight_button()
1688                     break
1689                 except:
1690                     hildon.hildon_banner_show_information(self, "None", _("Invalid weight"))
1691             dialog.destroy()
1692
1693         def sensitivity_dialog(button):
1694             def seekbar_changed(seekbar):
1695                 label.set_text(str(seekbar.get_position()) + " %")
1696
1697             dialog = gtk.Dialog(_("Sensitivity"), self.dialog)
1698             dialog.add_button(_("OK"), gtk.RESPONSE_OK)
1699             seekbar = hildon.Seekbar()
1700             seekbar.set_size_request(400, -1)
1701             seekbar.set_total_time(200)
1702             seekbar.set_position(self.config.get_sensitivity())
1703             seekbar.connect("value-changed", seekbar_changed)
1704
1705             hbox = gtk.HBox()
1706             hbox.add(seekbar)
1707             label = gtk.Label(str(self.config.get_sensitivity()) + " %")
1708             label.set_size_request(30, -1)
1709             hbox.add(label)
1710
1711             dialog.vbox.add(hbox)
1712             dialog.show_all()
1713
1714             if dialog.run() == gtk.RESPONSE_OK:
1715                 value = seekbar.get_position()
1716                 self.config.set_sensitivity(value)
1717                 button.set_value(str(value) + " %")
1718
1719             dialog.destroy()
1720
1721         def stepLengthButton_value_update():
1722             if self.config.get_height() == 5:
1723                 l_unit = ["m", "ft"]
1724                 stepLengthButton.set_value(_("Custom value") + ": %.2f %s" % (self.config.get_step_length(), l_unit[self.config.get_unit()]))
1725             else:
1726                 h = [ ["< 1.50 m", "1.50 - 1.65 m", "1.66 - 1.80 m", "1.81 - 1.95 m", " > 1.95 m"],
1727                       ["< 5 ft", "5 - 5.5 ft", "5.5 - 6 ft", "6 - 6.5 ft", "> 6.5 ft"]]
1728                 str = _("Using predefined value for height") + ": %s" % h[self.config.get_unit()][self.config.get_height()]
1729                 stepLengthButton.set_value(str)
1730
1731         def stepLength_dialog(button):
1732             def selectorH_changed(selector, data, dialog):
1733                 height = selector.get_active(0)
1734                 self.config.set_height(height)
1735                 stepLengthButton_value_update()
1736
1737             def manualButton_clicked(button, dialog):
1738                 dlg = gtk.Dialog()
1739                 dlg.set_title(_("Custom step length"))
1740                 dlg.add_button(_("OK"), gtk.RESPONSE_OK)
1741
1742                 label = gtk.Label(_("Length"))
1743
1744                 entry = hildon.Entry(gtk.HILDON_SIZE_AUTO_WIDTH)
1745                 if self.config.get_height() == 5:
1746                     entry.set_text(str(self.config.get_step_length()))
1747
1748                 labelSuffix = gtk.Label()
1749                 if self.config.get_unit() == 0:
1750                     labelSuffix.set_label("m")
1751                 else:
1752                     labelSuffix.set_label("ft")
1753                 hbox = gtk.HBox()
1754                 hbox.add(label)
1755                 hbox.add(entry)
1756                 hbox.add(labelSuffix)
1757                 dlg.vbox.add(hbox)
1758                 dlg.show_all()
1759
1760                 while 1:
1761                     response = dlg.run()
1762                     if response != gtk.RESPONSE_OK:
1763                         break
1764                     try:
1765                         value = float(entry.get_text())
1766                         if value <= 0:
1767                             raise ValueError
1768                         self.config.set_step_length(value)
1769                         self.config.set_height(5)
1770                         stepLengthButton_value_update()
1771                         break
1772                     except ValueError:
1773                         hildon.hildon_banner_show_information(self, "None", _("Invalid length"))
1774                 dlg.destroy()
1775                 dialog.destroy()
1776
1777             def heightButton_clicked(button, dialog):
1778                 dialog.destroy()
1779
1780             dialog = gtk.Dialog()
1781             dialog.set_title(_("Step length"))
1782
1783             manualButton = hildon.Button(gtk.HILDON_SIZE_AUTO_WIDTH | gtk.HILDON_SIZE_FINGER_HEIGHT, hildon.BUTTON_ARRANGEMENT_VERTICAL)
1784             manualButton.set_title(_("Enter custom value"))
1785             manualButton.set_alignment(0, 0.8, 1, 1)
1786             manualButton.connect("clicked", manualButton_clicked, dialog)
1787
1788             selectorH = hildon.TouchSelector(text=True)
1789             selectorH.set_column_selection_mode(hildon.TOUCH_SELECTOR_SELECTION_MODE_SINGLE)
1790             selectorH.append_text("< 1.50 m")
1791             selectorH.append_text("1.50 - 1.65 m")
1792             selectorH.append_text("1.66 - 1.80 m")
1793             selectorH.append_text("1.81 - 1.95 m")
1794             selectorH.append_text(" > 1.95 m")
1795
1796             selectorH_English = hildon.TouchSelector(text=True)
1797             selectorH_English.set_column_selection_mode(hildon.TOUCH_SELECTOR_SELECTION_MODE_SINGLE)
1798             selectorH_English.append_text("< 5 ft")
1799             selectorH_English.append_text("5 - 5.5 ft")
1800             selectorH_English.append_text("5.5 - 6 ft")
1801             selectorH_English.append_text("6 - 6.5 ft")
1802             selectorH_English.append_text("> 6.5 ft")
1803
1804             heightPicker = hildon.PickerButton(gtk.HILDON_SIZE_AUTO_WIDTH | gtk.HILDON_SIZE_FINGER_HEIGHT, hildon.BUTTON_ARRANGEMENT_VERTICAL)
1805             heightPicker.set_alignment(0.0, 0.5, 1.0, 1.0)
1806             heightPicker.set_title(_("Use predefined values for height"))
1807
1808
1809             unit = self.config.get_unit()
1810             if unit == 0:
1811                 heightPicker.set_selector(selectorH)
1812             else:
1813                 heightPicker.set_selector(selectorH_English)
1814
1815             height = self.config.get_height()
1816             if height < 5:
1817                 heightPicker.set_active(height)
1818
1819             heightPicker.get_selector().connect("changed", selectorH_changed, dialog)
1820             heightPicker.connect("value-changed", heightButton_clicked, dialog)
1821
1822             dialog.vbox.add(heightPicker)
1823             dialog.vbox.add(manualButton)
1824             dialog.show_all()
1825
1826             if  dialog.run() == gtk.RESPONSE_DELETE_EVENT:
1827                 dialog.destroy()
1828
1829         def donateButton_clicked(button, dialog):
1830             url = "https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=BKE6E9SLK7NP4&lc=RO&item_name=Pedometer%20Widget&currency_code=EUR&bn=PP%2dDonationsBF%3abtn_donateCC_LG%2egif%3aNonHosted"
1831             command = "dbus-send --system --type=method_call --dest=\"com.nokia.osso_browser\"  --print-reply /com/nokia/osso_browser/request com.nokia.osso_browser.load_url string:\"%s\"" % url
1832             os.system(command)
1833
1834         dialog = gtk.Dialog()
1835         dialog.set_title(_("Settings"))
1836         dialog.add_button(_("OK"), gtk.RESPONSE_OK)
1837         self.dialog = dialog
1838
1839         stepLengthButton = hildon.Button(gtk.HILDON_SIZE_AUTO_WIDTH | gtk.HILDON_SIZE_FINGER_HEIGHT, hildon.BUTTON_ARRANGEMENT_VERTICAL)
1840         stepLengthButton.set_title(_("Step length"))
1841         stepLengthButton.set_alignment(0, 0.8, 1, 1)
1842         stepLengthButton.connect("clicked", stepLength_dialog)
1843         stepLengthButton_value_update()
1844
1845         resetButton = hildon.Button(gtk.HILDON_SIZE_AUTO_WIDTH | gtk.HILDON_SIZE_FINGER_HEIGHT, hildon.BUTTON_ARRANGEMENT_VERTICAL)
1846         resetButton.set_title(_("Reset"))
1847         resetButton.set_value(_("All the stored values will be erased"))
1848         resetButton.set_alignment(0, 0.8, 1, 1)
1849         resetButton.connect("clicked", reset_total_counter)
1850
1851         alarmButton = hildon.Button(gtk.HILDON_SIZE_AUTO_WIDTH | gtk.HILDON_SIZE_FINGER_HEIGHT, hildon.BUTTON_ARRANGEMENT_VERTICAL)
1852         alarmButton.set_title(_("Alarm"))
1853         if self.config.get_alarm_enable():
1854             alarmButton.set_value(_("Enabled"))
1855         else:
1856             alarmButton.set_value(_("Disabled"))
1857         alarmButton.set_alignment(0, 0.8, 1, 1)
1858         alarmButton.connect("clicked", alarmButton_pressed)
1859
1860         selector = hildon.TouchSelector(text=True)
1861         selector.set_column_selection_mode(hildon.TOUCH_SELECTOR_SELECTION_MODE_SINGLE)
1862         selector.append_text(_("Walk"))
1863         selector.append_text(_("Run"))
1864         selector.connect("changed", selector_changed)
1865
1866         modePicker = hildon.PickerButton(gtk.HILDON_SIZE_AUTO_WIDTH | gtk.HILDON_SIZE_FINGER_HEIGHT, hildon.BUTTON_ARRANGEMENT_VERTICAL)
1867         modePicker.set_alignment(0.0, 0.5, 1.0, 1.0)
1868         modePicker.set_title(_("Mode"))
1869         modePicker.set_selector(selector)
1870         modePicker.set_active(self.config.get_mode())
1871
1872         weightButton = hildon.Button(gtk.HILDON_SIZE_AUTO_WIDTH | gtk.HILDON_SIZE_FINGER_HEIGHT, hildon.BUTTON_ARRANGEMENT_VERTICAL)
1873         weightButton.set_title(_("Weight"))
1874         weightButton.set_alignment(0, 0.8, 1, 1)
1875         update_weight_button()
1876         weightButton.connect("clicked", weight_dialog)
1877
1878         selectorUnit = hildon.TouchSelector(text=True)
1879         selectorUnit.set_column_selection_mode(hildon.TOUCH_SELECTOR_SELECTION_MODE_SINGLE)
1880         selectorUnit.append_text(_("Metric (km)"))
1881         selectorUnit.append_text(_("English (mi)"))
1882         selectorUnit.connect("changed", selectorUnit_changed)
1883
1884         unitPicker = hildon.PickerButton(gtk.HILDON_SIZE_AUTO_WIDTH | gtk.HILDON_SIZE_FINGER_HEIGHT, hildon.BUTTON_ARRANGEMENT_VERTICAL)
1885         unitPicker.set_alignment(0.0, 0.5, 1.0, 1.0)
1886         unitPicker.set_title(_("Unit"))
1887         unitPicker.set_selector(selectorUnit)
1888         unitPicker.set_active(self.config.get_unit())
1889
1890         selectorUI = hildon.TouchSelector(text=True)
1891         selectorUI = hildon.TouchSelector(text=True)
1892         selectorUI.set_column_selection_mode(hildon.TOUCH_SELECTOR_SELECTION_MODE_SINGLE)
1893         selectorUI.append_text(_("Show current + total + graph"))
1894         selectorUI.append_text(_("Show current + total"))
1895         selectorUI.append_text(_("Show only current"))
1896         selectorUI.append_text(_("Show only total"))
1897         selectorUI.connect("changed", selectorUI_changed)
1898
1899         UIPicker = hildon.PickerButton(gtk.HILDON_SIZE_AUTO_WIDTH | gtk.HILDON_SIZE_FINGER_HEIGHT, hildon.BUTTON_ARRANGEMENT_VERTICAL)
1900         UIPicker.set_alignment(0.0, 0.5, 1.0, 1.0)
1901         UIPicker.set_title(_("Widget aspect"))
1902         UIPicker.set_selector(selectorUI)
1903         UIPicker.set_active(self.config.get_aspect())
1904
1905         sensitivityButton = hildon.Button(gtk.HILDON_SIZE_AUTO_WIDTH | gtk.HILDON_SIZE_FINGER_HEIGHT, hildon.BUTTON_ARRANGEMENT_VERTICAL)
1906         sensitivityButton.set_title(_("Sensitivity"))
1907         sensitivityButton.set_alignment(0, 0.8, 1, 1)
1908         sensitivityButton.set_value(str(self.config.get_sensitivity()) + " %")
1909         sensitivityButton.connect("clicked", sensitivity_dialog)
1910
1911         donateButton = hildon.Button(gtk.HILDON_SIZE_AUTO_WIDTH | gtk.HILDON_SIZE_FINGER_HEIGHT, hildon.BUTTON_ARRANGEMENT_VERTICAL)
1912         donateButton.set_title(_("Donate"))
1913         donateButton.set_value(_("Please support the development of this opensource widget!"))
1914         donateButton.set_alignment(0, 0.8, 1, 1)
1915         donateButton.connect("clicked", donateButton_clicked, dialog)
1916
1917         logButton = hildon.CheckButton(gtk.HILDON_SIZE_AUTO_WIDTH | gtk.HILDON_SIZE_FINGER_HEIGHT)
1918         logButton.set_label(_("Log data"))
1919         logButton.set_active(self.config.get_logging())
1920         logButton.connect("toggled", logButton_changed)
1921
1922         idleButton = hildon.CheckButton(gtk.HILDON_SIZE_AUTO_WIDTH | gtk.HILDON_SIZE_FINGER_HEIGHT)
1923         idleButton.set_label(_("Pause time when not walking"))
1924         idleButton.set_active(self.config.get_noidletime())
1925         idleButton.connect("toggled", idleButton_changed)
1926
1927         pan_area = hildon.PannableArea()
1928         vbox = gtk.VBox()
1929         vbox.add(alarmButton)
1930         vbox.add(modePicker)
1931         vbox.add(stepLengthButton)
1932         vbox.add(weightButton)
1933         vbox.add(unitPicker)
1934         vbox.add(sensitivityButton)
1935         vbox.add(UIPicker)
1936         vbox.add(idleButton)
1937         vbox.add(resetButton)
1938         vbox.add(donateButton)
1939         #vbox.add(logButton)
1940
1941         pan_area.add_with_viewport(vbox)
1942         pan_area.set_size_request(-1, 300)
1943
1944         dialog.vbox.add(pan_area)
1945         dialog.show_all()
1946
1947         response = dialog.run()
1948         dialog.destroy()
1949
1950     def close_requested(self, widget):
1951         if self.controller.is_running:
1952             self.controller.stop_pedometer()
1953         self.controller.stop_midnight_callback()
1954
1955     def update_values(self):
1956         #TODO: do not update if the widget is not on the active desktop
1957         self.label_second_view.set_label(self.second_view_labels[self.config.get_secondview()])
1958         self.update_current()
1959         self.update_total()
1960
1961     def button_clicked(self, button):
1962         if self.controller.is_running:
1963             self.controller.stop_pedometer()
1964             self.button.set_icon(ICONSPATH + "play.png")
1965         else:
1966             self.controller.start_pedometer()
1967             self.button.set_icon(ICONSPATH + "stop.png")
1968             hildon.hildon_banner_show_information(self, "None", _("Keep the N900 in a pocket close to your hip for best results"))
1969
1970     def do_expose_event(self, event):
1971         cr = self.window.cairo_create()
1972         cr.region(event.window.get_clip_region())
1973         cr.clip()
1974         #cr.set_source_rgba(0.4, 0.64, 0.564, 0.5)
1975         style = self.rc_get_style()
1976         color = style.lookup_color("DefaultBackgroundColor")
1977         cr.set_source_rgba (color.red / 65535.0, color.green / 65335.0, color.blue / 65535.0, 0.75);
1978
1979         radius = 5
1980         width = self.allocation.width
1981         height = self.allocation.height
1982
1983         x = self.allocation.x
1984         y = self.allocation.y
1985
1986         cr.move_to(x + radius, y)
1987         cr.line_to(x + width - radius, y)
1988         cr.curve_to(x + width - radius, y, x + width, y, x + width, y + radius)
1989         cr.line_to(x + width, y + height - radius)
1990         cr.curve_to(x + width, y + height - radius, x + width, y + height, x + width - radius, y + height)
1991         cr.line_to(x + radius, y + height)
1992         cr.curve_to(x + radius, y + height, x, y + height, x, y + height - radius)
1993         cr.line_to(x, y + radius)
1994         cr.curve_to(x, y + radius, x, y, x + radius, y)
1995
1996         cr.set_operator(cairo.OPERATOR_SOURCE)
1997         cr.fill_preserve()
1998
1999         color = style.lookup_color("ActiveTextColor")
2000         cr.set_source_rgba (color.red / 65535.0, color.green / 65335.0, color.blue / 65535.0, 0.5);
2001         cr.set_line_width(1)
2002         cr.stroke()
2003
2004         hildondesktop.HomePluginItem.do_expose_event(self, event)
2005
2006     def do_realize(self):
2007         screen = self.get_screen()
2008         self.set_colormap(screen.get_rgba_colormap())
2009         self.set_app_paintable(True)
2010         hildondesktop.HomePluginItem.do_realize(self)
2011
2012 hd_plugin_type = PedometerHomePlugin
2013
2014 import math
2015 import logging
2016
2017 logger = logging.getLogger("pedometer")
2018 logger.setLevel(logging.INFO)
2019
2020 ch = logging.StreamHandler()
2021 formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
2022 ch.setFormatter(formatter)
2023 logger.addHandler(ch)
2024
2025 # The code below is just for testing purposes.
2026 # It allows to run the widget as a standalone process.
2027 if __name__ == "__main__":
2028     import gobject
2029     gobject.type_register(hd_plugin_type)
2030     obj = gobject.new(hd_plugin_type, plugin_id="plugin_id")
2031     obj.show_all()
2032     gtk.main()