Created 18.01 branch of the documentation.

git-svn-id: https://svn.eiffel.com/eiffel-org/trunk@1942 abb3cda0-5349-4a8f-a601-0c33ac3a8c38
This commit is contained in:
eiffel-org
2018-02-08 15:00:31 +00:00
parent 265a446dab
commit b5d5c80911
2923 changed files with 61520 additions and 0 deletions

View File

@@ -0,0 +1,5 @@
[[Property:title|EiffelPreferences Class Reference]]
[[Property:weight|1]]
[[Property:uuid|9929ec96-07e2-1e6c-26db-d19ab947e1be]]
==View the [[ref:libraries/preferences/reference/index|EiffelPreferences Class Reference]]==

View File

@@ -0,0 +1,44 @@
[[Property:title|EiffelPreferences Sample]]
[[Property:weight|2]]
[[Property:uuid|f492e71c-07a8-9b1d-f72a-d59330acbf16]]
<br/>
<br/>
==Compiling==
* Launch EiffelStudio.
* Click '''Add project'''
* Browse to ''$ISE_EIFFEL\examples\preferences\''.
* Choose ''preferences_example.ecf''
* Choose the location where the project will be compiled, by default the same directory containing the configuration file.
* Choose the target: ''registry'' (Windows only) will use the registry to store the preferences, ''xml'' will use a xml file to store the preferences.
* Click '''OK'''.
==Running==
After launching the application, you will see a window displayed with 2 buttons. When clicked each will display a window showing the preferences, one is the default view provided with the library, the other is a custom view for purposes of example. The default view looks like:
[[Image:normal|preferences_example_normal_view]]
The custom view looks like:
[[Image:custom|preferences_example_normal_view]]
In each dialog you can select the preferences and alter the values.
==Under the Hood==
This example shows you how to achieve the following tasks:
* Create preferences using the library supplied preference types and associated views
* Use the default widget for viewing preferences and manipulating their values
* Create a custom preference (a preference for storing correctly formatted directory path names)
* Create a widget to view and change the custom preference type value
* Create a custom manager to register custom types to the system
* Create a custom dialog for viewing all the preferences

View File

@@ -0,0 +1,7 @@
[[Property:title|EiffelPreferences Tutorial]]
[[Property:weight|0]]
[[Property:uuid|0c717db7-fb53-80b3-e32f-cc8356afa5f8]]
The EiffelPreferences library is a platform independent library that can be used to add preference and configuration settings to your application. Briefly, the library provides support for creating fully configurable preference values, on a per application or per user basis. It also provides a graphical interface for manipulation of these values, and a easily extensible design for you to add your own custom preference types.

View File

