.. _ui-tutorial:

Getting Started with :mod:`dip.ui`
==================================

In this section we work through a number of examples of building simple user
interfaces declaratively using the :mod:`dip.ui` module.  First of all we will
briefly introduce some terms and concepts that we will expand on later.

:mod:`dip.ui` uses the well known :term:`model`-:term:`view`-:term:`controller`
design pattern.  The data being displayed by the user interface is held in a
model, the user interface is implemented as a view, and the controller updates
the model as the user interacts with the view.

A model is implemented either as a Python dictionary or, more usually, as a
sub-class of :class:`~dip.model.Model` which is part of the :mod:`dip.model`
module.

If the default PyQt4 toolkit is used then a view is implemented as a hierarchy
of :class:`~PyQt4.QtGui.QWidget` and :class:`~PyQt4.QtGui.QLayout` instances.

The process of associating a view with a model is called binding.

A view that is bound to a particular attribute of a model is an :term:`editor`.

The controller decides if and when an editor updates the model attribute it is
bound to.


The Smallest Example
--------------------

The following is a complete example (which you can download from
:download:`here</examples/ui/simple.py>`).

.. literalinclude:: /examples/ui/simple.py

If you run the example from a command line prompt then the following is
displayed.

.. image:: /images/simple.png
    :align: center

If you enter some text and click on the close button then the value you
entered will be displayed at the command line.

We will now walk through the code a section at a time.

.. literalinclude:: /examples/ui/simple.py
    :end-before: Every application

The above line are the imports needed by the example.

.. literalinclude:: /examples/ui/simple.py
    :start-after: Every application
    :end-before: Create the

Assuming the default PyQt4 toolkit, the above line creates a
:class:`~PyQt4.QtGui.QApplication` instance adapted to the
:class:`~dip.ui.IApplication` interface.

.. literalinclude:: /examples/ui/simple.py
    :start-after: Create the
    :end-before: Define the

The above line creates the :term:`model`.  In this simple case we are using a
Python dictionary to implement the model.  The model has a single attribute,
called ``name`` and its initial value is an empty string.

.. literalinclude:: /examples/ui/simple.py
    :start-after: Define the
    :end-before: Create an instance

The above line defines the :term:`view factory`.  Using the default PyQt4
toolkit, :class:`~dip.ui.Form` will create a :class:`~PyQt4.QtGui.QFormLayout`
to layout its contents as a form (i.e. fields with associated labels) according
to the user interface guidelines of the current style.

.. literalinclude:: /examples/ui/simple.py
    :start-after: Create an instance
    :end-before: Make the instance

The above line calls the view factory to create the actual implementation of
the view and bind it to the model.  Because the view is a top-level view (i.e.
it is not contained in another view) the view factory will always make sure
that the toolkit specific object created can be displayed.

If required the actual toolkit specific widget can be obtained by passing the
view to the :func:`~dip.model.unadapted` function.  It is important to
emphasise that there is no need to implement complete user interfaces using the
:mod:`dip.ui` module.  An application may use a mixture of handwritten code,
designs created with design tools and view factories defined declaratively.

.. literalinclude:: /examples/ui/simple.py
    :start-after: Make the instance
    :end-before: Enter the

The above line makes the view visible to the user.

.. literalinclude:: /examples/ui/simple.py
    :start-after: Enter the
    :end-before: Show the

The above line is the :class:`~dip.ui.IApplication` call that enters the
application's event loop.  The call will return when the user clicks on the
close button.

.. literalinclude:: /examples/ui/simple.py
    :start-after: Show the
    :end-before: EOF

The above line displays the updated value of the model.

In this example we have created a usable user interface while specifying the
absolute minimum amount of information about the model and view.  In
particular the view has inferred what it should contain by looking at the
model.  This is very powerful, but you will usually want to exert some control
over the view in a real-life situation.  The following examples describe how
to do this.


Extending the Model
-------------------

In this example we will build on the previous one to add an ``age`` attribute
to the model.

The complete example can be downloaded from
:download:`here</examples/ui/extended_model.py>` and is displayed as shown
below.

.. image:: /images/extended_model.png
    :align: center

We will now walk through the significant changes to the previous example.

.. literalinclude:: /examples/ui/extended_model.py
    :start-after: Create the
    :end-before: Define the

The above line shows the new model definition.  Strictly speaking that's all
we need to do.  The view will infer from the model that a new :term:`editor`
is needed to handle the additional attribute and that editor should be able
to handle integers.  However, there is a problem.  The model is unordered so
there is no way for the view to infer the correct order in which the editors
should be displayed.

