merge
[gigfinder] / gig_finder.py
index f9e9625..0eb4383 100644 (file)
@@ -19,6 +19,10 @@ import hildon
 import location
 import time
 import gobject
+from threading import Thread
+import thread
+
+gtk.gdk.threads_init()
 
 class GigParser:
 
@@ -87,6 +91,51 @@ class GigParser:
                         result.tm_min, 
                         result.tm_sec)
 
+class LocationUpdater:
+
+    def __init__(self):
+        self.lat = None
+        self.long = None
+        self.loop = gobject.MainLoop()
+
+        self.control = location.GPSDControl.get_default()
+        self.control.set_properties(preferred_method=location.METHOD_USER_SELECTED,
+                               preferred_interval=location.INTERVAL_DEFAULT)
+        self.control.connect("error-verbose", self.on_error, self.loop)
+        self.control.connect("gpsd-stopped", self.on_stop, self.loop)
+
+        self.device = location.GPSDevice()
+        self.device.connect("changed", self.on_changed, self.control)
+
+    def update_location(self):
+        """ Run the loop and update lat and long """
+        self.reset()
+        gobject.idle_add(self.start_location, self.control)
+        self.loop.run()
+
+    def on_error(self, control, error, data):
+        print "location error: %d... quitting" % error
+        data.quit()
+
+    def on_changed(self, device, data):
+        if not device:
+            return
+        if device.fix:
+            if device.fix[1] & location.GPS_DEVICE_LATLONG_SET:
+                self.lat, self.long = device.fix[4:6]
+                data.stop()
+
+    def on_stop(self, control, data):
+        print "quitting"
+        data.quit()
+
+    def start_location(self, data):
+        data.start()
+        return False
+
+    def reset(self):
+        """ Reset coordinates """
+        self.device.reset_last_known()
 
 class GigFinder:
 
@@ -96,7 +145,9 @@ class GigFinder:
         self.url_base = "http://ws.audioscrobbler.com/2.0/"
         self.api_key = "1928a14bdf51369505530949d8b7e1ee"
         self.distance = '10'
-        self.loop = gobject.MainLoop()
+        self.banner = None
+        self.parser = GigParser()
+        self.location = LocationUpdater()
 
         program = hildon.Program.get_instance()
         self.win = hildon.StackableWindow()
@@ -112,66 +163,87 @@ class GigFinder:
         pannable_area.add_with_viewport(self.table)
 
         self.win.add(pannable_area)
-        self.update_gigs()
+
+        Thread(target=self.update_gigs).start()
 
     def main(self):
+        menu = self.create_menu()
+        self.win.set_app_menu(menu)
         self.win.show_all()
         gtk.main()
 
     def update_gigs(self):
         """ Get gig info """
-        self.get_lat_long()
-        parser = GigParser()
-        xml = self.get_xml()
-        events = parser.parse_xml(xml, self.lat, self.long)
+        gobject.idle_add(self.show_message, "Getting events")
+        gobject.idle_add(self.location.update_location)
+
+        # if no gps fix wait
+        while not self.location.lat:
+            time.sleep(1)
+        
+        events = self.get_events(self.location.lat, self.location.long)
+        gobject.idle_add(self.hide_message)
+        gobject.idle_add(self.show_events, events)
+
+    def show_message(self, message):
+        """ set window progress indicator and show message """
+        hildon.hildon_gtk_window_set_progress_indicator(self.win, 1)
+        self.banner = hildon.hildon_banner_show_information(self.win,
+                                                            '', 
+                                                            message)
+
+    def hide_message(self):
+        """ hide banner and sete progress indicator """
+        self.banner.hide()
+        hildon.hildon_gtk_window_set_progress_indicator(self.win, 0)
+
+    def get_events(self, lat, long):
+        """ retrieve xml and parse into events list """
+        xml = self.get_xml(lat, long)
+        events = self.parser.parse_xml(xml, 
+                                       lat,
+                                       long)
+        return events
+
+    def show_events(self, events):
+        """ sort events, set new window title and add events to table """
+        events = self.sort_gigs(events)
         self.win.set_title('Gig Finder (%s)' % len(events))
         self.add_events(events)
+
+    def distance_cmp(self, x, y):
+        """ compare distances for list sort """
+        if x > y:
+            return 1
+        elif x == y:
+            return 0
+        else:
+            return -1
+
+    def sort_gigs(self, events):
+        """ sort gig by distance """
+        events.sort(cmp=self.distance_cmp, key=lambda x: x['distance'])
+        return events
         
-    def get_xml(self):
+    def get_xml(self, lat, long):
         """ Return xml from lastfm """
         method = "geo.getevents"
         params = urllib.urlencode({'method': method,
                                    'api_key': self.api_key,
                                    'distance': self.distance,
-                                   'long': self.long,
-                                   'lat': self.lat})
+                                   'long': long,
+                                   'lat': lat})
         response = urllib.urlopen(self.url_base, params)
         return response.read()
 
-    def on_error(self, control, error, data):
-        print "location error: %d... quitting" % error
-        data.quit()
-
-    def on_changed(self, device, data):
-        if not device:
-            return
-        if device.fix:
-            if device.fix[1] & device.status:
-                self.lat, self.long = device.fix[4:6]
-                data.stop()
-
-    def on_stop(self, control, data):
-        print "quitting"
-        data.quit()
-
-    def start_location(self, data):
-        data.start()
-        return False
-
-    def get_lat_long(self):
-        """ Access gps and return current long lats """
-        # TODO: Improve geolocation code, very crude atm
-        control = location.GPSDControl.get_default()
-        device = location.GPSDevice()
-        device.reset_last_known()
-        control.set_properties(preferred_method=location.METHOD_USER_SELECTED,
-                               preferred_interval=location.INTERVAL_DEFAULT)
-        control.connect("error-verbose", self.on_error, self.loop)
-        device.connect("changed", self.on_changed, control)
-        control.connect("gpsd-stopped", self.on_stop, self.loop)
-        gobject.idle_add(self.start_location, control)
-        self.loop.run()
-        #self.lat, self.long = ('51.546228', '-0.075016')
+    def create_menu(self):
+        """ build application menu """
+        menu = hildon.AppMenu()
+        button = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
+        button.set_label('Placeholder')
+        menu.append(button)
+        menu.show_all()
+        return menu
 
     def show_details(self, widget, data):
         """ Open new window showing gig details """
@@ -201,7 +273,7 @@ class GigFinder:
         win.show_all()
         
     def add_events(self, events):
-        """ Return table of buttons """
+        """ Add a table of buttons """
         pos = 0
         for event in events:
             button = hildon.Button(gtk.HILDON_SIZE_AUTO_WIDTH | gtk.HILDON_SIZE_FINGER_HEIGHT, 
@@ -210,16 +282,7 @@ class GigFinder:
             button.connect("clicked", self.show_details, event)
             self.table.attach(button, 0, 1, pos, pos+1)
             pos += 1
-
-
-
-    #hildon.hildon_gtk_window_set_progress_indicator(win, 1)
-    #banner = hildon.hildon_banner_show_information(win,
-    #                                               "Updating", 
-    #                                               "Retrieving gig info")
-    #banner.hide()
-    #hildon.hildon_gtk_window_set_progress_indicator(win, 0)
-
+        self.table.show_all()
    
 if __name__ == "__main__":
     finder = GigFinder()