# GNU Enterprise Forms - GF Object Hierarchy - Layout
#
# 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.
#
# pylint: disable-msg=W0704
#
# $Id: GFLayout.py 9956 2009-10-11 18:54:57Z reinhard $
"""
Handles the <layout> tag.
"""

from gnue.common.definitions import GParser
from gnue.forms.GFObjects.GFObj import GFObj

__all__ = ['GFLayout', 'LayoutConceptError']

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

class LayoutConceptError(GParser.MarkupError):
    """ Element not allowed in a managed/positioning layout """
    def __init__(self, item, managed):
        if managed and item._type == 'GFBox':
            msg = u_("%(item)s '%(name)s' not allowed in a managed layout")\
                     % {'item': item._type[2:], 'name': item.name}
        elif managed:
            msg = u_("%(item)s '%(name)s' uses positioning information in a "
                     "managed layout") \
                     % {'item': item._type[2:], 'name': item.name}
        else:
            msg = u_("%(item)s '%(name)s' not allowed in a positioned layout")\
                     % {'item': item._type[2:], 'name': item.name}

        GParser.MarkupError.__init__(self, msg, item._url, item._lineNumber)


# =============================================================================
# Class implementing the layout tag
# =============================================================================

class GFLayout(GFObj):
    """
    Implementation of the <layout> tag
    """

    # -------------------------------------------------------------------------
    # Attributes
    # -------------------------------------------------------------------------

    tabbed = 'none'
    name   = 'layout'


    # -------------------------------------------------------------------------
    # Constructor
    # -------------------------------------------------------------------------

    def __init__(self, parent=None):

        GFObj.__init__(self, parent, "GFLayout")

        self.managed = False

        self._pageList = []
        self._triggerGlobal = 1
        self._xmlchildnamespaces = {}


    # -------------------------------------------------------------------------
    # Object creation
    # -------------------------------------------------------------------------

    def _buildObject(self):
        """
        Determine wether the layout is managed or not.  If there is a height or
        width defined (in GNUe:Layout:Char namespace) the layout is treated as
        a 'positioning' one, otherwise it is 'managed'.  In a managed layout,
        none of the children must have an x, y, height or width attribute.  For
        a positioned layout, all childrens x, y, height or width attributes are
        converted to numbers.
        """

        if hasattr(self, 'Char__width') or hasattr(self, 'Char__height'):
            self.managed = False
        else:
            self.managed = True

        self.walk(self.__check_xy)

        return GFObj._buildObject(self)


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

    def __check_xy(self, gf_object):

        for attr in ('x', 'y', 'height', 'width'):
            try:
                val = int(gf_object.__dict__['Char__%s' % attr])

                if self.managed:
                    raise LayoutConceptError(gf_object, self.managed)

                gf_object.__dict__['Char__%s' % attr] = val
                gf_object.__dict__['_Layout__%s' % attr] = val

            except KeyError:
                pass

        if self.managed and gf_object._type in ['GFBox']:
            raise LayoutConceptError(gf_object, self.managed)

        elif not self.managed and gf_object._type in ['GFVBox', 'GFHBox']:
            raise LayoutConceptError(gf_object, self.managed)



    # -------------------------------------------------------------------------
    # Implementation of virtual methods
    # -------------------------------------------------------------------------

    def _phase_1_init_(self):
        """
        Build a dictionary of all XML namespaces used by the layouts children
        """

        GFObj._phase_1_init_(self)
        self._xmlchildnamespaces = self.__find_namespaces(self)


    # -------------------------------------------------------------------------
    # Find the XML namespace in use by any child objects
    # -------------------------------------------------------------------------

    def __find_namespaces(self, gf_object):

        result = {}
        for child in gf_object._children:
            try:
                if child._xmlnamespaces:
                    result.update(child._xmlnamespaces)
                else:
                    result.update(self.__find_namespaces(child))

            except AttributeError:
                pass

        return result
