1 # -*- coding: utf-8 -*-
3 ###########################################################################
5 # Copyright (C) 2010 Simón Pena <spenap@gmail.com>
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.
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.
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 ###########################################################################
28 from webkit import WebView
30 from maeviesui.util import constants
31 from maeviesui.util.asyncworker import AsyncWorker, AsyncItem
32 from maeviesui.util.util import image_downloader
33 from maeviesui.util.moviemanager import MovieManager, TmdbMovie, TmdbMovieImage, \
36 moviemanager = MovieManager()
38 class Maevies(hildon.StackableWindow):
46 super(Maevies, self).__init__()
47 self.set_title('Maevies - 0.1')
48 self.connect('delete-event',
49 lambda widget, event: gtk.main_quit())
51 self.add(self._create_contents())
52 self.set_app_menu(self._create_app_menu())
56 def _create_button(self, title, subtitle, action):
58 box.set_border_width(20)
60 button = hildon.Button(gtk.HILDON_SIZE_THUMB_HEIGHT,
61 hildon.BUTTON_ARRANGEMENT_VERTICAL,
63 button.connect('clicked', self._button_clicked, action)
65 box.pack_start(button, expand=True, fill=False)
69 def _create_contents(self):
71 contents.set_border_width(60)
72 contents.set_homogeneous(True)
73 contents.pack_start(self._create_button('On Theaters',
75 self.ACTION_THEATERS),
76 expand=True, fill=True)
77 contents.pack_start(self._create_button('Favorites',
78 'Your saved searches',
79 self.ACTION_FAVORITES),
80 expand=True, fill=True)
81 contents.pack_start(self._create_button('Search',
84 expand=True, fill=True)
88 def _button_clicked(self, button, action):
89 if action == self.ACTION_THEATERS:
90 theaters_view = TheatersWindow()
91 theaters_view.display_shows()
92 elif action == self.ACTION_SEARCH:
93 search_dialog = SearchDialog(self)
94 if search_dialog.run() == gtk.RESPONSE_ACCEPT:
95 results_window = ResultsWindow()
96 results_window.start_search(search_dialog.get_search_term(),
97 search_dialog.get_search_category())
98 search_dialog.destroy()
99 elif action == self.ACTION_ABOUT:
100 about_dialog = AboutDialog(self)
102 about_dialog.destroy()
104 def _create_app_menu(self):
105 menu = hildon.AppMenu()
107 about = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
108 about.set_label('About')
109 about.connect('clicked', self._button_clicked, self.ACTION_ABOUT)
120 class SearchDialog(gtk.Dialog):
124 search_fields = {TMDB_SEARCH:'TMDb',
127 def __init__(self, parent):
128 super(SearchDialog, self).__init__(parent=parent,
129 flags=gtk.DIALOG_DESTROY_WITH_PARENT)
130 self.set_title('Enter search terms')
132 self.vbox.pack_start(self._create_contents(), True, False, 0)
133 self.add_button(gtk.STOCK_OK, gtk.RESPONSE_ACCEPT)
137 def _create_contents(self):
138 self._search_entry = hildon.Entry(gtk.HILDON_SIZE_FINGER_HEIGHT)
139 search_button = self._create_picker_button()
141 search_contents = gtk.VBox()
143 search_contents.pack_start(self._search_entry,
144 expand=True, fill=True)
145 search_contents.pack_start(search_button,
146 expand=True, fill=True)
148 return search_contents
150 def _create_picker_button(self):
151 self._picker_button = hildon.PickerButton(gtk.HILDON_SIZE_FINGER_HEIGHT,
152 hildon.BUTTON_ARRANGEMENT_HORIZONTAL)
153 self._picker_button.set_title('Search on')
155 selector = hildon.TouchSelector(text=True)
156 selector.set_column_selection_mode(hildon.TOUCH_SELECTOR_SELECTION_MODE_SINGLE)
158 for search_method in [self.TMDB_SEARCH, self.WATC_SEARCH]:
159 selector.append_text(self.search_fields[search_method])
161 self._picker_button.set_selector(selector)
162 self._picker_button.set_active(0)
164 return self._picker_button
166 def get_search_term(self):
167 return self._search_entry.get_text()
169 def get_search_category(self):
170 return self._picker_button.get_active()
172 class ResultsWindow(hildon.StackableWindow):
175 super(ResultsWindow, self).__init__()
176 self.set_title('Search results')
178 self.add(self._create_contents())
180 moviemanager.response_received_cb = self._response_received_cb
183 def _create_contents(self):
184 content_area = hildon.PannableArea()
185 self._movies_view = MoviesView()
186 self._movies_view.connect('row-activated', self._row_activated_cb)
188 content_area.add(self._movies_view)
191 def _row_activated_cb(self, view, path, column):
192 movie = view.get_movie_from_path(path)
193 if isinstance(movie, TmdbMovie):
195 elif isinstance(movie, WatcMovie):
198 def start_search(self, search_term, search_category):
199 self._show_banner(search_term, search_category)
200 hildon.hildon_gtk_window_set_progress_indicator(self, True)
201 moviemanager.query(search_term, search_category)
203 def _response_received_cb(self, movies):
204 self._movies_view.add_movies(movies)
205 hildon.hildon_gtk_window_set_progress_indicator(self, False)
207 def _show_banner(self, search_term, search_category):
208 message = ('Searching on <i>%(category)s</i> for <i>%(term)s</i>' %
209 {'category': SearchDialog.search_fields[search_category],
210 'term' : search_term})
211 banner = hildon.hildon_banner_show_information_with_markup(self,
214 banner.set_timeout(constants.TIMEOUT_TIME_MILLIS)
216 class MoviesView(gtk.TreeView):
219 super(MoviesView, self).__init__()
220 model = MoviesListStore()
221 self.set_model(model)
223 movie_image_renderer = gtk.CellRendererPixbuf()
224 column = gtk.TreeViewColumn('Image', movie_image_renderer,
225 pixbuf=model.IMAGE_COLUMN)
226 self.append_column(column)
228 movie_text_renderer = gtk.CellRendererText()
229 movie_text_renderer.set_property('ellipsize', pango.ELLIPSIZE_END)
230 column = gtk.TreeViewColumn('Name', movie_text_renderer,
231 markup=model.INFO_COLUMN)
232 self.append_column(column)
236 def add_movies(self, movie_list):
237 model = self.get_model()
239 model.add(movie_list)
241 def get_movie_from_path(self, path):
242 model = self.get_model()
243 return model[path][model.MOVIE_COLUMN]
245 class MoviesListStore(gtk.ListStore):
252 super(MoviesListStore, self).__init__(gtk.gdk.Pixbuf,
254 gobject.TYPE_PYOBJECT)
256 def add(self, movies_found):
258 for movie in movies_found:
259 row = {self.IMAGE_COLUMN: movie.get_placeholder_image(),
260 self.INFO_COLUMN: movie.get_info(),
261 self.MOVIE_COLUMN: movie,
263 self.append(row.values())
265 class AboutDialog(gtk.Dialog):
267 def __init__(self, parent):
268 super(AboutDialog, self).__init__(parent=parent,
269 flags=gtk.DIALOG_DESTROY_WITH_PARENT)
270 self.set_title('About Maevies')
274 class MovieWindow(hildon.StackableWindow):
276 def _fetch_movie_image(self, movie):
278 image.set_from_pixbuf(gtk.IconTheme().load_icon('general_video',
280 movie_image = movie.get_image('poster', 'mid')
281 if isinstance(movie_image, TmdbMovieImage):
282 image_file = os.path.abspath('/tmp/' + movie_image.get_id() + '.jpg')
283 if os.path.isfile(image_file):
284 image.set_from_pixbuf(gtk.gdk.pixbuf_new_from_file_at_size(image_file,
288 banner = hildon.hildon_banner_show_information_with_markup(self,
290 'Fetching movie poster')
291 banner.set_timeout(constants.TIMEOUT_TIME_MILLIS)
292 hildon.hildon_gtk_window_set_progress_indicator(self, True)
294 async_item = AsyncItem(image_downloader, (movie_image.get_url(),
295 '/tmp/' + movie_image.get_id()),
296 self._set_fetched_image, (image,))
297 self.async_worker.queue.put(async_item)
298 self.async_worker.start()
302 def _set_fetched_image(self, image, target, error):
304 image_file = os.path.abspath(target)
305 image.set_from_pixbuf(gtk.gdk.pixbuf_new_from_file_at_size(image_file,
308 hildon.hildon_gtk_window_set_progress_indicator(self, False)
310 def _create_contents(self, movie):
311 main_area = hildon.PannableArea()
313 main_box = gtk.VBox(False, 20)
314 main_box.set_border_width(20)
315 upper_content = gtk.HBox(False, 40)
316 upper_content.set_border_width(20)
318 image = self._fetch_movie_image(movie)
320 side_content = gtk.VBox(False, 30)
322 for key in movie.fields:
324 label.set_markup('<b>%(field)s:</b> <small>%(value)s</small>' %
326 'value' : movie.get_value(key)})
327 label.set_alignment(constants.LEFT_ALIGNMENT,
328 constants.CENTER_ALIGNMENT)
329 side_content.pack_start(label, False, False)
331 upper_content.pack_start(image, False, False)
332 upper_content.pack_start(side_content, False, False)
334 movie_overview = hildon.TextView()
335 movie_overview.set_placeholder('Overview')
336 movie_overview.set_wrap_mode(gtk.WRAP_WORD)
337 movie_overview.get_buffer().set_text(movie.get_overview())
340 label.set_markup('<b>Overview:</b>')
341 label.set_alignment(constants.LEFT_ALIGNMENT,
342 constants.CENTER_ALIGNMENT)
344 main_box.pack_start(upper_content, False, False)
345 main_box.pack_start(label, False, False)
346 main_box.pack_start(movie_overview, False, False)
348 main_area.add_with_viewport(main_box)
349 main_area.set_size_request_policy(hildon.SIZE_REQUEST_CHILDREN)
353 def __init__(self, movie):
354 super(MovieWindow, self).__init__()
355 self.async_worker = AsyncWorker()
356 self.set_title('Movie info')
357 self.add(self._create_contents(movie))
360 class WebkitWindow(hildon.StackableWindow):
363 super(WebkitWindow, self).__init__()
365 self.view = WebView()
366 self.view.connect('load-started', self._load_start)
367 self.view.connect('load-finished', self._load_finished)
368 self.view.set_full_content_zoom(True)
370 wbk_settings = self.view.get_settings()
371 wbk_settings.set_property('auto-shrink-images', True)
373 self.pannable = hildon.PannableArea()
374 self.pannable.add(self.view)
375 self.pannable.set_size_request_policy(hildon.SIZE_REQUEST_CHILDREN)
376 self.pannable.set_property("mov-mode", hildon.MOVEMENT_MODE_BOTH)
378 self.add(self.pannable)
381 def _load_start(self, view, data):
382 hildon.hildon_gtk_window_set_progress_indicator(self, True)
384 def _load_finished(self, view, data):
385 hildon.hildon_gtk_window_set_progress_indicator(self, False)
387 def load_url(self, url):
390 class TheatersWindow(WebkitWindow):
393 super(TheatersWindow, self).__init__()
396 def display_shows(self):
397 self.load_url('http://www.google.com/movies')
399 class WatcWindow(WebkitWindow):
401 def __init__(self, movie):
402 super(WatcWindow, self).__init__()
404 has_stingers = movie.get_stingers()
405 if has_stingers == 0:
407 elif has_stingers == 1:
411 url = ('http://whatsafterthecredits.com/index.php?title=%(title)s_(%(year)s)%(stingers)s' %
412 {'title':movie.get_title().strip(),
413 'year':movie.get_year().strip(),
414 'stingers':stingers})
418 if __name__ == '__main__':