A Tcl/Tk Front End for the Jade DSSSL Processor

Mark Wroth

Revision History
Revision 229 April 01
Revision 128 April 2001
Initial implementation.

Table of Contents
1. Background
2. Downloading and Installation
3. Implementation

1. Background

This Tcl/Tk script provides a simple front end for Jade. The purpose is to provide a somewhat configurable graphical front end for repetitive invocation of the program, for situations where the full setup of something like Pomade doesn't seem warranted.

Users who are considering adopting this script should also consider Pomade, which can be found at http://www.saremba.de/pomade/.

While this application shares no code with Pomade, the author is indebted to Andreas Saremba, Pomade's author for the inspiration for this program and an introduction to Tcl/Tk in general.

2. Downloading and Installation

This application is created using the DBLP literate programming system. The primary file is JadeTCL.sgm. The actual Tcl/Tk script is Jade.tcl, which is written by the literate programming system from the basic file.

All that is necessary to run the application is a functioning Tcl/Tk. However, to be useful, you will also probably want to create a file JadeRC.TCL. This file will be sourced after the default initialization, and is intended to contain definitions of additional (or substitute) DSSSL script definitions. This is how the system is customized to a particular environment. See Section 3.3 for more discussion on how this set of arrays are defined.

3. Implementation

3.1. Pack the Primary Window

The top level display of the GUI is a simple layout with the menu at the top, a display of the target file name and location below the menu, a column of checkboxes for the various scripts, and finally a row of buttons to start the various actions.

The bulk of the script is devoted to defining the various buttons that are packed in this display.

<Display the GUI (ID: DISPLAYGUI)>=

  1 pack .menubar -side top -fill x
  2 pack .pathname .browse  -side top -fill x
  3 foreach script [array names scripts] {
  4   pack .$script -side top -fill x
  5 }
  6 pack .go .showerr .exit -side left -expand 1 -fill x

3.2. Organization

Notice that the actual packing of the GUI can't take place until the various button structures have been defined.

<Jade.tcl (ID: MAINPROGRAM)>=

  1 <Initialization and Setup>
  2 <Define the BROWSE button>
  3 <Define the menu system>
  4 <Define the action buttons>
  5 <Display the GUI>
  6 <Define the Auxiliary procedures>

3.3. Initialization

The basic concept of the initialization is to define a minimum set of variables in the main script, and then to source another file which can define (or redefine) the variables that will actually be used in setting up the application.

