home *** CD-ROM | disk | FTP | other *** search
/ PC Welt 2006 November (DVD) / PCWELT_11_2006.ISO / casper / filesystem.squashfs / usr / lib / python2.4 / site-packages / serpentine / gaw.py < prev    next >
Encoding:
Python Source  |  2006-08-23  |  13.2 KB  |  387 lines

  1. # Copyright (C) 2004 Tiago Cogumbreiro <cogumbreiro@users.sf.net>
  2. #
  3. # This library is free software; you can redistribute it and/or
  4. # modify it under the terms of the GNU Library General Public
  5. # License as published by the Free Software Foundation; either
  6. # version 2 of the License, or (at your option) any later version.
  7. #
  8. # This library is distributed in the hope that it will be useful,
  9. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  11. # Library General Public License for more details.
  12. #
  13. # You should have received a copy of the GNU Library General Public
  14. # License along with this library; if not, write to the
  15. # Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  16. # Boston, MA 02111-1307, USA.
  17. #
  18. # Authors: Tiago Cogumbreiro <cogumbreiro@users.sf.net>
  19. """
  20. GConf Widget Persistency is a module for maintaining persistency between your
  21. existing widgets and the GConf keys. Not only it forces the schema you've
  22. defined for the key but also preserves the widget state, for example making it
  23. insensitive when the GConf key is insensitive.
  24.  
  25. It also implements a representation of a gconf key (GConfValue) that handles
  26. the repetitive hassles of a maintaining its integrity. 
  27. """
  28. import gconf, gobject
  29.  
  30. class Spec (object):
  31.     def __init__ (self, name, gconf_type, py_type, default):
  32.         self.__gconf_type = gconf_type
  33.         self.__py_type = py_type
  34.         self.__default = default
  35.         self.__name = name
  36.     
  37.     gconf_type = property (lambda self: self.__gconf_type)
  38.     py_type = property (lambda self: self.__py_type)
  39.     default = property (lambda self: self.__default)
  40.     name = property (lambda self: self.__name)
  41.  
  42. Spec.STRING = Spec ("string", gconf.VALUE_STRING, str, '')
  43. Spec.FLOAT = Spec ("float", gconf.VALUE_FLOAT, float, 0.0)
  44. Spec.INT = Spec ("int", gconf.VALUE_INT, int, 0)
  45. Spec.BOOL = Spec ("bool", gconf.VALUE_BOOL, bool, True)
  46.  
  47.  
  48. def data_file_chooser (button, key, use_directory = False, use_uri = True, default = None, client = None):
  49.     """
  50.     Returns a gaw.Data.
  51.     
  52.     use_directory - boolean variable setting if it's we're using files or directories.
  53.     use_uri - boolean variable setting if we're using URI's or normal filenames.
  54.     
  55.     Associates a gaw.Data to a gtk.FileChooserButton. 
  56.     """
  57.     if not use_directory and not use_uri:
  58.         getter = button.get_filename
  59.         setter = button.set_filename
  60.     elif not use_directory and use_uri:
  61.         getter = button.get_uri
  62.         setter = button.set_uri
  63.     elif use_directory and not use_uri:
  64.         getter = button.get_current_folder
  65.         setter = button.set_current_folder
  66.     elif use_directory and use_uri:
  67.         getter = button.get_current_folder_uri
  68.         setter = button.set_current_folder_uri
  69.         
  70.     return Data (button, getter, setter, "selection-changed", GConfValue (key, Spec.STRING, default = default, client = client))
  71.  
  72. def data_entry (entry, key, data_spec = Spec.STRING, default = None, client = None):
  73.     return Data (entry, entry.get_text, entry.set_text, "changed", GConfValue (key, data_spec, default, client))
  74.  
  75. def data_spin_button (spinbutton, key, use_int = True, default = None, client = None):
  76.     if use_int:
  77.         return Data (spinbutton, spinbutton.get_value_as_int, spinbutton.set_value, "value-changed", GConfValue (key, Spec.INT, default, client))
  78.     else:
  79.         return Data (spinbutton, spinbutton.get_value, spinbutton.set_value, "value-changed", GConfValue (key, Spec.FLOAT, default, client))
  80.  
  81. def data_toggle_button (toggle, key, default = None, client = None):
  82.     return Data (toggle, toggle.get_active, toggle.set_active, "toggled", GConfValue (key, Spec.BOOL, default, client))
  83.  
  84. class GConfValue (object):
  85.     """
  86.     The GConfValue represents the GConf key's data. You define a certain schema
  87.     (or type of data) and GConfValue keeps track of its integrity. It adds the
  88.     possibility to define a default value to be used when the key is inexistent
  89.     or contains an invalid data type. You can also define callbacks that notify
  90.     you when the key is altered.
  91.     
  92.     Taken from http://s1x.homelinux.net/documents/gaw_intro :
  93.         import gaw, gconf, gtk
  94.         gconf.client_get_default ().add_dir ("/apps/gaw", gconf.CLIENT_PRELOAD_NONE)
  95.  
  96.         key_str = gaw.GConfValue (
  97.           key = "/apps/gaw/key_str",
  98.           data_spec = gaw.Spec.STRING
  99.         )
  100.  
  101.         def on_changed (*args):
  102.           global key_str
  103.           print key_str.key, "=", key_str.data
  104.           gtk.main_quit ()
  105.           
  106.         tmp.set_callback (on_changed)
  107.         tmp.data = "Hello world"
  108.  
  109.         gtk.main ()
  110.     """
  111.     def __init__ (self, key, data_spec, default = None, client = None):
  112.         if not client:
  113.             client = gconf.client_get_default ()
  114.  
  115.         self.client = client
  116.     
  117.         self.key = key
  118.         
  119.         self.data_spec = data_spec
  120.         
  121.         # init the source id
  122.         self.__notify_id = None
  123.         
  124.         if default is not None:
  125.             self.default = default
  126.  
  127.     
  128.     # Returns the appropriate method which is bound to the GConfClient object
  129.     __setter = property (
  130.         # fget
  131.         lambda self: getattr (
  132.             self.client,
  133.             "set_" + self.data_spec.name
  134.         )
  135.     )
  136.     
  137.     def __get_data (self):
  138.         val = self.client.get (self.key)
  139.         if val is None:
  140.             return self.get_default ()
  141.         
  142.         return getattr (val, "get_" + self.data_spec.name)()
  143.     
  144.     
  145.     # The real getter and setter methods encapsulate the key
  146.     data = property (
  147.         fget = __get_data,#lambda self: self.__getter (self.key),
  148.         fset = lambda self, value: self.__setter (self.key, value)
  149.     )
  150.     
  151.     def set_callback (self, on_changed):
  152.         assert on_changed is None or callable (on_changed)
  153.         
  154.         if self.__notify_id is not None:
  155.             self.client_notify_remove (self.__notify_id)
  156.             self.__notify_id = None
  157.         
  158.         if on_changed is not None:
  159.             self.__notify_id = self.client.notify_add (
  160.                 self.key,
  161.                 on_changed
  162.             )
  163.     
  164.     def __del__ (self):
  165.         self.set_callback (None)
  166.     
  167.     def reset_default (self):
  168.         self.data = self.data_spec.default
  169.  
  170.     def get_default (self):
  171.         return getattr (self, "default", self.data_spec.default)
  172.  
  173. class RadioButtonData:
  174.     """A radio_group is a dictionary that associates a gconf boolean key
  175.     with a radio button.
  176.     data = RadioButtonData (
  177.         {
  178.             'cheese': cheese_btn,
  179.             'ham': ham_btn,
  180.             'fish': fish_btn
  181.         },
  182.     )
  183.     data.selected_by_default = 'ham'
  184.     
  185.     selected_value = data.data
  186.     data.data = 'fish'
  187.     """
  188.     
  189.     selected_by_default = None
  190.     
  191.     def __init__ (self, widgets, key, client = None):
  192.         self.widgets = widgets
  193.         self.keys = {}
  194.         self.gconf_value = GConfValue (key, Spec.STRING, client)
  195.         self.gconf_value.set_callback (self.__on_gconf_changed)
  196.         
  197.         notify_widget = False
  198.         for key, widget in widgets.iteritems ():
  199.             if not notify_widget:
  200.                 widget.connect ("toggled", self.__on_widget_changed)
  201.                 notify_widget = True
  202.             widget.connect ("destroy", self.__on_destroy)
  203.  
  204.             self.keys[widget] = key
  205.             
  206.         self.sync_widget ()
  207.         
  208.     def __on_destroy (self, widget):
  209.         key = self.keys[widget]
  210.         del self.widgets[key]
  211.         # Set the widget to none so that the key still exists
  212.         self.keys[widget] = None
  213.         
  214.     def _get_active (self):
  215.         for radio in self.keys:
  216.             if radio is not None and radio.get_active ():
  217.                 return radio
  218.         return None
  219.     
  220.     def __on_widget_changed (self, radio_button):
  221.         # Update gconf entries
  222.         self.sync_gconf ()
  223.         
  224.     def __on_gconf_changed (self, client, conn_id, entry, user_data):
  225.         
  226.         data_spec = self.gconf_value.data_spec
  227.  
  228.         for widget in self.keys:
  229.             widget.set_sensitive (client.key_is_writable (self.gconf_value.key))
  230.             
  231.         if entry.value is None or entry.value.type != data_spec.gconf_type:
  232.             self.sync_gconf ()
  233.  
  234.         else:
  235.             self.sync_widget ()
  236.             
  237.     def sync_widget (self):
  238.         key = self.gconf_value.data
  239.         
  240.         if key in self.widgets:
  241.             # value is in radio group
  242.             self.widgets[key].set_active (True)
  243.         
  244.         else:
  245.             # When there is a default value, set it
  246.             if self.selected_by_default is not None:
  247.                 self.data = self.selected_by_default
  248.             
  249.             # Otherwise deselect all entries
  250.             active = self._get_active ()
  251.             if active is not None:
  252.                 # Unset the active radio button
  253.                 active.set_active (False)
  254.         self.sync_gconf ()
  255.     
  256.     def sync_gconf (self):
  257.         active = self._get_active ()
  258.         if active is not None:
  259.             self.gconf_value.data = self.keys[active]
  260.         else:
  261.             self.gconf_value.reset_default ()
  262.         
  263.     def __set_data (self, value):
  264.         self.sync_gconf ()
  265.         self.gconf_value = value
  266.         
  267.     def __get_data (self):
  268.         self.sync_gconf ()
  269.         return self.gconf_value.data
  270.     
  271.     data = property (__get_data, __set_data)
  272.     
  273. class Data (object):
  274.     """
  275.     This utility class acts as a synchronizer between a widget and gconf entry.
  276.     This data is considered to have problematic backends, since widgets can be
  277.     destroyed and gconf can have integrity problems (for example permissions or
  278.     schema change).
  279.     
  280.     To use the gaw.Data object you just need to specify it's associated type
  281.     (the schema) and optionally a default value.
  282.     
  283.     Here's a simple example on how to use it (taken from http://s1x.homelinux.net/documents/gaw_intro): 
  284.     
  285.             
  286.     """
  287.     
  288.     def __init__ (self, widget, widget_getter, widget_setter, changed_signal, gconf_value):
  289.         self.__widget = widget
  290.         self.__widget_setter = widget_setter
  291.         self.__widget_getter = widget_getter
  292.         self.__gconf_value = gconf_value
  293.         
  294.         gconf_value.set_callback (self.__on_gconf_changed)
  295.  
  296.         widget.connect (changed_signal, self.__on_widget_changed)
  297.         widget.connect ("destroy", self.__on_destroy)
  298.  
  299.         if self.widget is not None:
  300.             self.sync_widget ()
  301.     
  302.     gconf_value = property (lambda self: self.__gconf_value)
  303.     widget = property (lambda self: self.__widget)
  304.     
  305.     def __get_data (self):
  306.         # policy is widget has the most up to date data, so update gconf key
  307.         
  308.         try:
  309.             # GConf is always our data resource, get data from there
  310.             return self.gconf_value.data
  311.         except gobject.GError:
  312.  
  313.             if self.widget is not None:
  314.                 # we had an error retrieving the error, return widget value
  315.                 val = self.__widget_getter ()
  316.             else:
  317.                 # no widget return default
  318.                 return self.gconf_value.get_default ()
  319.     
  320.     def __set_data (self, data):
  321.         assert isinstance (data, self.gconf_value.data_spec.py_type)
  322.         try:
  323.             self.gconf_value.data = data
  324.         except gobject.GError:
  325.             # when something goes wrong there's nothing we can do about it
  326.             pass
  327.  
  328.     data = property (__get_data, __set_data, None, "The data contained in this component.")
  329.  
  330.     def __on_destroy (self, widget):
  331.         self.__widget = None
  332.         
  333.     def __on_widget_changed (self, *args):
  334.         if self.widget is None:
  335.             return
  336.         self.sync_gconf ()
  337.             
  338.     def __on_gconf_changed (self, client, conn_id, entry, user_data = None):
  339.  
  340.         if self.widget is None:
  341.             return
  342.         
  343.         data_spec = self.gconf_value.data_spec
  344.         
  345.         self.widget.set_sensitive (client.key_is_writable (self.gconf_value.key))
  346.         if entry.value and entry.value.type == data_spec.gconf_type:
  347.             converter = getattr (entry.value, 'get_' + data_spec.name)
  348.             self.__widget_setter (converter ())
  349.             
  350.         else:
  351.             self.__widget_setter (self.gconf_value.get_default())
  352.             
  353.         # Because widgets can validate data, sync the gconf entry again
  354.         self.sync_gconf()
  355.     
  356.     def sync_widget (self):
  357.         """
  358.         Synchronizes the widget in favour of the gconf key. You must check if
  359.         there is a valid widget before calling this method.
  360.         """
  361.         assert self.widget, "Checking if there's a valid widget is a prerequisite."
  362.         try:
  363.             val = self.gconf_value.data
  364.  
  365.             if val:
  366.                 self.__widget_setter (val)
  367.  
  368.         except gobject.GError:
  369.  
  370.             self.__widget_setter (self.gconf_value.get_default ())
  371.         # Because some widgets change the value, update it to gconf again
  372.         self.sync_gconf ()
  373.     
  374.     def sync_gconf (self):
  375.         """
  376.         Synchronizes the gconf key in favour of the widget. You must check if
  377.         there is a valid widget before calling this method.
  378.         """
  379.         assert self.widget, "Checking if there's a valid widget is a prerequisite."
  380.         val = self.__widget_getter ()
  381.         try:
  382.             self.gconf_value.data = val
  383.             self.__widget_setter (self.gconf_value.data)
  384.             
  385.         except gobject.GError:
  386.             pass
  387.