7 import util.go_utils as go_utils
8 import util.misc as misc_utils
16 _moduleLogger = logging.getLogger(__name__)
19 class MagazinesWindow(windows._base.ListWindow):
21 def __init__(self, player, store, node):
22 windows._base.ListWindow.__init__(self, player, store, node)
23 self._window.set_title(self._node.title)
26 def _get_columns(cls):
27 yield gobject.TYPE_PYOBJECT, None
29 pixrenderer = gtk.CellRendererPixbuf()
30 column = gtk.TreeViewColumn("Covers")
31 column.pack_start(pixrenderer, expand=True)
32 column.add_attribute(pixrenderer, "pixbuf", 1)
33 yield gobject.TYPE_OBJECT, column
35 textrenderer = gtk.CellRendererText()
36 column = gtk.TreeViewColumn("Magazine")
37 column.pack_start(textrenderer, expand=True)
38 column.add_attribute(textrenderer, "text", 2)
39 yield gobject.TYPE_STRING, column
42 windows._base.ListWindow._refresh(self)
43 self._node.get_children(
48 @misc_utils.log_exception(_moduleLogger)
49 def _on_magazines(self, programs):
51 _moduleLogger.info("Download complete but window destroyed")
55 for i, programNode in enumerate(programs):
56 program = programNode.get_properties()
57 img = self._store.get_pixbuf_from_store(self._store.STORE_LOOKUP["nomagazineimage"])
58 row = programNode, img, program["title"]
59 self._model.append(row)
61 programNode.get_children(self._create_on_issues(i), self._on_error)
65 def _create_on_issues(self, row):
66 return lambda issues: self._on_issues(row, issues)
68 @misc_utils.log_exception(_moduleLogger)
69 def _on_issues(self, row, issues):
71 self._store.get_pixbuf_from_url(
72 issue.get_properties()["pictureURL"],
73 lambda pix: self._on_image(row, pix),
78 _moduleLogger.info("No issues for magazine %s" % row)
80 @misc_utils.log_exception(_moduleLogger)
81 def _on_image(self, row, pix):
82 treeiter = self._model.iter_nth_child(None, row)
83 self._model.set_value(treeiter, 1, pix)
84 treeiter = self._model.iter_nth_child(None, row)
85 self._model.row_changed((row, ), treeiter)
87 @misc_utils.log_exception(_moduleLogger)
88 def _on_error(self, exception):
90 self._errorBanner.push_message(str(exception))
92 def _window_from_node(self, node):
93 issuesWindow = MagazineIssuesWindow(self._player, self._store, node)
94 issuesWindow.window.set_modal(True)
95 issuesWindow.window.set_transient_for(self._window)
96 issuesWindow.window.set_default_size(*self._window.get_size())
97 issuesWindow.connect("quit", self._on_quit)
98 issuesWindow.connect("home", self._on_home)
99 issuesWindow.connect("jump-to", self._on_jump)
103 @misc_utils.log_exception(_moduleLogger)
104 def _on_row_activated(self, view, path, column):
105 itr = self._model.get_iter(path)
106 node = self._model.get_value(itr, 0)
107 self._window_from_node(node)
110 gobject.type_register(MagazinesWindow)
113 class MagazineIssuesWindow(windows._base.ListWindow):
115 def __init__(self, player, store, node):
116 windows._base.ListWindow.__init__(self, player, store, node)
117 self._window.set_title(self._node.title)
120 def _get_columns(cls):
121 yield gobject.TYPE_PYOBJECT, None
123 pixrenderer = gtk.CellRendererPixbuf()
124 column = gtk.TreeViewColumn("Covers")
125 column.pack_start(pixrenderer, expand=True)
126 column.add_attribute(pixrenderer, "pixbuf", 1)
127 yield gobject.TYPE_OBJECT, column
129 textrenderer = gtk.CellRendererText()
130 column = gtk.TreeViewColumn("Issue")
131 column.pack_start(textrenderer, expand=True)
132 column.add_attribute(textrenderer, "text", 2)
133 yield gobject.TYPE_STRING, column
136 windows._base.ListWindow._refresh(self)
137 self._node.get_children(
138 self._on_magazine_issues,
142 @misc_utils.log_exception(_moduleLogger)
143 def _on_magazine_issues(self, programs):
144 if self._isDestroyed:
145 _moduleLogger.info("Download complete but window destroyed")
149 for programNode in programs:
150 program = programNode.get_properties()
151 img = self._store.get_pixbuf_from_store(self._store.STORE_LOOKUP["nomagazineimage"])
152 row = programNode, img, program["title"]
153 self._model.append(row)
155 self._store.get_pixbuf_from_url(
156 program["pictureURL"],
157 self._create_on_image(programNode),
163 @misc_utils.log_exception(_moduleLogger)
164 def _on_error(self, exception):
166 self._errorBanner.push_message(str(exception))
168 def _create_on_image(self, programNode):
169 return lambda pix: self._on_image(programNode, pix)
171 @misc_utils.log_exception(_moduleLogger)
172 def _on_image(self, childNode, pix):
173 for i, row in enumerate(self._model):
174 if row[0] is childNode:
177 raise RuntimeError("Could not find %r" % childNode)
178 treeiter = self._model.iter_nth_child(None, i)
179 self._model.set_value(treeiter, 1, pix)
180 treeiter = self._model.iter_nth_child(None, i)
181 self._model.row_changed((i, ), treeiter)
183 def _window_from_node(self, node):
184 issuesWindow = MagazineArticlesWindow(self._player, self._store, node)
185 issuesWindow.window.set_modal(True)
186 issuesWindow.window.set_transient_for(self._window)
187 issuesWindow.window.set_default_size(*self._window.get_size())
188 issuesWindow.connect("quit", self._on_quit)
189 issuesWindow.connect("home", self._on_home)
190 issuesWindow.connect("jump-to", self._on_jump)
194 @misc_utils.log_exception(_moduleLogger)
195 def _on_row_activated(self, view, path, column):
196 itr = self._model.get_iter(path)
197 node = self._model.get_value(itr, 0)
198 self._window_from_node(node)
201 gobject.type_register(MagazineIssuesWindow)
204 class MagazineArticlesWindow(windows._base.ListWindow):
206 def __init__(self, player, store, node):
207 windows._base.ListWindow.__init__(self, player, store, node)
208 self._window.set_title(self._node.title)
211 def _get_columns(cls):
212 yield gobject.TYPE_PYOBJECT, None
214 textrenderer = gtk.CellRendererText()
215 column = gtk.TreeViewColumn("Article")
216 column.pack_start(textrenderer, expand=True)
217 column.add_attribute(textrenderer, "text", 1)
218 yield gobject.TYPE_STRING, column
221 windows._base.ListWindow._refresh(self)
222 self._node.get_children(
223 self._on_magazine_articles,
227 @misc_utils.log_exception(_moduleLogger)
228 def _on_magazine_articles(self, programs):
229 if self._isDestroyed:
230 _moduleLogger.info("Download complete but window destroyed")
234 for programNode in programs:
235 program = programNode.get_properties()
236 row = programNode, "%s\n%s" % (program["title"], program["author"])
237 self._model.append(row)
241 @misc_utils.log_exception(_moduleLogger)
242 def _on_error(self, exception):
244 self._errorBanner.push_message(str(exception))
246 def _window_from_node(self, node):
247 issuesWindow = MagazineArticleWindow(self._player, self._store, node)
248 issuesWindow.window.set_modal(True)
249 issuesWindow.window.set_transient_for(self._window)
250 issuesWindow.window.set_default_size(*self._window.get_size())
251 issuesWindow.connect("quit", self._on_quit)
252 issuesWindow.connect("home", self._on_home)
253 issuesWindow.connect("jump-to", self._on_jump)
257 @misc_utils.log_exception(_moduleLogger)
258 def _on_row_activated(self, view, path, column):
259 itr = self._model.get_iter(path)
260 node = self._model.get_value(itr, 0)
261 self._window_from_node(node)
264 gobject.type_register(MagazineArticlesWindow)
267 class MagazineArticleWindow(windows._base.BasicWindow):
269 def __init__(self, player, store, node):
270 windows._base.BasicWindow.__init__(self, player, store)
272 self._playerNode = self._player.node
273 self._nextSearch = None
274 self._updateSeek = None
276 self.connect_auto(self._player, "state-change", self._on_player_state_change)
277 self.connect_auto(self._player, "title-change", self._on_player_title_change)
278 self.connect_auto(self._player, "error", self._on_player_error)
280 self._loadingBanner = banners.GenericBanner()
282 self._presenter = presenter.StreamPresenter(self._store)
283 self._presenter.set_context(
284 self._store.STORE_LOOKUP["magazine_background"],
288 self._presenterNavigation = presenter.NavigationBox()
289 self._presenterNavigation.toplevel.add(self._presenter.toplevel)
290 self._presenterNavigation.connect("action", self._on_nav_action)
291 self._presenterNavigation.connect("navigating", self._on_navigating)
293 self._seekbar = hildonize.create_seekbar()
294 self._seekbar.connect("change-value", self._on_user_seek)
296 self._layout.pack_start(self._loadingBanner.toplevel, False, False)
297 self._layout.pack_start(self._presenterNavigation.toplevel, True, True)
298 self._layout.pack_start(self._seekbar, False, False)
300 self._window.set_title(self._node.title)
303 windows._base.BasicWindow.show(self)
304 self._window.show_all()
305 self._errorBanner.toplevel.hide()
306 self._loadingBanner.toplevel.hide()
307 self._set_context(self._player.state)
310 def jump_to(self, node):
311 assert self._node is node
315 return self._playerNode is self._node
317 def _show_loading(self):
318 animationPath = self._store.STORE_LOOKUP["loading"]
319 animation = self._store.get_pixbuf_animation_from_store(animationPath)
320 self._loadingBanner.show(animation, "Loading...")
322 def _hide_loading(self):
323 self._loadingBanner.hide()
325 def _set_context(self, state):
326 if state == self._player.STATE_PLAY:
328 self._presenter.set_state(self._store.STORE_LOOKUP["pause"])
330 self._presenter.set_state(self._store.STORE_LOOKUP["play"])
331 elif state == self._player.STATE_PAUSE:
332 self._presenter.set_state(self._store.STORE_LOOKUP["play"])
333 elif state == self._player.STATE_STOP:
334 self._presenter.set_state(self._store.STORE_LOOKUP["play"])
336 _moduleLogger.info("Unhandled player state %s" % state)
338 @misc_utils.log_exception(_moduleLogger)
339 def _on_user_seek(self, widget, scroll, value):
340 self._player.seek(value / 100.0)
342 @misc_utils.log_exception(_moduleLogger)
343 def _on_player_update_seek(self):
344 self._seekbar.set_value(self._player.percent_elapsed * 100)
345 return True if not self._isDestroyed else False
347 @misc_utils.log_exception(_moduleLogger)
348 def _on_player_state_change(self, player, newState):
349 if self._active and self._player.state == self._player.STATE_PLAY:
351 assert self._updateSeek is None
352 self._updateSeek = go_utils.Timeout(self._on_player_update_seek, once=False)
353 self._updateSeek.start(seconds=1)
356 self._updateSeek.cancel()
357 self._updateSeek = None
359 if not self._presenterNavigation.is_active():
360 self._set_context(newState)
362 @misc_utils.log_exception(_moduleLogger)
363 def _on_player_title_change(self, player, node):
364 if not self._active or node in [None, self._node]:
365 self._playerNode = player.node
367 self._playerNode = player.node
368 self.emit("jump-to", node)
369 self._window.destroy()
371 @misc_utils.log_exception(_moduleLogger)
372 def _on_player_error(self, player, err, debug):
373 _moduleLogger.error("%r - %r" % (err, debug))
375 @misc_utils.log_exception(_moduleLogger)
376 def _on_navigating(self, widget, navState):
377 if navState == "clicking":
378 if self._player.state == self._player.STATE_PLAY:
380 imageName = "pause_pressed"
382 imageName = "play_pressed"
383 elif self._player.state == self._player.STATE_PAUSE:
384 imageName = "play_pressed"
385 elif self._player.state == self._player.STATE_STOP:
386 imageName = "play_pressed"
388 _moduleLogger.info("Unhandled player state %s" % self._player.state)
389 elif navState == "down":
391 elif navState == "up":
392 if self._player.state == self._player.STATE_PLAY:
397 elif self._player.state == self._player.STATE_PAUSE:
399 elif self._player.state == self._player.STATE_STOP:
402 _moduleLogger.info("Unhandled player state %s" % self._player.state)
403 elif navState == "left":
405 elif navState == "right":
408 self._presenter.set_state(self._store.STORE_LOOKUP[imageName])
410 @misc_utils.log_exception(_moduleLogger)
411 def _on_nav_action(self, widget, navState):
412 self._set_context(self._player.state)
414 if navState == "clicking":
415 if self._player.state == self._player.STATE_PLAY:
419 self._player.set_piece_by_node(self._node)
421 elif self._player.state == self._player.STATE_PAUSE:
423 elif self._player.state == self._player.STATE_STOP:
424 self._player.set_piece_by_node(self._node)
427 _moduleLogger.info("Unhandled player state %s" % self._player.state)
428 elif navState == "down":
430 self._window.destroy()
431 elif navState == "up":
433 elif navState == "left":
437 assert self._nextSearch is None
438 self._nextSearch = stream_index.AsyncWalker(stream_index.get_next)
439 self._nextSearch.start(self._node, self._on_next_node, self._on_node_search_error)
440 elif navState == "right":
444 assert self._nextSearch is None
445 self._nextSearch = stream_index.AsyncWalker(stream_index.get_previous)
446 self._nextSearch.start(self._node, self._on_next_node, self._on_node_search_error)
448 @misc_utils.log_exception(_moduleLogger)
449 def _on_next_node(self, node):
450 self._nextSearch = None
451 self.emit("jump-to", node)
452 self._window.destroy()
454 @misc_utils.log_exception(_moduleLogger)
455 def _on_node_search_error(self, e):
456 self._nextSearch = None
457 self._errorBanner.push_message(str(e))
460 gobject.type_register(MagazineArticleWindow)