conduit r1873 - in trunk: . conduit/gtkui



Author: arosenfeld
Date: Sun Feb 15 06:13:27 2009
New Revision: 1873
URL: http://svn.gnome.org/viewvc/conduit?rev=1873&view=rev

Log:
2009-02-15  Alexandre Rosenfeld  <arosenfeld gemini>

	* conduit/gtkui/ConfigContainer.py:
	Removed code to detect item classes.
	* conduit/gtkui/ConfigItems.py:
	Added Item metaclass to register item classes.
	Every descendant to ConfigItem now gets
	automatically registered, no matter where they
	are (good for custom items).
	* conduit/gtkui/ConfigWidgets.py:
	* conduit/gtkui/Makefile.am:
	Renamed ConfigWidgets to ConfigItems.



Added:
   trunk/conduit/gtkui/ConfigItems.py   (contents, props changed)
      - copied, changed from r1872, /trunk/conduit/gtkui/ConfigWidgets.py
Removed:
   trunk/conduit/gtkui/ConfigWidgets.py
Modified:
   trunk/ChangeLog
   trunk/conduit/gtkui/ConfigContainer.py
   trunk/conduit/gtkui/Makefile.am

Modified: trunk/conduit/gtkui/ConfigContainer.py
==============================================================================
--- trunk/conduit/gtkui/ConfigContainer.py	(original)
+++ trunk/conduit/gtkui/ConfigContainer.py	Sun Feb 15 06:13:27 2009
@@ -16,7 +16,7 @@
 
 from gettext import gettext as _ 
 import conduit
-import conduit.gtkui.ConfigWidgets as ConfigWidgets
+import conduit.gtkui.ConfigItems as ConfigItems
 import conduit.Configurator as Configurator
 
 class Error(Exception):
@@ -33,10 +33,7 @@
     __gsignals__ = {
         'item-changed' : (gobject.SIGNAL_RUN_FIRST, None, (gobject.TYPE_OBJECT,)),
     }
-    
-    # List of registered items. Call register_item to change it.
-    __config_classes = {}
-    
+
     def __init__(self, dataprovider, configurator):
         super(ConfigContainer, self).__init__(dataprovider, configurator)
         
@@ -57,11 +54,7 @@
         self.config_widget = self.widgetTable
         
         self.firstRow = True
-    
-    @classmethod
-    def register_item(cls, name, item_class):
-        cls.__config_classes[name] = item_class
-        
+
     def _reset_modified_items(self, empty = True):
         '''
         Reset the list of modified items. If empty is true, just create a new
@@ -134,7 +127,7 @@
                     found = True
                     break
         if not use_existing or not found:
-            self.section = ConfigWidgets.Section(self, title, order, **kwargs)
+            self.section = ConfigItems.Section(self, title, order, **kwargs)
             self.sections.append(self.section)
         self._rebuild_widgets()
         return self.section
@@ -145,8 +138,6 @@
         
         You can pass properties to the configuration item in kwargs.
         '''
-        if kind not in self.__config_classes:
-            raise Error("Config widget %s not found" % kind)
         if not self.section:
             self.add_section()
         # If we have a saved configuration in the config dict from the dp, 
@@ -160,8 +151,12 @@
             if kwargs['config_name'] in self.config_values:
                 kwargs['initial_value'] = self.config_values[kwargs['config_name']]
         if 'enabled' not in kwargs:
-            kwargs['enabled'] = self.section.enabled            
-        item = self.__config_classes[kind](self, title, order, **kwargs)
+            kwargs['enabled'] = self.section.enabled
+        try:    
+            item_cls = ConfigItems.ConfigItem.items[kind]
+        except KeyError:
+            raise Error("Config kind %s not found" % kind)
+        item = item_cls(self, title, order, **kwargs)
         item.connect("value-changed", self._item_changed)
         self.items.append(item)
         self.section.add_item(item)
@@ -251,12 +246,3 @@
         super(ConfigContainer, self).cancel_config()
         self._reset()
         self._reset_modified_items()
-
-# Register all item classes in this module
-for klass_name in dir(ConfigWidgets):
-    klass = getattr(ConfigWidgets, klass_name)
-    #log.debug("Class: %s" % getattr(ConfigWidgets, klass_name))    
-    if isinstance(klass, type) and issubclass(klass, ConfigWidgets.ConfigItem) and klass != ConfigWidgets.ConfigItem:
-        #log.debug("-- ConfigItem: %s", klass)
-        ConfigContainer.register_item(klass.__item_name__, klass)
-

Copied: trunk/conduit/gtkui/ConfigItems.py (from r1872, /trunk/conduit/gtkui/ConfigWidgets.py)
==============================================================================
--- /trunk/conduit/gtkui/ConfigWidgets.py	(original)
+++ trunk/conduit/gtkui/ConfigItems.py	Sun Feb 15 06:13:27 2009
@@ -40,7 +40,7 @@
             table.resize(row, 2)
             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))
