conduit r1898 - in trunk: . conduit/gtkui conduit/modules conduit/modules/iPodModule



Author: arosenfeld
Date: Mon Feb 23 06:23:07 2009
New Revision: 1898
URL: http://svn.gnome.org/viewvc/conduit?rev=1898&view=rev

Log:
2009-02-23  Alexandre Rosenfeld  <airmind gmail com>

        * conduit/gtkui/ConfigContainer.py:
        Removed deprecated sets.Set (using set instead).
        
        * conduit/gtkui/ConfigItems.py:
        Added better support for choices handling, which
        is used by all choices-based items. Now it is
        possible to use a list of strings to all choice
        based items, instead of the (value, label) list.
        Better button callback handling. The button item
        is now the parameter to the callback (instead of
        the button widget).
        
        * conduit/gtkui/WindowConfigurator.py:
        Removed unnecessary comments.
        
        * conduit/modules/TestModule.py:
        Added more configuration items examples and added
        comments explaining them.
        
        * conduit/modules/iPodModule/iPodModule.py:
        Changes to the case where gpod cannot be loaded.


Modified:
   trunk/ChangeLog
   trunk/conduit/gtkui/ConfigContainer.py
   trunk/conduit/gtkui/ConfigItems.py
   trunk/conduit/gtkui/WindowConfigurator.py
   trunk/conduit/modules/TestModule.py
   trunk/conduit/modules/iPodModule/iPodModule.py

Modified: trunk/conduit/gtkui/ConfigContainer.py
==============================================================================
--- trunk/conduit/gtkui/ConfigContainer.py	(original)
+++ trunk/conduit/gtkui/ConfigContainer.py	Mon Feb 23 06:23:07 2009
@@ -7,15 +7,13 @@
 License: GPLv2
 '''
 
-import sys
-import sets
 import gobject
-import gtk, gtk.glade
+import gtk
+import gtk.glade
 import logging
 log = logging.getLogger("gtkui.ConfigContainer")
 
 from gettext import gettext as _ 
-import conduit
 import conduit.gtkui.ConfigItems as ConfigItems
 import conduit.Configurator as Configurator
 
@@ -63,7 +61,7 @@
         next time get_modified_items is called.
         '''
         if empty:
-            self.modified_items = sets.Set()
+            self.modified_items = set()
         else:
             self.modified_items = None
         
@@ -164,15 +162,15 @@
         self.section.add_item(item)
         self._rebuild_widgets()
         return item
-        
+    
     def get_modified_items(self):
         '''
         Return a list of items that has been modified
         '''
         if self.modified_items is None:
-            self.modified_items = sets.Set([item for item in self.items if not item.is_initial_value()])
+            self.modified_items = set([item for item in self.items if not item.is_initial_value()])
         return self.modified_items
-                
+    
     def is_modified(self):
         '''
         Returns true if any item has been modified
@@ -206,7 +204,7 @@
         '''
         super(ConfigContainer, self).show()
         self.config_widget.show_all()
-        
+
     def apply_config(self, items = None, sections = None):
         '''
         Save the current configuration state to the dataprovider and to each 

Modified: trunk/conduit/gtkui/ConfigItems.py
==============================================================================
--- trunk/conduit/gtkui/ConfigItems.py	(original)
+++ trunk/conduit/gtkui/ConfigItems.py	Mon Feb 23 06:23:07 2009
@@ -5,15 +5,14 @@
 License: GPLv2
 """
 import sys
-import os.path
+
 import gobject
-import pango
-import gtk, gtk.glade
+import gtk
+import gtk.glade
 import logging
 log = logging.getLogger("gtkui.Config")
 
-from gettext import gettext as _ 
-import conduit
+from gettext import gettext as _
 
 class Error(Exception):
     """Base exception for all exceptions raised in this module."""
@@ -42,7 +41,7 @@
             label.set_alignment(0.0, 0.5)
             label.set_use_markup(True)
             table.resize(row, 2)
-            table.attach(label, 0, 2, row - 1, row, xoptions = gtk.FILL | gtk.SHRINK, yoptions = 0 )
+            table.attach(label, 0, 2, row - 1, row, xoptions = gtk.FILL | gtk.SHRINK, yoptions = 0)
         for item in sorted(self.items, key = lambda item: item.order):
             row = item._attach(table, row, bool(self.title))
         return row
@@ -102,13 +101,13 @@
     __metaclass__ = ItemMeta
     
     __gsignals__ = {
-        'value-changed' : (gobject.SIGNAL_RUN_FIRST, None, [bool, object]),
+        'value-changed': (gobject.SIGNAL_RUN_FIRST, None, [bool, object]),
     }
     
-    def __init__(self, container, title, order, config_name=None, 
-            config_type=None, choices=[], needs_label=True, 
-            needs_space=False, initial_value=None, initial_value_callback=None,
-            save_callback=None, fill=False, enabled=True):
+    def __init__(self, container, title, order, config_name = None,
+        config_type = None, choices = [], needs_label = True,
+        needs_space = False, initial_value = None, initial_value_callback = None,
+        save_callback = None, fill = False, enabled = True):
         '''
         Creates a config item.
         