.. literalinclude:: /examples/ui/extended_model.py
    :start-after: Define the
    :end-before: Create an instance

The above line is the new view definition where we have told the view what we
want to display and in what order.  If the model contained other attributes
then they would be ignored by the view.  We also provide a title for the
window.

.. literalinclude:: /examples/ui/extended_model.py
    :start-after: print
    :end-before: EOF

The above line simply displays the extra attribute.


Configuring Views
-----------------

As has been shown in the previous examples, a view (in actual fact the
toolkit) will decide which editor to create for an attribute according to the
type of that attribute.  If we want to configure a view or an editor, or we
wish the view to use a different editor, then we need to specify it explicitly.

In this example we want to configure the editor used to handle the ``age``
attribute so that it has a ``years`` suffix as shown below.

.. image:: /images/configure_views.png
    :align: center

The complete example can be downloaded from
:download:`here</examples/ui/configure_views.py>`.  We will now walk
through the changes to the previous example.

.. literalinclude:: /examples/ui/configure_views.py
    :end-before: Every application

The above line now also imports the :class:`~dip.ui.SpinBox` view factory.  As
the view that the factory creates is actually an editor (because it can be
bound to a particular attribute of a model) then we also sometimes refer to it
as an editor factory.

.. literalinclude:: /examples/ui/configure_views.py
    :start-after: Define the
    :end-before: Create an instance

The above lines show the new view definition.  Instead of just giving the name
of the ``age`` attribute and leaving it to the view to use the default editor
factory, we tell it to use a particular editor factory configured the way we
want it.

Any arguments to an editor factory that aren't known to the factory are passed
on to the toolkit where they may be used or ignored.  The default PyQt4 toolkit
assumes them to be the names and values of Qt properties to be applied to the
actual editor that is created.  In this example the ``suffix`` argument is
handled in this way.


Using a Dialog
--------------

In the previous examples the model has always been updated as the user
interacts with the view.  This isn't always desirable.  For example, you may
not want a model to be updated by a dialog view unless the user clicks the
``Ok`` button.

Whether or not a model is updated immediately is determined by the
:term:`controller` which manages the interaction between the view and the
model.  You may provide a controller to implement a particular behaviour,
otherwise a controller will be created automatically as required.  Controllers
are covered in more detail in a later section.

The default controller that is created by a dialog will not automatically
update the model when the user changes an editor.

In this section we modify the example, shown below, to use a dialog and to
show that the model is only updated when the ``Ok`` button is clicked.

.. image:: /images/dialog.png
    :align: center

The complete example can be downloaded from
:download:`here</examples/ui/dialog.py>`.  We will now walk through the
changes to the previous example.

.. literalinclude:: /examples/ui/dialog.py
    :end-before: Every application

The above line imports the additional objects used by the example.

.. literalinclude:: /examples/ui/dialog.py
    :start-after: Define the view
    :end-before: Create an instance

The above lines show the new view definition based on a dialog rather than a
form.  Note that the contents of the view have been arranged (under the
covers) using a :class:`~dip.ui.Form`.  This is the default when the dialog
has more than one sub-view.

.. literalinclude:: /examples/ui/dialog.py
    :start-after: Enter the
    :end-before: Show the

The above line is the :class:`~dip.ui.IDialog` call that displays the dialog
and enters its event loop.  If the user clicks the ``Ok`` button then the model
is updated from the dialog.


Using :mod:`dip.settings` with Views
------------------------------------

Every time you run the previous example the dialog will be displayed at its
default size and position on the screen.  This is fine for simple applications
but more complex applications may allow the user to configure details of the
user interface, e.g. to adjust sliders, to adjust the size of table columns, to
position dock widgets, to resize the whole of the user interface.  The user
will expect that those adjustments will be saved between invocations of the
application.  Using the :mod:`dip.settings` module this can be achieved very
easily.

A version of the previous example that uses :mod:`dip.settings` can be
downloaded from :download:`here</examples/ui/dialog_with_settings.py>`.  We
will now walk through the changes to the example.

First of all we import the singleton :class:`~dip.settings.SettingsManager`.

.. literalinclude:: /examples/ui/dialog_with_settings.py
    :end-before: from dip.ui

Next we load the application's settings with the following line of code.