@@ -0,0 +1,154 @@
[[Property:title|Initialization]]
[[Property:weight|1]]
[[Property:uuid|2f69a1b5-b5fd-57be-46e0-60eb2406ff5d]]
This document details how to setup preferences for your application.
==Initializating the preferences==
The first thing you must do to setup preferences for your application is create a <eiffel>PREFERENCES</eiffel> object. Ideally any access to preference information should be done through this object. There are 5 creation routines available to initialize the preferences:
* 2 recommended routines (more flexible)
** <eiffel>make_with_storage</eiffel>
** <eiffel>make_with_defaults_and_storage</eiffel>
* and 3 other routines (might become obsolete one day)
** <eiffel>make</eiffel>
** <eiffel>make_with_location</eiffel>
** <eiffel>make_with_defaults_and_location</eiffel>
The <eiffel>make_with_storage</eiffel> will create an instance of <eiffel>PREFERENCES</eiffel> using the underlying storage passed as argument, and without any default preference values.
The current supported underlying storages are ''XML file'' (<eiffel>PREFERENCES_STORAGE_XML</eiffel>), and on Windows-only ''Windows Registry'' storage (<eiffel>PREFERENCES_STORAGE_REGISTRY</eiffel>).
''Note:'' that you can build your own custom storage, by implementing the class <eiffel>PREFERENCES_STORAGE_I</eiffel>, and use such object as storage in the associated creation routine.
The option <eiffel>make_with_defaults_and_storage</eiffel> is similar to <eiffel>make_with_storage</eiffel> except an additional parameter is given to retrieve one or more default file locations. This will be one or more XML files on disk containing the default values to use for some or all of your preferences. It is a convenient way to initialize your application with all the default values required `out of the box` for correct or preferred functioning. Those files also contain additional attributes for preference configuration such as more detailed descriptions of the preference. If two files list the same preference, the last one to mention it takes precedence.
The format of the XML default file is very simple:
<xml><EIFFEL_DOCUMENT>
<PREF NAME="some_manager.some_name" DESCRIPTION="Preference description here" HIDDEN="True/False" RESTART="True/False"><TYPE>Value here</TYPE></PREF>
...More preferences...
<EIFFEL_DOCUMENT>
</xml>
The "HIDDEN" attribute indicates if this preference is to be hidden from view and is used for preferences that you do not wish for your users to modify or see. The "RESTART" attribute allows for you to flag that when a particular preference is changed it may be necessary to restart the application for the changes to take effect. You can handle this in your application by querying for this value in the preference and dispalying appropriate dialogs and messages for your application.
For backward compatibility, there is a default <eiffel>PREFERENCES_STORAGE_DEFAULT</eiffel>, which is based on XML file or Windows Registry depending if you compile using the ''preferences_xml.ecf'' or the ''preferences_registry.ecf'' configuration file (nb: on non Windows platform, only the XML version is supported).
And if you use the <eiffel>make</eiffel>, <eiffel>make_with_location</eiffel>, <eiffel>make_with_defaults_and_location</eiffel>, this is pretty similar to use an object <eiffel>PREFERENCES_STORAGE_DEFAULT</eiffel> instantiated with the specified location (if any), see next ''Storage'' section for more details.
== Storage ==
To create an implementation of <eiffel>PREFERENCES_STORAGE_I</eiffel> (XML or Windows Registry), there are 2 creation routines available:
* make_empty
* make_with_location
The option <eiffel>make_empty</eiffel> will create a preferences storage (implementer of <eiffel>PREFERENCES_STORAGE_I</eiffel>) object for you with no specific underlying datastore location.
In this scenario an underlying data store location will be created for you automatically based on the current system settings. For example, if you are using the Windows Registry as your data store, and your program is is called ''my_program.exe'', then a registry key will be created in ''HKEY_CURRENT_USER\Software\myprogram.exe''. In between user sessions the preference name-value pairs will be stored in this key location. This particular method of creating preferences is ideal if you are not particularly concerned where the values are stored. You may think of it as the "it just works" mode, and it is ideal for development and simple use.
The option ( <eiffel>make_with_location</eiffel>) will take a location value to use for the underlying data storage. Values will be stored to and retrieved from this location between sessions (it could be a specific XML file location, or a specific Windows Registry path, depending if you use XML or REGISTRY storage).
==Managers==
Once you have created a <eiffel>PREFERENCES</eiffel> object using one of the creation routines described above you will create a <eiffel>PREFERENCE_MANAGER</eiffel> to store related preference values. For example, if your application is a web browser control that has preferences for user favorites and also a user browsing history you could create 2 managers, one for the favorites and one for the history. It is not mandatory that you create 2 managers and you could just create one and have all preferences stored therein, but for reasons of management 2 would be better. Each separate manager must have a unique name to distinguish it from the other managers in the system. We may have one called "favorites" and one called "history".
==Creating preferences==
Now you have your preferences and at least one manager to put them in you can create the actual preferences. Preferences are generic, and all preferences inherit the class TYPED_PREFERENCE [G]. G denotes the type of the preference, for example INTEGER for a preference containing an integer value. Depending on the type you will use a factory class to actually create the new preference. By default the library supports 6 types of preferences, 4 basic type ones and 2 graphical types. The table below clearly indicates the currently available preferences and the factory class you should use to create them:
{| border="1"
|-
| '''Preference type'''
| '''Description'''
| '''Factory class'''
| '''Factory method'''
|-
| <eiffel>BOOLEAN_PREFERENCE</eiffel>
| Stores boolean value (true or false)
| <eiffel>BASIC_PREFERENCE_FACTORY</eiffel>
| <eiffel>new_boolean_preference_value</eiffel>
|-
| <eiffel>INTEGER_PREFERENCE</eiffel>
| Stores an integer value
| <eiffel>BASIC_PREFERENCE_FACTORY</eiffel>
| <eiffel>new_integer_preference_value</eiffel>
|-
| <eiffel>STRING_PREFERENCE</eiffel>
| Stores a string value
| <eiffel>BASIC_PREFERENCE_FACTORY</eiffel>
| <eiffel>new_string_preference_value</eiffel>
|-
| <eiffel>ARRAY_PREFERENCE</eiffel>
| Stores a list of string values
| <eiffel>BASIC_PREFERENCE_FACTORY</eiffel>
| <eiffel>new_array_preference_value</eiffel>
|-
| <eiffel>COLOR_PREFERENCE</eiffel>
| Stores a color value (rgb)
| <eiffel>GRAPHICAL_PREFERENCE_FACTORY</eiffel>
| <eiffel>new_color_preference_value</eiffel>
|-
| <eiffel>FONT_PREFERENCE</eiffel>
| Stores a font value (font name, face, height, etc)
| <eiffel>GRAPHICAL_PREFERENCE_FACTORY</eiffel>
| <eiffel>new_font_preference_value</eiffel>
|}
As you can see creating preferences is very easy. Also you will notice that color and font preferences use the <eiffel>GRAPHICAL_PREFERENCE_FACTORY</eiffel>. If you wish to use these preferences in your application you will need to use EiffelVision2 since these preference values are stored as <eiffel>EV_COLOR</eiffel> and <eiffel>EV_FONT</eiffel> types. If you wish to store preference value that are different to those offered by the 6 available preferences it also very easy to extend the design and add your own custom types. Simply inherit TYPED_PREFERENCE [G] and implement the deferred features for your specific preference. There is an example of this in the sample application.
==Default Values==
When you create a preference using a factory class you will provide a manager, a name for the preference, and a value. For example, in <eiffel>BASIC_PREFERENCE_FACTORY</eiffel> you create an integer preference by calling <eiffel>new_integer_preference_value</eiffel>:
<code>
new_integer_preference_value (a_manager: PREFERENCE_MANAGER; a_name: STRING; a_fallback_value: INTEGER): INTEGER_PREFERENCE
-- Add a new integer preference with name `a_name'. If preference cannot be found in
-- underlying datastore or in a default values then `a_fallback_value' is used for the value.
require
name_valid: a_name /= Void
name_not_empty: not a_name.is_empty
not_has_preference: not a_manager.known_preference (a_name)
ensure
has_result: Result /= Void
preference_name_set: Result.name.is_equal (a_name)
preference_added: a_manager.preferences.has_preference (a_name)
end
</code>
An appropriate example in code of this could be:
<code>
window_width_preference: INTEGER_PREFERENCE
-- Preference holding value for width of application main window
initialize_my_preferences
-- Initialize the application preferences
local
factory: BASIC_PREFERENCE_FACTORY
do
create factory
window_width_preference := factory.new_integer_preference_value (my_manager, "window_width", 480)
end</code>
This will create a new preference, which you can then use in your application to get, set and save the corresponding value when necessary. The issue to be aware of here though involves the value that the preference will contain when it is created. You see in the code above we pass the integer value 480. '''This does not mean, however, the initial value of the preference will be 480'''. This may sound odd, so let me explain...
The value of a preference when initialized is determined by a number of factors. The first of these is the underlying data store value. If a preference value was changed in a previous session, by the user or by the application directly, and was saved to the underlying data store, then this value will be given priority. This makes sense, since if a user changes their preferences they don't want to have to do it every time they use your program. So, if they want the default window width to be larger, say 600, then this will be the value of the preference named "window_width" when initialized next time. Following this, if there is no previously saved value then the library will look for a default value to use. If a default file was given when the preferences were created (see above), and this default specifies a default value of 240 for the integer preference called "window_width", then this will be used. Finally, if no preference value was previously stored ''and'' no value is provided as a default value then the supplied value in the code is used - our 480 value from the example above. Although this process may seem confusing it is infact very simple and intuitive way to initialze the preferences. The process chart below illustrates more clearly the various permutations.
[[Image:value-chart]]
==Using and Manipulating Preferences==
Now you have preferences created you may use them from your application. Using the example preference above, window_width_preference, you can query the value of the preferences by simply querying the preference directly:
<code>window_width := window_width_preference.value</code>
Or for a value which should always be associated to the preference:
<code>
window_width: INTEGER
-- Width of window
do
Result := window_width_preference.value
end
</code>
If you need to react when a preference value is changed you can hook up an agent to the <eiffel>change_actions</eiffel> of the preference:
<code>window_width_preference.change_actions.extend (agent my_agent_routine)</code>
To manually set the value of the preference call <eiffel>set_value</eiffel> or <eiffel>set_value_from_string</eiffel>, and to set a value for the default value call <eiffel>set_default_value</eiffel>. To reset a preference value back to it's original default value use <eiffel>reset</eiffel>.
To save the current preference to the underlying data store you must call <eiffel>save_preference</eiffel> on the PREFERENCES object. This will persist the value to the data store for retrieval in the next session. Remember, if you change a preference value during execution and do not save it then the value will be lost when execution has finished.
The preference window interface provided with the library will allow users to set there own preference values and will save the values upon confirmation. However, if you are using preferences in your code and do not wish to provide an interface for preference modification you must remember to manually save the preferences.
You can save all preferences at once my calling <eiffel>save_preferences</eiffel> in <eiffel>PREFERENCES</eiffel>, or individually with <eiffel>save_preference</eiffel>.

