beb191f402daee24c4a4d8147425693665db7bd2
[maevies] / ui / maeviesui / maeviesui / gui.py
1 # -*- coding: utf-8 -*-
2
3 ###########################################################################
4 #    Maevies
5 #    Copyright (C) 2010 Simón Pena <spenap@gmail.com>
6 #
7 #    This program is free software: you can redistribute it and/or modify
8 #    it under the terms of the GNU General Public License as published by
9 #    the Free Software Foundation, either version 3 of the License, or
10 #    (at your option) any later version.
11 #
12 #    This program is distributed in the hope that it will be useful,
13 #    but WITHOUT ANY WARRANTY; without even the implied warranty of
14 #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 #    GNU General Public License for more details.
16 #
17 #    You should have received a copy of the GNU General Public License
18 #    along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 ###########################################################################
20
21 import pygtk
22 pygtk.require('2.0')
23 import gtk
24 import hildon
25 import pango
26 import gobject
27
28 from maeviesui.util import constants
29 from maeviesui.util.moviemanager import MovieManager
30
31 class Maevies(hildon.StackableWindow):
32
33     ACTION_SEARCH = 0
34     ACTION_ABOUT = 1
35     ACTION_THEATERS = 2
36     ACTION_FAVORITES = 3
37
38     def __init__(self):
39         super(Maevies, self).__init__()
40         self.set_title('Maevies - 0.1')
41         self.connect('delete-event',
42                      lambda widget, event: gtk.main_quit())
43
44         self.add(self._create_contents())
45         self.set_app_menu(self._create_app_menu())
46
47         self.show_all()
48
49     def _create_button(self, title, subtitle, action):
50         box = gtk.VBox()
51         box.set_border_width(20)
52
53         button = hildon.Button(gtk.HILDON_SIZE_THUMB_HEIGHT,
54                                hildon.BUTTON_ARRANGEMENT_VERTICAL,
55                                title, subtitle)
56         button.connect('clicked', self._button_clicked, action)
57
58         box.pack_start(button, expand=True, fill=False)
59
60         return box
61
62     def _create_contents(self):
63         contents = gtk.HBox()
64         contents.set_border_width(60)
65         contents.set_homogeneous(True)
66         contents.pack_start(self._create_button('On Theaters',
67                                                 'Movies playing',
68                                                 self.ACTION_THEATERS),
69                             expand=True, fill=True)
70         contents.pack_start(self._create_button('Favorites',
71                                                 'Your saved searches',
72                                                 self.ACTION_FAVORITES),
73                             expand=True, fill=True)
74         contents.pack_start(self._create_button('Search',
75                                                 'Enter a new search',
76                                                 self.ACTION_SEARCH),
77                             expand=True, fill=True)
78
79         return contents;
80
81     def _button_clicked(self, button, action):
82         if action == self.ACTION_SEARCH:
83             search_dialog = SearchDialog(self)
84             if search_dialog.run() == gtk.RESPONSE_ACCEPT:
85                 results_window = ResultsWindow()
86                 results_window.start_search(search_dialog.get_search_term(),
87                                             search_dialog.get_search_category())
88             search_dialog.destroy()
89         elif action == self.ACTION_ABOUT:
90             about_dialog = AboutDialog(self)
91             about_dialog.run()
92             about_dialog.destroy()
93
94     def _create_app_menu(self):
95         menu = hildon.AppMenu()
96
97         about = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
98         about.set_label('About')
99         about.connect('clicked', self._button_clicked, self.ACTION_ABOUT)
100
101         menu.append(about)
102
103         menu.show_all()
104
105         return menu
106
107     def run(self):
108         gtk.main()
109
110 class SearchDialog(gtk.Dialog):
111
112     _search_fields = [
113            'Movies',
114            'People',
115            ]
116
117     def __init__(self, parent):
118         super(SearchDialog, self).__init__(parent=parent,
119                                            flags=gtk.DIALOG_DESTROY_WITH_PARENT)
120         self.set_title('Enter search terms')
121
122         self.vbox.pack_start(self._create_contents(), True, False, 0)
123         self.add_button(gtk.STOCK_OK, gtk.RESPONSE_ACCEPT)
124
125         self.show_all()
126
127     def _create_contents(self):
128         self._search_entry = hildon.Entry(gtk.HILDON_SIZE_FINGER_HEIGHT)
129         search_button = self._create_picker_button()
130
131         search_contents = gtk.VBox()
132
133         search_contents.pack_start(self._search_entry,
134                                    expand=True, fill=True)
135         search_contents.pack_start(search_button,
136                                    expand=True, fill=True)
137
138         return search_contents
139
140     def _create_picker_button(self):
141         self._picker_button = hildon.PickerButton(gtk.HILDON_SIZE_FINGER_HEIGHT,
142                                                   hildon.BUTTON_ARRANGEMENT_HORIZONTAL)
143         self._picker_button.set_title('Search for')
144
145         selector = hildon.TouchSelector(text=True)
146         selector.set_column_selection_mode(hildon.TOUCH_SELECTOR_SELECTION_MODE_SINGLE)
147
148         for field in self._search_fields:
149             selector.append_text(field)
150
151         self._picker_button.set_selector(selector)
152         self._picker_button.set_active(0)
153
154         return self._picker_button
155
156     def get_search_term(self):
157         return self._search_entry.get_text()
158
159     def get_search_category(self):
160         return self._search_fields[self._picker_button.get_active()]
161
162 class ResultsWindow(hildon.StackableWindow):
163
164     def __init__(self):
165         super(ResultsWindow, self).__init__()
166         self.set_title('Search results')
167
168         self.add(self._create_contents())
169
170         self.moviemanager = MovieManager(response_received_cb=self._response_received_cb)
171         self.show_all()
172
173     def _create_contents(self):
174         content_area = hildon.PannableArea()
175         self._movies_view = MoviesView()
176         self._movies_view.connect('row-activated', self._row_activated_cb)
177
178         content_area.add(self._movies_view)
179         return content_area
180
181     def _row_activated_cb(self, view, path, column):
182         movie = view.get_movie_from_path(path)
183         MovieWindow(movie)
184
185     def start_search(self, search_term, search_category):
186         self._show_banner(search_term, search_category)
187         hildon.hildon_gtk_window_set_progress_indicator(self, True)
188         self.moviemanager.query(search_term)
189
190     def _response_received_cb(self, movies):
191         self._movies_view.add_movies(movies)
192         hildon.hildon_gtk_window_set_progress_indicator(self, False)
193
194     def _show_banner(self, search_term, search_category):
195         message = ('Searching <i>%(category)s</i> for <i>%(term)s</i>' %
196                    {'category': search_category,
197                     'term' : search_term})
198         banner = hildon.hildon_banner_show_information_with_markup(self,
199                                                                    'ignored',
200                                                                    message)
201         banner.set_timeout(constants.TIMEOUT_TIME_MILLIS)
202
203 class MoviesView(gtk.TreeView):
204
205     def __init__(self):
206         super(MoviesView, self).__init__()
207         model = MoviesListStore()
208         self.set_model(model)
209
210         movie_image_renderer = gtk.CellRendererPixbuf()
211         column = gtk.TreeViewColumn('Image', movie_image_renderer,
212                                     pixbuf=model.IMAGE_COLUMN)
213         self.append_column(column)
214
215         movie_text_renderer = gtk.CellRendererText()
216         movie_text_renderer.set_property('ellipsize', pango.ELLIPSIZE_END)
217         column = gtk.TreeViewColumn('Name', movie_text_renderer,
218                                     markup=model.INFO_COLUMN)
219         self.append_column(column)
220
221         self.show_all()
222
223     def add_movies(self, movie_list):
224         model = self.get_model()
225         model.add(movie_list)
226
227     def get_movie_from_path(self, path):
228         model = self.get_model()
229         return model[path][model.MOVIE_COLUMN]
230
231 class MoviesListStore(gtk.ListStore):
232
233     IMAGE_COLUMN = 0
234     INFO_COLUMN = 1
235     MOVIE_COLUMN = 2
236
237     def __init__(self):
238         super(MoviesListStore, self).__init__(gtk.gdk.Pixbuf,
239                                               str,
240                                               gobject.TYPE_PYOBJECT)
241
242     def add(self, movies_found):
243         self.clear()
244         for movie in movies_found:
245             row = {self.IMAGE_COLUMN: movie.get_image(),
246                    self.INFO_COLUMN: movie.get_info(),
247                    self.MOVIE_COLUMN: movie,
248                   }
249             self.append(row.values())
250
251 class AboutDialog(gtk.Dialog):
252
253     def __init__(self, parent):
254         super(AboutDialog, self).__init__(parent=parent,
255                                           flags=gtk.DIALOG_DESTROY_WITH_PARENT)
256         self.set_title('About Maevies')
257
258         self.show_all()
259
260 class MovieWindow(hildon.StackableWindow):
261
262     def _create_contents(self, movie):
263         main_area = hildon.PannableArea()
264
265         main_box = gtk.VBox(False, 20)
266         main_box.set_border_width(20)
267         upper_content = gtk.HBox(False, 40)
268         upper_content.set_border_width(20)
269
270         image = gtk.Image()
271         image.set_from_pixbuf(gtk.IconTheme().load_icon('mediaplayer_default_album',
272                                                         256, 0))
273
274         side_content = gtk.VBox(False, 30)
275
276         for key in movie.fields:
277             label = gtk.Label()
278             label.set_markup('<b>%(field)s:</b> <small>%(value)s</small>' %
279                              {'field' : key,
280                               'value' : movie.get_value(key)})
281             label.set_alignment(constants.LEFT_ALIGNMENT,
282                                 constants.CENTER_ALIGNMENT)
283             side_content.pack_start(label, False, False)
284
285         upper_content.pack_start(image, False, False)
286         upper_content.pack_start(side_content, False, False)
287
288         movie_overview = hildon.TextView()
289         movie_overview.set_placeholder('Overview')
290         movie_overview.set_wrap_mode(gtk.WRAP_WORD)
291         movie_overview.get_buffer().set_text(movie.get_overview())
292
293         label = gtk.Label()
294         label.set_markup('<b>Overview:</b>')
295         label.set_alignment(constants.LEFT_ALIGNMENT,
296                             constants.CENTER_ALIGNMENT)
297
298         main_box.pack_start(upper_content, False, False)
299         main_box.pack_start(label, False, False)
300         main_box.pack_start(movie_overview, False, False)
301
302         main_area.add_with_viewport(main_box)
303         main_area.set_size_request_policy(hildon.SIZE_REQUEST_CHILDREN)
304
305         return main_area
306
307     def __init__(self, movie):
308         super(MovieWindow, self).__init__()
309         self.set_title('Movie info')
310         self.add(self._create_contents(movie))
311         self.show_all()
312
313 if __name__ == '__main__':
314     maevies = Maevies()
315     maevies.run()