.. literalinclude:: /examples/ui/dialog_with_settings.py
    :start-after: # Load the application's
    :end-before: # Create the model

The argument identifies the organization responsible for the application.  It
is recommended that a fully qualified domain name is used.  The
:meth:`~dip.settings.ISettingsManager.load` method also accepts an optional
application name argument.  This defaults to the base name of :attr:`sys.argv`
with any extension removed.  If you want to share the settings between a number
of applications then you should explicitly specify an application name.

The next step is to restore the settings for all of the application's views
with the following line of code.

.. literalinclude:: /examples/ui/dialog_with_settings.py
    :start-after: # Restore the geometry
    :end-before: # Enter the dialog's

Which views support settings, and in what way, is toolkit dependent.  We simply
pass the sequence of all views - any views that don't support settings (i.e.
cannot be adapted to the :class:`~dip.settings.ISettings` interface) will just
be ignored.

Finally we want to save any settings that were changed when the user was
interacting with the application.  This is done after the event loop exits with
the following line of code.

.. literalinclude:: /examples/ui/dialog_with_settings.py
    :start-after: # Save the geometry
    :end-before: # Show the value

Our simple application has a single dialog as its user interface.  A more
typical application will have some sort of main window and a number of
temporary dialogs.  The same approach is taken, i.e. the application's settings
are loaded once and then every time the event loop is about to be entered the
:meth:`~dip.settings.ISettingsManager.restore` method is called with the
appropriate sequence of views, and then after the event loop exits the
:meth:`~dip.settings.ISettingsManager.save` method is called with the same
sequence of views.

Every setting has a string identifier.  With a view's settings this is usually
the identifier of the view.  A view has a default identifier which is not
guaranteed to be unique.  For example the default identifier of a dialog
created by the :class:`~dip.ui.Dialog` factory is ``dip.dialog``.  If an
application has a number of different dialogs created this way then they will
all have the same identifier, and so will share the same settings.  This is
probably not what the user expects.  Therefore it is recommended that such
dialogs (and wizards) be given explicit and unique identifiers.  This also
helps when automating user interfaces.

A final point to make is that the
:meth:`~dip.settings.ISettingsManager.restore` and
:meth:`~dip.settings.ISettingsManager.save` methods have no effect if the
:meth:`~dip.settings.ISettingsManager.load` method has not been called.  This
means that user interfaces that are parts of libraries can support settings by
making calls to the :meth:`~dip.settings.ISettingsManager.restore` and
:meth:`~dip.settings.ISettingsManager.save` methods but it remains the
responsibility of the application using the library to decide if settings are
actually used.


Non-declarative Views
---------------------

So far we have created views by calling a view factory that has been defined
declaratively.  The view factory will also, under the covers, bind the view to
a model.  This is the most concise way to create a user interface that will
automatically update the model, and also will itself be automatically updated
when the model is changed.  However there are several reasons why you might
want to use a view created by some other means (e.g. by making toolkit specific
calls, or using the :mod:`dip.pui` module):

- to re-use an existing user interface

- to incorporate widgets that don't have a corresponding view factory

- to configure a widget which cannot be done by setting the widget properties

- you just prefer the traditional programming style.

Even though we create the view programmatically we can still use the view with
other dip modules as if it has been created declaratively.  For example the
view can be automated and tested using the :mod:`dip.automate` module.

If we don't use view factories to create the view we need to explicitly bind
the view to a model.  To do this we define the bindings as an instance of the
:class:`~dip.ui.Bindings` class.  We then call the instance's
:meth:`~dip.ui.Bindings.bind` method to bind the particular view and model.

We will now look at a version of an earlier example that creates the view
programmatically.  The complete example can be dowloaded from
:download:`here</examples/ui/bindings.py>`.

In the earlier example the view was defined with the following line of code.

.. literalinclude:: /examples/ui/extended_model.py
    :start-after: Define the view
    :end-before: Create an instance

The view was then created and bound to the model with the following line of
code.

.. literalinclude:: /examples/ui/extended_model.py
    :start-after: Create an instance
    :end-before: Make the instance

In the new example we create the view with the following code.  This should be
very familiar to a PyQt developer.  The key thing to note is that the
:class:`~PyQt4.QtGui.QLineEdit` and :class:`~PyQt4.QtGui.QSpinBox` widgets have
each had their ``objectName`` property set.  This is used to identify the
widget when binding it to a particular attribute of the model.

.. literalinclude:: /examples/ui/bindings.py
    :start-after: Create the view
    :end-before: Define the bindings

