:mod:`dip.shell`
================
.. module:: dip.shell

The :mod:`dip.shell` module implements the infrastructure for defining and
interfacing with a :term:`shell`.

Plugins must provide appropriate support for the following extension points:

``dip.shell.model_factories``
    This must be supported by any plugin that configures an object implementing
    the :class:`dip.shell.IModelManagerTool` interface.  A contribution must be
    a callable.

``dip.shell.tools``
    This must be supported by any plugin that configures an object implementing
    the :class:`dip.shell.IShell` interface.  A contribution must implement the
    :class:`dip.shell.ITool` interface.


:class:`BaseManagedModelTool`
-----------------------------
.. class:: BaseManagedModelTool

    Base class: :class:`~dip.model.Model`

    The BaseManagedModelTool class is a base class for :term:`tools<tool>`
    that handle :term:`managed models<managed model>`.  It automatically manages
    the different lists of views and provides a convenient interface to the
    changing of the active view and model.

    .. method:: BaseManagedModelTool.create_views(model)

        Create the views for a managed model.
        
        This must be implemented by a sub-class.
        
        :param model:
            is the model.
        :return:
            the list of views.

    .. method:: BaseManagedModelTool.open_model(location)

        Open a model at a storage location.
        
        :param location:
            is the storage location.

    .. method:: BaseManagedModelTool.veto(view)

        Determine if the view is to be prevented from being closed.
        
        :param view:
            is the view.
        :return:
            ``True`` if the close of the view is to be prevented.


:class:`BaseShellAdapter`
-------------------------
.. class:: BaseShellAdapter

    Base class: :class:`~dip.model.Adapter`

    The BaseShellAdapter class is a base class for adapters to the IShell
    interface.  It implements housekeeping common to all shells.

    .. method:: BaseShellAdapter.__init__()

        Initialise the adapter. 

    .. method:: BaseShellAdapter.close_view(view=None)

        Close a view if possible.
        
        :param view:
            is the view.  If it is not specified then the current view is
            closed.
        :return:
            ``True`` if the view was closed.

    .. method:: BaseShellAdapter.new_view_allowed()

        This determines if the main area policy allows for a new view to
        be added.
        
        :return:
            ``True`` if a new view is allowed.

    .. method:: BaseShellAdapter.open(tool_id, location, format='')

        Open the model at a location and add it to a tool.
        
        :param tool_id:
            is the identifier of the tool to handle the model.
        :param location:
            is the location as a string.
        :param format:
            is the identifier of the optional format.


:class:`BaseShellFactory`
-------------------------
.. class:: BaseShellFactory

    Base class: :class:`~dip.ui.ViewFactory`

    The BaseShellFactory class is a base class for shell factories.  It
    creates views that can be adapted to the :class:`~dip.shell.IShell`
    interface.

    .. attribute:: id = 'dip.shell'

        The identifier of a shell.

    .. attribute:: main_area_policy = Enum('multi', 'on_demand', 'single')

        This determines how multiple views placed in the main area of the shell
        are handled.  'multi' means that the area may contain any number of views
        and will visualise the area in the same way irrespective of the number of
        views.  'on_demand' means that the area may contain any number of views
        but it may visualise the area differently if it contains a single view.
        'single' means that the area may only ever contain one view and an old
        view must be discarded before a new view is added.

    .. attribute:: tool_factories = List(Callable())

        The tool factories.  A factory should return an object that implements or
        can be adapted to :class:`~dip.shell.ITool`.

    .. attribute:: window_title_template = Str()

         The template from which the window title is derived.  Tokens in the
         template are replaced by their corresponding values:
        
         [view] is replaced by the :attr:`~dip.ui.IDisplay.name` of the active
         view.
        
         Note that, as with :attr:`~dip.ui.IView.window_title`, [*] will be
         replaced with the application modification state by the toolkit.

    .. method:: BaseShellFactory.create(model, controller, parent)

        Create the shell view.
        
        :param model:
            is the model.
        :param controller:
            is the controller.
        :param parent:
            is the optional parent view.
        :return:
            the view which can be adapted to the :class:`~dip.shell.IShell`
            interface.

    .. method:: BaseShellFactory.create_shell(model, controller, parent)

        Create the view that implements the shell.  This should be
        reimplemented by a sub-class.
        
        :param model:
            is the model.
        :param controller:
            is the controller.
        :param parent:
            is the optional parent view.
        :return:
            the shell.


:class:`IActionHints`
---------------------
.. class:: IActionHints

    Base class: :class:`~dip.model.Interface`

    The IActionHints interface defines metadata that an object may provide
    for an :term:`action`.

    .. attribute:: id = Str()

        The identifier of the action.

    .. attribute:: within = Str()

        The optional identifier of a collection of actions that this action will
        be placed within.