@@ -178,6 +177,26 @@
         #    self.emit('initial-state')
         self.emit('value-changed', self.is_initial_value(), self.value)
         
+    def _get_choices_labels(self):
+        for value, label in self._get_choices_all():
+            yield label
+        
+    def _get_choices_values(self):
+        for value, label in self._get_choices_all():
+            yield value
+        
+    def _get_choices_all(self):
+        try:
+            for choice in self.choices:
+                if isinstance(choice, tuple):
+                    if len(choice) != 2:
+                        raise ValueError
+                    yield choice
+                else:
+                    yield choice, str(choice)
+        except (ValueError, TypeError):
+            raise Error("Choices '%s' for '%s' is not valid, it should be a (value, label) list or a list of labels" % (self.choices, self.title))
+        
     def _build_choices(self):
         '''
         Implement this when you need to build the choices of a widget.
@@ -241,7 +260,7 @@
             table.attach(widget, 1, 2, row - 1, row, xoptions = gtk.FILL | gtk.EXPAND, yoptions = yoptions)
         else:
             align.add(widget)
-            table.attach(align, 0, 2, row - 1, row, xoptions = gtk.FILL | gtk.EXPAND, yoptions = yoptions)    
+            table.attach(align, 0, 2, row - 1, row, xoptions = gtk.FILL | gtk.EXPAND, yoptions = yoptions)
         return row        
 
     def get_label(self):
@@ -263,7 +282,7 @@
         self.__label = label        
         
     label = property(lambda self: self.get_label(), 
-                     lambda self, v: self.set_label(v))        
+                     lambda self, v: self.set_label(v))
 
     def get_widget(self):
         '''
@@ -420,27 +439,29 @@
     def __init__(self, *args, **kwargs):
         action = kwargs.pop('action', None)
         ItemBase.__init__(self, *args, **kwargs)
-        self.callback_id = None
         self.callback = None
         self.needs_space = kwargs.get('needs_space', True)
         self.needs_label = kwargs.get('needs_label', False)
         if action:
             self.initial_value = action
         self.read_only = True
+        
+    def _button_clicked(self, button_widget):
+        if self.callback:
+            self.callback(self)
     
     def _build_widget(self):
         self.widget = gtk.Button(self.title)
+        self.widget.connect("clicked", self._button_clicked)
         
     def _set_value(self, value):
-        if self.callback_id:
-            self.widget.disconnect(self.callback_id)
-        self.callback_id = None
-        self.callback = None
-        if not callable(value):
-            return None        
+        #if self.callback_id:
+        #    self.widget.disconnect(self.callback_id)
+        #self.callback_id = None
+        #self.callback = None
+        if value is not None and not callable(value):
+            raise Error("Button callback must be callable (%s is not)" % (value))
         self.callback = value
-        if self.callback:
-            self.callback_id = self.widget.connect("clicked", value)            
         
     def _get_value(self):
         return self.callback
@@ -450,7 +471,7 @@
     
     def __init__(self, *args, **kwargs):
         self.directory = kwargs.pop('directory', False)
-        ItemBase.__init__(self, *args, **kwargs)        
+        ItemBase.__init__(self, *args, **kwargs)
         self._current_filename = None
     
     def _selection_changed(self, filechooser):
@@ -493,7 +514,7 @@
   
     def _build_choices(self):
         last_button = None
-        for value, text in self.choices:
+        for value, text in self._get_choices_all():
             last_button = gtk.RadioButton(last_button, text)
             last_button.connect("toggled", self._button_changed)
             last_button.show()
