Now able to display the list of radio programs
authorEd Page <eopage@byu.net>
Wed, 5 May 2010 02:52:05 +0000 (21:52 -0500)
committerEd Page <eopage@byu.net>
Wed, 5 May 2010 03:31:17 +0000 (22:31 -0500)
src/index.py [new file with mode: 0644]
src/mormonchannel_gtk.py
src/util/go_utils.py
src/windows.py

diff --git a/src/index.py b/src/index.py
new file mode 100644 (file)
index 0000000..b7440d7
--- /dev/null
@@ -0,0 +1,35 @@
+from util import go_utils
+import backend
+
+
+class AudioIndex(object):
+
+       def __init__(self):
+               self._backend = backend.Backend()
+               self._indexing = go_utils.AsyncPool()
+
+       def start(self):
+               self._indexing.start()
+
+       def stop(self):
+               self._indexing.stop()
+
+       def download_radio(self, on_success, on_error, *ids):
+               self._indexing.clear_tasks()
+               if ids:
+                       assert len(ids) == 1
+                       self._indexing.add_task(
+                               self._backend.get_radio_channel_programming,
+                               (ids[0], ),
+                               {},
+                               on_success,
+                               on_error,
+                       )
+               else:
+                       self._indexing.add_task(
+                               self._backend.get_radio_channels,
+                               (),
+                               {},
+                               on_success,
+                               on_error,
+                       )
index 8ac8d4c..4f9aa14 100755 (executable)
@@ -12,14 +12,10 @@ import gc
 import logging
 import ConfigParser
 
+import gobject
 import gtk
 
 try:
-       import hildon
-except ImportError:
-       hildon = None
-
-try:
        import osso
 except ImportError:
        osso = None
@@ -30,6 +26,7 @@ import util.misc as misc_utils
 
 import imagestore
 import player
+import index
 import windows
 
 
@@ -41,8 +38,11 @@ class MormonChannelProgram(hildonize.get_app_class()):
 
        def __init__(self):
                super(MormonChannelProgram, self).__init__()
-               self._player = player.Player()
                self._store = imagestore.ImageStore("../data", "../data")
+               self._index = index.AudioIndex()
+               self._player = player.Player()
+
+               self._index.start()
 
                if not hildonize.IS_HILDON_SUPPORTED:
                        _moduleLogger.info("No hildonization support")
@@ -56,7 +56,7 @@ class MormonChannelProgram(hildonize.get_app_class()):
                        self._osso_c = None
                        self._deviceState = None
 
-               self._sourceSelector = windows.SourceSelector(self._player, self._store)
+               self._sourceSelector = windows.SourceSelector(self._player, self._store, self._index)
                self._sourceSelector.window.connect("destroy", self._on_destroy)
                self._load_settings()
 
@@ -89,9 +89,14 @@ class MormonChannelProgram(hildonize.get_app_class()):
 
        @misc_utils.log_exception(_moduleLogger)
        def _on_destroy(self, widget = None, data = None):
+               self.quit()
+
+       def quit(self):
                try:
                        self._save_settings()
 
+                       self._index.stop()
+
                        try:
                                self._deviceState.close()
                        except AttributeError:
@@ -119,10 +124,17 @@ class MormonChannelProgram(hildonize.get_app_class()):
 
 
 def run():
+       gobject.threads_init()
+       gtk.gdk.threads_init()
+
        hildonize.set_application_title(constants.__pretty_app_name__)
        app = MormonChannelProgram()
        if not PROFILE_STARTUP:
-               gtk.main()
+               try:
+                       gtk.main()
+               except KeyboardInterrupt:
+                       app.quit()
+                       raise
 
 
 if __name__ == "__main__":
index 20ccac1..ba66f26 100644 (file)
@@ -153,6 +153,10 @@ class AsyncPool(object):
                        pass # eat up queue to cut down dumb work
                self.__workQueue.put(_QUEUE_EMPTY)
 
+       def clear_tasks(self):
+               for _ in algorithms.itr_available(self.__workQueue):
+                       pass # eat up queue to cut down dumb work
+
        def add_task(self, func, args, kwds, on_success, on_error):
                task = func, args, kwds, on_success, on_error
                self.__workQueue.put(task)
index 91f995b..97556bc 100644 (file)
@@ -1,4 +1,5 @@
 import ConfigParser
+import datetime
 import logging
 
 import gobject
@@ -31,11 +32,12 @@ class BasicWindow(gobject.GObject):
                ),
        }
 
-       def __init__(self, player, store):
+       def __init__(self, player, store, index):
                gobject.GObject.__init__(self)
 
                self._player = player
                self._store = store
+               self._index = index
 
                self._clipboard = gtk.clipboard_get()
                self._windowInFullscreen = False