:class:`IAreaHints`
-------------------
.. class:: IAreaHints

    Base class: :class:`~dip.model.Interface`

    The IAreaHints interface defines the metadata that an object may
    provide for an :term:`area`.

    .. attribute:: area = Str()

        The identifier of the area where the view should be placed.  An empty
        string corresponds to the shell-specific default area.


:class:`ICloseViewVeto`
-----------------------
.. class:: ICloseViewVeto

    Base class: :class:`~dip.model.Interface`

    The ICloseViewVeto interface defines the API to be implemented by a
    :term:`tool` that wants to exert control over whether or not a view can be
    closed.

    .. method:: ICloseViewVeto.veto(view)

        Determine if the view is to be prevented from being closed.
        
        :param view:
            is the view.
        :return:
            ``True`` if the close of the view is to be prevented.


:class:`IDirty`
---------------
.. class:: IDirty

    Base class: :class:`~dip.model.Interface`

    The IDirty interface defines the API implemented by objects that need
    to maintain state to determine if the object has been modified.

    .. attribute:: dirty = Bool(False)

        This is set if the object has been modified.


:class:`IManagedModel`
----------------------
.. class:: IManagedModel

    Base class: :class:`~dip.shell.IDirty`

    The IManagedModel interface defines the API of a :term:`managed model`.
        

    .. attribute:: location = Instance(IStorageLocation)

        The :term:`storage location` of the model.  It will be ``None`` if it is
        not stored.  It will be updated automatically.

    .. attribute:: native_format = Str()

        The identifier of the model's native format.

    .. attribute:: invalid_reason = Str()

        This explains why the model is invalid.  It will be an empty string if the
        model is valid.

    .. attribute:: views = List(IView)

        The views that, when active, will cause the appropriate managed model
        actions to be enabled.


:class:`IManagedModelTool`
--------------------------
.. class:: IManagedModelTool

    Base class: :class:`~dip.shell.ITool`

    The IManagedModelTool interface defines the API for a :term:`tool` that
    handles one or more :term:`managed models<managed model>`.

    .. attribute:: manager = Instance(IModelManagerTool)

        The model manager that is managing this tool's models.

    .. attribute:: model_policy = Enum('many', 'one', 'zero_or_one')

        This defines how the tool handles multiple models.  ``many`` means the
        tool can handle any number of models at a time.  ``one`` means that the
        tool handles exactly one model at a time - this means a new model will be
        created automatically without user intervention.  ``zero_or_one`` means
        that the tool handles no more than one model at time.

    .. attribute:: models = List(IManagedModel)

        The managed models the tool is handling.

    .. attribute:: new_tool = Bool(True)

        This is set if the tool is suitable for handling a model in the context
        of a "New" operation.

    .. attribute:: open_tool = Bool(True)

        This is set if the tool is suitable for handling a model in the context
        of an "Open" operation.

    .. method:: IManagedModelTool.handles(model)

        Check if the tool can handle a particular model.
        
        :param model:
            is the model.
        :return:
            ``True`` if a tool can handle the model.


:class:`IModelManagerTool`
--------------------------
.. class:: IModelManagerTool

    Base class: :class:`~dip.shell.ITool`

    The IModelManagerTool interface defines the API made available to
    implementations of the :class:`~dip.shell.IManagedModelTool` interface.

    .. attribute:: model_factories = List(Callable())

        The managed model factories.  A factory should return an object that
        implements or can be adapted to :class:`~dip.shell.IManagedModel`.  If an
        application may include more than one model type then the factory should
        implement the :class:`~dip.ui.IDisplay` interface.

    .. method:: IModelManagerTool.open_model(location, tool)

        This handles :meth:`~dip.shell.IOpenModel.open_model` on behalf of
        an implementation of the :class:`~dip.shell.IManagedModelTool`
        interface.
        
        :param location:
            is the storage location.
        :param tool:
            is the tool.

    .. method:: IModelManagerTool.veto_close_view(view, tool)

        This handles :meth:`~dip.shell.ICloseViewVeto.veto` on behalf of an
        implementation of the :class:`~dip.shell.IManagedModelTool` interface.
        
        :param view:
            is the view.
        :param tool:
            is the tool.
        :return:
            ``True`` if the close of the view is to be prevented.


:class:`IOpenModel`
-------------------
.. class:: IOpenModel

    Base class: :class:`~dip.model.Interface`

    The IOpenModel interface defines the API to be implemented by a
    :term:`tool` that can open a model typically from a location provided on
    the command line.

    .. method:: IOpenModel.open_model(location)

        Open a model at a storage location.
        
        :param location:
            is the storage location.


:class:`IQuitVeto`
------------------
.. class:: IQuitVeto

    Base class: :class:`~dip.model.Interface`

    The IQuitVeto interface defines the API to be implemented by an object
    that is allowed to veto a user's request to quit the application.

    .. attribute:: reasons = List(Str())

        The list of separate reasons why the quit request should be vetoed.
        Each reason must be a short, properly punctuated, one line sentence.  If
        the list is empty then the request will not be vetoed.


