# Kiwi: a Framework and Enhanced Widgets for Python
#
# Copyright (C) 2005,2006,2008 Async Open Source
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
# USA
#
# Author(s): Johan Dahlin <jdahlin@async.com.br>
#

import gtk

from gobject import list_properties, GObject

from kiwi.log import Logger
from kiwi.ui.objectlist import ObjectList
from kiwi.ui.widgets import checkbutton, combobox, entry, spinbutton, textview

log = Logger("builderloader")

class BuilderWidgetTree:
    KIWI_WIDGET_MAP = {
        gtk.CheckButton: checkbutton.ProxyCheckButton,
        gtk.ComboBox: combobox.ProxyComboBox,
        gtk.Entry: entry.ProxyEntry,
        gtk.SpinButton: spinbutton.ProxySpinButton,
        gtk.TextView: textview.ProxyTextView,
    }
    
    WIDGET_DATA_TYPES = {
        gtk.Entry: str,
        gtk.SpinButton: int,
        gtk.CheckButton: bool
    }

    def __init__(self, view, gladefile, domain=None):
        self._view = view
        self._gladefile = gladefile
        self._builder = gtk.Builder()
        self._builder.add_from_file(gladefile)
        
        if domain is not None:
            self._builder.set_translation_domain(domain)
        
        self._widgets = []
        
        for obj in self._builder.get_objects():
            try:
                assert obj.get_name()
            except (AttributeError, AssertionError):
                pass
            else:
                self._widgets.append(obj.get_name())
        
        self._attach_widgets()
    
    def get_widget(self, name):
        """Retrieves the named widget from the View (or glade tree)"""
        name = name.replace(".", "_")
        widget = self._builder.get_object(name)

        if widget is None:
            raise AttributeError("Widget %s not found in view %s" % \
                (name, self._view))
        
        return widget
    
    def get_widgets(self):
        return self._builder.get_objects()
    
    def get_sizegroups(self):
        return []
    
    def signal_autoconnect(self, obj):
        self._builder.connect_signals(obj)
    
    def _attach_widgets(self):
        for widget_name in self._widgets:
            if widget_name:
                widget = self._builder.get_object(widget_name)
                
                try:
                    if widget.__class__ is gtk.ScrolledWindow \
                        and widget_name.endswith("_list"):
                        kiwi_widget = ObjectList()
                        kiwi_widget.show()
                        treeview = kiwi_widget.get_treeview()
                        
                        self.copy_properties(widget.get_child(), treeview)
                    else:
                        assert widget.__class__ in self.KIWI_WIDGET_MAP
                        kiwi_widget = self.KIWI_WIDGET_MAP[widget.__class__]()
                    
                    self.copy_properties(widget, kiwi_widget)
                    
                    parent = widget.get_parent()
                    child_props = {}
                    
                    if isinstance(parent, gtk.Container):
                        child_props = self.get_child_properties(parent, widget)
                    
                    parent.remove(widget)
                    parent.add(kiwi_widget)
                    
                    self.set_child_properties(parent, kiwi_widget, child_props)
                    
                    if widget.__class__ in self.WIDGET_DATA_TYPES:
                        data_type = self.WIDGET_DATA_TYPES[widget.__class__]
                        kiwi_widget.data_type = data_type
                        
                        # More recent versions of Kiwi do this on their own:
                        kiwi_widget.model_attribute = widget_name
                    
                    widget = kiwi_widget
                    widget.show()
                except Exception, e:
                    pass
            
                setattr(self._view, widget_name, widget)
    
    def copy_properties(self, dest, target):
        for prop in list_properties(dest):
            try:
                copy_complex_objects = (gtk.Adjustment)
                key = prop.name
                dest_value = dest.get_property(key)
                target_value = target.get_property(key)
                
                # Don't copy complex objects based on GObject by default. This
                # is not desired in most cases (e.g. parent or style property).
                # There are some type of objects that need to be copied though.
                # The values contained by a gtk.Adjustment object are needed
                # by gtk.SpinButtons for example.
                if isinstance(dest_value, GObject):
                    if isinstance(dest_value, copy_complex_objects) \
                        and type(dest_value) is type(target_value):
                            self.copy_properties(dest_value, target_value)
                elif not isinstance(target_value, GObject):
                    target.set_property(key, dest_value)
            except:
                pass
    
    def get_child_properties(self, parent, child):
        props = {}
        
        for prop in parent.list_child_properties():
            try:
                props[prop.name] = parent.child_get_property(child, prop.name)
            except:
                pass
        
        return props
    
    def set_child_properties(self, parent, child, properties):
        for key, value in properties.iteritems():
            try:
                parent.child_set_property(child, key, value)
            except:
                pass
