#------------------------------------------------------------------------------
#
#  Copyright (c) 2008, Enthought, Inc.
#  All rights reserved.
#
#  This software is provided without warranty under the terms of the BSD
#  license included in enthought/LICENSE.txt and may be redistributed only
#  under the conditions described in the aforementioned license.  The license
#  is also available online at http://www.enthought.com/licenses/BSD.txt
#
#  Thanks for using Enthought open source!
#
#  Author: David C. Morrill
#
#------------------------------------------------------------------------------
""" Defines the tuple editor factory for all traits user interface toolkits.
"""

#-------------------------------------------------------------------------------
#  Imports:
#-------------------------------------------------------------------------------



from traits.trait_base import SequenceTypes

from traits.api import Bool, HasTraits, List, Tuple, Unicode, Int, Any, TraitType

# CIRCULAR IMPORT FIXME: Importing from the source rather than traits.ui.api
# to avoid circular imports, as this EditorFactory will be part of
# traits.ui.api as well.
from ..view import View

from ..group import Group

from ..item import Item

from ..editor_factory import EditorFactory

from ..editor import Editor

#-------------------------------------------------------------------------------
#  'ToolkitEditorFactory' class:
#-------------------------------------------------------------------------------

class ToolkitEditorFactory ( EditorFactory ):
    """ Editor factory for tuple editors.
    """
    #---------------------------------------------------------------------------
    #  Trait definitions:
    #---------------------------------------------------------------------------

    # Trait definitions for each tuple field
    types = Any

    # Labels for each of the tuple fields
    labels = List( Unicode )

    # Editors for each of the tuple fields:
    editors = List( EditorFactory )

    # Number of tuple fields or rows
    cols   = Int( 1 )

    # Is user input set on every keystroke? This is applied to every field
    # of the tuple, provided the field does not already have an 'auto_set'
    # metadata or an editor defined.
    auto_set = Bool( True )

    # Is user input set when the Enter key is pressed? This is applied to
    # every field of the tuple, provided the field does not already have an
    # 'enter_set' metadata or an editor defined.
    enter_set = Bool( False )

#-------------------------------------------------------------------------------
#  'SimpleEditor' class:
#-------------------------------------------------------------------------------

class SimpleEditor ( Editor ):
    """ Simple style of editor for tuples.

    The editor displays an editor for each of the fields in the tuple, based on
    the type of each field.
    """
    #---------------------------------------------------------------------------
    #  Finishes initializing the editor by creating the underlying toolkit
    #  widget:
    #---------------------------------------------------------------------------

    def init ( self, parent ):
        """ Finishes initializing the editor by creating the underlying toolkit
            widget.
        """
        self._ts     = ts = TupleStructure( self )
        self._ui     = ui = ts.view.ui( ts, parent, kind = 'subpanel' ).set(
                                        parent = self.ui )
        self.control = ui.control
        self.set_tooltip()

    #---------------------------------------------------------------------------
    #  Updates the editor when the object trait changes external to the editor:
    #---------------------------------------------------------------------------

    def update_editor ( self ):
        """ Updates the editor when the object trait changes external to the
            editor.
        """
        ts = self._ts
        for i, value in enumerate( self.value ):
            setattr( ts, 'f%d' % i, value )

    #---------------------------------------------------------------------------
    #  Returns the editor's control for indicating error status:
    #---------------------------------------------------------------------------

    def get_error_control ( self ):
        """ Returns the editor's control for indicating error status.
        """
        return self._ui.get_error_controls()

#-------------------------------------------------------------------------------
#  'TupleStructure' class:
#-------------------------------------------------------------------------------

class TupleStructure ( HasTraits ):
    """ Creates a view containing items for each field in a tuple.
    """
    #---------------------------------------------------------------------------
    #  Trait definitions:
    #---------------------------------------------------------------------------

    # Editor this structure is linked to
    editor = Any

    # The constructed View for the tuple
    view = Any

    # Number of tuple fields
    fields = Int

    #---------------------------------------------------------------------------
    #  Initializes the object:
    #---------------------------------------------------------------------------

    def __init__ ( self, editor ):
        """ Initializes the object.
        """
        factory = editor.factory
        types   = factory.types
        labels  = factory.labels
        editors = factory.editors
        cols    = factory.cols

        # Save the reference to the editor:
        self.editor = editor

        # Get the tuple we are mirroring:
        object = editor.value

        # For each tuple field, add a trait with the appropriate trait
        # definition and default value:
        content     = []
        self.fields = len( object )
        len_labels  = len( labels )
        len_editors = len( editors )

        if types is None:
            type = editor.value_trait.handler
            if isinstance( type, Tuple ):
                types = type.types

        if not isinstance( types, SequenceTypes ):
            types = [ types ]

        len_types = len( types )
        if len_types == 0:
            types     = [ Any ]
            len_types = 1

        for i, value in enumerate( object ):
            type = types[ i % len_types ]

            auto_set = enter_set = None
            if isinstance(type, TraitType):
                auto_set = type.auto_set
                enter_set = type.enter_set
            if auto_set is None:
                auto_set = editor.factory.auto_set
            if enter_set is None:
                enter_set = editor.factory.enter_set

            label = ''
            if i < len_labels:
                label = labels[i]

            field_editor = None
            if i < len_editors:
                field_editor = editors[i]

            name = 'f%d' % i
            self.add_trait( name, type( value, event = 'field',
                                               auto_set = auto_set,
                                               enter_set = enter_set ) )
            item = Item( name = name, label = label, editor = field_editor )
            if cols <= 1:
                content.append( item )
            else:
                if (i % cols) == 0:
                    group = Group( orientation = 'horizontal' )
                    content.append( group )

                group.content.append( item )

        self.view = View( Group( show_labels = (len_labels != 0), *content ) )

    #---------------------------------------------------------------------------
    #  Updates the underlying tuple when any field changes value:
    #---------------------------------------------------------------------------

    def _field_changed ( self, name, old, new ):
        """ Updates the underlying tuple when any field changes value.
        """
        index = int( name[ 1: ] )
        value = self.editor.value
        if new != value[ index ]:
            self.editor.value = tuple( 
                [ getattr( self, 'f%d' % i ) for i in range( self.fields ) ] )


# Define the TupleEditor class.
TupleEditor = ToolkitEditorFactory

### EOF #######################################################################