View File

@@ -0,0 +1,53 @@
[[Property:title|Interface for preferences]]
[[Property:weight|2]]
[[Property:uuid|6f4964b1-8cf6-d9d4-0778-94d8a3737cad]]
This document describes the use of graphical widgets to display and manipulate preferences.
The preference library contains a cluster called <eiffel>interface</eiffel>. This cluster provides some basic classes which can be used to graphically display and manipulate the <eiffel>PREFERENCE</eiffel> types used by the library. There are various widget classes which correspond to particular types of preferences and can be used to view and change the values of an associated preference. The table below illustrates which widgets are used to display each of the known preference types:
{| border="1"
|-
| '''Preference Type'''
| '''Associated Widget'''
|-
| <eiffel>INTEGER_PREFERENCE</eiffel>
| <eiffel>STRING_PREFERENCE_WIDGET</eiffel>
|-
| <eiffel>BOOLEAN_PREFERENCE</eiffel>
| <eiffel>BOOLEAN_PREFERENCE_WIDGET</eiffel>
|-
| <eiffel>STRING_PREFERENCE</eiffel>
| <eiffel>STRING_PREFERENCE_WIDGET</eiffel>
|-
| <eiffel>ARRAY_PREFERENCE</eiffel>
| <eiffel>STRING_PREFERENCE_WIDGET</eiffel> or <eiffel>CHOICE_PREFERENCE_WIDGET</eiffel>
|-
| <eiffel>COLOR_PREFERENCE</eiffel>
| <eiffel>COLOR_PREFERENCE_WIDGET</eiffel>
|-
| <eiffel>FONT_PREFERENCE</eiffel>
| <eiffel>FONT_PREFERENCE_WIDGET</eiffel>
|}
All of these widgets inherit the abstract base class <eiffel>PREFERENCE_WIDGET</eiffel> and implement the required deferred features therein. Each implementation implements handling of an <eiffel>EV_GRID_ITEM</eiffel> widget from EiffelVision2 for use in the <eiffel>EV_GRID</eiffel> control, which allows for viewing and editing of the underlying preference value. For example, <eiffel>BOOLEAN_PREFERENCE_WIDGET</eiffel> uses an <eiffel>EV_GRID_CHECKABLE_LABEL_ITEM</eiffel> to display the 'True' and 'False' properties of a <eiffel>BOOLEAN_PREFERENCE</eiffel>. Another example: <eiffel>CHOICE_PREFERENCE_WIDGET</eiffel> uses <eiffel>EV_GRID_CHOICE_ITEM</eiffel>, when the widget is loaded it displays the current value of the associated preference in the combo box. When the user changes the combo box value the preference value is changed also, and optionally saved.
Using these supplied widgets in your interface is simply a matter of creating the object and adding the <eiffel>change_item_widget</eiffel> to an instance of <eiffel>EV_GRID</eiffel>.
By default the library provides such a view, in the form of <eiffel>PREFERENCES_GRID_CONTROL</eiffel>, and for easier usage <eiffel>PREFERENCES_GRID_DIALOG</eiffel>, which is a dialog control that contains a grid <eiffel>PREFERENCES_GRID_CONTROL</eiffel> and has all the necessary logic to handle graphical manipulation of the preference types provided in the library.
The <eiffel>PREFERENCES_GRID_DIALOG</eiffel> is a <eiffel>EV_DIALOG</eiffel> with a navigable tree/grid for finding groups of related preferences (i.e. managers), and the various preferences as a row. It is a useful, general purpose interface for preference manipulation.
You have the possibility to view the preferences as a ''tree'', or a ''flat view''. In this ''flat view'', you can filter the preferences to find easily a preference.
As with preferences themselves you may create your own custom view if this dialog is not sufficient for your needs, and can use the code therein as a template for your own code. You can also use the <eiffel>PREFERENCES_GRID_CONTROL</eiffel> to embed the preferences grid control in your application interface.
Below is an image of the supplied window as it appears in the EiffelStudio preferences environment.
[[Image:preference-window]]
For an example of creating custom widget views for individual preferences, or a custom view for all preferences, please refer to the [[EiffelPreferences Sample|example]] in this documentation.

