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

In this section we work through a number of examples of building simple user
interfaces 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.

A view is implemented as a PyQt GUI, i.e. a hierarchy of
:class:`~PyQt4.QtGui.QWidget` and :class:`~PyQt4.QtGui.QLayout` instances.  A
view can be created programmatically, using Qt Designer, or declaratively using
the view factories provided by :mod:`dip.ui`.

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.

A :term:`toolkit` is used, usually by declarative view factories, to do the
work of creating specific widgets when required.


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 printed.

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

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

The above lines are the imports needed by the example.

.. literalinclude:: /examples/ui/simple.py
    :start-after: Every PyQt
    :end-before: We need

The above line creates the :class:`~PyQt4.QtGui.QApplication` instance needed
by every PyQt GUI application.

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

dip uses a :term:`toolkit` to actually create widgets and layouts.  The above
line creates an instance of the toolkit included with dip that creates
standard Qt widgets and layouts.  Alternative toolkits may be provided, one
using KDE would be an obvious example.

.. 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` (or, more accurately, the view
factory).  Using the Qt 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.  A view factory will always make sure that a
:class:`~PyQt4.QtGui.QWidget` instance is created.

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

The above line is the standard PyQt call that makes a user interface visible
to the user.  It is important to realise that instances of views are ordinary
PyQt layouts and widgets and can be used as such in applications.  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 Qt
Designer and view factories defined declaratively.

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

The above line is the standard PyQt 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.

.. 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
    :start-after: from PyQt4
    :end-before: from dip.ui.toolkits

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 line shows the new view definition.  :class:`~dip.ui.SpinBox` is the
default editor factory for integer attributes and creates a spin box widget.

In this case, 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 assumed to be the names and
values of Qt properties to be applied to the actual editor that is created.  In
this case the factory doesn't use the ``suffix`` argument itself and so passes
it on to the editor when it creates it.


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
    :start-after: from PyQt4
    :end-before: from dip.ui.toolkits

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

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

The above line shows 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 make a standard PyQt call to display the dialog and enter its
event loop.  If the user clicks the ``Ok`` button then the model is updated
from the dialog.


Creating Views Programmatically
-------------------------------

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 create a view programmatically, i.e. by making normal PyQt calls:

- 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.  Note that we still need to pass a
toolkit even though we have already created the view.

.. 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
:class:`~PyQt4.QtGui.QPushButton` below it::

    layout = QVBoxLayout()
    layout.addWidget(QListWidget(objectName='values_editor'))
    layout.addWidget(QPushButton("Add", objectName='add_button'))

    ui = QWidget()
    ui.setLayout(layout)

We want to add a new entry to the list when the button is pressed.

Now we define the bindings::

    bindings = Bindings(
            values_editor=ListWidget(
                    'values', column=ListColumn(column_type=Int())),
            add_button=AddButton('values'))

First the :class:`~PyQt4.QtGui.QListWidget` is bound to the
:class:`~dip.ui.ListWidget` view factory.  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.

Secondly the :class:`~PyQt4.QtGui.QPushButton` is bound to the
:class:`~dip.ui.AddButton` view factory which is itself linked to the
:class:`~PyQt4.QtGui.QListWidget`.  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 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, toolkit)
    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 connected to the same model.

In this section we modify the example, shown below, to demonstrate both of
these features.

.. 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
    :start-after: import sys
    :end-before: import Form

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

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

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

Note that all editors will use any ``statusTip``, ``toolTip`` or ``whatsThis``
text found in a type's meta-data.

.. literalinclude:: /examples/ui/real_model.py
    :start-after: Create the model
    :end-before: Define the 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 share
the same model.

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

The above lines are standard PyQt calls that create a
:class:`~PyQt4.QtGui.QWidget` containing the two views side by side.

.. 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: import QtToolkit
    :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
``validator`` value, because it is a string, is used by the
:class:`~dip.ui.LineEdit` editor factory to create a
:class:`~PyQt4.QtGui.QRegExpValidator`.  It may also be a callable that is
passed a parent object as its only argument and returns a
:class:`~PyQt4.QtGui.QValidator`.

.. literalinclude:: /examples/ui/validate.py
    :start-after: driving_license = Str
    :end-before: # Every PyQt

The above code is the implementation of the controller.  This is a sub-class of
dip's default :class:`~dip.ui.Controller` class that reimplements the
:meth:`~dip.ui.IController.validate_view` method.  This method is called
whenever the user changes an editor or the application changes the model.

A controller automatically provides attributes that correspond to each editor.
The name of the attribute is the name of the corresponding attribute in the
model with ``_editor`` appended.

Using these attributes the following code disables the ``Children`` editor if
the ``Gender`` editor has an inappropriate value.

.. literalinclude:: /examples/ui/validate.py
    :start-after: The 'children'
    :end-before: The super-class

Normally a reimplementation of :meth:`~dip.ui.IController.validate_view` will
call the base class implementation to handle the validation of the individual
editors as shown in the following code.

.. literalinclude:: /examples/ui/validate.py
    :start-after: The super-class
    :end-before: if invalid_reason

If the individual editors are valid then the controller checks to see that the
``Age`` and ``Driving license`` editors have compatible values as shown in the
following code.

.. literalinclude:: /examples/ui/validate.py
    :start-after: if invalid_reason
    :end-before: return invalid_reason

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 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.  By passing the
``auto_update_model=False`` argument we ensure that the model is only updated
when the ``Ok`` button is clicked.

.. 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


Actions
-------

An action is an abstraction of a user operation that triggers some change in
an application.  It is implemented in PyQt by the
:class:`~PyQt4.QtGui.QAction` class.  An action can be visualised in a GUI as
an item in a :class:`~PyQt4.QtGui.QMenu` or a :class:`~PyQt4.QtGui.QToolBar`
amongst others.  An action will often be visualised more than once allowing
the user to perform the same operation using, for example, a menu, a tool bar
and a context menu.  The great advantage of actions is that when their state
changes, the widgets being used to visualise them update their appearence
automatically.

The basic dip action is defined by the :class:`~dip.ui.IAction` interface.  It
has a string identifier and can be positioned relative to other actions.  It is
recommended that a naming convention be adopted for action identifiers.

The :class:`~dip.ui.ActionCollection` class, which implements the
:class:`~dip.ui.IAction` interface, is used to define a collection of actions,
possibly organised in a hierarchy, which can be turned into an appropriate
widget such as a :class:`~PyQt4.QtGui.QMenu` or :class:`~PyQt4.QtGui.QToolBar`.

An :class:`~dip.ui.ActionCollection` has an optional title, and a list of
members.  The title is normally used when the collection is visualised.  If
there is no title then the collection may be visualised differently.

Each member of a collection may be either an object that implements the
:class:`~dip.ui.IAction` interface or a string.  A string may be either empty
or be the identifier of an action.  An empty string is usually interpreted as
being some sort of separator when the collection is visualised.  If the string
is the identifer of an action then it acts as a place holder and will be
replaced by the action when the collection is visualised.

The :class:`~dip.ui.Action` class, which also implements the
:class:`~dip.ui.IAction` interface, is a convenient wrapper around a
:class:`~PyQt4.QtGui.QAction` so that it can be positioned within an
:class:`~dip.ui.ActionCollection`.


Menus
-----

In this section we will describe how to use menus whose structure is defined
using an :class:`~dip.ui.ActionCollection`.  We start with a simple example
and work through a number of changes so that we end up with something
reflecting the structure of a real application.

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

.. literalinclude:: /examples/ui/menus_1.py

Running the example shows the menu hierarchy.  Clicking on the ``Exit`` entry
of the ``File`` menu will exit the application.

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

We will now go through the example, but we won't bother with the imports and
the standard PyQt calls common to all applications.

.. literalinclude:: /examples/ui/menus_1.py
    :start-after: Create the main window
    :end-before: Create the action

The above line creates the :class:`~PyQt4.QtGui.QMainWindow` that will contain
the menus.

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

The above line creates the :class:`~dip.ui.Action` that will terminate the
application.  Note the use of the keyword argument to connect the
:meth:`~PyQt4.QtGui.QAction.triggered` signal.

.. literalinclude:: /examples/ui/menus_1.py
    :start-after: Define the action
    :end-before: Create the factory

The above line defines the action hierarchy.  It consists of a single
collection containing the the action we created previously.  Note that we
don't bother to give either the action or the collection an identifier.

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

Now that we have the definition of the action hierarchy we create an instance
of :class:`~dip.ui.MenuBar` that will use it to create a particular
visualisation of the collection.

.. literalinclude:: /examples/ui/menus_1.py
    :start-after: Create an instance
    :end-before: Add the menu

To create a visualisation of the collection using a
:class:`~PyQt4.QtGui.QMenuBar` we simple call the :class:`~dip.ui.MenuBar`
instance as shown in the above line.

.. literalinclude:: /examples/ui/menus_1.py
    :start-after: Add the menu
    :end-before: Make the main window

Finally we attach the instance of the menu hierarchy to the
:class:`~PyQt4.QtGui.QMainWindow` as shown in the above line.

So how might this example be improved?  One potential problem with it is that
the :class:`~dip.ui.Action` instance is coupled to the definition of the action
hierarchy rather than a particular instance of it.  While this isn't a problem
for small applications, it might cause problems for larger, extensible
applications.

A slightly modified version of the example (which you can download from
:download:`here</examples/ui/menus_2.py>`) avoids this problem.

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

In the above lines we have given the action the identifier ``example.exit``.

.. literalinclude:: /examples/ui/menus_2.py
    :start-after: Define the action
    :end-before: Create the factory

In the above line we have provided the action's identifier rather than the
instance itself.

.. literalinclude:: /examples/ui/menus_2.py
    :start-after: Create an instance
    :end-before: Add the menu

In the final change, shown in the above line, we pass the action itself when
we create the instance of the menu hierarchy.  (If, as is likely, we have more
than one action then they are simply passed as additional arguments.)
The result is that we have decoupled the action from the definition of the
menu hierarchy.

It is recommended that a naming convention be adopted for action identifiers.


More on Toolkits and View Properties
------------------------------------

dip uses a :term:`toolkit` to create all the widgets and layouts that it needs
itself.  A toolkit also defines the factory used to create the editor for an
:term:`attribute type`.  Toolkits are lightweight objects that should not
contain state information.  Therefore they can be created and destroyed as and
when required.

It is important to understand that a toolkit is not a mechanism primarily
designed for writing toolkit-independent applications.  However, with a little
care, it is possible to do so.

A toolkit is not required to create widgets that have a consistent API.  For
example the :class:`~dip.ui.toolkits.qt.QtToolkit` included with dip will
create an instance of :class:`~PyQt4.QtGui.QSpinBox` when asked to by the
:class:`~dip.ui.SpinBox` editor factory.  Another toolkit may create an
instance of a completely different class when asked to do the same thing.  In
other words, applications cannot assume that the API of a widget created by
one toolkit is compatible with the API created by another.

This is particularly an issue when configuring a view with property names
and values when specifying a view factory.

This all makes it sound very difficult to create toolkit-independent
applications.  However:

- tookits will not be fundamentally different to each other.  All widgets will
  be instances of :class:`~PyQt4.QtGui.QWidget`, and in most cases a toolkit
  will create a sub-class of a standard Qt widget.  For example a KDE toolkit
  will create an instance of ``KIntSpinBox`` which is a sub-class of
  :class:`~PyQt4.QtGui.QSpinBox`.  Therefore if an application restricts
  itself to the :class:`~PyQt4.QtGui.QSpinBox` API it will be portable but
  still look like a KDE application

- properties that are invalid for a particular view will be ignored and will
  not raise an exception.

In summary, making an application work with multiple toolkits isn't as simple
as just using an instance of the new toolkit in place of the old.  The
application needs to be checked against any documented toolkit
incompatibilites.  However it is expected that there will be very few of
these.


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.

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 is shown below.

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

The directory name is stored as a string.  By specifying the ``required``
meta-data we are telling any editor that dip creates to modify the value that
it must consist of at least one character.  By specifying the ``validator``
meta-data we are also saying that the value must be the name of an existing
directory.

The declaration of the list of filters is shown below.

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

Here the meta-data means that each filter must contain at least one
non-whitespace character.

Next we declare an attribute that holds the :term:`toolkit` that will be used
to create the GUI.

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

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.  We have configured the wizard itself by setting the
``windowTitle`` and ``options`` properties.  We have specified that the
``Finish`` button will be shown on all pages.  This is because the second page
of the wizard is completely optional.

The first page of the wizard 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.FileSelector` 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 ``Next`` and ``Finish`` buttons are
disabled.  They 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 components in this page are the central :class:`~dip.ui.ListWidget`
where the filters can be edited, and the :class:`~dip.ui.CollectionButtons`
that are used to manipulate the entries in the list.  The tool buttons may also
be used individually or not at all.  They can also be placed anywhere within
the page.  For example, as the filters are independent of each other there is
no real need to be able to move them around with the up and down buttons.
Therefore we could instead do something like::

    HBox(Stretch(), AddButton('filters'), RemoveButton('filters')),

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: 63-65

The first of the above lines creates the :class:`~PyQt4.QtGui.QWizard` instance
itself by calling the :class:`~dip.ui.Wizard` factory.  The two arguments are
the model (i.e. ``self``) and the toolkit.  A different toolkit may mean that
some other implementation of a wizard may be created instead.

The second of the above lines is the standard PyQt call to display the wizard
and 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 toolkit's
:meth:`~dip.ui.IToolkit.information` method.

.. literalinclude:: /examples/ui/line_count.py
    :start-after: # Tell the user
    :end-before: @toolkit.default

An example of the output produced is shown below.

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

The final part of the model/view is the method that creates the default
toolkit, the body of which is shown below.

.. literalinclude:: /examples/ui/line_count.py
    :start-after: """ Create the default
    :end-before: # Every PyQt

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 PyQt
    :end-before: EOF

Here we create the :class:`~PyQt4.QtGui.QApplication` 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.
