"Fossies" - the Fresh Open Source Software Archive

Member "pysize-0.2/pysize/ui/gtk/gazpacho_loader/custom.py" (11 Mar 2007, 33937 Bytes) of package /linux/privat/old/pysize-0.2.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file.

    1 # Copyright (C) 2005 Johan Dahlin
    2 #
    3 # This program is free software; you can redistribute it and/or
    4 # modify it under the terms of the GNU Lesser General Public License
    5 # as published by the Free Software Foundation; either version 2
    6 # of the License, or (at your option) any later version.
    7 #
    8 # This program 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
   11 # GNU General Public License for more details.
   12 #
   13 # You should have received a copy of the GNU Lesser General Public License
   14 # along with this program; if not, write to the Free Software
   15 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
   16 
   17 import gobject
   18 import gtk
   19 from gtk import gdk
   20 
   21 def enumfromstring(value_name, pspec=None, enum=None):
   22     if not value_name:
   23         return 0
   24 
   25     try:
   26         value = int(value_name)
   27     except ValueError:
   28         if pspec:
   29             enum_class = pspec.enum_class
   30             if enum_class is None:
   31                 return 0
   32         elif enum:
   33             enum_class = enum
   34         else:
   35             raise ValueError("Need pspec or enm")
   36 
   37         for value, enum in enum_class.__enum_values__.items():
   38             if value_name in (enum.value_name, enum.value_nick):
   39                 return value
   40 
   41     raise ValueError("Invalid enum value: %r" % value_name)
   42 
   43 def flagsfromstring(value_name, pspec=None, flags=None):
   44     if not value_name:
   45         return 0
   46 
   47     try:
   48         return int(value_name)
   49     except ValueError:
   50         pass
   51 
   52     value_names = [v.strip() for v in value_name.split('|')]
   53 
   54     if pspec:
   55         flags_class = pspec.flags_class
   56     elif flags:
   57         flags_class = flags
   58     else:
   59         raise ValueError("need pspec or flags")
   60 
   61     flag_values = flags_class.__flags_values__
   62     new_value = 0
   63     for mask, flag in flag_values.items():
   64         if (flag.value_names[0] in value_names or
   65             flag.value_nicks[0] in value_names):
   66             new_value |= mask
   67 
   68     return new_value
   69 
   70 def valuefromstringsimpletypes(gtype, string):
   71     if gtype in (gobject.TYPE_CHAR, gobject.TYPE_UCHAR):
   72         value = string[0]
   73     elif gtype == gobject.TYPE_BOOLEAN:
   74         value = str2bool(string)
   75     elif gtype in (gobject.TYPE_INT, gobject.TYPE_UINT):
   76         value = int(string)
   77     elif gtype in (gobject.TYPE_LONG, gobject.TYPE_ULONG):
   78         value = long(string)
   79     elif gtype in (gobject.TYPE_FLOAT, gobject.TYPE_DOUBLE):
   80         value = float(string)
   81     elif gtype == gobject.TYPE_STRING:
   82         value = string
   83     elif gobject.type_is_a(gtype, gobject.TYPE_PYOBJECT):
   84         value = string
   85     elif gobject.type_is_a(gtype, gobject.GBoxed):
   86         print 'TODO: boxed'
   87         value = None
   88     else:
   89         raise TypeError("type %r is unknown" % gtype)
   90 
   91     return value
   92 
   93 def str2bool(value):
   94     return value[0].lower() in ('t', 'y') or value == '1'
   95 
   96 def get_child_pspec_from_name(gtype, name):
   97     for pspec in gtk.container_class_list_child_properties(gtype):
   98         if pspec.name == name:
   99             return pspec
  100 
  101 def get_pspec_from_name(gtype, name):
  102     for pspec in gobject.list_properties(gtype):
  103         if pspec.name == name:
  104             return pspec
  105 
  106 class AdapterMeta(type):
  107     def __new__(mcs, name, bases, dict):
  108         t = type.__new__(mcs, name, bases, dict)
  109         t.add_adapter()
  110         return t
  111 
  112 class IObjectAdapter:
  113     """This interface is used by the loader to build
  114     a custom object.
  115 
  116     object_type is a GType representing which type we can construct
  117     """
  118     object_type = None
  119 
  120     def construct(self, name, properties):
  121         """constructs a new type of type gtype
  122         name:  string representing the type name
  123         gtype: gtype of the object to be constructed
  124         properties: construct properties
  125         """
  126         pass
  127 
  128     def add(self, gobj, child, properties, type):
  129         """Adds a child to gobj with properties"""
  130         pass
  131 
  132     def get_properties(self, gtype, obj_id, properties):
  133         pass
  134 
  135     def set_properties(self, gobj, properties):
  136         pass
  137 
  138     def prop_set_NAME(self, widget, value_string):
  139         """
  140         Sets the property NAME for widget, note that you have to convert
  141         from a string manully"""
  142         pass
  143 
  144     def find_internal_child(self, gobj, name):
  145         """Returns an internal child"""
  146 
  147     def get_internal_child_name(self, gobj, child):
  148         """
  149         Returns the name of a widget, as an internal child or None
  150         if it cannot be found
  151         """
  152 
  153 class Adapter(object):
  154     __metaclass__ = AdapterMeta
  155     _adapters = []
  156     _properties = {}
  157 
  158     def __init__(self, build):
  159         self._build = build
  160 
  161     def get_raw_property(self, object, name):
  162         object_id = object.get_data('gazpacho::object-id')
  163         if not object_id in self._properties:
  164             raise KeyError(object_id)
  165         return self._properties[object_id][name]
  166 
  167     def add_adapter(cls):
  168         if cls.__name__ != 'Adapter':
  169             cls._adapters.append(cls)
  170     add_adapter = classmethod(add_adapter)
  171 
  172     def get_adapters(cls):
  173         return cls._adapters
  174     get_adapters = classmethod(get_adapters)
  175 
  176 class AdapterRegistry:
  177     def __init__(self):
  178         # GObject typename -> adapter instance
  179         self._adapters = {}
  180 
  181         for adapter in Adapter.get_adapters():
  182             self.register_adapter(adapter)
  183 
  184     def _add_adapter(self, name, adapter):
  185         self._adapters[name] = adapter
  186 
  187     def register_adapter(self, adapter):
  188         adict = adapter.__dict__
  189         # Do not register abstract adapters
  190         if adict.has_key('object_type'):
  191             object_type = adict.get('object_type')
  192             if type(object_type) != tuple:
  193                 object_type = object_type,
  194 
  195             for klass in object_type:
  196                 self._add_adapter(gobject.type_name(klass), adapter)
  197         elif adict.has_key('object_name'):
  198             self._add_adapter(adict.get('object_name'), adapter)
  199 
  200     def get_adapter(self, gobj, type_name=None, build=None):
  201         # Name is optional, for performance reasons we want
  202         # to send it as often as we can, normally it's already
  203         # known at the callsite.
  204         if type_name == None:
  205             type_name = gobject.type_name(gobj)
  206         orig_name = type_name
  207 
  208         while True:
  209             adapter = self._adapters.get(type_name)
  210             if adapter:
  211                 # Store a reference for the adapter, to make the
  212                 # next lookup faster
  213                 self._adapters[orig_name] = adapter
  214                 return adapter(build)
  215 
  216             gobj = gobject.type_parent(gobj)
  217             type_name = gobject.type_name(gobj)
  218 
  219 class GObjectAdapter(Adapter):
  220     object_type = gobject.GObject
  221     child_names = []
  222     def construct(self, name, gtype, properties):
  223         # Due to a bug in gobject.new() we only send in construct
  224         # only properties here, the rest are set normally
  225         gobj = gobject.new(gtype, **properties)
  226         return gobj
  227 
  228     def get_properties(self, gtype, obj_id, properties):
  229         return self._getproperties(gtype, obj_id, properties)
  230 
  231     def set_properties(self, gobj, properties):
  232         prop_names = []
  233         for name, value in properties:
  234             #print '%s.%s = %r' % (gobject.type_name(gobj), name, value)
  235             func_name = 'prop_set_%s' % name.replace('-', '_')
  236             func = getattr(self, func_name, None)
  237             if func:
  238                 func(gobj, value)
  239             else:
  240                 gobj.set_property(name, value)
  241 
  242             prop_names.append(name)
  243 
  244         gobj.set_data('gobject.changed_properties', prop_names)
  245 
  246     def _getproperties(self, gtype, obj_id, properties, child=False):
  247         if child:
  248             get_pspec = get_child_pspec_from_name
  249         else:
  250             get_pspec = get_pspec_from_name
  251 
  252         propdict = self._properties
  253         if not propdict.has_key(obj_id):
  254             props = propdict[obj_id] = {}
  255         else:
  256             props = propdict[obj_id]
  257 
  258         construct = {}
  259         normal = []
  260         for prop in properties:
  261             propname = prop.name.replace('_', '-')
  262             #full = '%s::%s' % (gobject.type_name(gtype), propname)
  263             props[prop.name] = prop.data
  264             if hasattr(self, 'prop_set_%s' % prop.name):
  265                 normal.append((prop.name, prop.data))
  266                 continue
  267 
  268             pspec = get_pspec(gtype, propname)
  269             if not pspec:
  270                 print ('Unknown property: %s:%s (id %s)' %
  271                        (gobject.type_name(gtype),
  272                         prop.name,
  273                         obj_id))
  274                 continue
  275 
  276             try:
  277                 value = self._valuefromstring(obj_id, pspec, prop.data)
  278             except ValueError:
  279                 print ("Convertion failed for %s:%s (id %s), "
  280                        "expected %s but found %r" %
  281                        (gobject.type_name(gtype),
  282                         prop.name,
  283                         obj_id,
  284                         gobject.type_name(pspec.value_type),
  285                         prop.data))
  286                 continue
  287 
  288             # Could not
  289             if value is None:
  290                 continue
  291 
  292             if pspec.flags & gobject.PARAM_CONSTRUCT_ONLY != 0:
  293                 construct[pspec.name] = value
  294             else:
  295                 normal.append((pspec.name, value))
  296 
  297         if child:
  298             assert not construct
  299             return normal
  300 
  301         return construct, normal
  302 
  303     def _valuefromstring(self, obj_id, pspec, string):
  304         # This is almost a 1:1 copy of glade_xml_set_value_from_string from
  305         # libglade.
  306         prop_type = pspec.value_type
  307 
  308         if (prop_type in (gobject.TYPE_INT, gobject.TYPE_UINT)
  309             and gobject.type_name(pspec) == 'GParamUnichar'):
  310             value = unicode(string and string[0] or "")
  311             return value
  312 
  313         try:
  314             value = valuefromstringsimpletypes(prop_type, string)
  315         except TypeError:
  316             pass # it's ok if we fail so far, we'll try other types
  317         else:
  318             return value
  319 
  320         if gobject.type_is_a(prop_type, gobject.TYPE_ENUM):
  321             value = enumfromstring(string, pspec)
  322         elif gobject.type_is_a(prop_type, gobject.TYPE_FLAGS):
  323             value = flagsfromstring(string, pspec)
  324         elif gobject.type_is_a(prop_type, gobject.GObject):
  325             if gobject.type_is_a(prop_type, gtk.Adjustment):
  326                 value = gtk.Adjustment(0, 0, 100, 1, 10, 10)
  327                 (value.value, value.lower, value.upper,
  328                  value.step_increment, value.page_increment,
  329                  value.page_size) = map(float, string.split(' '))
  330             elif gobject.type_is_a(prop_type, gdk.Pixbuf):
  331                 filename = self._build.find_resource(string)
  332                 value = None
  333                 if filename:
  334                     # XXX: Handle GError exceptions.
  335                     value = gdk.pixbuf_new_from_file(filename);
  336             elif (gobject.type_is_a(gobject.GObject, prop_type) or
  337                   gobject.type_is_a(prop_type, gobject.GObject)):
  338                 value = self._build.get_widget(string)
  339                 if value is None:
  340                     self._build.add_delayed_property(obj_id, pspec, string)
  341             else:
  342                 value = None
  343         else:
  344             raise AssertionError("type %r is unknown" % prop_type)
  345 
  346         return value
  347 
  348     def add(self, parent, child, properties, type):
  349         raise NotImplementedError
  350 
  351     def find_internal_child(self, gobj, name):
  352         if name in self.child_names:
  353             return getattr(gobj, name)
  354 
  355     def get_internal_child_name(self, gobj, child):
  356         for child_name in self.child_names:
  357             if getattr(gobj, child_name) == child:
  358                 return child_name
  359 
  360 class UIManagerAdapter(GObjectAdapter):
  361     object_type = gtk.UIManager
  362     def add(self, parent, child, properties, type):
  363         parent.insert_action_group(child, 0)
  364 
  365 class WidgetAdapter(GObjectAdapter):
  366     object_type = gtk.Widget
  367     def construct(self, name, gtype, properties):
  368         widget = GObjectAdapter.construct(self, name, gtype, properties)
  369         widget.set_name(name)
  370         return widget
  371 
  372     def prop_set_has_default(self, widget, value):
  373         value = str2bool(value)
  374         if value:
  375             self._build._default_widget = widget
  376 
  377     def prop_set_tooltip(self, widget, value):
  378         if isinstance(widget, gtk.ToolItem):
  379             # XXX: factor to separate Adapter
  380             widget.set_tooltip(self._build._tooltips, value, None)
  381         else:
  382             self._build._tooltips.set_tip(widget, value, None)
  383 
  384     def prop_set_visible(self, widget, value):
  385         value = str2bool(value)
  386         widget.set_data('gazpacho::visible', value)
  387         widget.set_property('visible', value)
  388 
  389     def prop_set_has_focus(self, widget, value):
  390         value = str2bool(value)
  391         if value:
  392             self._build._focus_widget = widget
  393         widget.set_data('gazpacho::has-focus', value)
  394 
  395     def prop_set_is_focus(self, widget, value):
  396         value = str2bool(value)
  397         widget.set_data('gazpacho::is-focus', value)
  398 
  399     def prop_set_sizegroup(self, widget, value):
  400         widget.set_data('gazpacho::sizegroup', value)
  401 
  402     def prop_set_response_id(self, widget, value):
  403         widget.set_data('gazpacho::response-id', int(value))
  404 
  405 class PythonWidgetAdapter(WidgetAdapter):
  406     def construct(self, name, gtype, properties):
  407         obj = self.object_type()
  408         obj.set_name(name)
  409         return obj
  410 
  411 class ContainerAdapter(WidgetAdapter):
  412     object_type = gtk.Container
  413     def add(self, container, child, properties, type):
  414         if not self._add_to_dialog(container, child):
  415             container.add(child)
  416 
  417         self._set_child_properties(container, child, properties)
  418 
  419     def _add_to_dialog(self, parent, widget):
  420         response_id = widget.get_data('gazpacho::response-id')
  421         if response_id is not None:
  422             dialog = None
  423             while parent:
  424                 if isinstance(parent, gtk.Dialog):
  425                     dialog = parent
  426                     break
  427                 parent = parent.parent
  428 
  429             if dialog:
  430                 # FIXME: Limit to action_area
  431                 dialog.add_action_widget(widget, response_id)
  432 
  433                 # Reset, the real properties will be set afterwards
  434                 widget.parent.set_child_packing(widget, True, True, 0,
  435                                                 gtk.PACK_START)
  436                 return True
  437         return False
  438 
  439     def _set_child_properties(self, container, child, properties):
  440         properties = self._getproperties(type(container),
  441                                          child.get_name(),
  442                                          properties,
  443                                          child=True)
  444 
  445         for name, value in properties:
  446             #print '%s.%s = %r (of %s)' % (child.get_name(), name, value,
  447             #                              gobj.get_name())
  448             container.child_set_property(child, name, value)
  449 
  450 class ActionGroupAdapter(GObjectAdapter):
  451     object_type = gtk.ActionGroup
  452     def construct(self, name, gtype, properties):
  453         if not properties.has_key('name'):
  454             properties['name'] = name
  455         return GObjectAdapter.construct(self, name, gtype, properties)
  456 
  457     def add(self, parent, child, properties, type):
  458         accel_key = child.get_data('accel_key')
  459         if accel_key:
  460             accel_path = "<Actions>/%s/%s" % (parent.get_property('name'),
  461                                               child.get_name())
  462             accel_mod = child.get_data('accel_mod')
  463             gtk.accel_map_add_entry(accel_path, accel_key, accel_mod)
  464             child.set_accel_path(accel_path)
  465             child.set_accel_group(self._build.ensure_accel())
  466         parent.add_action(child)
  467 
  468 class ActionAdapter(GObjectAdapter):
  469     object_type = gtk.Action
  470     def construct(self, name, gtype, properties):
  471         # Gazpacho doesn't save the name for actions
  472         # So we have set it manually.
  473         if not properties.has_key('name'):
  474             properties['name'] = name
  475 
  476         return GObjectAdapter.construct(self, name, gtype, properties)
  477 
  478     def _set_accel(self, action, accel_key, accel_mod):
  479         if not accel_key:
  480             return
  481 
  482         action.set_data('accel_key', accel_key)
  483         action.set_data('accel_mod', accel_mod)
  484 
  485     def prop_set_accelerator(self, action, value):
  486         if not value:
  487             return
  488         self._set_accel(action, *gtk.accelerator_parse(value))
  489 
  490     def prop_set_stock_id(self, action, value):
  491         action.set_property('stock-id', value)
  492 
  493         # Set the accelerator from the stock item, but only if it's
  494         # not set already
  495         if action.get_data('accel_key'):
  496             return
  497 
  498         # FIXME: Should we print a warning if it cannot be found
  499         stock_item = gtk.stock_lookup(value)
  500         if stock_item:
  501             self._set_accel(action, stock_item[3], stock_item[2])
  502 
  503     # This is for backwards compatibility
  504     def prop_set_callback(self, action, value):
  505         if value:
  506             self._build.add_signal(action, 'activate', value)
  507 
  508 class PixmapAdapter(WidgetAdapter):
  509     object_type = gtk.Pixmap
  510     def prop_set_build_insensitive(self, pixmap, value):
  511         pixmap.set_build_insensitive(str2bool(value))
  512 
  513     def prop_set_filename(self, pixmap, value):
  514         filename = self._build.find_resource(value);
  515         if not filename:
  516             print 'No such a file or directory: %s' % value
  517             return
  518 
  519         try:
  520             pb = gdk.pixbuf_new_from_file(filename)
  521         except gobject.GError, e:
  522             print 'Error loading pixmap: %s' % e.message
  523             return
  524         except TypeError, e:
  525             print 'Error loading pixmap: %s' % e
  526             return
  527 
  528         pix, bit = pb.render_pixmap_and_mask(127)
  529         pixmap.set(pix, bit)
  530 
  531 class ProgressAdapter(WidgetAdapter):
  532     object_type = gtk.Progress
  533     def prop_set_format(self, progress, value):
  534         progress.set_format_string(value)
  535 
  536 class ButtonAdapter(ContainerAdapter):
  537     object_type = gtk.Button
  538 
  539 class OptionMenuAdapter(ButtonAdapter):
  540     object_type = gtk.OptionMenu
  541     def add(self, parent, child, properties, type):
  542         if not isinstance(child, gtk.Menu):
  543             print ("warning: the child of the option menu '%s' was "
  544                    "not a GtkMenu"  % (child.get_name()))
  545             return
  546 
  547         parent.set_menu(child)
  548         self._set_child_properties(parent, child, properties)
  549 
  550     def prop_set_history(self, optionmenu, value):
  551         optionmenu.set_history(int(value))
  552 
  553 class EntryAdapter(WidgetAdapter):
  554     object_type = gtk.Entry
  555     def prop_set_invisible_char(self, entry, value):
  556         entry.set_invisible_char(value.decode()[0])
  557 
  558 class TextViewAdapter(ButtonAdapter):
  559     object_type = gtk.TextView
  560     def prop_set_text(self, textview, value):
  561         buffer = gtk.TextBuffer()
  562         buffer.set_text(value)
  563         textview.set_buffer(buffer)
  564 
  565 class CalendarAdapter(WidgetAdapter):
  566     object_type = gtk.Calendar
  567     def prop_set_display_options(self, calendar, value):
  568         options = flagsfromstring(value, flags=gtk.CalendarDisplayOptions)
  569         calendar.display_options(options)
  570 
  571 class WindowAdapter(ContainerAdapter):
  572     object_type = gtk.Window
  573     def prop_set_wmclass_class(self, window, value):
  574         window.set_wmclass(value, window.wmclass_class)
  575 
  576     def prop_set_wmclass_name(self, window, value):
  577         window.set_wmclass(value, window.wmclass_name)
  578 
  579     def prop_set_type_hint(self, window, value):
  580         window.set_data('gazpacho::type-hint',
  581                         enumfromstring(value, enum=gdk.WindowTypeHint))
  582 
  583 class NotebookAdapter(ContainerAdapter):
  584     object_type = gtk.Notebook
  585     def add(self, notebook, child, properties, type):
  586         tab_item = False
  587         for propinfo in properties[:]:
  588             if (propinfo.name == 'type' and
  589                 propinfo.data == 'tab'):
  590                 tab_item = True
  591                 properties.remove(propinfo)
  592                 break
  593 
  594         if tab_item:
  595             children = notebook.get_children()
  596             body = notebook.get_nth_page(len(children) - 1)
  597             notebook.set_tab_label(body, child)
  598         else:
  599             notebook.append_page(child)
  600 
  601         self._set_child_properties(notebook, child, properties)
  602 
  603 class ExpanderAdapter(ContainerAdapter):
  604     object_type = gtk.Expander, gtk.Frame
  605     def _get_label_item(self, properties):
  606         for propinfo in properties[:]:
  607             if (propinfo.name == 'type' and
  608                 propinfo.data == 'label_item'):
  609                 properties.remove(propinfo)
  610                 return True
  611         return False
  612 
  613     def add(self, expander, child, properties, type):
  614         if self._build._version == 'libglade':
  615             label_item = self._get_label_item(properties)
  616         elif type == 'label_item':
  617             label_item = True
  618         else:
  619             label_item = False
  620 
  621         if label_item:
  622             expander.set_label_widget(child)
  623         else:
  624             expander.add(child)
  625 
  626         self._set_child_properties(expander, child, properties)
  627 
  628 class MenuItemAdapter(ContainerAdapter):
  629     object_type = gtk.MenuItem
  630     def add(self, menuitem, child, properties, type):
  631         if isinstance(child, gtk.Menu):
  632             menuitem.set_submenu(child)
  633         else:
  634             print 'FIXME: Adding a %s to a %s' % (gobject.type_name(child),
  635                         gobject.type_name(self.object_type))
  636             # GtkWarning: Attempting to add a widget with type GtkImage to a
  637             # GtkImageMenuItem, but as a GtkBin subclass a GtkImageMenuItem
  638             # can only contain one widget at a time; it already contains a
  639             # widget of type GtkAccelLabel'
  640             #menuitem.add(child)
  641 
  642         self._set_child_properties(menuitem, child, properties)
  643 
  644     def prop_set_label(self, menuitem, value):
  645         child = menuitem.child
  646 
  647         if not child:
  648             child = gtk.AccelLabel("")
  649             child.set_alignment(0.0, 0.5)
  650             menuitem.add(child)
  651             child.set_accel_widget(menuitem)
  652             child.show()
  653 
  654         if isinstance(child, gtk.Label):
  655             child.set_text(value)
  656 
  657     def prop_set_use_underline(self, menuitem, value):
  658         child = menuitem.child
  659 
  660         if not child:
  661             child = gtk.AccelLabel("")
  662             child.set_alignment(0.0, 0.5)
  663             menuitem.add(child)
  664             child.set_accel_widget(menuitem)
  665             child.show()
  666 
  667         if isinstance(child, gtk.Label):
  668             child.set_use_underline(str2bool(value))
  669 
  670     def prop_set_use_stock(self, menuitem, value):
  671         child = menuitem.child
  672 
  673         if not child:
  674             child = gtk.AccelLabel("")
  675             child.set_alignment(0.0, 0.5)
  676             menuitem.add(child)
  677             child.set_accel_widget(menuitem)
  678             child.show()
  679 
  680         value = str2bool(value)
  681         if not isinstance(child, gtk.Label) or not value:
  682             return
  683 
  684         stock_id = child.get_label()
  685 
  686         retval = gtk.stock_lookup(stock_id)
  687         if retval:
  688             _, label, modifier, keyval, _ = retval
  689             # put in the stock image next to the text.  Done before
  690             # messing with the label child, so that stock_id doesn't
  691             # become invalid.
  692             if isinstance(menuitem, gtk.ImageMenuItem):
  693                 image = gtk.image_new_from_stock(stock_id, gtk.ICON_SIZE_MENU)
  694                 menuitem.set_image(image)
  695                 image.show()
  696 
  697             child.set_text(label)
  698             child.set_use_underline(True)
  699 
  700             if keyval:
  701                 # This triggers a segfault on exit (pachi.glade), weird
  702                 menuitem.add_accelerator('activate',
  703                                          self._build.ensure_accel(),
  704                                          keyval, modifier,
  705                                          gtk.ACCEL_VISIBLE)
  706         else:
  707             print "warning: could not look up stock id '%s'" % stock_id
  708 
  709 class CheckMenuItemAdapter(MenuItemAdapter):
  710     object_type = gtk.CheckMenuItem
  711     def prop_set_always_show_toggle(self, check, value):
  712         check.set_show_toggle(value)
  713 
  714 class RadioMenuItemAdapter(MenuItemAdapter):
  715     object_type = gtk.RadioMenuItem
  716     def prop_set_group(self, radio, value):
  717         group = self._build.get_widget(value)
  718         if not group:
  719             print "warning: Radio button group %s could not be found" % value
  720             return
  721 
  722         if group == radio:
  723             print "Group is self, skipping."
  724             return
  725 
  726         radio.set_group(group.get_group()[0])
  727 
  728 class ImageMenuItemAdapter(MenuItemAdapter):
  729     object_type = gtk.ImageMenuItem
  730     def find_internal_child(self, menuitem, childname):
  731         if childname == 'image':
  732             pl = menuitem.get_image()
  733             if not pl:
  734                 pl = gtk.Image()
  735                 menuitem.set_image(pl)
  736             return pl
  737         return MenuItemAdapter.find_internal_child(self, menuitem, childname)
  738 
  739     def get_internal_child_name(self, parent, child):
  740         if parent.get_image() == child:
  741             return 'image'
  742         return MenuItemAdapter.get_internal_child_name(self, parent, child)
  743 
  744 class ToolbarAdapter(ContainerAdapter):
  745     object_type = gtk.Toolbar
  746     def prop_set_tooltips(self, toolbar, value):
  747         toolbar.set_tooltips(str2bool(value))
  748 
  749 class StatusbarAdapter(ContainerAdapter):
  750     object_type = gtk.Statusbar
  751     def prop_set_has_resize_grip(self, status, value):
  752         status.set_has_resize_grip(str2bool(value))
  753 
  754 class RulerAdapter(WidgetAdapter):
  755     object_type = gtk.Ruler
  756     def prop_set_metric(self, ruler, value):
  757         ruler.set_metric(enumfromstring(value,
  758                                         enum=gtk.MetricType))
  759 
  760 class ToolButtonAdapter(ContainerAdapter):
  761     object_type = gtk.ToolButton
  762     def prop_set_icon(self, toolbutton, value):
  763         filename = self._build.find_resource(value)
  764         if not filename:
  765             print 'No such a file or directory: %s' % value
  766             return
  767 
  768         pb = gdk.pixbuf_new_from_file(filename)
  769         if not pb:
  770             print "warning: Couldn't find image file: %s" %  value
  771             return
  772         image = gtk.Image()
  773         image.set_from_pixbuf(pb)
  774         image.show()
  775         toolbutton.set_icon_widget(image)
  776 
  777 class ToggleToolButtonAdapter(ToolButtonAdapter):
  778     object_type = gtk.ToggleToolButton
  779     def prop_set_active(self, toolbutton, value):
  780         toolbutton.set_active(str2bool(value))
  781 
  782 def combobox_set_content_from_string(combobox, value):
  783     # If the "items" property is set, we create a simple model with just
  784     # one column of text.
  785     store = gtk.ListStore(str)
  786     combobox.set_model(store)
  787 
  788     # GtkComboBoxEntry creates the cell renderer itself, but we have to set
  789     # the column containing the text.
  790     if isinstance(combobox, gtk.ComboBoxEntry):
  791         if combobox.get_text_column() == -1:
  792             combobox.set_text_column(0)
  793     else:
  794         cell = gtk.CellRendererText()
  795         combobox.pack_start(cell, True)
  796         combobox.set_attributes(cell, text=0)
  797 
  798     for part in value.split('\n'):
  799         store.append([part])
  800 
  801         active = combobox.get_data('gazpacho::active')
  802         if active:
  803             combobox.set_active(active)
  804 
  805 class ComboBoxAdapter(ContainerAdapter):
  806     # FIXME: Internal child: entry -> get_child()
  807     object_type = gtk.ComboBox, gtk.ComboBoxEntry
  808     def prop_set_items(self, combobox, value):
  809         combobox_set_content_from_string(combobox, value)
  810 
  811     def prop_set_active(self, combobox, value):
  812         combobox.set_data('gazpacho::active', int(value))
  813 
  814         # We don't need to set the actual property here, it's done in
  815         # prop_set_items.
  816 
  817 # FIXME: PyGTK does not expose vscrollbar and hscrollbar.
  818 #
  819 #class ScrolledWindowAdapter(WindowAdapter):
  820 #    child_names = ['vscrollbar', 'hscrollbar']
  821 #    object_type = gtk.ScrolledWindow
  822 #    def get_internal_child_name(self, parent, child):
  823 #        if parent.vscrollbar == child:
  824 #            return 'vscrollbar'
  825 #        elif parent.hscrollbar == child:
  826 #            return 'hscrollbar'
  827 #        return WindowAdapter.get_internal_child_name(self, parent, child)
  828 
  829 class DialogAdapter(WindowAdapter):
  830     child_names = ['vbox', 'action_area']
  831     object_type = gtk.Dialog
  832     def get_internal_child_name(self, parent, child):
  833         if parent.vbox == child:
  834             return 'vbox'
  835         elif parent.action_area == child:
  836             return 'action_area'
  837         return WindowAdapter.get_internal_child_name(self, parent, child)
  838 
  839 class ColorSelectionDialogAdapter(DialogAdapter):
  840     child_names = DialogAdapter.child_names + ['ok_button',
  841                                                'cancel_button',
  842                                                'help_button',
  843                                                'colorsel']
  844     object_type = gtk.ColorSelectionDialog
  845     def find_internal_child(self, gobj, name):
  846         if name == 'color_selection':
  847             return gobj.colorsel
  848 
  849         return DialogAdapter.find_internal_child(self, gobj, name)
  850 
  851     def get_internal_child_name(self, parent, child):
  852         if parent.colorsel == child:
  853             return 'color_selection'
  854         return DialogAdapter.get_internal_child_name(self, parent, child)
  855 
  856 class FontSelectionDialogAdapter(DialogAdapter):
  857     object_type = gtk.FontSelectionDialog
  858     child_names = DialogAdapter.child_names + ['ok_button',
  859                                                'cancel_button',
  860                                                'apply_button',
  861                                                'fontsel']
  862     def find_internal_child(self, gobj, name):
  863         if name == 'font_selection':
  864             return gobj.fontsel
  865 
  866         return DialogAdapter.find_internal_child(self, gobj, name)
  867 
  868     def get_internal_child_name(self, parent, child):
  869         if parent.fontsel == child:
  870             return 'font_selection'
  871         return DialogAdapter.get_internal_child_name(self, parent, child)
  872 
  873 class TreeViewAdapter(ContainerAdapter):
  874     object_type = gtk.TreeView
  875     def add(self, treeview, child, properties, type):
  876         if not isinstance(child, gtk.TreeViewColumn):
  877             raise TypeError("Children of GtkTreeView must be a "
  878                             "GtkTreeViewColumns, not %r" % child)
  879 
  880         treeview.append_column(child)
  881 
  882         # Don't chain to Container add since children are not widgets
  883 
  884 class CellLayoutAdapter(GObjectAdapter):
  885     def set_cell_renderer_attributes(self, gobj, cell_renderer, attributes):
  886         raise NotImplementedError
  887 
  888 class TreeViewColumnAdapter(CellLayoutAdapter):
  889     object_type = gtk.TreeViewColumn
  890 
  891     def construct(self, name, gtype, properties):
  892         gobj = super(TreeViewColumnAdapter, self).construct(name, gtype,
  893                                                             properties)
  894         gobj.name = name
  895         return gobj
  896 
  897     def add(self, column, child, properties, type):
  898         if not isinstance(child, gtk.CellRenderer):
  899             raise TypeError("Children of GtkTreeViewColumn must be a "
  900                             "GtkCellRenderers, not %r" % child)
  901 
  902         expand = True
  903         pack_start = True
  904         for propinfo in properties[:]:
  905             name = propinfo.name
  906             if name == 'expand':
  907                 expand = str2bool(propinfo.data)
  908                 properties.remove(propinfo)
  909             elif name == 'pack_start':
  910                 pack_start = str2bool(propinfo.data)
  911                 properties.remove(propinfo)
  912             else:
  913                 raise AssertionError("Unknown property for "
  914                                      "GtkTreeViewColumn: %s" % name)
  915         if pack_start:
  916             column.pack_start(child, expand)
  917         else:
  918             column.pack_end(child, expand)
  919 
  920     def set_cell_renderer_attributes(self, column, cell_renderer, attributes):
  921         for name, value in attributes.items():
  922             column.add_attribute(cell_renderer, name, value)
  923 
  924         # this is ugly but's the only way to retrieve the attributes later on
  925         cell_renderer.set_data('gazpacho::attributes', attributes)
  926 
  927 # Gross hack to make it possible to use FileChooserDialog on win32.
  928 # See bug http://bugzilla.gnome.org/show_bug.cgi?id=314527
  929 class FileChooserDialogHack(gtk.FileChooserDialog):
  930     def get_children(self):
  931         return []
  932 
  933 class FileChooserDialogAdapter(DialogAdapter):
  934     gobject.type_register(FileChooserDialogHack)
  935 
  936 class ImageAdapter(WidgetAdapter):
  937     object_type = gtk.Image
  938     def prop_set_file(self, image, value):
  939         newvalue = self._build.find_resource(value)
  940         if newvalue:
  941             image.set_property('file', newvalue)
  942         image.set_data('image-file-name', value)
  943 
  944 class ListStoreAdapter(GObjectAdapter):
  945     object_type = gtk.ListStore
  946 
  947     def construct(self, name, gtype, properties):
  948         gobj = super(ListStoreAdapter, self).construct(name, gtype,
  949                                                        properties)
  950         gobj.name = name
  951         return gobj
  952 
  953     def set_column_types(self, store, columns):
  954         if columns:
  955             types = [col.type for col in columns]
  956             store.set_column_types(*types)
  957 
  958     def fill(self, store, rows):
  959         types = [store.get_column_type(i) for i in range(store.get_n_columns())]
  960         for row_info in rows:
  961             values = []
  962             for col_info in row_info.cols:
  963                 gtype = types[col_info.id]
  964                 value = valuefromstringsimpletypes(gtype, col_info.data)
  965                 values.append(value)
  966 
  967             store.append(values)
  968 
  969 # Global registry
  970 adapter_registry = AdapterRegistry()