No need for parser to be a class
[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 location
16 import time
17 import gobject
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
43     def main(self):
44         """ Build the gui and start the update thread """
45         program = hildon.Program.get_instance()
46         menu = self.create_menu()
47
48         self.win.set_title(self.app_title)
49         self.win.connect("destroy", gtk.main_quit, None)
50         self.win.set_app_menu(menu)
51
52         Thread(target=self.update_gigs).start()
53
54         self.win.show_all()
55         gtk.main()
56
57     def show_about(self, widget, data):
58         """ Show about dialog """
59         dialog = gtk.AboutDialog()
60         dialog.set_name('Gig Finder')
61         dialog.set_version(__version__)
62         dialog.set_authors(__authors__)
63         dialog.set_comments('Display gigs close by.\nUsing the http://www.last.fm api.')
64         dialog.set_license('Distributed under the MIT license.\nhttp://www.opensource.org/licenses/mit-license.php')
65         dialog.set_copyright(__copyright__)
66         dialog.show_all()
67
68     def update(self, widget, data):
69         """ Start update process """
70         self.win.set_title(self.app_title)
71         self.location.reset()
72         self.win.remove(self.pannable_area)
73         Thread(target=self.update_gigs).start()
74
75     def update_gigs(self):
76         """ Get gig info """
77         gobject.idle_add(self.show_message, "Getting events")
78         gobject.idle_add(self.location.update_location)
79
80         # if no gps fix wait
81         # TODO: needs a timeout
82         while not self.location.lat or not self.location.long:
83             time.sleep(1)
84
85         events = self.events.get_events(self.location.lat, 
86                                         self.location.long, 
87                                         self.distance)
88         gobject.idle_add(self.hide_message)
89         gobject.idle_add(self.show_events, events)
90         thread.exit()
91
92     def show_message(self, message):
93         """ Set window progress indicator and show message """
94         hildon.hildon_gtk_window_set_progress_indicator(self.win, 1)
95         self.banner = hildon.hildon_banner_show_information(self.win,
96                                                             '', 
97                                                             message)
98
99     def hide_message(self):
100         """ Hide banner and set progress indicator """
101         self.banner.hide()
102         hildon.hildon_gtk_window_set_progress_indicator(self.win, 0)
103
104     def show_events(self, events):
105         """ Sort events, set new window title and add events to table """
106         if events:
107             self.win.set_title('%s (%s)' % (self.app_title, len(events)))
108             self.add_events(events)
109         else:
110             label = gtk.Label('No events available')
111             vbox = gtk.VBox(False, 0)
112             vbox.pack_start(label, True, True, 0)
113             vbox.show_all()
114             self.win.add(vbox)
115
116     def create_menu(self):
117         """ Build application menu """
118         update_button = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
119         update_button.set_label('Update')
120         update_button.connect('clicked',
121                               self.update,
122                               None)
123
124         about_button = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
125         about_button.set_label('About')
126         about_button.connect('clicked',
127                              self.show_about,
128                              None)
129
130         menu = hildon.AppMenu()
131         menu.append(update_button)
132         menu.append(about_button)
133         menu.show_all()
134         return menu
135
136     def show_details(self, widget, data):
137         """ Open new window showing gig details """
138         win = hildon.StackableWindow()
139         win.set_title(data['title'])
140
141         win.vbox = gtk.VBox()
142         win.add(win.vbox)
143
144         scroll = hildon.PannableArea()
145         win.vbox.pack_start(scroll, True, True, 0)
146
147         view = hildon.TextView()
148         view.set_editable(False)
149         view.unset_flags(gtk.CAN_FOCUS)
150         view.set_wrap_mode(gtk.WRAP_WORD)
151         buffer = view.get_buffer()
152         end = buffer.get_end_iter()
153         buffer.insert(end, '%s\n' % data['title'])
154         buffer.insert(end, 'Artists: %s\n' % data['artists'])
155         buffer.insert(end, 'Venue: %s\n' % data['venue'])
156         buffer.insert(end, '%s\n' % data['address'])
157         buffer.insert(end, 'When: %s\n' % data['date'].strftime('%H:%M %d/%M/%Y'))
158         buffer.insert(end, '\n')
159         scroll.add_with_viewport(view)
160
161         win.show_all()
162
163     def add_table(self):
164         """ Add table for events """
165         self.table = gtk.Table(columns=1)
166         self.table.set_row_spacings(10)
167         self.table.set_col_spacings(10)
168
169         self.pannable_area = hildon.PannableArea()
170         self.pannable_area.add_with_viewport(self.table)
171         self.pannable_area.show_all()
172         self.win.add(self.pannable_area)
173         
174     def add_events(self, events):
175         """ Add a table of buttons """
176         self.add_table()
177         pos = 0
178         for event in events:
179             button = hildon.Button(gtk.HILDON_SIZE_AUTO_WIDTH | gtk.HILDON_SIZE_FINGER_HEIGHT, 
180                                    hildon.BUTTON_ARRANGEMENT_VERTICAL)
181             button.set_text(event['title'], "distance: %0.02f km" % event['distance'])
182             button.connect("clicked", self.show_details, event)
183             self.table.attach(button, 0, 1, pos, pos+1)
184             pos += 1
185         self.table.show_all()
186    
187 if __name__ == "__main__":
188     finder = GigFinder()
189     finder.main()