View File

@@ -0,0 +1,32 @@
[[Property:title|Overview]]
[[Property:weight|0]]
[[Property:uuid|8f90ea04-493b-0e00-1327-c707a49e1c04]]
This document gives a brief overview of the EiffelPreferences library.
==Introduction==
Simply, preferences are name-value pairs. All preferences are descendants of the deferred class <eiffel>PREFERENCE</eiffel>, and therefore all inherit the common properties of name, value, default values and string representations. Common to all <eiffel>PREFERENCE</eiffel> objects is the notion of `manager`. All preferences belong to a manager, which is a helper class used for organizational and hierarchical management of your applications preferences.
So, all preferences belong to a <eiffel>PREFERENCE_MANAGER</eiffel>. The manager itself belongs to a set of related <eiffel>PREFERENCES</eiffel>. In fact, when you create a new manager for a group of preferences you must provide a <eiffel>PREFERENCES</eiffel> object to the creation routine to indicate which set of preferences the new manager will be associated:
<code>
make (a_preferences: PREFERENCES; a_namespace: STRING)
-- New manager.
require
preferences_not_void: a_preferences /= Void
namespace_not_void: a_namespace /= Void
namespace_not_empty: not a_namespace.is_empty
ensure
has_preferences: preferences /= Void
inserted_in_preferences: preferences.has_manager (namespace)
has_namespace: namespace /= Void
namespace_valid: not a_namespace.is_empty
end
</code>
You can see in the post-condition <eiffel>inserted_in_preferences</eiffel> that indeed the <eiffel>PREFERENCES</eiffel> object will have the new manager in its list of managers.
For every group of preferences or configuration values you therefore wish to create for your project, you will need a corresponding <eiffel>PREFERENCES</eiffel> object. In general one <eiffel>PREFERENCES</eiffel> object should be sufficient for most applications, and will be the point of reference for all preference values in the entire application. This class may be initialized in a number of ways, depending on the specific configuration of your application. It will be used to create new managers, store default preference values, and handle the saving and retrieval of preference values to and from the underlying data store between sessions. In between sessions the preference name and value pairs are persisted to an underlying data store. This may be any imaginable datastore, such as a file, database or external storage device. Support for XML and the Windows Registry is provided in the library by default, but EiffelPreferences allows you to provide an implementation tailored to your specific needs (such as SQL database store).

View File

@@ -0,0 +1,11 @@
[[Property:title|EiffelPreferences]]
[[Property:weight|1]]
[[Property:uuid|f56ec405-6032-67dd-55e1-5a5ff7a4193c]]
==EiffelPreferences Library==
Type: Library <br/>
Platform: Any <br/>
Eiffel classes for adding preferences and settings to applications.

View File

@@ -0,0 +1,6 @@
[[Property:title|Preferences]]
[[Property:weight|-5]]
[[Property:uuid|08efd11f-6326-90e0-bd63-8dfed4b55890]]
== Application preferences management solutions ==