Next we define the bindings as shown in the following line of code.  The name
of each keyword argument corresponds to the ``objectName`` of a widget in the
view.  The value of the keyword argument is the name of the attribute in the
model that the widget is to be bound to.

.. literalinclude:: /examples/ui/bindings.py
    :start-after: Define the bindings
    :end-before: Bind the view

Finally, the following line of code uses the bindings we have defined to bind a
particular view to a particular model.

.. literalinclude:: /examples/ui/bindings.py
    :start-after: Bind the view
    :end-before: Make the instance

In the above we have bound the name of a widget to the name of an attribute.
We may also bind the name of a widget to an instance of a view factory.  The
view factory itself is bound to the name of the attribute in the usual way,
i.e. by passing it as the first argument to the factory.  This allows us to
provide additional information about a widget and to add specific behaviour to
it.

For example, say we have a model which contains a list of integer values::

    model = dict(values=[])

We create a view containing a :class:`~PyQt4.QtGui.QListWidget` with a pair of
:class:`~PyQt4.QtGui.QPushButton` to the right of it::

    button_layout = QVBoxLayout()
    button_layout.addWidget(QPushButton("Add", objectName='add'))
    button_layout.addWidget(QPushButton("Remove", objectName='remove'))
    button_layout.addStretch()

    layout = QHBoxLayout(objectName='values_editor')
    layout.addWidget(QListWidget())
    layout.addLayout(button_layout)

    ui = QWidget()
    ui.setLayout(layout)

We want to add a new entry to the list when the ``Add`` button is pressed and
to remove the current entry when the ``Remove`` button is pressed.

Now we define the bindings::

    bindings = Bindings(
            values_editor=ListEditor(
                    'values', column=ListColumn(column_type=Int())))

Our ``layout`` will be bound to the :class:`~dip.ui.ListEditor` view factory
because it fulfills the (toolkit specific) requirements of a list editor.  In
this case those requirements are:

- a :class:`~PyQt.QtGui.QListWidget` that is directly contained in the layout
- a :class:`~PyQt.QtGui.QAbstractButton` with an ``objectName`` of ``'add'``
  that is contained in the layout or a sub-layout
- a :class:`~PyQt.QtGui.QAbstractButton` with an ``objectName`` of ``'remove'``
  that is contained in the layout or a sub-layout.

The view factory is itself bound to the ``values`` attribute of the model.  In
addition we have used the :class:`~dip.ui.ListColumn` to specify the type of an
element of the list.  We have to do this because there is no way to infer it
from a dict-based model.

As a result, when the bindings's :meth:`~dip.ui.Bindings.bind` method is called
dip is able to connect everything up to achieve the desired behaviour.


Creating Views with Qt Designer
-------------------------------

You can incorporate views created with Qt Designer (or any other toolkit
specific GUI design tool) by creating them as you would normally do and
explicitly binding the relevant widgets to attributes of a model as described
in the previous section.

You may also use the :class:`~dip.ui.Designer` view factory to do this for you
by giving it the name of the ``.ui`` file created using Qt Designer.

For example, say we have a model which contains a single string::

    model = dict(name='')

We have a file called ``name_editor.ui`` created with Qt Designer that contains
a widget that can edit a string and which has an ``objectName`` of
``lineEdit``.

We then create a view factory specifiying the name of the ``.ui`` file and the
bindings that define the relationship between the ``lineEdit`` widget and the
``name`` attribute of the model::

    view = Designer('name_editor.ui', bindings=Bindings(lineEdit='name'))

We then call the view factory and show the user interface it creates as
normal::

    ui = view(model)
    ui.show()


Using a Real Model
------------------

So far in our examples we have implemented the model using a Python
dictionary.  Normally models are implemented as sub-classes of
:class:`~dip.model.Model`.  Doing so has two particular advantages when using
views.

- A view can automatically use any meta-data provided by an
  :term:`attribute type` that correspond to the names of properties that can be
  applied to an editor.

- A view will automatically update itself if the value of any of the model's
  attributes changes.  Model changes can be made programmatically or by the
  user using another view bound to the same model.

In this section we modify the example, shown below, to demonstrate both of
these features.  We also choose to create some of the GUI using the toolkit
specific API just to demonstrate how easy it is to mix the toolkit independent
and toolkit specific APIs.

.. image:: /images/real_model.png
    :align: center