@@ -514,7 +535,7 @@
         if new_value in self.buttons:
             self.buttons[new_value].set_active(True)
         else:
-            log.warn("Value %s could not be applied to config %s" % (repr(self.title), new_value))
+            log.warn("Value %s could not be applied to config %s" % (new_value, self.title))
 
 class ConfigSpin(ItemBase):
     __item_name__ = 'spin'
@@ -541,21 +562,11 @@
             log.warn("Value %s could not be applied to config %s" % (repr(self.title), value))        
 
 class ConfigCombo(ItemBase):
-    '''
-    A box where the user can select one value from several
-    
-    The combo box takes as choices a list of tuples, with a value and a 
-    description. 
-    The value is what is returned by get_value and what should be set with 
-    set_value. The value can have any type.
-    The description is the text shown to the user.
-    '''
     __item_name__ = 'combo'
     
     def _build_choices(self):
-        if self.choices:
-            for value, text in self.choices:
-                self.widget.append_text(text)
+        for label in self._get_choices_labels():
+            self.widget.append_text(label)
     
     def _clear_choices(self):
         self.widget.get_model().clear()
@@ -568,17 +579,17 @@
     def _get_value(self):
         active = self.widget.get_active()
         if len(self.choices) > active and active >= 0:
-            return self.choices[active][0]
+            return [value for value in self._get_choices_values()][active]
         else:
-            log.warning("No value selected in combo")
+            log.warn("No value selected in combo")
             return None
     
     def _set_value(self, new_value):
-        for idx, (value, text) in enumerate(self.choices):
+        for idx, value in enumerate(self._get_choices_values()):
             if value == new_value:
                 self.widget.set_active(idx)
                 return
-        log.warn("%s not found in %s" % (new_value, self.title))
+        log.warn("Value %s not found in config %s" % (new_value, self.title))
         
 class ConfigComboText(ConfigCombo):
     __item_name__ = 'combotext'
@@ -599,7 +610,7 @@
     
     def __init__(self, password = False, **kwargs):
         self.password = password #kwargs.pop('password', False)
-        ItemBase.__init__(self, **kwargs)        
+        ItemBase.__init__(self, **kwargs)
     
     def _build_widget(self):
         self.widget = gtk.Entry()
@@ -634,19 +645,8 @@
         self._value_changed()
     
     def _build_choices(self):
-        try:
-            for choice in self.choices:
-                if isinstance(choice, tuple):
-                    if len(choice) != 2:
-                        raise ValueError
-                    value, label = choice
-                else:
-                    label = choice
-                #Set's the list text and initial (unchecked) value, it will be
-                #checked or unchecked later by set_value
-                self.model.append((str(label), False))
-        except (ValueError, TypeError):
-            raise Error("Choices is not valid, it should be a (value, label) list or a list of labels (%s is not)" % self.choices)
+        for label in self._get_choices_labels():
+            self.model.append((str(label), False))
 
     def _clear_choices(self):
         self.model.clear()
@@ -669,12 +669,12 @@
         self.list.set_model(self.model)        
         check_renderer = gtk.CellRendererToggle()
         check_renderer.set_property('activatable', True)
-        check_renderer.connect( 'toggled', self._cellcheck_cb, self.model )
+        check_renderer.connect('toggled', self._cellcheck_cb, self.model)
         #FIXME: We could probably support more columns, maybe by automatically
         # detecting if choices include tuples, and which types are inside the 
         # tuple.
-        self.list.append_column(gtk.TreeViewColumn("Enabled", check_renderer, active=1))                    
-        self.list.append_column(gtk.TreeViewColumn("Label", gtk.CellRendererText(), text=0))   
+        self.list.append_column(gtk.TreeViewColumn("Enabled", check_renderer, active = 1))
+        self.list.append_column(gtk.TreeViewColumn("Label", gtk.CellRendererText(), text = 0))
         self._clear_choices()  
         self._build_choices()
         self.scrolled_window.add(self.list)
@@ -698,7 +698,7 @@
                 if row[1]:
                     self._checked_items.append(row[0])
         except:
-            log.warn("Value %s could not be applied to config %s" % (value, repr(self.title)))
+            log.warn("Value %s could not be added to list %s" % (value, repr(self.title)))
         self._update_total()
 
 class ConfigCheckBox(ItemBase):

