# GNU Enterprise Forms - GF Object Hierarchy - Base class for all GF-Objects
#
# 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: GFObj.py 10044 2009-11-18 15:36:46Z reinhard $
"""
Base class for all objects represented by an XML tag in a GFD tree.
"""

from gnue.common.definitions.GObjects import GObj
from gnue.common.logic.GTrigger import GTriggerExtension
from gnue.common.definitions import GParser

__all__ = ['BlockNotFoundError', 'GFObj']

# =============================================================================
# Exceptions
# =============================================================================

class BlockNotFoundError(GParser.MarkupError):
    """ Element references non-existent block """
    def __init__(self, item):
        itemType = item._type[2:]
        msg = u_("%(item)s '%(name)s' references non-existent "
                 "block '%(block)s'") \
              % {'item': itemType, 'name': item.name, 'block': item.block}
        GParser.MarkupError.__init__(self, msg, item._url, item._lineNumber)


# =============================================================================
# Base class for GF* objects
# =============================================================================

class GFObj(GObj, GTriggerExtension):
    """
    A GFObj is the base class for all objects of a GF object tree. It
    implements the GTriggerExtension interface, so all GF objects are capable
    of associating and calling triggers.
    """
    
    # -------------------------------------------------------------------------
    # Constructor
    # -------------------------------------------------------------------------

    def __init__(self, parent=None, object_type='GFObj'):
    
        GTriggerExtension.__init__(self)
        GObj.__init__(self, parent, object_type)

        self.hidden = False
        self.name = "%s%x" % (("%s" % self.__class__).split('.')[-1][:-2], id(self))

        self._visibleIndex = 0
        self._rows = 1
        self._gap = 0
        self._inits = [self.phase_1_init]
        self._form = None

        # The reference to the uiWidget will be set by the
        # uidrivers._base.UIdriver._buildUI () function.
        self.uiWidget = None


    # -------------------------------------------------------------------------
    # Phase 1 initialization
    # -------------------------------------------------------------------------

    def phase_1_init(self):
        """
        Phase 1 initialization called after all objects of the XML tree were
        created.
        """

        self._phase_1_init_()


    # -------------------------------------------------------------------------
    # Get an option of the object
    # -------------------------------------------------------------------------

    def get_option(self, name):
        """
        Return the value of a given option of the object or None if no such
        option is present.

        @param name: name of the option to be queried
        @returns: the value of the requested option or None
        """

        option = None

        for child in self.findChildrenOfType('GFOption', False, True):
            if child.name == name:
                option = child.value
                break

        return option


    # --------------------------------------------------------------------------
    # Get the block this control is a member of
    # -------------------------------------------------------------------------

    def get_block(self):
        """
        Return the objects' block from the block mapping.

        @returns: the block of the current object or None if the current object
          does not support blocks.
        @raises BlockNotFoundError: if the block specified by the object is not
          listed in the block mapping of the logic instance
        """

        # Sometimes other objects in the tree access in their own
        # _phase_1_init_, so we have to make sure _block is initialized.
        if not hasattr(self, '_block'):
            self.__init_form_and_block()

        return self._block


    # --------------------------------------------------------------------------
    # Get the block this control is bound to
    # -------------------------------------------------------------------------

    def get_bound_block(self):
        """
        Return the objects' block from the block mapping.

        @returns: the block of the current object or None if the current object
          does not support blocks.
        @raises BlockNotFoundError: if the block specified by the object is not
          listed in the block mapping of the logic instance
        """

        return self._bound_block


    # -------------------------------------------------------------------------
    # Phase 1 initialization
    # -------------------------------------------------------------------------

    def _phase_1_init_(self):
        """
        Phase 1 initialization called after all objects of the XML tree were
        created. Descendants can overwrite this function to perform actions
        after construction of the objects.
        """

        if not hasattr(self, '_block'):
            self.__init_form_and_block()


    # -------------------------------------------------------------------------
    # Find block for this object
    # -------------------------------------------------------------------------

    def __init_form_and_block(self):

        # The form this object is a member of.
        self._form = self.findParentOfType('GFForm')

        # The block this object is a member of. In case of an entry which is
        # linked to a grid, this is the grid's block.
        parent = self
        while parent:
            block_name = getattr(parent, 'block', None)
            if block_name:
                if not block_name in self._form._logic._blockMap:
                    raise BlockNotFoundError, parent
                self._block = self._form._logic._blockMap[block_name]
                break
            parent = parent.getParent()
        else:
            self._block = None

        # The block this object is bound to. In case of an entry which is
        # linked to a grid, this is the entry's block.
        self._bound_block = self._block


    # -------------------------------------------------------------------------
    # Indicate whether this widget makes use of the separate label column
    # -------------------------------------------------------------------------

    def __get_has_label(self):

        return False

    has_label = property(__get_has_label)