When running the example you will see that the ``age`` is limited to the
values defined by the meta-data in the model, and that changes to either view
are instantly reflected in the other.

The complete example can be downloaded from
:download:`here</examples/ui/real_model.py>`.  We will now walk through the
changes to the previous example.

.. literalinclude:: /examples/ui/real_model.py
    :end-before: import Application

The above lines import the additional objects used by the example.

.. literalinclude:: /examples/ui/real_model.py
    :start-after: Define the model
    :end-before: Every application

The above lines define the model.  Hopefully this is fairly self-explanatory.

Note that all editors will use any ``status_tip``, ``tool_tip`` or
``whats_this`` text found in a type's meta-data.

.. literalinclude:: /examples/ui/real_model.py
    :start-after: Create the model
    :end-before: Define the sub-view

The above line simply creates an instance of the model.

.. literalinclude:: /examples/ui/real_model.py
    :start-after: Create two instances
    :end-before: Create a regular

The above lines define two identical instances of the view.  Both views are
bound to the same model.

.. literalinclude:: /examples/ui/real_model.py
    :start-after: Create a regular
    :end-before: Enter the

The above lines are standard PyQt calls that create and display a
:class:`~PyQt4.QtGui.QWidget` containing the two views side by side.  Note the
calls to :func:`~dip.model.unadapted` to get the toolkit specific widgets from
the sub-views.

.. literalinclude:: /examples/ui/real_model.py
    :start-after: Show the value
    :end-before: EOF

The above lines display the model's attribute values.


Controllers and Validation
--------------------------

We have already briefly mentioned that a view has a :term:`controller` that is
responsible for the interaction between the view and the model.  The specific
responsibilities of the controller are:

- to determine if the data in the view is valid

- to update the model with valid data from the view

- to update the view if the model changes

- to enable and disable the editors in the view, typically in response to
  changes made by the user to other editors

- to provide easy programatic access to the editors in the view.

If a controller is not explicitly set for a view then a default controller is
automatically created.  The default controller considers a view to be valid if
all the enabled editors contain valid data.  It will update the model when any
valid data changes.  As we have already mentioned the default controller
created for a :class:`~dip.ui.Dialog` will only update the model with valid
data when the ``Ok`` button is clicked.

You will usually want to create and explicitly set a controller for a view when
you need to provide more sophisticated validation of a view, or to disable
certain editors when other editors contain particular values.

In this section we will walk through a more complicated example, shown below,
of a view that demonstrates the use of validation, help and the creation of an
explicit controller.

.. image:: /images/validate.png
    :align: center

The example has the following features.

- Tool tip and What's This help is provided for some editors.

- The ``Name`` editor ensures any entered data matches a regular expression.

- The ``Children`` editor is disabled if the gender is inappropriate.

- The view is invalid if the values of the ``Age`` and ``Driving license`` are
  incompatible.

- A user friendly explanation of why the view is invalid is provided.

- The ``Ok`` button is only enabled when the view contains valid data.

The following is the complete example (which you can download from
:download:`here</examples/ui/validate.py>`).

.. literalinclude:: /examples/ui/validate.py

We will now walk through the significant parts of the code.

.. literalinclude:: /examples/ui/validate.py
    :start-after: SpinBox)
    :end-before: class PersonController

The above code defines the ``Person`` model.  The main thing to note are the
keyword arguments to the different types.  These are all meta-data, i.e. they
are ignored by the types themselves but are available to other code.  In this
case they are used by the view we create later on.  We could just as easily
pass them as property values to the corresponding editor factory, but including
them with the model means that they will be used automatically by any view that
uses the model.  If an editor factory does explicitly specify a property value
of the same name then it will be used in preference to that in the model.

The meta-data themselves should be fairly self-explanatory.  The ``required``
argument of the ``name`` attribute is used by :class:`~dip.ui.LineEditor` to
configure an instance of :class:`~dip.ui.StringValidator` to ensure that a name
doesn't have any leading or trailing spaces.

Our controller is a sub-class of dip's :class:`~dip.ui.DialogController` class
that reimplements the :meth:`~dip.ui.IController.validate_view` and
:meth:`~dip.ui.IController.update_view` methods.

The :meth:`~dip.ui.IController.validate_view` method is called after each of
the view's enabled editors have been successfully validated.  Its purpose is to
perform any additional validation where particular combinations of (otherwise
valid) editor values are invalid.  In our example, shown below, the view is
invalid if the ``Age`` and ``Driving license`` editors have incompatible
values.