:class:`IShell`
---------------
.. class:: IShell

    Base class: :class:`~dip.model.Interface`

    The IShell interface defines the API of a :term:`shell`.
    
    The following action identifiers are considered to be well known.  A shell
    would normally be expected to honour them.
    
        dip.ui.actions.close
        dip.ui.actions.export
        dip.ui.actions.import
        dip.ui.actions.new
        dip.ui.actions.open
        dip.ui.actions.quit
        dip.ui.actions.save
        dip.ui.actions.save_as
        dip.ui.actions.whats_this
    
    The following action collection identifiers are considered to be well
    known.  A shell, if it supports the concept of action collections, would
    normally be expected to honour them.
    
        dip.ui.collections.edit
        dip.ui.collections.file
        dip.ui.collections.help
        dip.ui.collections.print
        dip.ui.collections.tools
        dip.ui.collections.undo
        dip.ui.collections.view
    
    The following area identifiers, used to position views, are defined.  A
    shell may interpret these in any way.  An empty string implies the main
    area.
    
        dip.shell.areas.left
        dip.shell.areas.right
        dip.shell.areas.bottom
        dip.shell.areas.top

    .. attribute:: current_view = Instance(IView)

        The current view.  It is not necessarily the active view.

    .. attribute:: main_area_policy = Enum('multi', 'on_demand', 'single')

        This determines how multiple views placed in the main area of the shell
        are handled.  'multi' means that the area may contain any number of views
        and will visualise the area in the same way irrespective of the number of
        views.  'on_demand' means that the area may contain any number of views
        but it may visualise the area differently if it contains a single view.
        'single' means that the area may only ever contain one view and an old
        view must be discarded before a new view is added.

    .. attribute:: publication_manager = Instance(IPublicationManager)

        The publication manager.

    .. attribute:: tools = List(ITool)

        The list of the shell's tools.

    .. attribute:: views = List(IView)

        The list of the shell's views.

    .. attribute:: window_title_template = Str()

         The template from which the window title is derived.  Tokens in the
         template are replaced by their corresponding values:
        
         [view] is replaced by the :attr:`~dip.ui.IDisplay.name` of the active
         view.
        
         Note that, as with :attr:`~dip.ui.IView.window_title`, [*] will be
         replaced with the application modification state by the toolkit.

    .. method:: IShell.close_view(view=None)

        Close a view if possible.
        
        :param view:
            is the view.  If it is not specified then the current view is
            closed.
        :return:
            ``True`` if the view was closed.

    .. method:: IShell.new_view_allowed()

        This determines if the main area policy allows for a new view to
        be added.
        
        :return:
            ``True`` if a new view is allowed.  If not then the user will be
            informed.

    .. method:: IShell.open(tool_id, location, format='')

        Open the model at a location and add it to a tool.
        
        :param tool_id:
            is the identifier of the tool to handle the model.
        :param location:
            is the location as a string.
        :param format:
            is the identifier of the optional format.


:class:`ITool`
--------------
.. class:: ITool

    Base class: :class:`~dip.model.Interface`

    The ITool interface defines the API to be implemented by a
    :term:`tool`.

    .. attribute:: actions = List(Instance(IAction, IActionCollection))

        The tool's actions.  Any initial actions will be automatically added to
        the shell.  If there are none then the tool is introspected for any
        :class:`~dip.ui.ActionCollection` attributes and then any
        :class:`~dip.ui.Action` attributes.

    .. attribute:: current_view = Instance(IView)

        The tool's current view.  It will be ``None`` if the shell's current view
        does not belong to this tool.

    .. attribute:: id = Str()

        The tool's identifier.

    .. attribute:: shell = Instance(.IShell)

        The shell that the tool is attached to.

    .. attribute:: views = List(IView)

        The tool's views.  Any initial views will be automatically added to the
        shell.


:class:`SimpleViewTool`
-----------------------
.. class:: SimpleViewTool

    Base class: :class:`~dip.model.Model`

    The SimpleViewTool class is a base class for shell tools implemented
    as a single view and that allows for the use of an action that toggles the
    visibility of the view.

    .. attribute:: action_id = Str()

        The identifier to use for any action.

    .. attribute:: area = Str('dip.shell.areas.left')

        The identifier of the area where the view should be placed.

    .. attribute:: name = Str()

        The tool's name.

    .. attribute:: view = Instance(IView)

        The view implementation.

    .. attribute:: views = Tuple(IView)

        The tool's views.  Any initial views will be automatically added to the
        shell.

    .. attribute:: within = Str()

        The optional identifier of a collection of actions that any action will
        be placed within.
