

1.0 The Scope of the proposal
-----------------------------
The issues discussed here are in relation to a proposal to add validation
features to the entry widgets in gtk. The widgets targeted by this
proposal are the GtkEntry, GtkSpinButton and GtkCombo widgets.
The proposal can be found at the URL :
http://bugzilla.gnome.org/show_bug.cgi?id=50276
The proposal is an attachment and is labeled as attachment id=13397.
The entry widgets mentioned above all allow the user to type
text into an entry field. From a code modelling point of view,
the GtkSpinButton is derived from GtkEntry and the GtkCombo
contains a GtkEntry, so a common approach can be taken by
just dealing with the GtkEntry widget.
The idea of entry validation is to allow the user to type
text into the entry widget and then when they are finished typing,
a validation function is called to check that the text that was
typed is valid text.
The proposal mentioned above only deals with validation for
an entry widget as an individual entity. The proposal does not
deal with the case when a number of widgets need to be validated
together as a group. See the section below with the heading
"Validation of a group of widgets" for some ideas about extending
the proposal to handle a group of widgets.


There are many approaches to entry validation
---------------------------------------------
There are many different approaches that can be taken in order to
implement entry validation. Here is a list of some of the 
possible approaches.

  Approach 1
  ----------
  One approach is to present the user with a modal
  dialog box which contains entry widgets and allow the user to type
  into the widgets and then when the OK or APPLY button is pressed,
  the validation of the widgets occurs. This approach is already
  supported by GTK and does not need any extra consideration.
  The disadvantage of this approach is that it
  involves a modal dialog box that obscures the underlying
  user interface (why use an extra pop up dialog when you dont need to?).

  Approach 2
  ----------
  Another approach is similar to approach 1 but does not involve
  a modal dialog box. In this approach, the main window contains
  entry widgets and also has an OK or APPLY button. The disadvantage
  of this approach is, because the entry widgets are not in a modal
  dialog box, the user may click on any arbituary widget on the user
  interface. This means that other widgets on the user interface
  will receive BUTTON_PRESS events while unvalidated text exists
  in the entry widgets. This complicates the design of a program
  because other widgets have to be aware of the validation state
  of entry widgets. It would be better if entry widgets never
  contained invalid text.

  Approach 3
  ----------
  Another approach is similar to approach 2 but does not involve
  an OK or APPLY button. In this approach, the main window contains
  entry widgets and when the user enters text into an entry widget
  and then clicks out of the widget onto a different widget, the
  validation occurs. This approach suffers from the same disadvantage
  as Approach 2 because the entry validation logic has to be
  distributed amongst multiple widgets rather that just the widget
  that requires validation.


The validation logic should be localised
----------------------------------------
If a user interface contains entry widgets and those widgets need
to be validated, then the validation logic should be directly
associated with the entry widgets that need validation,
rather than being distributed amongst every other widget
that could possibly receive the focus.


Why not use the focus out event for validation ?
------------------------------------------------
One solution to entry validation may be to connect
to the focus-out signal of the entry widget
and perform the validation when the focus leaves.
This is not viable because the BUTTON_PRESS
event is delivered to a different widget before the focus-out
event is delivered to the entry widget and hence the 
different widget has to deal with the fact that unvalidated
text exists in the entry widget.
In addition, it is not possible to return TRUE from a
focus-out signal handler , indicating that the event
should not be propagated because this causes an error
from GTK.


Why not use the widget "grab" mechanism ?
-----------------------------------------
Another possible approach to take may be to use the grab mechanism
to make the entry widget the current "grabbed" widget. That would
prevent the user from transfering the focus to any other widget
until the text entered was validated. This approach is not
viable because when a grab is in effect, all of the other widgets
on the user interface are completely un-responsive, that is,
they do not even receive the ENTER_NOTIFY or LEAVE_NOTIFY events
and hence widgets do not highlight when the mouse moves over them.
This causes problems because when a different widget eventualy does
receive the focus (after the grab is released) some widgets do not
function correctly (such as a checkbox) because they require the
ENTER_NOTIFY to occur before they receive the BUTTON_PRESS.
I have prototyped this solution and it is possible to send a
synthetic ENTER_NOTIFY event to the widget that is receiving the
focus after the grab is released.
I do not beleive this is a good solution because the
user interface is completely un-responsive when a grab is in
effect and does not provide a pleasant user experience.


A description of the approach taken
-----------------------------------
The approach I have taken is to allow the developer to install
a validation callback on a GtkEntry widget. When the focus enters
the GtkEntry widget, validation is marked as pending for that widget
if the developer has installed a callback.
When an event arrives that would have caused the focus to leave the GtkEntry
{button press or key press}, the validation callback is called.
If the validation fails then the event is ignored so that
the focus does not leave the GtkEntry. If the validation passes then the
event is propagated in the normal way.
The user may display a modal dialog from within the validation callback
or may cause a beep sound to occur or may do nothing at all because the
focus will not leave the GtkEntry if the callback returns FALSE.



Validation of a group of widgets
--------------------------------
The approach proposed here could fairly easily be extended to
a group of widgets rather than just a single widget.
Say, for example, that an entry widget and a checkbox had to
be validated together as a pair rather than as individuals.
In this case, the user could click on either of the 2 widgets
and validation would not occur, only when the user clicks on
a different widget (other than the entry and the checkbox)
would the validation occur. If the validation failed then the
focus would not leave the widget that currently has the focus.
This could be implemented as a simple extenstion of the current
proposal by using a list of widgets that are pending validation
rather than just a single widget. 
Each of the widgets in the group would install a validation 
callback but the validation callback function would be the
same function. When a widget installed a validation callback,
an additional argument would be required, this argument would
specify the "validation group name".
This extension to the current proposal is probably better
than the current proposal because it handles the generalised
case of multiple widgets as well as the single widget case.


Responses to comments on the patch made by Matthias Clasen
----------------------------------------------------------

  MC : 1) I think it would be nicer to add a validate() virtual function to
     : GtkWidget instead of poking in the entry internals from gtkwidget.c.
     : The default implementation would simply return TRUE;

  SB : This is a good idea. This would be needed for the extended
     : proposal (Validation of a group of widgets) because the
     : proposal is no longer targetting just entry widgets.

  MC : 2) I believe you should drop entry_pending_validation and work with 
     : gtk_window_get_focus() instead.

  SB : Yes, gtk_window_get_focus() is a better way to go.

  MC : 3) Should use GDK_Tab/GDK_KP_Tab instead of a numerical keyval (the
     : code currently seems to miss Shift-Tab (for cycling backwards)

  SB : Yes, a numerical keyval is not as good as using the symbolic
     : name. I did miss the Shift-Tab key in my patch. In addition,
     : I think I also missed the accelerator keys, like Alt-F to access
     : the File menu. I am not sure how to deal with these cases.