.. literalinclude:: /examples/ui/validate.py
    :pyobject: PersonController.validate_view

In the above code we make use of the fact that a controller automatically
provides attributes that correspond to each editor.  The name of the attribute
is the identifier of the editor with ``_editor`` appended.  If the identifier
is in *dotted* format then only the last part of the identifier is used in the
comparison.  The default identifier is the name of the attribute in the model
that the editor is bound to.

A controller provides similar access to actions (using the ``_action`` suffix)
and views (using the ``_view`` suffix).

The :meth:`~dip.ui.IController.update_view` method is called after the view has
been fully validated and the model as been updated (if the
:attr:`~dip.ui.IController.auto_update_model` attribute has been set).  Its
purpose is to update the state of any editors (or sub-views) that are dependent
on the values of any other editors.  In our example, shown below, the
``Children`` editor is only enabled if the ``Gender`` editor has an appropriate
value.

.. literalinclude:: /examples/ui/validate.py
    :start-after: return invalid_reason
    :end-before: # Every application

Note that we also call the super-class
:meth:`~dip.ui.DialogController.update_view` implementation which ensures that
the ``Ok`` button is only enabled when the view is valid.

The next significant code to look at is that which defines the view.

.. literalinclude:: /examples/ui/validate.py
    :start-after: # Define the view
    :end-before: # Create the controller

The main point of interest in the above code is the use of
:class:`~dip.ui.MessageArea`.  If this is specified then the controller uses it
to display any messages to the user.  It can be configured via its (toolkit
specific) properties.  For example a message area defined as follows will show
white text on a red background::

    MessageArea(styleSheet='background-color: red; color: white')

The following line creates the instance of the controller.

.. literalinclude:: /examples/ui/validate.py
    :start-after: # Create the controller
    :end-before: # Create an instance

Finally, the following line creates the instance of the view and uses the
controller instance we have just created rather than a default one.

.. literalinclude:: /examples/ui/validate.py
    :start-after: # Create an instance
    :end-before: # Enter the


Menus, Tool Buttons and Actions
-------------------------------

An :term:`action` is an abstraction of a user operation that triggers some
change in an application.  An action can be visualised in a GUI as, for
example, an item in a menu or a tool bar or both.  The great advantage of
actions is that when their state changes, the widgets being used to visualise
them update their appearence automatically.

As you would expect actions (instances of which implement the
:class:`~dip.ui.IAction` interface) can be defined declaratively using the
:class:`~dip.ui.Action` factory.  However this factory can be used in two
different ways depending on the use case.  It can be used as an
:term:`attribute type`, similar to :class:`~dip.model.Int`, or as a simple
factory that creates actions than can be bound to an attribute of a model,
similar to the way an editor factory works.  Using :class:`~dip.ui.Action` to
define an attribute type is described in the section :ref:`shell-tutorial`.

When created by an :class:`~dip.ui.Action` used as a simple factory, an action
(like an :term:`editor`) is bound to an attribute of a model.  If an action is
not bound then it is hidden.  Again like editors, actions have string
identifers that default to the name of the attribute to which they are bound.

A menu is defined as a list of items.  An item can either be a sub-menu, an
empty string (indicating a separator), or the identifier of an action.

A tool button can be bound to either a model attribute (like any other editor)
or to an action.  If there is an action with an identifier that is the same as
the name of a model attribute then the tool button will be bound to the action.

When a view is created by a view factory the individual actions are also
created and added to the controller.

The following is a complete example (which you can download from
:download:`here</examples/ui/menus.py>`) that demonstrates:

- the declarative definitions of a set of actions, including well known actions
- the declarative definition of a simple menu hierarchy
- binding the same action to a menu item and to a tool button
- the different methods of responding to the triggering of an action
- changing the state of an action.

.. literalinclude:: /examples/ui/menus.py

We will now walk through the significant parts of the code starting with the
implementation of the model.

.. literalinclude:: /examples/ui/menus.py
    :start-after: from dip.ui.actions
    :end-before: class ExampleController

Typically we define a :class:`~dip.model.Trigger` attribute for each action we
will be defining later on and we will :func:`~dip.model.observe` the attribute
and execute the code that implements the action when it is triggered.  The code
is usually implemented in the controller.  This is how the ``quit`` attribute
is handled in our example.

It is also possible to bind an action to a :class:`~dip.model.Bool` attribute
of a model.  In this case the action is configured to be checkable and will
automatically maintain the value of the attribute.  This is how the ``male``
attribute is handled in our example.

