How to use the Preferences Manager
Document #: ??
Authors: Louis Salvail (CWI)
Editor: (none)
Reviewer: (none)
Status: Draft Version. 2 for JDK1.1, SEMPER internal
To be done
- Improve exceptions handling,
- Use of the advanced access control services
- Use of the JDK1.1 serialization interface instead of semper.util.serial
- Allow selective Access Control for group operations.
General Overview
The Preferences Block
works with 4 main classes:
- Configuration class is
responsible for the management of user configuration. In order to be
initialised, this class must be able to retrieve a configuration file
stored in the target files system.
It is possible to initialise with the default configuration file
or any other configuration file by specifying the path and the name
for that file. The configuration file is editable by the user. The
general format for that file is:
- #Name_of_the_configuration_field Value_of_the_field
- #Name_of_another_configuration_field Value_of_the_field
- etc...
In the above representation it is assumed that no blank (or space) appears in
both the field name and the field value. It is not allowed in general to include
blank in the field name but it is possible to include blank for field values.
In order to define a field value with blanks the following can be sed:
- #Name_of_the_configuration_field "this is a value with blanks"
Note that the symbol " should not be used as part of a field value.
The Configuration manager does not accept the symbol " in field
values with blanks. For field values with no blank symbol, the configuration manager
accepts symbols " if they don't start the field value.
- Preferences class :
is the front end for accessing user preferences.
This class must be initialised after Configuration initialisation
before being used. During initialisation, user preferences are retrieved
from the Archive via a default record. If the default file has not been
retrieved the manager is not initialised.
The Preferences Manager includes methods to construct preferences environment.
A preferences environment contains a set of preferences
groups. Operations on groups are:
- adding (addGroup),
- removing (delGroup) and
- getting (getGroup) a particular
group of preferences are defined in that class.
If there is no user preferences in the Archive, a new environment can be
built from scratch. Once this is done, the new environment can be saved
in the default record (or another one) and initialisation can now be performed.
In addition,
method for
- launching interactive edition (editGroup) is also
provided.
This Preferences Class is also responsible for:
- storing (save) and
- retrieving (load) from the Archive Manager a previously
defined preferences environment.
Preferences environments are
stored encrypted in the Archive using encryption services provided
by the Archive manager. That means that Access controls for the use
of the encryption/decryption keys are assumed to be performed in the
Archive block.
Methods
- update() and cancel()
allow to record and cancel changes made by the user during
interactive edition.
It is also possible to put groups toghether in subgroups. The preferences
manager only uses this group-subgroup structure for the preferences menu
creation. Even if the current preferences environment contains subgroups,
each group is accessible by its name. The subgroup in which it belongs is
not taken into account. The preferences manager allows to:
- Create new subgroups below a supergroup
- Put groups in a subgroup
- Retrieve the menu structure defined by the group-subgroup structure.
- PreGroup class
defines a set of preferences fields logically
put together. A group has an internal name by which further
references are made (this is a string). It is by the groupName
that references to that group are made through the Preferences
class. In addition, a label is attached to each group and used to
display the name of the group to the user (like the menu items in
the Test program). Methods
allow to add and
get a field for the current group. In addition,
- delField() method removes
a field of the current group.
- update() and cancel() methods
are used by the Preferences class to update or cancel user's
changes during interactive edition. These two methods should not
be used directly from the outside.
It will also be possible to
- save (savePrefGroup()) and
- load (loadPrefGroup()) a group
from Archive.
The method
- showme(frame) add to the frame the components of the
group in the same order by which the fields have been added. This
is important for formatting reasons.
- PrefField class is an
abstract data class providing the methods
needed to define a preferences field. Each user-pereferences field
items is a subclass of that data class. Each field has a name by which
further references (through PrefGroup object) are made. A PrefField object
has a value which is
- get by the getValue() method and
- set by the setValue() method.
In addition a PrefField object may have a description. That description
can be set for each field. When the user, while passing the mouse
over a PrefField, double-clicked on the left mouse button the description
appears in a window waiting for "OK" to be pressed.
An important point is the appearance of a field.
A PrefField object always provides a
- showme() method ables to put the
component in a PrefFrame .
A PrefField component is placed into a frame by setting a set of
GridBagConstraints values.
These values are used to display the current component according to
the previous one. The order by which the fields are added is important for
that reason.
Methods cancel(), isModified(), applyModification() are used to manage
interactive edition of each field in the same way than explain
before .
The method isOK(), returns true if the new value of this field is allowed.
The Preferences manager records user's changes of a field only if that field
has isOk() == true . Examples of non-trivial isOK() method can be
found in String field when the
string constraints are
Integers.
Notification of changes
A PrefField can also be used to get notice of change of a value by the user.
If a manager wants to be notified when the user selects a new value for a PrefField,
it registers the class name responsible to deal with these changes. A PrefField
allows to register a class by a call to the method registerForNotify(className).
The className must be a fully qualified description of the class like in
"semper.preferences.Test.BuildPref". In addition the className
must represents a class which implements the
PrefNotify interface.
Each time a new value is selected for a PrefField, each registered class
will be called with the names of the group and the field as input to the
notifyChange(groupName,fieldName) method.
It is the responsability of the PrefNotify implementation to
deal with the change of value. For more details consult the
BuildPref example.
The notification is called on button reaction and thus during evant handling. If on
notification some interactive process has to be launched, a thread should be
started in order for the calling process to return from the call.
Other classes are needed to help the three others:
- PrefFrame is a frame allowing to put each
field appearance. This frame
has a GridBagConstraints layout to allow flexible display. The PrefFrame
intercept an update of the values selected by the user after interactive
edition, a reset of changes and a cancel of these modifications.
The add(comp, csts) method
is used to add a new component comp with the constraints csts to the
frame.
- The other classes:
are all subclasses of PrefField.
They define different field with different appearance. The field
PrefFieldNegotiable allows to define
fields to represent priority lists. The field looks like 2 lists of items,
the first one contains a list of unused items while the other is
the priority list itself. By selecting one element from the unused list
and one from the priority list the user indicate that the selected unused
item will be added in the priority list at the selected position. If no
poisition is selected in the priority list, the new item is added
in last position. It is also possible to select an item in the priority list
and put it back in the unused list.
The PrefFieldPassWord class implements preferences fields dealing with passwords.
It is possible to associate to a password a preferences field allowing to modify it.
A PrefFieldPassWord appears like a button on a preferences group.
When the user press the button, the control is given to the TINGUIN for asking
the user to enter the password to change. If the user succeeds then (s)he is asked
to select a new password by giving it twice. The change is processed if at the end
the user press the "use" button of the preferences group.
How to create a Negotiation Field (other fields are similar)?
Just by specifying the available items, the fieldname and the formatting
constraints (optional).
String it[] = new String[6];
it[0] = new String( "item 1" );
it[1] = new String( "item 2" );
it[2] = new String( "item 3" );
it[3] = new String( "item 4" );
it[4] = new String( "item 5" );
it[5] = new String( "item 6" );
PrefFieldNegotiable neg1 = new PrefFieldNegotiable( new String("neg1"),
it,
4,
cs);
Here cs is the constraints for the position of that field in the group. They
are GridBagConstraints from the stantard awt package. If you are not concern
with these constraints, you always have access to a constructor with no
constraints. In that case defaults are used. Every field is then put one
below the previous one. From the previous exemple:
PrefFieldNegotiable neg1 = new PrefFieldNegotiable( new String("neg1"),
it,
4);
Now the description for that field can be set by
neg1.setDescription("The description intendended to the user. /n This will appear when the left
mouse button is doubleclicked.");
The surface of reaction to the double-clicked depends on the particular field. A PrefFieldString
for instance, does not react on double-clicking over the text area but just on the label
area. A PrefFieldList does not react on the list component but everywhere else.
Therefore it is possible that before getting the description the mous has to be moved a bit.
How to create a Group?
groupe1 = new PrefGroup(new String("G1"), new String("Group 1"));
groupe2 = new PrefGroup(new String("G2"),new String("Group 2"));
This two lines create two groups . To put a field in a group just call the
method put() provides by the PrefGroup class. To add neg1 in the group
groupe1 just perform:
groupe1.put(neg1);
You just have to continue like that until all fields are added in the group.
For more details on how to create groups see the PrefTestC.java file in the
Test directory.
How to create a Preferences environment?
To create a preferences environment, you just have to add group
in the Preferences class. If groupe1 and groupe2 have already been defined,
you can add them by doing:
Preferences.addGroup(groupe1);
Preferences.addGroup(groupe2);
How to create subgroups?
In order to create a menu structure from which the user
selects the group he wants to edit, the following can be used. Assume
that group1,group2 and group3 have been defined and added to the preferences
manager like described above:
Preferences.addToSubGroup(groupe2.getName(),"SuperGroup");
Preferences.newSubGroupBelow("SuperGroup2","SuperGroup");
Preferences.addToSubGroup(groupe3.getName(),"SuperGroup2");
The result is that:
- group1 is accessible from the first level of the preferences menu
- group2 is accessible in the submenu SuperGroup
- group3 is accessible in the submenu SuperGroup2 which is a subgroup
of SuperGroup.
By default when a new group is added to the preferences manager whithout specifiying
in which subgroup it will appear, the group will be put at the root level. That means
that the group will be accessible at the first level of the menu structure.
Do not confuse groups and subgroups, they are different things. A group is
a PrefGroup object while a subgroup is just a string. Subgroups are only
used to display the menu structure. For the preferences manager all
preferences groups are at the same level.
In order to retrieve the menu structure currently defined in the preferences manager
one should use:
Preferences.getMenuStruct(pref_menu);
where pref_menu is an object of class java.awt.Menu.
How to get the values?
To get the values for a particular field, you must first retrieve
the group which contains the field you are looking for:
group = Preferences.getGroup("G1");
Now group contains the group having the name "G1". Then you can get the
the field with name "neg1" by doing:
field = group.get("neg1");
The field value is then obtain by calling:
val = field.getVal();
In that case, since that field is PrefFieldNegotiable field type the value
returned by getVal() is a vector. Thus, val.size() is the size for that vector
and val[i] contains the i^th string items in priority selected by the user.
Also available is the Test package where you
can learn how to use the Preferences manager by examples.
Date: August, 1996 .