7 import util.misc as misc_utils
14 _moduleLogger = logging.getLogger(__name__)
17 class RadioWindow(windows._base.BasicWindow):
19 def __init__(self, player, store, node):
20 windows._base.BasicWindow.__init__(self, player, store)
22 self._childNode = None
24 self.connect_auto(self._player, "state-change", self._on_player_state_change)
25 self.connect_auto(self._player, "title-change", self._on_player_title_change)
27 self._loadingBanner = banners.GenericBanner()
29 headerPath = self._store.STORE_LOOKUP["radio_header"]
30 self._header = self._store.get_image_from_store(headerPath)
31 self._headerNavigation = presenter.NavigationBox()
32 self._headerNavigation.toplevel.add(self._header)
33 self._headerNavigation.connect("action", self._on_nav_action)
34 self._headerNavigation.connect("navigating", self._on_navigating)
36 self._programmingModel = gtk.ListStore(
41 textrenderer = gtk.CellRendererText()
42 timeColumn = gtk.TreeViewColumn("Time")
43 timeColumn.pack_start(textrenderer, expand=True)
44 timeColumn.add_attribute(textrenderer, "text", 0)
46 textrenderer = gtk.CellRendererText()
47 titleColumn = gtk.TreeViewColumn("Program")
48 titleColumn.pack_start(textrenderer, expand=True)
49 titleColumn.add_attribute(textrenderer, "text", 1)
51 self._treeView = gtk.TreeView()
52 self._treeView.set_headers_visible(False)
53 self._treeView.set_model(self._programmingModel)
54 self._treeView.append_column(timeColumn)
55 self._treeView.append_column(titleColumn)
56 self._treeView.get_selection().connect("changed", self._on_row_changed)
58 self._treeScroller = gtk.ScrolledWindow()
59 self._treeScroller.add(self._treeView)
60 self._treeScroller.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
62 self._presenter = presenter.StreamMiniPresenter(self._store)
63 self._presenterNavigation = presenter.NavigationBox()
64 self._presenterNavigation.toplevel.add(self._presenter.toplevel)
65 self._presenterNavigation.connect("action", self._on_nav_action)
66 self._presenterNavigation.connect("navigating", self._on_navigating)
68 self._radioLayout = gtk.VBox(False)
69 self._radioLayout.pack_start(self._headerNavigation.toplevel, False, False)
70 self._radioLayout.pack_start(self._treeScroller, True, True)
71 self._radioLayout.pack_start(self._presenterNavigation.toplevel, False, True)
73 self._layout.pack_start(self._loadingBanner.toplevel, False, False)
74 self._layout.pack_start(self._radioLayout, True, True)
76 self._dateShown = datetime.datetime.now()
80 windows._base.BasicWindow.show(self)
82 self._errorBanner.toplevel.hide()
83 self._loadingBanner.toplevel.hide()
87 def jump_to(self, node):
88 _moduleLogger.info("Only 1 channel, nothing to jump to")
90 def _update_title(self):
91 self._window.set_title("%s - %s" % (self._node.title, self._dateShown.strftime("%m/%d")))
95 return self._player.node is self._childNode
97 def _set_context(self, state):
98 if state == self._player.STATE_PLAY:
100 self._presenter.set_state(self._store.STORE_LOOKUP["pause"])
102 self._presenter.set_state(self._store.STORE_LOOKUP["play"])
103 elif state == self._player.STATE_PAUSE:
104 self._presenter.set_state(self._store.STORE_LOOKUP["play"])
105 elif state == self._player.STATE_STOP:
106 self._presenter.set_state(self._store.STORE_LOOKUP["play"])
108 _moduleLogger.info("Unhandled player state %s" % state)
109 self._presenter.set_state(self._store.STORE_LOOKUP["play"])
111 def _show_loading(self):
112 animationPath = self._store.STORE_LOOKUP["loading"]
113 animation = self._store.get_pixbuf_animation_from_store(animationPath)
114 self._loadingBanner.show(animation, "Loading...")
116 def _hide_loading(self):
117 self._loadingBanner.hide()
121 self._programmingModel.clear()
122 self._node.get_children(
126 self._set_context(self._player.state)
128 def _get_current_row(self):
129 nowTime = self._dateShown.strftime("%H:%M:%S")
131 for i, row in enumerate(self._programmingModel):
140 @misc_utils.log_exception(_moduleLogger)
141 def _on_player_state_change(self, player, newState):
142 if self._headerNavigation.is_active() or self._presenterNavigation.is_active():
145 self._set_context(newState)
147 @misc_utils.log_exception(_moduleLogger)
148 def _on_player_title_change(self, player, node):
149 if node is not self._childNode or node is None:
150 _moduleLogger.info("Player title magically changed to %s" % player.title)
153 @misc_utils.log_exception(_moduleLogger)
154 def _on_navigating(self, widget, navState):
155 if navState == "clicking":
156 if self._player.state == self._player.STATE_PLAY:
158 imageName = "pause_pressed"
160 imageName = "play_pressed"
161 elif self._player.state == self._player.STATE_PAUSE:
162 imageName = "play_pressed"
163 elif self._player.state == self._player.STATE_STOP:
164 imageName = "play_pressed"
166 imageName = "play_pressed"
167 _moduleLogger.info("Unhandled player state %s" % self._player.state)
168 elif navState == "down":
171 if self._player.state == self._player.STATE_PLAY:
176 self._presenter.set_state(self._store.STORE_LOOKUP[imageName])
178 @misc_utils.log_exception(_moduleLogger)
179 def _on_nav_action(self, widget, navState):
180 self._set_context(self._player.state)
182 if navState == "clicking":
183 if self._player.state == self._player.STATE_PLAY:
187 self._player.set_piece_by_node(self._childNode)
189 elif self._player.state == self._player.STATE_PAUSE:
191 elif self._player.state == self._player.STATE_STOP:
192 self._player.set_piece_by_node(self._childNode)
195 _moduleLogger.info("Unhandled player state %s" % self._player.state)
196 elif navState == "down":
197 self.window.destroy()
198 elif navState == "up":
200 elif navState == "left":
201 self._dateShown += datetime.timedelta(days=1)
204 elif navState == "right":
205 self._dateShown -= datetime.timedelta(days=1)
209 @misc_utils.log_exception(_moduleLogger)
210 def _on_channels(self, channels):
211 if self._isDestroyed:
212 _moduleLogger.info("Download complete but window destroyed")
216 if 1 < len(channels):
217 _moduleLogger.warning("More channels now available!")
218 self._childNode = channels[0]
219 self._childNode.get_programming(
225 @misc_utils.log_exception(_moduleLogger)
226 def _on_channel(self, programs):
227 if self._isDestroyed:
228 _moduleLogger.info("Download complete but window destroyed")
232 for program in programs:
233 row = program["time"], program["title"]
234 self._programmingModel.append(row)
236 currentDate = datetime.datetime.now()
237 if currentDate.date() != self._dateShown.date():
238 self._treeView.get_selection().set_mode(gtk.SELECTION_NONE)
240 self._treeView.get_selection().set_mode(gtk.SELECTION_SINGLE)
241 path = (self._get_current_row(), )
242 self._treeView.scroll_to_cell(path)
243 self._treeView.get_selection().select_path(path)
245 @misc_utils.log_exception(_moduleLogger)
246 def _on_load_error(self, exception):
248 self._errorBanner.push_message(str(exception))
250 @misc_utils.log_exception(_moduleLogger)
251 def _on_row_changed(self, selection):
252 if len(self._programmingModel) == 0:
255 rowIndex = self._get_current_row()
257 if not selection.path_is_selected(path):
258 # Undo the user's changing of the selection
259 selection.select_path(path)
262 gobject.type_register(RadioWindow)