7 import util.misc as misc_utils
14 _moduleLogger = logging.getLogger(__name__)
17 class RadioWindow(windows._base.BasicWindow):
19 def __init__(self, app, player, store, node):
20 windows._base.BasicWindow.__init__(self, app, 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.set_property("sizing", gtk.TREE_VIEW_COLUMN_FIXED)
44 timeColumn.set_property("fixed-width", 80)
45 timeColumn.pack_start(textrenderer, expand=True)
46 timeColumn.add_attribute(textrenderer, "text", 0)
48 textrenderer = gtk.CellRendererText()
49 titleColumn = gtk.TreeViewColumn("Program")
50 titleColumn.set_property("sizing", gtk.TREE_VIEW_COLUMN_FIXED)
51 titleColumn.pack_start(textrenderer, expand=True)
52 titleColumn.add_attribute(textrenderer, "text", 1)
54 self._treeView = gtk.TreeView()
55 self._treeView.set_property("fixed-height-mode", True)
56 self._treeView.set_headers_visible(False)
57 self._treeView.set_model(self._programmingModel)
58 self._treeView.append_column(timeColumn)
59 self._treeView.append_column(titleColumn)
60 self._treeView.get_selection().connect("changed", self._on_row_changed)
62 self._treeScroller = gtk.ScrolledWindow()
63 self._treeScroller.add(self._treeView)
64 self._treeScroller.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
66 self._presenter = presenter.StreamMiniPresenter(self._store)
67 self._presenterNavigation = presenter.NavigationBox()
68 self._presenterNavigation.toplevel.add(self._presenter.toplevel)
69 self._presenterNavigation.connect("action", self._on_nav_action)
70 self._presenterNavigation.connect("navigating", self._on_navigating)
72 self._radioLayout = gtk.VBox(False)
73 self._radioLayout.pack_start(self._headerNavigation.toplevel, False, False)
74 self._radioLayout.pack_start(self._treeScroller, True, True)
75 self._radioLayout.pack_start(self._presenterNavigation.toplevel, False, True)
77 self._layout.pack_start(self._loadingBanner.toplevel, False, False)
78 self._layout.pack_start(self._radioLayout, True, True)
80 self._dateShown = datetime.datetime.now()
84 windows._base.BasicWindow.show(self)
86 self._errorBanner.toplevel.hide()
87 self._loadingBanner.toplevel.hide()
91 def jump_to(self, node):
92 _moduleLogger.info("Only 1 channel, nothing to jump to")
94 def _update_title(self):
95 self._window.set_title("%s - %s" % (self._node.title, self._dateShown.strftime("%m/%d")))
99 return self._player.node is self._childNode
101 def _set_context(self, state):
102 if state == self._player.STATE_PLAY:
104 self._presenter.set_state(self._store.STORE_LOOKUP["pause"])
106 self._presenter.set_state(self._store.STORE_LOOKUP["play"])
107 elif state == self._player.STATE_PAUSE:
108 self._presenter.set_state(self._store.STORE_LOOKUP["play"])
109 elif state == self._player.STATE_STOP:
110 self._presenter.set_state(self._store.STORE_LOOKUP["play"])
112 _moduleLogger.info("Unhandled player state %s" % state)
113 self._presenter.set_state(self._store.STORE_LOOKUP["play"])
115 def _show_loading(self):
116 animationPath = self._store.STORE_LOOKUP["loading"]
117 animation = self._store.get_pixbuf_animation_from_store(animationPath)
118 self._loadingBanner.show(animation, "Loading...")
120 def _hide_loading(self):
121 self._loadingBanner.hide()
125 self._programmingModel.clear()
126 self._node.get_children(
130 self._set_context(self._player.state)
132 def _get_current_row(self):
133 nowTime = self._dateShown.strftime("%H:%M:%S")
135 for i, row in enumerate(self._programmingModel):
144 @misc_utils.log_exception(_moduleLogger)
145 def _on_player_state_change(self, player, newState):
146 if self._headerNavigation.is_active() or self._presenterNavigation.is_active():
149 self._set_context(newState)
151 @misc_utils.log_exception(_moduleLogger)
152 def _on_player_title_change(self, player, node):
153 if node is not self._childNode or node is None:
154 _moduleLogger.info("Player title magically changed to %s" % player.title)
157 @misc_utils.log_exception(_moduleLogger)
158 def _on_navigating(self, widget, navState):
159 if navState == "clicking":
160 if self._player.state == self._player.STATE_PLAY:
162 imageName = "pause_pressed"
164 imageName = "play_pressed"
165 elif self._player.state == self._player.STATE_PAUSE:
166 imageName = "play_pressed"
167 elif self._player.state == self._player.STATE_STOP:
168 imageName = "play_pressed"
170 imageName = "play_pressed"
171 _moduleLogger.info("Unhandled player state %s" % self._player.state)
172 elif navState == "down":
175 if self._player.state == self._player.STATE_PLAY:
180 self._presenter.set_state(self._store.STORE_LOOKUP[imageName])
182 @misc_utils.log_exception(_moduleLogger)
183 def _on_nav_action(self, widget, navState):
184 self._set_context(self._player.state)
186 if navState == "clicking":
187 if self._player.state == self._player.STATE_PLAY:
191 self._player.set_piece_by_node(self._childNode)
193 elif self._player.state == self._player.STATE_PAUSE:
195 elif self._player.state == self._player.STATE_STOP:
196 self._player.set_piece_by_node(self._childNode)
199 _moduleLogger.info("Unhandled player state %s" % self._player.state)
200 elif navState == "down":
201 self.window.destroy()
202 elif navState == "up":
204 elif navState == "left":
205 self._dateShown += datetime.timedelta(days=1)
208 elif navState == "right":
209 self._dateShown -= datetime.timedelta(days=1)
213 @misc_utils.log_exception(_moduleLogger)
214 def _on_channels(self, channels):
215 if self._isDestroyed:
216 _moduleLogger.info("Download complete but window destroyed")
220 if 1 < len(channels):
221 _moduleLogger.warning("More channels now available!")
222 self._childNode = channels[0]
223 self._childNode.get_programming(
229 @misc_utils.log_exception(_moduleLogger)
230 def _on_channel(self, programs):
231 if self._isDestroyed:
232 _moduleLogger.info("Download complete but window destroyed")
236 for program in programs:
237 row = program["time"], program["title"]
238 self._programmingModel.append(row)
240 currentDate = datetime.datetime.now()
241 if currentDate.date() != self._dateShown.date():
242 self._treeView.get_selection().set_mode(gtk.SELECTION_NONE)
244 self._treeView.get_selection().set_mode(gtk.SELECTION_SINGLE)
245 path = (self._get_current_row(), )
246 self._treeView.scroll_to_cell(path)
247 self._treeView.get_selection().select_path(path)
249 @misc_utils.log_exception(_moduleLogger)
250 def _on_load_error(self, exception):
252 self._errorBanner.push_message(str(exception))
254 @misc_utils.log_exception(_moduleLogger)
255 def _on_row_changed(self, selection):
256 if len(self._programmingModel) == 0:
259 rowIndex = self._get_current_row()
261 if not selection.path_is_selected(path):
262 # Undo the user's changing of the selection
263 selection.select_path(path)
266 gobject.type_register(RadioWindow)