jprefs.tcl
The
jprefs.tcl library is distributed as part of the
jstools package. It consists of procedures to support application
configuration files (written in Tcl) and user preference files
(as Tcl code).
This document describes
jprefs.tcl version 4.1/4.4.
Accessing the Library
In order to use the
jprefs.tcl library, it (and any other libraries it depends on) must be
in your Tcl
auto_path, described in
tclvars(n). Information about how to arrange that, and other conventions
common to
the
jstools libraries, is in
the
Usage section of
The jstools Libraries.
Preferences and Preference Files
These procedures manage user preferences by saving and reading
automatically generated files of Tcl code. (Earlier versions
of this library used Xstyle defaults files.) These files are
managed internally; the user need not edit them directly.
Users' preferences are stored in global arrays that an application
can consult to see the current state of user preferences. By
default, these procedures use the global array
J_PREFS and the file
~/.tk/defaults.tcl, both of which are intended to store crossapplication defaults.
The Preference Hierarchy
Preferences are organised into a threelevel hierarchy. At
the lowest level are individual preferences. These preferences
are grouped into (hopefully) related
modules. For instance, all font preferences might be associated into
a module, or all preferences to do with printing. Preference
modules are grouped into
panels. All the preferences within (modules within) a panel share
the same global array, and they're written into and read from
the same file.
Panels are the highestlevel grouping of preferences; simple
applications will probably only need one preference panel.
However, it's not easy to save a single preference (or module)
without saving all the other preferences in the same panel.
The
jstools applications use a single panel (.global_prefs) for all their shared (i.e. crossapplication) preferences, and
some of them use an applicationspecific preference panel too.
If you use the
jprefpanel.tcl library for your userinterface, this threelevel division
is reflected in the interface: each panel is displayed in its
own toplevel dialogue box, and within each panel, preferences
in a single module are displayed together. In this case the
term
panel is intuitive. If you use some different userinterface,
though, you can think of a
panel as just a level of grouping - a group of (modules of) preferences
associated with a single global array and a single file.
Global Preferences
The
j:read_global_prefs procedure reads the standard
jstools crossapplication preferences, most of which are used by
the
jstools libraries. You should make sure you read the user's global preferences,
either by calling
j:read_global_prefs or, better yet, by calling
j:jstools_init (in
jinit.tcl), early in your code; otherwise your application won't work
consistently with other applications using the libraries, and
some library procedures might not work at all. You should also
give your users access to
the
jstools Global Preferences panel, which you can bring up with the
j:global_pref_panel procedure in
jprefpanel.tcl.
(Many of the other
jstools libraries make use of the preferences read by
j:read_global_prefs, so users may see their effects even if you don't specifically
check for them.)
Author
Jay Sekora
js@aq.org
http://www.aq.org/~js/
Copyright
The library is copyright © 1992-1996 by Jay Sekora, but may be
freely redistributed under the conditions at the top of the file.
Procedures
j:source_config - read user configuration from a file
j:read_prefs - read X defaults for preferences from file, set array
j:read_global_prefs - read common
jstools preferences from
~/.tk/defaults.tcl
j:read_standard_prefs - alias for
j:read_global_prefs (deprecated)
j:write_prefs - write Tcl code for preferences to file from array
j:pref:read_panel - read all preferences in a particular panel
j:pref:write_panel - write all preferences in a particular panel
j:pref:panel - create a panel and associate it with a global variable and
a file
j:pref:module - create a module and associate it with a panel
j:pref:preference - create a preference and associate it with a module
j:pref:create_pref - alias for
j:pref:preference (deprecated)
j:pref:create_global_prefs - create standard prefs for global preference panel
j:pref:create_standard_prefs - alias for
j:pref:create_global_prefs (deprecated)
See Also
jprefpanel.tcl
jbindentry.tcl
jbindtext.tcl
jinit.tcl
jldb.tcl
Usage
j:source_config
[-directory
directory]
filename
Argument
filename is the name of the file to source
Option
-directory
directory
(default
~/.tk)
Description
This procedure is used for reading configuration files. It
sources the file
filename, normally in the user's
.tk directory but in
directory if specified. The file is sourced in the context of the
calling procedure, so any variables set by the sourced file will
be visible to the procedure calling
j:source_config (and if they're global in the calling procedure, they'll be
global to
j:source_config as well).
Usage
j:read_prefs
[options]
defaults
Options
-array
array
(default
J_PREFS) - array to read defaults into
-directory
dir
(default
~/.tk) - directory file is in
-file
file
(default
defaults) - defaults file to read
-prefix
prefix
(default
{}) - prefix to keys in
array
Argument
defaults - list of
{pref
default} sublists
Example
j:read_prefs -array BROWSERPREFS -file jbrowser-defaults {
{fancy 0}
{lbwidth 20}
{lbheight 20}
{lbfont default}
}
[...]
if $BROWSERPREFS(fancy) {
[...] }
set mode READONLY
j:read_prefs -array TESTPREFS -file test-${mode}-defaults
\
-prefix $mode {
{always_ask 1}
{keep_backups 1}
}
[...]
if $TESTPREFS($mode,always_ask) {
[...] }
Description
This procedure reads a preferences file, and extracts each specified
pref from it into the array
array. If a particular
pref doesn't occur in the preferences file (or the defaults file
doesn't exist at all), the corresponding
default is used instead. The file name will be
defaults.tcl unless
file is specified, and it will be searched for in
~/.tk unless
directory is specified.
(The format of
file is a set of Tcl variable assignments, but you should not count
on being able to put arbitrary Tcl code in the file, since it's
rewritten whenever a user saves hir preferences.)
If
file is specified, it will have a
.tcl suffix tacked onto it to produce the actual file name.
As a special case, if a
pref is
tk_strictMotif, then the
tk_strictMotif global variable will be set as well as the
tk_strictMotif element in
array.
If
prefix is specified and nonnull, it (plus a comma) is prepended to
each preference name, so that for instance you can specify `-prefix friend' and access preferences (and array indices) like `friend,name', `friend,age', etc. (This mechanism is used by
jedit for modespecific preferences, with
prefix being the name of the mode.)
Usage
j:read_global_prefs
Description
This procedure reads a standard set of defaults from the file
~/.tk/defaults.tcl, and sets the corresponding elements of the
J_PREFS global array (and the
tk_strictMotif global variable). It's a shorthand for using
j:read_prefs with a particular fixed set of defaults.
Currently, the standard defaults handled (and the hardwired values
used if they don't occur in
~/.tk/defaults.tcl) are:
language (default
en) - ISO code for language to display text in
autoposition (default
0) - whether to centre popup panels
bindings (default
basic) - keyboard bindings (emacs,
edt,
vi, or
basic)
typeover (default
1) - whether typing replaces the selection
confirm (default
1) - whether to confirm before certain actions
printer (default
lp) - name of preferred printer
scrollbarside (default
right) - which side of windows scrollbars are on
visiblebell (default
1) - whether to flash the window to simulate a bell
audiblebell (default
1) - whether to ring the display's bell
j_fs_fast (default
0) - if
1, don't
stat(2) files in file selector list
tk_strictMotif (default
0) - if
1, don't hilight active widgets
Many of these are used by other procedures in
the
jstools libraries (or by Tk itself), but some of them have to be handled by your
application. In particular,
bindings has to be processed by your application. There are procedures
in the
jbindtext.tcl and
jbindentry.tcl libraries to make it easy to set up bindings. The simplest
way to read users' global preferences and set up keyboard bindings
appropriately, though, is to call
j:jstools_init early in your code; that procedure calls
j:read_global_prefs, and then sets up bindings appropriately.
In version 3.6/2.0 of
jstools, this procedure was called
j:read_standard_prefs, and that name is still supported for backwardscompatibility.
(Don't rely on it staying, though.)
Usage
j:write_prefs
[options]
Options
-array array
(default
J_PREFS) - array to read current values from
-directory dir
(default
~/.tk) - directory defaults file is in
-file file
(default
defaults) - defaults file to write
-prefix
prefix
(default
{}) - prefix to keys in
array
Examples
j:write_prefs -array BROWSERPREFS -file jbrowser-defaults
j:write_prefs -array TESTPREFS \
-file test-${mode}-defaults -prefix $mode
Description
This procedure is used to save user preferences. By default,
it writes all elements of array
array which do
not have a comma in their names into a preference file. The
file name will be
defaults.tcl unless
file is specified, and it will be put in
~/.tk unless
directory is specified. The directory is created if necessary (and
possible).
If
file is specified, it will have a
.tcl suffix tacked onto it to produce the actual file name.
If
prefix is specified and nonnull, then it writes all elements of
array whose names start with
prefix followed by a comma. For instance you can specify `-prefix friend' and write preferences (and array indices) like `friend,name', `friend,age', etc. (This mechanism is used by
jedit for modespecific preferences, with
prefix being the name of the mode.)
Usage
j:pref:read_panel
panel
defaults
Arguments
panel - the name of the panel whose preferences will be read
defaults (optional) - a list of twoelement preference-default pairs
Example
j:pref:panel .visual \
-title "Visual Appearance" \
-file visual \
-directory ~/.app_prefs \
-array VISUAL
[. . .]
j:pref:read_panel .visual {
{color_scheme LightSkyBlue}
{width 640}
{height 480}
}
Description
This procedure reads preferences from the file specified in a
call to
j:pref:panel to hold
panel's preferences. (I.e., assuming such a file exists and was
created properly, it reads in the preferences for the modules
in
panel.)
If
defaults is provided, it is a list of twoelement sublists which provide
default values for
panel's preferences in case the preference file doesn't exist yet.
The first element of each sublist is the name of a preference
(see
j:pref:preference), and the second is the default value for that preference.
Usage
j:pref:write_panel
panel
Argument
panel - the name of the panel whose preferences are to be saved
Description
This procedure saves all the preferences associated with
panel; i.e., the preferences in the various modules in
panel. It does this by finding the Tcl global array associated with
panel (which is used by all the preferences in
panel's modules) and saving the current value of all its elements as
Tcl code in the file and directory associated with
panel. Those values are set by
j:pref:panel.
If you use
jprefpanel.tcl to create your user interface, this procedure will be invoked
by the Save button on a preference panel. However, you can
also invoke it yourself whenever you want to checkpoint the values
of preferences associated with a panel (for instance, if you provide
an additional interface to change them).
Usage
j:pref:panel
panel
options
Argument
panel - the name of the panel, a legal Tk toplevel widget pathname
Options
-title
title
(default
Global Preferences) -
localisable title for window
-array
array
(default
J_PREFS) - global array for all preferences in panel
-file
file
(default
defaults) - file preferences are saved in/loaded from
-directory
dir
(default
~/.tk) - directory containing
file
Example
See
j:prefe:preference for an example
Description
This procedure registers the title and window name for a new preference
panel, the Tcl global array that preferences in that panel will
be stored in, and the name of the file (and its directory) where
those preferences will be saved and loaded by
j:write_prefs and
j:read_prefs. It must be called before
j:pref:module (which in turn must be called before
j:pref:preference).
If you use
the
jprefpanel.tcl library to create your interface, the Tk toplevel window created
to hold the preference panel will be named
panel, which must be a valid widget name, and the window's title will
be
title (or its localised equivalent). If you're not using
jprefpanel.tcl,
panel can be an arbitrary string, and
title is ignored.
Usage
j:pref:module
module
options
Argument
module - the name of the module to create
Options
-label
label
(default
Preferences) - localisable name for module
-panel
panel
(default
main) - name of panel to display this module in
Example
See
j:prefe:preference for an example
Description
This procedure creates and registers a new preferences module
module. It must be called before any actual preferences are registered
with
j:pref:preference. The global array preferences in
module are stored in, and the file (and directory) they are read from
and written to, are based on
panel and set by
j:pref:panel.
If you use
the
jprefpanel.tcl library to create your interface, the userinterface components
that allow the user to set preferences in
module will appear on the panel named
panel, which should be a legal Tk toplevel name. You should provide
a (localisable) humanreadable name for the module as
label, which will be used as a title for the preferences in
module.
Usage
j:pref:preference
[pref
module
options]
Arguments
pref - the name of the global variable that stores this preference
module - the module to which this preference belongs
Options
-prompt
prompt
(default
{}) - localisable label for this preference
-type
type
(default
string) - kind of preference
-link
link
(default
{}) - unimplemented
-text
text
(default
{}) - unimplemented
-values
values
- permissible values for oneofmany preferences
-default
default
(default
{}) - initial factory setting for this preference
Examples
j:pref:panel .printing_prefs \
-title "Printing Preferences" \
-array PRINT \
-file printing_prefs
j:pref:module document \
-label Output \
-panel .printing_prefs
j:pref:preference size document \
-prompt {Font size:} -default 12
j:pref:preference font document \
-type radio -prompt {Font:} -default
/Courier \
-values {
{/Courier Courier}
{/Times-Roman Times}
{/Helvetica Helvetica}
}
j:pref:preference landscape document \
-type boolean -prompt {Landscape:} -default 0
j:pref:module media \
-label Media \
-panel .printing_prefs
j:pref:preference paper media \
-type radio -prompt {Paper:} -default plain \
-values {
{plain {Plain white paper}}
{transparency {Transparency}}
{letterhead {Corporate printed letterhead}}
}
j:pref:preference colour media \
-type radio -prompt {Colour printing?} -default 0 \
-values {{0 {Black and white}} {1 Colour}}
j:pref:preference resolution media \
-type boolean -prompt {High resolution:} -default 0
j:pref:show_panel .printing_prefs
Description
This procedure registers a new preference
pref within
module. The given
module must already have been registered by a call to
j:pref:module (and the modules panel must already have been registered by
a call to
j:pref:panel. The preference will be stored in the global array specified
for
module's panel with the name of the preference as the key; for instance,
in the extended example above, the value of the
font preference is stored in the global variable
PRINT(font).
The
prompt option is a
localisable humanreadable label to be associated with the preference.
The kind of preference is specified by
type, which can currently be one of
string,
boolean, or
radio.
If
type is
string (or unspecified), the value of the preference can be any arbitrary
string. If it is
boolean, the value can be true or false (1 or
0). If it is
radio, the value can be one of a set of values provided by
values.
The
values option is an arbitrarilylong list of twoelement sublists.
The first element in each sublist is the value of the variable
(i.e., a machinereadable setting for the preference); the second
element is a label corresponding to it (i.e., a humanreadable
setting for the preference).
The
default option provides a default value for the preference; if the
variable corresponding to the preference does not already exist,
it will be created and set to
default.
In previous versions of
jstools, this procedure was called
j:pref:create_pref, and that name is still supported for backwardscompatibility.
(Don't rely on it staying, though.)
Bugs and Misfeatures
- The
-prefix option to
j:read_prefs and
j:write_prefs seems like a kludge to me. I put it in because I didn't
want to have to have separate procedures in
jedit just to read and write modespecific preferences.
- There should be a mechanism for multiple levels of inheritable
preferences - e.g., sitewide > peruser > perapplication
> permode > perdocument