Stop using a MainLoop
[gigfinder] / src / opt / gigfinder / gigfinder.py
1 #!/usr/bin/env python
2
3 """Simple program to display local gigs
4
5 Intended for use on the N900, uses the devices gps to find local gigs.
6 """
7
8 __authors__ = ["Jon Staley"]
9 __copyright__ = "Copyright 2010 Jon Staley"
10 __license__ = "MIT"
11 __version__ = "0.0.1"
12
13 import gtk
14 import hildon
15 import time
16 import gobject
17 import os.path
18 from threading import Thread
19 import thread
20
21 from locator import LocationUpdater
22 from events import Events
23
24 gtk.gdk.threads_init()
25
26 # TODO: 
27 # Add user settings for distance, date
28 # maybe switch to json
29 # maybe do km to mile conversions
30
31 class GigFinder:
32
33     def __init__(self):
34         self.lat = None
35         self.long = None
36         self.distance = '10'
37         self.banner = None
38         self.location = LocationUpdater()
39         self.events = Events()
40         self.win = hildon.StackableWindow()
41         self.app_title = "Gig Finder"
42         self.update_thread = Thread(target=self.update_gigs)
43
44     def main(self):
45         """ Build the gui and start the update thread """
46         program = hildon.Program.get_instance()
47         menu = self.create_menu()
48
49         self.win.set_title(self.app_title)
50         self.win.connect("destroy", gtk.main_quit, None)
51         self.win.set_app_menu(menu)
52         self.add_button_area()
53
54         self.update_thread.start()
55
56         self.win.show_all()
57         gtk.gdk.threads_enter()
58         gtk.main()
59         gtk.gdk.threads_leave()
60
61     def show_about(self, widget, data):
62         """ Show about dialog """
63         dialog = gtk.AboutDialog()
64         dialog.set_name('Gig Finder')
65         dialog.set_version(__version__)
66         dialog.set_authors(__authors__)
67         dialog.set_comments('Display gigs close by.\nUsing the http://www.last.fm api.')
68         dialog.set_license('Distributed under the MIT license.\nhttp://www.opensource.org/licenses/mit-license.php')
69         dialog.set_copyright(__copyright__)
70         dialog.show_all()
71
72     def update(self, widget, data):
73         """ Start update process """
74         self.win.set_title(self.app_title)
75         self.location.reset()
76         self.win.remove(self.pannable_area)
77         self.update_thread.start()
78
79     def update_gigs(self):
80         """ Get gig info """
81         gobject.idle_add(self.show_message, "Getting events")
82         
83         if not 'applications' in os.path.abspath(__file__):
84             gobject.idle_add(self.location.update_location)
85
86             # if no gps fix wait
87             # TODO: needs a timeout
88             while not self.location.lat or not self.location.long:
89                 time.sleep(1)
90         else:
91             self.location.lat = float(51.517369)
92             self.location.long = float(-0.082998)
93          
94         events = self.events.get_events(self.location.lat, 
95                                         self.location.long, 
96                                         self.distance,)
97         gobject.idle_add(self.show_events, events)
98         gobject.idle_add(self.hide_message)
99
100     def show_message(self, message):
101         """ Set window progress indicator and show message """
102         hildon.hildon_gtk_window_set_progress_indicator(self.win, 1)
103         self.banner = hildon.hildon_banner_show_information(self.win,
104                                                             '', 
105                                                             message)
106
107     def hide_message(self):
108         """ Hide banner and set progress indicator """
109         self.banner.hide()
110         hildon.hildon_gtk_window_set_progress_indicator(self.win, 0)
111
112     def show_events(self, events):
113         """ Sort events, set new window title and add events to table """
114         if events:
115             self.win.set_title('%s (%s)' % (self.app_title, len(events)))
116             self.add_events(events)
117         else:
118             label = gtk.Label('No events available')
119             vbox = gtk.VBox(False, 0)
120             vbox.pack_start(label, True, True, 0)
121             vbox.show_all()
122             self.win.add(vbox)
123
124     def create_menu(self):
125         """ Build application menu """
126         update_button = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
127         update_button.set_label('Update')
128         update_button.connect('clicked',
129                               self.update,
130                               None)
131
132         about_button = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
133         about_button.set_label('About')
134         about_button.connect('clicked',
135                              self.show_about,
136                              None)
137
138         menu = hildon.AppMenu()
139         menu.append(update_button)
140         menu.append(about_button)
141         menu.show_all()
142         return menu
143
144     def show_details(self, widget, data):
145         """ Open new window showing gig details """
146         win = hildon.StackableWindow()
147         win.set_title(data.title)
148
149         win.vbox = gtk.VBox()
150         win.add(win.vbox)
151
152         scroll = hildon.PannableArea()
153         win.vbox.pack_start(scroll, True, True, 0)
154
155         view = hildon.TextView()
156         view.set_editable(False)
157         view.unset_flags(gtk.CAN_FOCUS)
158         view.set_wrap_mode(gtk.WRAP_WORD)
159         buffer = view.get_buffer()
160         end = buffer.get_end_iter()
161         buffer.insert(end, '%s\n' % data.title)
162         buffer.insert(end, 'Artists: %s\n' % data.artists)
163         buffer.insert(end, 'Venue: %s\n' % data.venue_name)
164         buffer.insert(end, '%s\n' % data.address)
165         buffer.insert(end, 'When: %s\n' % data.start_date.strftime('%H:%M %d/%m/%Y'))
166         buffer.insert(end, '\n')
167         scroll.add_with_viewport(view)
168
169         win.show_all()
170
171     def add_button_area(self):
172         self.box = gtk.VBox(True,0)
173         self.pannable_area = hildon.PannableArea()
174         self.pannable_area.add_with_viewport(self.box)
175         self.pannable_area.show_all()
176         self.win.add(self.pannable_area)
177         
178     def add_events(self, events):
179         """ Add a table of buttons """
180         for event in events:
181             button = hildon.Button(gtk.HILDON_SIZE_AUTO_WIDTH | gtk.HILDON_SIZE_FINGER_HEIGHT, 
182                                    hildon.BUTTON_ARRANGEMENT_VERTICAL)
183             button.set_text(event.title, "distance: %0.02f km" % event.get_distance_from(self.location.long, self.location.lat))
184             button.connect("clicked", self.show_details, event)
185             self.box.pack_start(button)
186         self.box.show_all()
187             
188 if __name__ == "__main__":
189     finder = GigFinder()
190     finder.main()