A more concise method of connecting an action to the code that implements the
action is also provided.  An action can be bound to the name of a method in the
model.  When the action is triggered then that method is called with the
controller passed as the only argument.  This is demonstrated by the
``toggle_quit()`` method in our example.  It can be argued that placing this
code in the model, rather than the controller, breaks the design pattern
although it might mean that there is no need for a specific controller at all.
It is up to you to decide which approach you are more comfortable with.

We now look at the line of the ``toggle_quit()`` method that gets a reference
to the ``quit`` action.

.. literalinclude:: /examples/ui/menus.py
    :start-after: # Get the toolkit
    :end-before: # Toggle the

A controller automatically provides attributes that correspond to each action
in the same way as it does for each editor and view.  The name of the attribute
is the identifier of the action with ``_action`` appended.  If the identifier
is in *dotted* format then only the last part of the identifier is used in the
comparison.

We will now look at the controller.

.. literalinclude:: /examples/ui/menus.py
    :start-after: action.enabled
    :end-before: # Every application
  
The ``__on_male_changed()`` method is invoked whenever the ``male`` attribute
of the model changes.  In our example we simply display the new value.

Similarly the ``__on_quit_changed()`` method is invoked whenever the ``quit``
attribute of the model is triggered.  In our example we call the toolkit
independent API for terminating the application.

We will now look at the definition of the view.

.. literalinclude:: /examples/ui/menus.py
    :start-after: # Define the view
    :end-before: # Create an instance

The GUI that will be created will be a menu bar, a form and a tool button
arranged vertically.  The view also defines the actions and a factory for
creating the controller.

The menu bar is defined as a hierachy of menus.  A menu is defined as a list of
menu items each being a string identifier or a sub-menu.  An identifier is the
identifier of the action that is visualised by the menu.  Note that the
identifier is not the name of an attribute in the model even though, in this
example, there are attributes in the model with the same names.  If an
identifier is the empty string then this is interpreted as a menu separator.

The definition of the form is as you would expect and contains a single editor
that is bound to the ``name`` attribute of the model.

A tool button is slightly different to other GUI elements in that it can be
bound to either an action (like a menu item) or an attribute of a model (like a
regular editor).  If there is an action with the same identifier as the name of
an attribute in the model then the tool button will always be bound to the
action.  Therefore in our example we have a menu item and the tool button both
bound to the action whose identifier is ``quit``.

The actions are specified as a list of :class:`~dip.ui.Action` factories.  dip
supports a number of *well known* actions corresponding to actions common to
many applications.  These should be used if possible as they may implement
toolkit specific standards for text, shortcuts and icons for example.  In our
example we are using the :class:`~dip.ui.actions.QuitAction` action factory.
With any action that is bound to an attribute, the action's identifier is set
to the name of the attribute in the model that the action is bound to.

Rather than create a controller explicitly and passing it to the view factory
as we have done in previous examples, we have chosen to specify the type of our
controller as a controller factory.  As well as being a little more concise
this has the advantage that, internally, the controller is created with the
model as an initial argument.  This means that we can use
:func:`~dip.model.observe` to decorate the controller's methods.  If we didn't
do this then the controller's :attr:`~dip.ui.IController.model` attribute would
be set as a separate step which would mean that we would have to provide a
decorated method than was invoked when the model was set and we would then
explicitly :func:`~dip.model.observe` the model's attributes as required.


A Pattern for Simple GUI Utilities
----------------------------------

Although dip contains lots of functionality intended to support the development
of large, complex applications it is also very suitable for writing simple GUI
utilities.  In this section we walk through the code of a line counting
utility using a pattern that can be used whenever there is a need to gather
some information from the user, perform some task using that information as
input and then displaying the output.

Such applications are typically dialog or wizard based and rarely need features
of a specific toolkit.  We have chosen to write this example without using any
toolkit specific code.  It is also interesting to note that the application
will run unchanged under Python v3 and v2.

The complete source code (which you can download from
:download:`here</examples/ui/line_count.py>`) is shown below.

.. literalinclude:: /examples/ui/line_count.py

The code comprised three sections:

- the ``import`` statements

- a combined model/view class that represents the input data, declaratively
  defines the GUI used to gather the data from the user and actually counts the
  lines

- the code to create the model/view instance and call its methods to create the
  GUI and count the lines.