Modified: trunk/conduit/gtkui/WindowConfigurator.py
==============================================================================
--- trunk/conduit/gtkui/WindowConfigurator.py	(original)
+++ trunk/conduit/gtkui/WindowConfigurator.py	Mon Feb 23 06:23:07 2009
@@ -30,11 +30,6 @@
         self.showing = False
         self.built_configs = False
         
-        #self.dialogParent = window
-        #The dialog is loaded from a glade file
-        #gladeFile = os.path.join(conduit.SHARED_DATA_DIR, "conduit.glade")
-        #widgets = gtk.glade.XML(gladeFile, "DataProviderConfigDialog")
-
         self.dialog = gtk.Dialog(self.CONFIG_WINDOW_TITLE_TEXT,
                           window,
                           gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
@@ -47,17 +42,10 @@
         self.dialog.set_has_separator(False)
         self.dialog.set_response_sensitive(gtk.RESPONSE_HELP, False)
         self.dialog.set_default_size(300, -1)
-        #self.dialog = widgets.get_widget("DataProviderConfigDialog")
-        #self.dialog.set_transient_for(self.dialogParent)
-        #self.dialog.set_title(WindowConfigurator.CONFIG_WINDOW_TITLE_TEXT)
-        #self.dialog.set_border_width(6)
         
-        #self.configVBox = widgets.get_widget("configVBox")
         self.dialog_box = self.dialog.vbox
-        
-        self.dialog_box.pack_start(self._make_config_widget())        
-        #self.configVBox.pack_start(self.conduit_config.get_config_widget())
-        self.dialog_box.show_all()        
+        self.dialog_box.pack_start(self._make_config_widget())
+        self.dialog_box.show_all()
         
         self.container_widgets = {}
         
@@ -78,25 +66,13 @@
         self.built_containers = False
         
         self.containers = containers
-        #self.configVBox.hide()
-        #import threading
-        #log.debug("THREADS: %s" % threading.activeCount())
-        #if self.notebook:
-        #    self.configVBox.remove(self.notebook)
-        #self.notebook = gtk.Notebook()
-        #self.configVBox.pack_start(self.notebook)
-        
-        #self.notebook.show_all()
-        #self.configVBox.pack_start(self.config.get_config_widget())
         
     def _clear_containers(self):
         if self.NOTEBOOK:
-            #self.notebook.foreach(lambda widget: self.notebook.remove(widget))
             while self.notebook.get_n_pages() > 0:
                 self.notebook.remove_page(0)
             self.tabs = {}
         else:
-            #self.containers_box.foreach(lambda widget: self.containers_box.remove(widget))
             for container, widget in self.container_widgets.iteritems():
                 self.containers_box.remove(widget)
                 container_widget = container.get_config_widget()
@@ -125,7 +101,6 @@
                 title_box.pack_start(lbl, False, False, 4)
                 title_box.show_all()
                 container_box.pack_start(title_box, False, False)
-            #config_widget = config.get_config_widget()
             container_box.pack_start(container_widget, True, True)
             container_box.pack_start(gtk.HSeparator(), False, False)
             self.containers_box.pack_start(container_box)
@@ -171,10 +146,7 @@
             assert config_container in self.container_widgets
             for container, container_widget in self.container_widgets.iteritems():
                 if container != config_container:
-                    #log.debug("Hiding: %s" % container)
-                    container_widget.hide()       
-                    
-            #log.debug("Showing: %s" % config_container)         
+                    container_widget.hide()
             config_container.show()
             self.container_widgets[config_container].show()
             containers = [config_container]
@@ -185,13 +157,11 @@
             containers = self.container_widgets.keys()
         if self.NOTEBOOK and config_container:
             self.notebook.set_current_page(self.tabs[config_container])
-        #self.dialog.show()
         self.dialog.reshow_with_initial_size()
         resp = self.dialog.run()
         for container in containers:
             container.hide()
         self.dialog.hide()
-        #self.dialog = None
         self.showing = False
         if resp == gtk.RESPONSE_OK:
             for container in containers:

Modified: trunk/conduit/modules/TestModule.py
==============================================================================
--- trunk/conduit/modules/TestModule.py	(original)
+++ trunk/conduit/modules/TestModule.py	Mon Feb 23 06:23:07 2009
@@ -113,7 +113,7 @@
         DataProvider.DataProviderBase.__init__(self)
         self.update_configuration(
             folder = ('', self._set_folder, lambda: self.folder),
-            checktest = 1,
+            checktest = "Choice 3",
             number = 0,
             items = [],
             password = '',
@@ -123,74 +123,77 @@
         self.folder = f
         
     def config_setup(self, config):
-        config.add_section("Test1")
+        status_label = config.add_item("Status label", "label")
+        def status_changed(config, item):
+            status_label.value = "%s: %s" % (item.title, item.value)
+        config.connect("item-changed", status_changed)
+        
+        def change_label_callback(button_item):
+            status_label.value = text_config.value
+        text_config = config.add_item("Type some text", "text", initial_value = "Then click below")    
+        config.add_item("Change label", "button", initial_value = change_label_callback)
+        
+        config.add_section("Section")
         config.add_item("Select folder", "filebutton", order = 1,
             config_name = "folder",
             directory = True,
         )
+        #The next item shows most choice-based features.
         radio_config = config.add_item("Radio button test", "radio",
             config_name = "checktest",
-            choices = [(1, "Test 1"), (2, "Test 2"), (3, "Test 3")],
+            choices = [1, ("My value 2", "Choice 2"), "Choice 3"],
+        )
+        
+        #Defining a order prioritize sections. The grouping is done by sections
+        #of the same order, then on the order they were declared.
+        #So, even if this is declared here, because it has order 1, it will be
+        #below all other sections, which are order -1 by default.
+        #This allows for subclasses to put sections below or above it's parents
+        #sections.
+        config.add_section('Section', order = 1)
+        combo_config = config.add_item("Combo test", "combo",
+            initial_value = 0,
+            choices = [choice for choice in enumerate(["Choice %s" % i for i in range(5)])],
         )
-        config.add_section('Test2', order = 1)
-        config.add_section()
+        
         config.add_item("Number", "spin",
             config_name = "number",
             maximum = 100,
-        )        
-        config.add_section("Test1")
+        )
+
+        #These items will actually be added in "Section 1" defined above, 
+        #because by default it will look for existing sections with this title
+        section = config.add_section("Section")
         items_config = config.add_item("Items", "list",
             config_name = "items",
+            # The actual value returned from this list would be either True or
+            # False, but their text would be tst and tst2 respectively
             choices = [(True,"tst"), (False,"tst2")],
         )
         config.add_item("Password", "text",
             config_name = "password",
             password = True
         )
-        config.add_section("Test3", order = -1)
-        def radio_buttons_clicked(button):
-            #radio_config.set_choices([(1, 'TestI'), (2, 'TestII'), (3, 'TestIII')])
-            radio_config.set_value(2)
-            #radio_config.set_enabled(not items_config.enabled)
-            config.add_item("Radio buttons", "button",
-            initial_value = radio_buttons_clicked
-        )
+        
+        #use_existing allows for duplicate sections with the same title.
+        #By default, and prefereable, adding another with the same title, adds
+        #items to the existing section instead of creating a new one.
+        #Please keep in mind two sections with the same title is very confusing.
+        #config.add_section("Section 1", use_existing = False)
         def button_clicked(button):
-            items_config.set_choices(['Test1', 'Test2', 'Test3', 'Test4', 'Test5'])
-            items_config.set_enabled(not items_config.enabled)
-            config.add_section("Test1", use_existing = False)
-            config.add_item("Check values", "button",
+            #A list is smart enough to detect if choices contain tuples with
+            #values and labels, or just labels.
+            items_config.choices = ['Test1', 'Test2', 'Test3', 'Test4', 'Test5']
+            #items_config.enabled = not items_config.enabled
+            section.enabled = not section.enabled
+            
+        #Adding an empty section actually puts next items unidented in the
+        #configuration dialog, so it looks to be outside a section.
+        config.add_section()            
+        config.add_item("Disable section / Change choices", "button",
             initial_value = button_clicked
         )
 
-    '''
-    def get_configuration(self):            
-        return {'folder': self.folder,
-                'checktest': self.checktest,
-                'number': self.number,
-                'items': self.items,
-                'password': self.password}
-    
-    def set_configuration(self, values):
-        super(TestEasyConfig, self).set_configuration(values,
-            folder = str,
-            checktest = int,
-            number = int,
-            items = list,
-            password = str
-        )
-                if 'folder' in values:
-            self.folder = values['folder']
-        if 'checktest' in values:
-            self.checktest = values['checktest']
-        if 'number' in values:
-            self.number = values['number']
-        if 'items' in values:
-            self.items = values['items']
-        if 'password' in values:
-            self.password = values['password']
-        '''
-
 class _TestBase:
     _configurable_ = True
     def __init__(self):

Modified: trunk/conduit/modules/iPodModule/iPodModule.py
==============================================================================
--- trunk/conduit/modules/iPodModule/iPodModule.py	(original)
+++ trunk/conduit/modules/iPodModule/iPodModule.py	Mon Feb 23 06:23:07 2009
@@ -43,24 +43,21 @@
             "iPodFactory" :         { "type":   "dataprovider-factory"  },
         }
         log.info("Module Information: %s" % Utils.get_module_information(gpod, 'version_info'))
-    MEDIATYPE_MUSICVIDEO = gpod.ITDB_MEDIATYPE_MUSICVIDEO
-    MEDIATYPE_MOVIE = gpod.ITDB_MEDIATYPE_MOVIE
-    MEDIATYPE_TVSHOW = gpod.ITDB_MEDIATYPE_TVSHOW
-    MEDIATYPE_AUDIO = gpod.ITDB_MEDIATYPE_AUDIO
-    MEDIATYPE_PODCAST = gpod.ITDB_MEDIATYPE_PODCAST
 except ImportError:
-    errormsg = "iPod support disabled"
+    errormsg = "iPod support disabled (python-gpod not availiable)"
 except locale.Error:
     errormsg = "iPod support disabled (Incorrect locale)"
 
 if errormsg:
     MODULES = {}
-    log.info(errormsg)
-    MEDIATYPE_MUSICVIDEO = 0
-    MEDIATYPE_MOVIE = 1
-    MEDIATYPE_TVSHOW = 2
-    MEDIATYPE_AUDIO = 3
-    MEDIATYPE_PODCAST = 4
+    log.warn(errormsg)
+    #Solve the initialization problem without gpod
+    class gpod():
+        ITDB_MEDIATYPE_MUSICVIDEO = 0
+        ITDB_MEDIATYPE_MOVIE = 1
+        ITDB_MEDIATYPE_TVSHOW = 2
+        ITDB_MEDIATYPE_AUDIO = 3
+        ITDB_MEDIATYPE_PODCAST = 4
 
 def _string_to_unqiue_file(txt, base_uri, prefix, postfix=''):
     for i in range(1, 10000):
@@ -674,10 +671,10 @@
         
     def set_info_from_file(self, video):
         IPodFileBase.set_info_from_file(video)
-        self.track['mediatype'] = {'movie': MEDIATYPE_MOVIE,
-                                   'musicvideo': MEDIATYPE_MUSICVIDEO,
-                                   'tvshow': MEDIATYPE_TVSHOW,
-                                   'podcast': MEDIATYPE_PODCAST
+        self.track['mediatype'] = {'movie': gpod.ITDB_MEDIATYPE_MOVIE,
+                                   'musicvideo': gpod.ITDB_MEDIATYPE_MUSICVIDEO,
+                                   'tvshow': gpod.ITDB_MEDIATYPE_TVSHOW,
+                                   'podcast': gpod.ITDB_MEDIATYPE_PODCAST
                                    } [self.video_kind]
 
 class DBCache:
@@ -921,7 +918,7 @@
     _icon_ = "audio-x-generic"
     _configurable_ = True
 
-    _mediatype_ = (MEDIATYPE_AUDIO,)
+    _mediatype_ = (gpod.ITDB_MEDIATYPE_AUDIO,)
     _ipodmedia_ = IPodAudio
 
     def __init__(self, *args):
@@ -955,7 +952,7 @@
     _icon_ = "video-x-generic"
     _configurable_ = True
 
-    _mediatype_ = (MEDIATYPE_MUSICVIDEO, MEDIATYPE_MOVIE, MEDIATYPE_TVSHOW)
+    _mediatype_ = (gpod.ITDB_MEDIATYPE_MUSICVIDEO, gpod.ITDB_MEDIATYPE_MOVIE, gpod.ITDB_MEDIATYPE_TVSHOW)
     _ipodmedia_ = IPodVideo
 
     def __init__(self, *args):



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]