+            row = item._attach(table, row, bool(self.title))
         return row
     
     enabled = property(lambda self: self.__enabled, 
@@ -57,6 +57,25 @@
     def apply(self):
         self.container.apply_config(sections = [self])
         
+class ItemMeta(gobject.GObjectMeta):
+    '''
+    Meta class to automatically register item classes.
+    '''
+    def __init__(cls, name, bases, attrs):
+        gobject.GObjectMeta.__init__(cls, name, bases, attrs)
+        if not hasattr(cls, 'items'):
+            # This branch only executes when processing the mount point itself.
+            # So, since this is a new plugin type, not an implementation, this
+            # class shouldn't be registered as a plugin. Instead, it sets up a
+            # list where plugins can be registered later.
+            cls.items = {}
+        else:
+            # This must be a plugin implementation, which should be registered.
+            # Simply appending it to the list is all that's needed to keep
+            # track of it later.
+            if hasattr(cls, '__item_name__'):
+                cls.items[cls.__item_name__] = cls
+        
 class ConfigItem(gobject.GObject):
     '''
     A config item is basically a wrapper to a widget.
@@ -79,7 +98,7 @@
             is called. It is especially useful for items that keep their state
             somewhere else.
         :choices: Valid when the user needs to select a value from a list.
-            It has be a tuple with ``(value, label)``.
+            It has to be a tuple with ``(value, label)``.
         :needs_label: If True, the widget will have a label with title as
             the text.
         :needs_space: If ``needs_label`` is False, but the widget still wants 
@@ -89,9 +108,14 @@
     selected and the value must be saved.
         
     Signals emitted:
-        :value-changed: Emitted everytime the value changes.   
+        :value-changed: Emitted everytime the value changes, emitting two 
+            parameters, the first is a bool wheter the value is the same
+            as the initial value, and the second is the value.
     '''
     
+    #Automatically registers item descendants
+    __metaclass__ = ItemMeta
+    
     __gsignals__ = {
         'value-changed' : (gobject.SIGNAL_RUN_FIRST, None, [bool, object]),
         #'reset' : (gobject.SIGNAL_RUN_LAST, None, []),
@@ -125,7 +149,10 @@
 
     def _value_changed(self, *args):
         '''
-        Called everytime the value changes.
+        Called everytime the value changes. Emits the value-changed signal.
+        
+        This method can be chained into widget signals. It will safely ignore
+        any argument passed to it.
         '''
         #if self.is_initial_value():
         #    self.emit('initial-state')
@@ -160,13 +187,13 @@
     
     def is_initial_value(self):
         '''
-        Returns True if the current value is the initial value
+        Returns True if the current value is the initial value.
         '''
         return self.initial_value == self.value
         
     def set_enabled(self, enabled):
         '''
-        Set the button sensibility.
+        Set the widget sensibility.
         '''
         self.enabled = enabled
         if self.widget:
@@ -174,7 +201,7 @@
         
     def reset(self):
         '''
-        Resets the widget to it's initial state
+        Resets the widget to it's initial value.
         '''
         if self.__widget:
             #self.emit('reset')
@@ -185,7 +212,7 @@
     
     def save_state(self):
         '''
-        Set the current value as the initial value.
+        Save the current value as the initial value.
         '''
         value = self.get_value()
         self.initial_value = value
@@ -194,7 +221,7 @@
         
     def apply(self):
         '''
-        Set the current value as the initial value and calls the dataprovider
+        Save the current value as the initial value and calls the dataprovider
         to save the current value
         '''
         self.save_state()
@@ -262,21 +289,39 @@
         else:
             return {self.config_name: value}
     
-    def _get_value(self):
-        self.get_value()
-    
     #Set value as a property and make sure get_value and set_value can be 
     #overriden in descendants without conflicting with this property
     value = property(lambda self: self.get_value(),
                      lambda self, v: self.set_value(v))
         
     def get_value(self):
-        pass
+        '''
+        Gets the value from the widget.
+        
+        This is a public interface method, should not be overriden by 
+        descendants. Implement _get_value instead.
+        '''
+        return self._get_value()
     
     def set_value(self, value):
-        pass
+        '''
+        Sets the value from the widget.
+        
+        This is a public interface method, should not be overriden by 
+        descendants. Implement _set_value instead.
+        '''
+        #FIXME: We should probably check for exceptions here, to avoid not 
+        # showing the configuration dialog because a value was invalid,
+        # which could occur with invalid config values.
+        # We should probably assign the initial value here in case of an 
+        # Exception. In case of another Exception, then it's the module fault,
+        # and no exception handling should be done.
+        self._set_value(value)
 
-    def attach(self, table, row, in_section):
+    def _attach(self, table, row, in_section):
+        '''
+        Attach this item's widget to a table.
+        '''
         widget = self.get_widget()
         label = self.get_label()
         row += 1
@@ -303,10 +348,10 @@
 
 #FIXME: Finish the CustomWidget implementation (if we need the custom widget support)
 #class ConfigCustomWidget(ConfigItem):
-#    def get_value(self):
+#    def _get_value(self):
 #        return self.load_callback(self.widget)
 #    
-#    def set_value(self, value):
+#    def _set_value(self, value):
 #        self.widget_callback(self.widget)
 
 class ConfigLabel(ConfigItem):
@@ -323,10 +368,10 @@
         self.widget.set_alignment(self.xalignment, self.yalignment)
         self.widget.set_use_markup(self.use_markup)
     
-    def get_value(self):
+    def _get_value(self):
         return self.widget.get_text()
     
-    def set_value(self, value):
+    def _set_value(self, value):
         if self.use_markup:
             self.widget.set_markup(str(value))
         else:
@@ -347,7 +392,7 @@
     def build_widget(self):
         self.widget = gtk.Button(self.title)
         
-    def set_value(self, value):
+    def _set_value(self, value):
         if self.callback_id:
             self.widget.disconnect(self.callback_id)
         self.callback_id = None
@@ -358,7 +403,7 @@
         if self.callback:
             self.callback_id = self.widget.connect("clicked", value)            
         
-    def get_value(self):
+    def _get_value(self):
         return self.callback
     
 class ConfigFileButton(ConfigItem):
@@ -382,10 +427,10 @@
         else:
             self.widget.set_action(gtk.FILE_CHOOSER_ACTION_OPEN)
     
-    def set_value(self, value):
+    def _set_value(self, value):
         self.widget.set_filename(str(value))
     
-    def get_value(self):
+    def _get_value(self):
         return self._current_filename
 
 class ConfigRadio(ConfigItem):
@@ -420,13 +465,13 @@
         self.widget = gtk.VBox()
         self._build_choices()
     
-    def get_value(self):
+    def _get_value(self):
         for value, button in self.buttons.iteritems():
             if button == self._active_button:
                 return value
         return None
     
-    def set_value(self, new_value):
+    def _set_value(self, new_value):
         if new_value in self.buttons:
             self.buttons[new_value].set_active(True)
         else:
@@ -446,10 +491,10 @@
         self.widget = gtk.SpinButton(self.adjust)
         self.widget.connect("value-changed", self._value_changed)
     
-    def get_value(self):
+    def _get_value(self):
         return float(self.widget.get_value())
     
-    def set_value(self, value):
+    def _set_value(self, value):
         try:
             value = float(value)
             self.widget.set_value(value)
@@ -481,7 +526,7 @@
         self._build_choices()
         self.widget.connect("changed", self._value_changed)
 
-    def get_value(self):
+    def _get_value(self):
         active = self.widget.get_active()
         if len(self.choices) > active and active >= 0:
             return self.choices[active][0]
@@ -489,7 +534,7 @@
             log.warning("No value selected in combo")
             return None
     
-    def set_value(self, new_value):
+    def _set_value(self, new_value):
         for idx, (value, text) in enumerate(self.choices):
             if value == new_value:
                 self.widget.set_active(idx)
@@ -504,10 +549,10 @@
         self._build_choices()
         self.widget.connect("changed", self._value_changed)
     
-    def get_value(self):
+    def _get_value(self):
         return self.widget.child.get_text()
     
-    def set_value(self, value):
+    def _set_value(self, value):
         self.widget.child.set_text(str(value))
     
 class ConfigText(ConfigItem):
@@ -522,10 +567,10 @@
         self.widget.connect("notify::text", self._value_changed)
         self.widget.set_visibility(not self.password)
     
-    def get_value(self):
+    def _get_value(self):
         return self.widget.get_text()
     
-    def set_value(self, value):
+    def _set_value(self, value):
         self.widget.set_text(str(value))
             
 class ConfigList(ConfigItem):
@@ -577,13 +622,13 @@
     def _update_total(self):
         self.total_label.set_text("Total: %d" % len(self._checked_items))
     
-    def get_value(self):
+    def _get_value(self):
         if not self._checked_items:
             self._checked_items = sorted([row[0] for row in self.model if row[1]])
             self._update_total()
         return self._checked_items
     
-    def set_value(self, value):
+    def _set_value(self, value):
         self._checked_items = []
         try:
             for row in self.model:
@@ -606,10 +651,10 @@
         self.widget.set_label(self.title)
         self.widget.connect("toggled", self._value_changed)
     
-    def get_value(self):
+    def _get_value(self):
         return self.widget.get_active()
     
-    def set_value(self, value):
+    def _set_value(self, value):
         self.widget.set_active(bool(value))
 
 

Modified: trunk/conduit/gtkui/Makefile.am
==============================================================================
--- trunk/conduit/gtkui/Makefile.am	(original)
+++ trunk/conduit/gtkui/Makefile.am	Sun Feb 15 06:13:27 2009
@@ -2,7 +2,7 @@
 conduit_PYTHON = \
 	Canvas.py \
 	ConfigContainer.py \
-	ConfigWidgets.py \
+	ConfigItems.py \
 	ConflictResolver.py \
 	Database.py \
 	__init__.py \



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