@@ -119,8 +121,8 @@ class BasicWindow(gobject.GObject):
 
 class SourceSelector(BasicWindow):
 
-       def __init__(self, player, store):
-               BasicWindow.__init__(self, player, store)
+       def __init__(self, player, store, index):
+               BasicWindow.__init__(self, player, store, index)
 
                self._radioButton = self._create_button("radio", "Radio")
                self._radioButton.connect("clicked", self._on_radio_selected)
@@ -175,7 +177,7 @@ class SourceSelector(BasicWindow):
 
        @misc_utils.log_exception(_moduleLogger)
        def _on_radio_selected(self, *args):
-               radioView = RadioView(self._player, self._store)
+               radioView = RadioView(self._player, self._store, self._index)
                radioView.window.set_modal(True)
                radioView.window.set_transient_for(self._window)
                radioView.window.set_default_size(*self._window.get_size())
@@ -183,21 +185,44 @@ class SourceSelector(BasicWindow):
 
 class RadioView(BasicWindow):
 
-       def __init__(self, player, store):
-               BasicWindow.__init__(self, player, store)
+       def __init__(self, player, store, index):
+               BasicWindow.__init__(self, player, store, index)
 
                self._loadingBanner = banners.GenericBanner()
 
                headerPath = self._store.STORE_LOOKUP["radio_header"]
                self._header = self._store.get_image_from_store(headerPath)
 
+               self._programmingModel = gtk.ListStore(
+                       gobject.TYPE_STRING,
+                       gobject.TYPE_STRING,
+               )
+
+               textrenderer = gtk.CellRendererText()
+               timeColumn = gtk.TreeViewColumn("Time")
+               timeColumn.pack_start(textrenderer, expand=True)
+               timeColumn.add_attribute(textrenderer, "text", 0)
+
+               textrenderer = gtk.CellRendererText()
+               titleColumn = gtk.TreeViewColumn("Program")
+               titleColumn.pack_start(textrenderer, expand=True)
+               titleColumn.add_attribute(textrenderer, "text", 1)
+
                self._treeView = gtk.TreeView()
+               self._treeView.set_headers_visible(False)
+               self._treeView.set_model(self._programmingModel)
+               self._treeView.append_column(timeColumn)
+               self._treeView.append_column(titleColumn)
+
+               self._treeScroller = gtk.ScrolledWindow()
+               self._treeScroller.add(self._treeView)
+               self._treeScroller.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
 
                self._presenter = presenter.StreamMiniPresenter(self._player, self._store)
 
                self._radioLayout = gtk.VBox(False)
                self._radioLayout.pack_start(self._header, False, False)
-               self._radioLayout.pack_start(self._treeView, True, True)
+               self._radioLayout.pack_start(self._treeScroller, True, True)
                self._radioLayout.pack_start(self._presenter.toplevel, False, True)
 
                self._layout.pack_start(self._loadingBanner.toplevel, False, False)
@@ -208,6 +233,9 @@ class RadioView(BasicWindow):
                self._errorBanner.toplevel.hide()
                self._loadingBanner.toplevel.hide()
 
+               self._show_loading()
+               self._index.download_radio(self._on_channels, self._on_load_error)
+
        def _show_loading(self):
                animationPath = self._store.STORE_LOOKUP["loading"]
                animation = self._store.get_pixbuf_animation_from_store(animationPath)
@@ -215,3 +243,37 @@ class RadioView(BasicWindow):
 
        def _hide_loading(self):
                self._loadingBanner.hide()
+
+       @misc_utils.log_exception(_moduleLogger)
+       def _on_channels(self, channels):
+               channels = list(channels)
+               if 1 < len(channels):
+                       _moduleLogger.warning("More channels now available!")
+               channel = channels[0]
+               self._index.download_radio(self._on_channel, self._on_load_error, channel["id"])
+
+       @misc_utils.log_exception(_moduleLogger)
+       def _on_channel(self, programs):
+               self._hide_loading()
+               for program in programs:
+                       row = program["time"], program["title"]
+                       self._programmingModel.append(row)
+
+               path = (self._get_current_row(), )
+               self._treeView.scroll_to_cell(path)
+               self._treeView.get_selection().select_path(path)
+
+       def _get_current_row(self):
+               now = datetime.datetime.now()
+               nowTime = now.strftime("%H:%M:%S")
+               print nowTime
+               for i, row in enumerate(self._programmingModel):
+                       if nowTime < row[0]:
+                               return i - 1
+               else:
+                       return i
+
+       @misc_utils.log_exception(_moduleLogger)
+       def _on_load_error(self, exception):
+               self._hide_loading()
+               self._errorBanner.push_message(exception)