To add a DSSSL script to the application, edit the configuration file to add the new script. Each script needs three strings: an id (which is never seen in the GUI, but is used internally in the script; a DSSSL script name, including (if needed) the path to it; and a type, which is the Jade output type. The DSSSL script name and the output type are stored in associative arrays, indexed by the id.

So to add a new script, you will choose a new script-id, and set two variables: scripts(script-id), which is set to the name of the DSSSL script (including, if necessary, the path to the script), and type(script-id), which is set to the Jade output type (the -t option).

To change a default script, adopt the same process, except that the script-id is that of the script you are replacing.

The other configuration variables can also be reset in the configuration file, although this should usually not be necessary. The main options would appear to be the name (and path to) the Jade processor (in jade_name), and the catalog file name (in catalog_name).

<Initialization and Setup (ID: INITIALIZATION)>=

  1 set config_filename "JadeRC.TCL"
  2 set jade_name "jade"
  3 set catalog_name "C:/catalog"
  4 set debug 0
  5 set scripts(htm) "not set"
  6 set type(htm) "sgml"
  7 set scripts(rtf) "c:/usr/dsssl/docbook/print/docbook.dsl"
  8 set type(rtf) "rtf"
  9 set scripts(tangle) "c:/usr/dtd/dblp/SGMLTangle.dsl"
 10 set type(tangle) "sgml"
 12 if [file exists $config_filename] {
 13  source $config_filename
 14  }
 16 set target [tk_getOpenFile \
 17     -title "Set Target File Name" \
 18     -filetypes {
 19      {{SGML files} {.sgm}}
 20      {{XML files} {.xml}}
 21      {{All files} {".*"}}
 22      }]
 23 set target_path [file dirname $target]
 24 set target_name [file tail $target]
 25 eval cd \"$target_path\"

3.4. Define the Configuration Button

<Define the BROWSE button (ID: BROWSEBUTTON)>=

  1 button .browse -textvariable target_name -command { 
  2 set target [tk_getOpenFile \
  3      -title "Select New Target File Name" \
  4      -filetypes {
  5       {{SGML files} {.sgm}}
  6       {{XML files} {.xml}}
  7       {{All files} {".*"}}
  8       }]
  9   set target_path [file dirname $target]
 10   set target_name [file tail $target]
 11   eval cd \"$target_path\"
 13 } 
 14 label .pathname -textvariable target_path

3.5. Define the Action Buttons

The most complicated set of action buttons are the check buttons that decide which scripts will be executed. In addition to actually defining the buttons, this part of the script also defines the command actions. This could, in principle, be separated into its own loop.

<Define the action buttons (ID: ACTIONS)>=

  1 foreach script [array names scripts] {
  2   <Define the cmd array>
  3   checkbutton .$script \
  4     -textvariable scripts($script) \
  5     -variable do($script) \
  6     -onvalue  1 \
  7     -offvalue 0 \
  8     -anchor w 
  9 }

Continued in ACTIONS-01

The actual definition of the command is a simple assembly from the various pieces already defined.

<Define the cmd array (ID: DEFINECMD)>=

  1   set outfile($script) ""
  2   append outfile($script) [file rootname $target_name] "." $script
  3   set cmd($script) ""
  4   append cmd($script) "\"$jade_name\" " 
  5   append cmd($script) " " -c " " \"$catalog_name\" " "
  6   append cmd($script) " " -d " \"" $scripts($script) "\"" 
  7   append cmd($script) " " -t " " $type($script)
  8   append cmd($script) " " \"$target_name\" 
  9   append cmd($script) " " 2>> jadetcl.err 
 10   append cmd($script) " " > $outfile($script) 

The Go button is the key button of the GUI, at least in the sense that it is the one that actually executes the actions that are the whole purpose of the program.

The basic approach is to loop over all of the array indicies, and, if the relevant checkbox is checked, executing the command defined while we were doing the setup of the program.

<Define the action buttons (ID: ACTIONS-01)>+=

  2 button .go -text "Go" -command {
  3   if [file exists jadetcl.err] {file delete jadetcl.err}
  4   foreach script [array names scripts] {
  5     if $do($script) {
  6       if $debug {tk_messageBox -message $cmd($script)}
  7       catch {eval exec $cmd($script)}
  8       catch {
  9         if [expr [file size jadetcl.err] > 0] {
 10           showFile jadetcl.err
 11           } else {
 12           file delete jadetcl.err
 13           }
 14         }
 15       } else {}
 16   }
 17 }

Continued in ACTIONS-02

The remaining action buttons are straightforward, and define commands to view the error log and exit from the application. The showFile procedure is defined in Section 3.7.

<Define the action buttons (ID: ACTIONS-02)>+=

  2 button .showerr -text "Show Err" -command {
  3   showFile jadetcl.err
  4 }
  6 button .exit -text "EXIT" -command {exit}

3.6. Define the Menus

More as a programming exercise than anything else, menus were added to the ancestor of this program. However, they provide a convenient way to give the user access to functions that are not needed very often, so we retain and extend their use in this application.

In addition to infrequently used configurations, we also include some obvious functions, such as changing the target file, even if they are also accessible from GUI buttons.

<Define the menu system (ID: MENUS)>=

  1 frame .menubar -relief groove -borderwidth 4 

Continued in MENUS-01

The first menu we set up is the File menu. This allows the user to change the target file, read a new configuration file, or exit the program.

<Define the menu system (ID: MENUS-01)>+=

  2 menubutton .menubar.file   -text "File" \
  3   -direction below -menu .menubar.file.menu 
  4 menu .menubar.file.menu\
  5   -tearoff 0
  6 .menubar.file.menu add command -label "Set target" -command {
  7   set target [tk_getOpenFile -title "File" -filetypes {
  8       {{SGML files} {.sgm}}
  9       {{XML files} {.xml}}
 10       {{All files} {".*"}}
 11       }]
 12   set target_path [file dirname $target]
 13   set target_name [file tail $target]
 14   eval cd \"$target_path\"
 15   }
 16 .menubar.file.menu add command -label "Read config" \
 17   -command {
 18    source  [tk_getOpenFile -filetypes {
 19       {{TCL Files} {.tcl}}
 20       {{All files} {".*"}}
 21   }]
 22   }
 23 .menubar.file.menu add command -label "Exit" -command {
 24   exit}

Continued in MENUS-02

The Config menu allows the user to reconfigure the program to use, for example, a different set of DSSSL files, or a different Jade executable.

<Define the menu system (ID: MENUS-02)>+=

  2 menubutton .menubar.config -text "Config" \
  3   -direction below -menu .menubar.config.menu
  4 menu .menubar.config.menu \
  5   -tearoff 0 
  6 .menubar.config.menu add command -label "Jade" -command {
  7   set jade [tk_getOpenFile -filetypes {
  8       {{Executables} {.exe}}
  9       {{All files} {".*"}}
 10   }]
 11   } 
 12 .menubar.config.menu add command -label "Catalog File" -command {
 13   set catalog_name [tk_getOpenFile -title "catalog" -filetypes {
 14       {{All files} {".*"}}
 15   }]
 16   } 

Continued in MENUS-03

The Help menu provides some very sketchy help functions, and the "About" information on the program.

<Define the menu system (ID: MENUS-03)>+=

  2 menubutton .menubar.help   -text "Help" \
  3   -direction below -menu .menubar.help.menu
  4 menu .menubar.help.menu \
  5   -tearoff 0 
  6 .menubar.help.menu add command -label "Help" \
  7         -command {showHelp}
  8 .menubar.help.menu add command -label "About" -command {
  9   tk_messageBox -type ok -message \
 10   "This is Jade.tcl, a TCL/Tk application providing a 
 11    graphical front end for Jade.\n\n
 12    Copyright (c) Mark Wroth <mark@astrid.upland.ca.us> 2001\n\n
 13    Free distribution under the terms of the Gnu Public License
 14    is authorized."
 15   }

Continued in MENUS-04

Finally, we pack the menus into the menubar, which will itself be packed into the main window later.

<Define the menu system (ID: MENUS-04)>+=

  2 pack .menubar.file .menubar.config  -side left -fill x
  3 pack .menubar.help -side right -fill x

3.7. Auxiliary Procedures

Several auxiliary procedures are needed at various places in the overall script.

3.7.1. Help Display

<Define the Auxiliary procedures (ID: AUXILIARYPROCS)>=

  1 proc showHelp {} {
  2      set helptext "\
  3                    OVERVIEW
  4                    This is a Tcl/Tk front end for the Jade \
  5                    processor. It takes a single target file and (as \
  6                    part of its initialization) an array of DSSSL \
  7                    scripts and output types.  When commanded, it \
  8                    runs Jade on each script in turn.
 10                    TARGET FILE
 11                    The name of the target file is displayed in a text button near \
 12                    the top of the application window, with the path to that file \
 13                    displayed above it.  The jade process will execute in this \
 14                    directory, which means that all relative path names defined \
 15                    in the target file will be interpreted relative to this directory.
 16                    \tTo change the target file, click on the text button containing \
 17                    the target file name.  A file requester will appear; navigate to and \
 18                    select the new target file using the requester.  By default, the \
 19                    requester will show only files ending in \".sgm\", since this is the \
 20                    usual extension given to SGML target files.
 21                    \tThe target file requester can also be summoned via the \"File\" \
 22                    menu. \n
 24                    GO\n
 25                    To execute Jade with the currently selected target file and options, click \
 26                    on the button labeled \"Go\".
 27                    CONFIGURATION\n
 28                    The application assumes that the Jade executable is found \
 29                    somewhere in the operating system path.  If this is not the case, the path \
 30                    to the nuweb executable can be set using the \"Config\" menu \"Jade\" \
 31                    option.
 32                    EXITING FROM THE APPLICATION\n
 33                    There are three different ways to exit from the Nuweb Tcl application:
 34                    \t - Click on the button marked \"Exit\"
 35                    \t - Select the \"Exit\" item on the \"File\" menu
 36                    \t - Click on the \"Close Window\" button provided by the operating \
 37                    system's window manager.
 38                    "
 39      set w .text
 40      catch {destroy $w}
 41      toplevel $w
 42      wm title $w "Jade TCL/Tk Help"
 43      wm iconname $w "text"
 45      frame $w.buttons 
 46      pack $w.buttons -side bottom -fill x -pady 2m
 47      button $w.buttons.dismiss -text Dismiss -command "destroy $w"
 48      pack $w.buttons.dismiss  -side bottom -expand 1
 50      text $w.text -relief sunken -bd 2 -yscrollcommand "$w.scroll set" \
 51         -setgrid 1 -height 30 \
 52         -tabs {1c 2c 3c} \
 53         -wrap word  
 54      scrollbar $w.scroll -command "$w.text yview"
 55      pack $w.scroll -side right -fill y
 56      pack $w.text -expand yes -fill both
 57      $w.text insert end $helptext
 58      $w.text mark set insert 0.0 } 

Continued in AUX-01

3.7.2. File Display

<Define the Auxiliary procedures (ID: AUX-01)>+=

  2 proc showFile {thefile} {
  3      set w .text
  4      catch {destroy $w}
  5      toplevel $w
  6      wm title $w "$thefile"
  7      wm iconname $w "text"
  9      frame $w.buttons
 10      pack $w.buttons -side bottom -fill x -pady 2m
 11      button $w.buttons.dismiss -text Dismiss -command "destroy $w"
 12      pack $w.buttons.dismiss  -side bottom -expand 1
 14      text $w.text -relief sunken -bd 2 -yscrollcommand "$w.scroll set" \
 15         -setgrid 1 -height 30
 16      scrollbar $w.scroll -command "$w.text yview"
 17      pack $w.scroll -side right -fill y
 18      pack $w.text -expand yes -fill both
 19      textLoadFile $w.text $thefile
 20      $w.text mark set insert 0.0 } 

Continued in AUX-02

3.7.3. Load a Text File

<Define the Auxiliary procedures (ID: AUX-02)>+=

  2 proc textLoadFile {w file} {
  3     if [file exists $file] {
  4       set f [open $file]
  5       $w delete 1.0 end
  6       while {![eof $f]} {
  7          $w insert end [read $f 10000]
  8       }
  9       close $f
 10   }
 11 }