ui: Completed basic search functionality
[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 from maeviesui.util import constants
22
23 import hildon
24 import pygtk
25 import pango
26 import gobject
27 from maeviesui.util.moviemanager import MovieManager
28 pygtk.require("2.0")
29 import gtk
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, title, subtitle)
55         button.connect("clicked", self._button_clicked, action)
56
57         box.pack_start(button, expand = True, fill = False)
58
59         return box
60
61     def _create_contents(self):
62         contents = gtk.HBox()
63         contents.set_border_width(60)
64         contents.set_homogeneous(True)
65         contents.pack_start(self._create_button("On Theaters", "Movies playing",
66                                              self.ACTION_THEATERS),
67                             expand = True, fill = True)
68         contents.pack_start(self._create_button("Favorites", "Your saved searches",
69                                              self.ACTION_FAVORITES),
70                             expand = True, fill = True)
71         contents.pack_start(self._create_button("Search", "Enter a new search",
72                                              self.ACTION_SEARCH),
73                             expand = True, fill = True)
74
75         return contents;
76
77     def _button_clicked(self, button, action):
78         if action == self.ACTION_SEARCH:
79             search_dialog = SearchDialog(self)
80             if search_dialog.run() == gtk.RESPONSE_ACCEPT:
81                 ResultsWindow(search_term = search_dialog.get_search_term(),
82                               search_category = search_dialog.get_search_category())
83             search_dialog.destroy()
84         elif action == self.ACTION_ABOUT:
85             about_dialog = AboutDialog(self)
86             about_dialog.run()
87             about_dialog.destroy()
88
89     def _create_app_menu(self):
90         menu = hildon.AppMenu()
91
92         about = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
93         about.set_label("About")
94         about.connect("clicked", self._button_clicked, self.ACTION_ABOUT)
95
96         menu.append(about)
97
98         menu.show_all()
99
100         return menu
101
102     def run(self):
103         gtk.main()
104
105 class SearchDialog(gtk.Dialog):
106
107     _search_fields = [
108            "Movies",
109            "People",
110            ]
111
112     def __init__(self, parent):
113         super(SearchDialog, self).__init__(parent = parent,
114                                             flags = gtk.DIALOG_DESTROY_WITH_PARENT)
115         self.set_title("Enter search terms")
116
117         self.vbox.pack_start(self._create_contents(), True, False, 0)
118         self.add_button(gtk.STOCK_OK, gtk.RESPONSE_ACCEPT)
119
120         self.show_all()
121
122     def _create_contents(self):
123         self._search_entry = hildon.Entry(gtk.HILDON_SIZE_FINGER_HEIGHT)
124         search_button = self._create_picker_button()
125
126         search_contents = gtk.VBox()
127
128         search_contents.pack_start(self._search_entry,
129                                    expand = True, fill = True)
130         search_contents.pack_start(search_button,
131                                    expand = True, fill = True)
132
133         return search_contents
134
135     def _create_picker_button(self):
136         self._picker_button = hildon.PickerButton(gtk.HILDON_SIZE_FINGER_HEIGHT,
137                                             hildon.BUTTON_ARRANGEMENT_HORIZONTAL)
138         self._picker_button.set_title("Search for")
139
140         selector = hildon.TouchSelector(text = True)
141         selector.set_column_selection_mode(hildon.TOUCH_SELECTOR_SELECTION_MODE_SINGLE)
142
143         for field in self._search_fields:
144             selector.append_text(field)
145
146         self._picker_button.set_selector(selector)
147         self._picker_button.set_active(0)
148
149         return self._picker_button
150
151     def get_search_term(self):
152         return self._search_entry.get_text()
153
154     def get_search_category(self):
155         return self._search_fields[self._picker_button.get_active()]
156
157 class ResultsWindow(hildon.StackableWindow):
158
159     def __init__(self, search_term, search_category):
160         super(ResultsWindow, self).__init__()
161         self.set_title("Search results")
162
163         self.add(self._create_contents())
164
165         self.moviemanager = MovieManager(response_received_cb = self._response_received_cb)
166         self._start_search(search_term, search_category)
167         self.show_all()
168
169     def _create_contents(self):
170         content_area = hildon.PannableArea()
171         self._movies_view = MoviesView()
172         self._movies_view.connect('row-activated', self._row_activated_cb)
173
174         content_area.add(self._movies_view)
175         return content_area
176
177     def _row_activated_cb(self, view, path, column):
178         movie = view.get_movie_from_path(path)
179         MovieWindow(movie)
180
181     def _start_search(self, search_term, search_category):
182         self._show_banner(search_term, search_category)
183         hildon.hildon_gtk_window_set_progress_indicator(self, True)
184         self.moviemanager.query(search_term)
185
186     def _response_received_cb(self, movies):
187         self._movies_view.add_movies(movies)
188         hildon.hildon_gtk_window_set_progress_indicator(self, False)
189
190     def _show_banner(self, search_term, search_category):
191         message = "Searching <i>%(category)s</i> for <i>%(term)s</i>" % {'category': search_category,
192                                                                          'term' : search_term}
193         banner = hildon.hildon_banner_show_information_with_markup(self,
194                                                                    "ignored",
195                                                                    message)
196         banner.set_timeout(constants.TIMEOUT_TIME_MILLIS)
197
198 class MoviesView(gtk.TreeView):
199
200     def __init__(self):
201         super(MoviesView, self).__init__()
202         model = MoviesListStore()
203         self.set_model(model)
204
205         movie_image_renderer = gtk.CellRendererPixbuf()
206         column = gtk.TreeViewColumn('Image', movie_image_renderer, pixbuf = model.IMAGE_COLUMN)
207         self.append_column(column)
208
209         movie_text_renderer = gtk.CellRendererText()
210         movie_text_renderer.set_property('ellipsize', pango.ELLIPSIZE_END)
211         column = gtk.TreeViewColumn('Name', movie_text_renderer, markup = model.INFO_COLUMN)
212         self.append_column(column)
213
214         self.show_all()
215
216     def add_movies(self, movie_list):
217         model = self.get_model()
218         model.add(movie_list)
219
220     def get_movie_from_path(self, path):
221         model = self.get_model()
222         return model[path][model.MOVIE_COLUMN]
223
224 class MoviesListStore(gtk.ListStore):
225
226     IMAGE_COLUMN = 0
227     INFO_COLUMN = 1
228     MOVIE_COLUMN = 2
229
230     def __init__(self):
231         super(MoviesListStore, self).__init__(gtk.gdk.Pixbuf,
232                                               str,
233                                               gobject.TYPE_PYOBJECT)
234
235     def add(self, movies_found):
236         self.clear()
237         for movie in movies_found:
238             row = {self.IMAGE_COLUMN: movie.get_image(),
239                    self.INFO_COLUMN: movie.get_info(),
240                    self.MOVIE_COLUMN: movie,
241                   }
242             self.append(row.values())
243
244 class AboutDialog(gtk.Dialog):
245
246     def __init__(self, parent):
247         super(AboutDialog, self).__init__(parent = parent,
248                                           flags = gtk.DIALOG_DESTROY_WITH_PARENT)
249         self.set_title("About Maevies")
250
251         self.show_all()
252
253 class MovieWindow(hildon.StackableWindow):
254
255     def _create_contents(self, movie):
256         main_area = hildon.PannableArea()
257
258         main_box = gtk.VBox(False, 20)
259         main_box.set_border_width(20)
260         upper_content = gtk.HBox(False, 40)
261         upper_content.set_border_width(20)
262
263         image = gtk.Image()
264         image.set_from_pixbuf(gtk.IconTheme().load_icon('mediaplayer_default_album', 256, 0))
265
266         side_content = gtk.VBox(False, 30)
267
268         for key in movie.fields:
269             label = gtk.Label()
270             label.set_markup("<b>%(field)s:</b> <small>%(value)s</small>" % {'field' : key,
271                                                                              'value' : movie.get_value(key)})
272             label.set_alignment(constants.LEFT_ALIGNMENT, constants.CENTER_ALIGNMENT)
273             side_content.pack_start(label, False, False)
274
275         upper_content.pack_start(image, False, False)
276         upper_content.pack_start(side_content, False, False)
277
278         movie_overview = hildon.TextView()
279         movie_overview.set_placeholder("Overview")
280         movie_overview.set_wrap_mode(gtk.WRAP_WORD)
281         movie_overview.get_buffer().set_text(movie.get_overview())
282
283         label = gtk.Label()
284         label.set_markup("<b>Overview:</b>")
285         label.set_alignment(constants.LEFT_ALIGNMENT, constants.CENTER_ALIGNMENT)
286
287         main_box.pack_start(upper_content, False, False)
288         main_box.pack_start(label, False, False)
289         main_box.pack_start(movie_overview, False, False)
290
291         main_area.add_with_viewport(main_box)
292         main_area.set_size_request_policy(hildon.SIZE_REQUEST_CHILDREN)
293
294         return main_area
295
296     def __init__(self, movie):
297         super(MovieWindow, self).__init__()
298         self.set_title("Movie info")
299         self.add(self._create_contents(movie))
300         self.show_all()
301
302 if __name__ == "__main__":
303     maevies = Maevies()
304     maevies.run()