Note that we have chosen to use a wizard to gather the input data from the
user.  However the amount of data doesn't really justify this (a simple dialog
would be sufficient) but we wanted to demonstrate how easy it is to create a
wizard.

The ``import`` statements are shown below.

.. literalinclude:: /examples/ui/line_count.py
    :end-before: class LineCounter

The model/view class is called ``LineCounter`` and is a sub-class of
:class:`~dip.model.Model` as you would expect.

.. literalinclude:: /examples/ui/line_count.py
    :start-after: WizardPage)
    :end-before: # The name of the root

The input data we want to gather from the user is the name of a directory and
an optional list of glob-like patterns that are used to filter the names of
files in the directory.  These are represented as attributes in the model.  The
directory name, stored as a string is shown below.

.. literalinclude:: /examples/ui/line_count.py
    :start-after: # The name of the root
    :end-before: # The list of glob-like

The declaration of the list of filters is shown below.

.. literalinclude:: /examples/ui/line_count.py
    :start-after: # hierachy
    :end-before: # The wizard

By specifying the ``required`` meta-data we are telling any editor that dip
creates to modify the attribute that each filter must contain at least one
non-whitespace character.

The final attribute is the declaration of the wizard used to gather the input
data.  Note that this is an ordinary class attribute.

.. literalinclude:: /examples/ui/line_count.py
    :start-after: # ordinary class
    :end-before: def populate

The wizard has two pages the first of which is shown below as it appears when
the utility is started.

.. image:: /images/line_count_page_1.png
    :align: center

The interesting part of the page is the
:class:`~dip.ui.FilesystemLocationEditor` arranged in a :class:`~dip.ui.Form`.
The :class:`~dip.ui.MessageArea` towards the bottom of the page reflects the
fact that the directory name is currently empty.  Because the page is invalid
the ``Continue`` button (or ``Next`` button depending on your platform) is
disabled.  It will be automatically enabled as soon as the user enters the name
of an existing directory.

The second wizard page is shown below after we have added a ``*.py`` filter.

.. image:: /images/line_count_page_2.png
    :align: center

The main component in this page is the central :class:`~dip.ui.ListEditor`
where the filters can be edited.

The next part of the model/view is the ``populate()`` method, the body of which
is shown below.

.. literalinclude:: /examples/ui/line_count.py
    :lines: 57-59

The first of the above lines calls the :class:`~dip.ui.Wizard` factory to
create a wizard that implements the :class:`~dip.ui.IWizard` interface.

The second of the above lines calls the :meth:`~dip.ui.IWizard.execute` method
of the :class:`~dip.ui.IWizard` interface to allow the user to interact with
it.  The ``populate()`` method then returns ``True`` if the user didn't cancel.

The next part of the model/view is the ``perform()`` method which does the
actual work of counting the lines in the files.  The first section of the
method, shown below, builds up the full list of files taking any filters into
account.

.. literalinclude:: /examples/ui/line_count.py
    :start-after: """ Count the number
    :end-before: # Count the files

The next section of the method, shown below, reads each file and adds the
number of lines in each to a running total.

.. literalinclude:: /examples/ui/line_count.py
    :start-after: # Count the files
    :end-before: # Tell the user

The final section of the method, shown below, displays the total line count and
the number of files as a dialog using the
:meth:`~dip.ui.Application.information` static method.

.. literalinclude:: /examples/ui/line_count.py
    :start-after: # Tell the user
    :end-before: # Every application

An example of the output produced is shown below.

.. image:: /images/line_count_output.png
    :align: center

That completes our walk through of the ``LineCounter`` model/view class.

.. note::

    This example uses a :term:`controller` that is created automatically.
    What if we needed to use a specialised controller, perhaps to perform some
    additional validation?
    
    This is most easily done (in a simple utility such as this) by combining it
    with the existing model/view.  In other words, ``LineCounter`` should be
    sub-classed from :class:`~dip.ui.WizardController` instead of
    :class:`~dip.model.Model`.  All you need to do then is to provide
    ``LineCounter`` with an implementation of
    :meth:`~dip.ui.WizardController.validate_page`.

The final section of the whole utility is shown below.

.. literalinclude:: /examples/ui/line_count.py
    :start-after: # Every application
    :end-before: EOF

Here we create the toolkit specific :class:`~dip.ui.Application` instance
required by every GUI based application, create the instance of our model/view,
populate the model, and (if the user didn't cancel) perform the task of
counting the lines of the specified files.
