"""
Tree editor for hierarchal data

Demonstrates using the TreeEditor to display a hierarchically organized data
structure.

In this case, the tree has the following hierarchy:

  - Partner

    - Company

      - Department

        - Employee

The TreeEditor generates a hierarchical tree control, consisting of nodes. It is
useful for cases where objects contain lists of other objects.

The tree control is displayed in one pane of the editor, and a user interface
for the selected object is displayed in the other pane. The layout orientation
of the tree and the object editor is determined by the *orientation* parameter
of TreeEditor(), which can be 'horizontal' or 'vertical'.

You must specify the types of nodes that can appear in the tree using the
*nodes* parameter, which must be a list of instances of TreeNode (or of
subclasses of TreeNode).

You must specify the classes whose instances the node type applies to. Use the
**node_for** attribute of TreeNode to specify a list of classes; often, this
list contains only one class. You can have more than one node type that applies
to a particular class; in this case, each object of that class is represented by
multiple nodes, one for each applicable node type.

See the Traits User Manual for more details.
"""

# FIXME: provide accessible copy or equivalent of factories_advanced_extra.rst

from traits.api import HasTraits, Str, Regex, List, Instance
from traitsui.api import Item, View, TreeEditor, TreeNode

class Employee(HasTraits):
    """ Defines a company employee. """

    name  = Str('<unknown>')
    title = Str
    phone = Regex(regex = r'\d\d\d-\d\d\d\d')

    def default_title(self):
        self.title = 'Senior Engineer'

class Department(HasTraits):
    """ Defines a department with employees. """

    name      = Str('<unknown>')
    employees = List(Employee)

class Company(HasTraits):
    """ Defines a company with departments and employees. """

    name        = Str('<unknown>')
    departments = List(Department)
    employees   = List(Employee)

# Create an empty view for objects that have no data to display:
no_view = View()

# Define the TreeEditor used to display the hierarchy:
tree_editor = TreeEditor(
    nodes = [
        # The first node specified is the top level one
        TreeNode(node_for  = [ Company ],
                  auto_open = True,
                  # child nodes are
                  children  = '',
                  label     = 'name',  # label with Company name
                  view      = View([ 'name' ])
        ),
        TreeNode(node_for  = [ Company ],
                  auto_open = True,
                  children  = 'departments',
                  label     = '=Departments',  # constant label
                  view      = no_view,
                  add       = [ Department ],
        ),
        TreeNode(node_for  = [ Company ],
                  auto_open = True,
                  children  = 'employees',
                  label     = '=Employees',   # constant label
                  view      = no_view,
                  add       = [ Employee ]
        ),
        TreeNode(node_for  = [ Department ],
                  auto_open = True,
                  children  = 'employees',
                  label     = 'name',   # label with Department name
                  view      = View([ 'name' ]),
                  add       = [ Employee ]
        ),
        TreeNode(node_for  = [ Employee ],
                  auto_open = True,
                  label     = 'name',   # label with Employee name
                  view      = View([ 'name', 'title', 'phone' ])
        )
    ]
)

class Partner(HasTraits):
    """ Defines a business partner."""

    name    = Str('<unknown>')
    company = Instance(Company)

    view = View(
        Item(name       = 'company',
              editor     = tree_editor,
              show_label = False
        ),
        title     = 'Company Structure',
        buttons   = [ 'OK' ],
        resizable = True,
        style     = 'custom',
        width     = .3,
        height    = 500
    )

# Create an example data structure:
jason  = Employee(name  = 'Jason',
                   title = 'Senior Engineer',
                   phone = '536-1057')
mike   = Employee(name  = 'Mike',
                   title = 'Senior Engineer',
                   phone = '536-1057')
dave   = Employee(name  = 'Dave',
                   title = 'Senior Software Developer',
                   phone = '536-1057')
martin = Employee(name  = 'Martin',
                   title = 'Senior Engineer',
                   phone = '536-1057')
duncan = Employee(name  = 'Duncan',
                   title = 'Consultant',
                   phone = '526-1057')

# Create the demo:
demo = Partner(
    name    = 'Enthought, Inc.',
    company = Company(
        name        = 'Enthought',
        employees   = [ dave, martin, duncan, jason, mike ],
        departments = [
            Department(
                name      = 'Business',
                employees = [ jason, mike ]
            ),
            Department(
                name      = 'Scientific',
                employees = [ dave, martin, duncan ]
            )
        ]
    )
)

# Run the demo (if invoked from the command line):
if __name__ == '__main__':
    demo.configure_traits()
