# GNU Enterprise Forms - GTK UI Driver - base class for UI widgets
#
# Copyright 2001-2009 Free Software Foundation
#
# This file is part of GNU Enterprise
#
# GNU Enterprise is free software; you can redistribute it
# and/or modify it under the terms of the GNU General Public
# License as published by the Free Software Foundation; either
# version 3, or (at your option) any later version.
#
# GNU Enterprise 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public
# License along with program; see the file COPYING. If not,
# write to the Free Software Foundation, Inc., 59 Temple Place
# - Suite 330, Boston, MA 02111-1307, USA.
#
# $Id: _base.py 10007 2009-10-26 21:19:19Z reinhard $

import gtk
import types

from gnue.common import events
from gnue.common.apps import i18n
from gnue.forms.GFForm import *
from gnue.forms.uidrivers._base.widgets._base import UIWidget
from gnue.forms.uidrivers.gtk2.common import _setDefaultEventHandlers


# =============================================================================
# This class implements the common behaviour of GTK2 widgets
# =============================================================================

class UIHelper (UIWidget):
  """
  Implements the common behaviour of GTK2 widgets
  """

  # ---------------------------------------------------------------------------
  # Create a new GTK widget
  # ---------------------------------------------------------------------------

  def _create_widget_ (self, event, spacer):
    """
    This function creates a new GTK widget and adds it to the cross reference
    table.
    """
    gfObject           = event.object
    self._eventHandler = event.eventHandler
    self.items = []

    if hasattr (gfObject, 'Char__y'):
      posY = gfObject.Char__y
      gap  = gfObject._gap + 1
      self.itemY = (posY + spacer * gap) * event.widgetHeight

    if hasattr (gfObject, 'Char__height'):
      self.itemHeight = gfObject.Char__height * event.widgetHeight

    newWidget = self._create_widget (event, spacer)
    if event.initialize:
      self._addToCrossRef (newWidget, gfObject, self)

    return newWidget


  # ---------------------------------------------------------------------------
  # Add a widget to the cross reference tables
  # ---------------------------------------------------------------------------

  def _addToCrossRef (self, widget, gfobject, uiobject):
    self._uiDriver._WidgetToGFObj [widget] = gfobject
    self._uiDriver._WidgetToUIObj [widget] = uiobject


  # ---------------------------------------------------------------------------
  # Remove a widget from the cross reference tables
  # ---------------------------------------------------------------------------

  def _deleteFromCrossRef (self, widget, object):
    try:
      del self._uiDriver._WidgetToGFObj [widget]
      del self._uiDriver._WidgetToUIObj [widget]

    except:
      pass


  # ---------------------------------------------------------------------------
  # Add all default event handler to the widget
  # ---------------------------------------------------------------------------

  def _addDefaultEventHandler (self, widget, lookup = None):
    _setDefaultEventHandlers (widget, self._eventHandler, True, self._uiDriver,
                              lookup)



  # ---------------------------------------------------------------------------
  # Add a focus-in handler to a widget
  # ---------------------------------------------------------------------------

  def _addFocusHandler (self, widget, lookupWidget = None, after = False):
    """
    This function connects a handler to the widget's focus-in-event signal
    passing an optional lookup widget to it. A lookup widget will be used for
    retrieving the GFObject from the lookup table. If no lookup widget is given
    the mandatory widget will be used for lookups.
    """

    if lookupWidget is None:
      lookupWidget = widget
    method = after and widget.connect_after or widget.connect
    widget._focusHandler = method ('focus-in-event', self.__focusInHandler,
                                   lookupWidget)


  # ---------------------------------------------------------------------------
  # Handle focus signals from widgets
  # ---------------------------------------------------------------------------

  def __focusInHandler (self, widget, event, lookupWidget):

    assert gDebug (6, "focus-in-event: %s for %s" % (widget, lookupWidget))
    gfObject = self._uiDriver._WidgetToGFObj [lookupWidget]
    gfObject._event_set_focus(self.widgets.index(lookupWidget))
    return False


  # ---------------------------------------------------------------------------
  # Show all ui-widgets managed by this object
  # ---------------------------------------------------------------------------

  def show (self):
    """
    This function calls the show () on all gtk-widgets managed by this
    instance. This is needed if a row-count greater than 0 is given.
    """
    for widget in self.widgets:
      widget.show ()


  # ---------------------------------------------------------------------------
  # Hide all ui-widgets managed by this object
  # ---------------------------------------------------------------------------

  def hide (self):
    """
    This function calls the hide () on all gtk-widgets managed by this
    instance. This is needed if a row-count greater than 0 is given.
    """
    for widget in self.widgets:
      widget.hide ()


  def destroy (self):
    assert gDebug (1, "destroy not implemented for gtk2 driver")


  # ---------------------------------------------------------------------------
  # Focus handling
  # ---------------------------------------------------------------------------

  def _ui_set_focus_ (self, index):

    widget = self.widgets [index]
    assert gDebug (6, "indexed_focus: %s [%s]" % (widget, index))

    item = isinstance (widget, gtk.ComboBoxEntry) and widget.child or widget

    self._blockHandler (item, '_focusHandler')

    assert gDebug (6, "Grab focus to %s for %s" % (item, widget))
    item.grab_focus ()

    # To avoid the automatic select-all in a combo box, we explicitly set the
    # selection to the current position only
    if isinstance (widget, gtk.ComboBoxEntry):
      pos = item.get_position ()
      item.select_region (pos, pos)

    self._blockHandler (item, '_focusHandler', True)

  # ---------------------------------------------------------------------------

  def _ui_focus_in_(self, index):

    # Change the background of a widget if requested via gnue.conf
    widget = self.widgets [index]
    item = isinstance (widget, gtk.ComboBoxEntry) and widget.child or widget
    if gConfigForms ('focusColor'):
      focusColor = gtk.gdk.color_parse ('#' + gConfigForms ('focusColor'))
      mode   = ['base', 'bg'] [isinstance (item, gtk.Button)]
      setcol = getattr (item, 'modify_%s' % mode)

      if not hasattr (item, '_color'):
        item._color   = getattr (item.get_style (), mode) [gtk.STATE_NORMAL]
        item._setback = setcol

      setcol (gtk.STATE_NORMAL, focusColor)

  # ---------------------------------------------------------------------------

  def _ui_focus_out_(self, index):

      widget = self.widgets[index]
      assert gDebug (6, "Lose focus: %s" % widget)

      item = isinstance (widget, gtk.ComboBoxEntry) and widget.child or widget

      if hasattr (item, '_color'):
        item._setback (gtk.STATE_NORMAL, item._color)

      if isinstance (item, gtk.Entry):
        item.select_region (0,0)

  # -------------------------------------------------------------------------

  def _ui_set_current_row_(self, index):
      
    pass


  # ---------------------------------------------------------------------------
  # Set the value of a widget
  # ---------------------------------------------------------------------------

  def _ui_set_value_ (self, index, value):
    """
    This function sets the value of a widget and optionally enables or disables
    the widget.
    """
    widget = self.widgets [index]
    assert gDebug (6, "set_value %s [%s] %s" % (repr (value), index, widget))

    if not isinstance (widget, gtk.CheckButton) and \
        type (value) != types.UnicodeType:
      assert gDebug (6, "converting %s to unicode using %s" % \
          (repr (value), gConfigForms ('textEncoding')))
      value = unicode (value, gConfigForms ('textEncoding'))


    if isinstance (widget, gtk.ComboBoxEntry):
      gfObject = self._uiDriver._WidgetToGFObj [widget]

      self._blockHandler (widget.child, '_insert_handler')
      self._blockHandler (widget.child, '_delete_handler')

      widget.child.set_text (value)

      self._blockHandler (widget.child, '_insert_handler', True)
      self._blockHandler (widget.child, '_delete_handler', True)


    elif isinstance (widget, gtk.CheckButton):
      self._blockHandler (widget, '_clickedHandler')
      if value is None:
        widget.set_active (False)
        widget.set_inconsistent (True)
      else:
        widget.set_inconsistent (False)
        widget.set_active (value)
      self._blockHandler (widget, '_clickedHandler', True)

    elif isinstance (widget, gtk.TreeView):
      gfObject = self._uiDriver._WidgetToGFObj [widget]

      if value in self.items:
        path = "%s" % self.items.index (value)
        assert gDebug (6, "Changing path of treeView to %s" % path)
        self._blockHandler (self.selection, '_changedHandler')
        widget.set_cursor (path)
        self._blockHandler (self.selection, '_changedHandler', True)

    elif isinstance (widget, gtk.Label):
      gfObject = self._uiDriver._WidgetToGFObj [widget]
      lines = hasattr (gfObject, 'Char__height') and gfObject.Char__height or 1

      widget.set_text ('\n'.join (value.splitlines () [:lines]))

    else:
      item = isinstance (widget, gtk.TextView) and widget.get_buffer () or \
          widget

      self._blockHandler (item, '_insert_handler')
      self._blockHandler (item, '_delete_handler')

      item.set_text (value)

      self._blockHandler (item, '_insert_handler', True)
      self._blockHandler (item, '_delete_handler', True)


  # ---------------------------------------------------------------------------
  # Block or unblock a given event handler of a widget
  # ---------------------------------------------------------------------------

  def _blockHandler (self, widget, handlerName, unblock = False):
    """
    This function blocks or unblocks an event handler of a widget it is
    assigned.
    """
    method = unblock and widget.handler_unblock or widget.handler_block
    if hasattr (widget, handlerName):
      handler = getattr (widget, handlerName)
      # assert gDebug (6, "%s '%s' (%s) for %s" % \
      #     (['Block', 'Unblock'] [unblock], handlerName, handler, widget))
      method (handler)


  # ---------------------------------------------------------------------------
  # Make sure a string will be converted into unicode
  # ---------------------------------------------------------------------------

  def _makeSafe (self, value):
    if isinstance (value, types.StringType):
      value = unicode (value, i18n.encoding)
    return value
