====================================================================== SEARHC Electronic Timesheet Copyright 1996 Southeast Alaska Regional Health Consortium Copyright 1996 Anthony Taylor Copyright 1996 Valerie Dodson ====================================================================== ---------- DISCLAIMER ---------- This document is part of the SEARHC Electronic Timesheet Tcl/Tk package. Neither Southeast Alaska Health Consortium nor the author make any guarantees to its suitability for any purpose whatsoever. Also, both SEARHC and the author disclaim any liabilities for injury, loss of money or life or limb, or any other negative result from the use of this package. (Or, more succinctly, "Use at your own risk.") Nor would I suggest using this program as a style guide for learning Tcl or Tk. Actually, you could almost use it as an anti-style guide. However, I'm fairly proud of the outcome. It's not bad for a first program in the language, really. And I discovered a couple neat tricks, too. A few good ideas hide underneath the crufty code. However, this program is merely the front end to the real heart of our timesheet system, a FrameMaker document. We use Unimerge to merge the information produced by this program into the Frame document, and then have FrameMaker print it out. However, with the PostScript capabilities of Tk, an extension to this program could do virtually the same job. Or tsprint could initiate a Perl program to merge the numbers into a prepared TeX document and print it out. Or (as this distribution does) a tcl script can merge the information into a prepared postscript template. Or just about anything that works for the setup at your site. ------- Invoice ------- This should come with a whole bunch of files. Here's the list: The program: ------------ timesheet.tk The main routine. The forms (ts.*.tk): ts.timesheet.tk ts.worksheet.tk ts.leave.tk ts.setup.tk ts.print.tk ts.help.tk Other routines: datestuff.tcl Various date manipulation routines routines.tk Miscellaneous routines used by the forms merge.tcl The merge routines ts.merge.tcl A wrapper for the merge routines Data files: timesheet.holidays A list of observed holidays site.list A list of company sites, used in setup timesheet.ps.template The PS skeleton, with embedded merge codes Icons and Bitmaps: timesheet.icon The minimized timesheet icon logo.xbm The company logo on the timesheet form print.xbm Used in the print dialog Shell scripts: tsprint A script called from the print form tsview A script called from the print form tsprint.unimerge The unimerge print script Frame and Unimerge files: SEARHC.Timesheet.ctl The unimerge control file SEARHC.Timesheet.mif The FrameMaker timesheet template Other Directories: help/ On-line help files printer/ Available printer, listed by site Files created: ~/.timesheet.conf ~/timesheet.out ~/ts.err Printer errors go here ~/.isd.archive/ A directory to hold old timesheets ~/timesheet.ps The finished postscript timesheet Documentation: ts.doc.Z An MS-Word document, compressed. (Why Word? It would have been postscript, but I was testing WABI when I wrote the documentation. I dislike Word, myself.) ------------ Installation ------------ Install the tcl/Tk code wherever you want. I keep mine in /usr/local/bin/timesheet, and I keep the support files in /usr/local/bin. Just keep the tcl/Tk files together. To run, issue this command: wish timesheet.tk Currently, there are two methods of printing the timesheet. One is the method outlined above, using UniMerge and FrameMaker. (This is the method we use here at SEARHC.) The other is a little cruder, but it works, and this is how it works: the print button in the print form calls the script tsprint, which in turn calls a tcl script called ts.merge.tcl, which is a wrapper for a procedure called merge. The merge procedure uses a template document called timesheet.ps.template which merge fills with information from the ~/timesheet.out data file. The resulting merged document is saved as ~/timesheet.ps, which is then dumped directly to a printer. This is the default for this distribution. This same techinique could be used to view the finished document with ghostview. I know this will work; I've done it. Simply modify the tsview shell script to use the tcl-based merge, and initiate ghostview with the -monochrome option (for best results). --- Use --- The program should be pretty much self-explanatory. If the user hasn't set up the timesheet before, it will go directly to the setup form. Otherwise, it will go straight to the main timesheet form. Probably the best coding is in the "datestuff.tcl". There are some good date routines to handle conversion from Julian to Gregorian dates, and vice-versa. There are other routines in there as well, which may or may not prove useful in other projects. Also, the merge routine is kinda nifty, as it uses tcl commands embedded in the document template to perform the actual merge. ------------------------ Using The Merge Function ------------------------ All merging is done with the function "merge" located in the file merge.tcl . The procedure is called thus: merge template.name datafile.name outputfile.name where the template has the embedded codes to extract information from the datafile, and the finished output is saved in outputfile.name . The datafile is a flat file with code lines like this: (SEE the file ~/timesheet.out for a more complete example.) ... Begin Example foo: This is the information for foo. ... End Example The datafile is read into the array "mrg", with the tag (in this case, foo) as the index name. (So mrg(foo) would contain "This is the information for foo.") This data can be accessed from the merge template document using standard tcl syntax. The merge token is a double-tilde (~~), and the merge command must be in braces. So, to merge foo into the template, the embedded merge command would be: ~~{$mrg(foo)} The merge function scans the template looking for the merge token ~~. When it encounters the token, it extracts the merge command, executes it, and replaces the token and command with the results of the command. For instance, if the datafile contains this line: mon1: Apr 15 and the merge template contains these lines: 3 11 Q (~~{[lindex $mrg(mon1) 0]}) 64.98 519.45 T 0 0 0 1 0 0 0 K then "~~{[lindex $mrg(mon1) 0]}" would be replaced with "Apr", and that section of the output file would look like this: 3 11 Q (Apr) 64.98 519.45 T 0 0 0 1 0 0 0 K Also, the abilities of the merge function can be extended with tcl procedures. For instance, the merge.tcl file contains the procedure mergeadd, which takes a list of numbers and adds them together, returning the result. So, the command ~~{[mergeadd $mrg(hh) $mrg(cht)]} would add the values of hh and cht from the datafile. Any tcl function that returns a value can be used within the merge function, so the abilities of the merge function are completely limitless. (In theory, at least. I personally don't have the hardware to destroy the universe, so I can't create a merge function to do so, either. Oh darn.) In fact, you could embed entire procedures within a merge document. For instance, you could hide a procedure behind a comment in a PostScript document like this: ... Begin example % ~~{[uplevel {proc mergeadd {args} {set answer 0; foreach arg $args {if {[string compare $arg ""]} { set answer [expr $answer + $arg]}}; if {$answer} {return $answer} else {return ""}}}]} ... End example Keep in mind there are !no! linebreaks in this code; what appear to be line breaks in the example above are merely figments of your imagination. This should all be one complete, unbroken line for the merge procedure to register the merge function. Also, please note this is the mergeadd function already in the merge.tcl code. Also, keep in mind the "%" in the example above is the PostScript comment token. For other merge documents, the comment symbol will most definitely be different. This is a very powerful idea; wonderfully simple, it still provides the ability to add any tcl functions to a document, and embed the functions directly into the template. No additional code needs to be shipped around and loaded up. Or, a seperate file *could* be included, and the document can source that file, simplifying the coding, and eliminating the need to add extra libraries for every document. Just load up the merge functions that are going to be used in the document template. For examples of a simple working merge template, check out timesheet.ps.template, in the timesheet directory. This is a postscript document, relatively simple to understand. Just load the document into your favorite (Emacs) text editor, and search for the double-tilde token "~~". A word of warning: the merge function is not recursive, so it cannot substitute more than one token per input line. However, modifying the procedure for recursive operation would be extremely simple. ------- License ------- It seems a bit silly to apply a user license to this code, but I'm going to anyway. Essentially, SEARHC and I reserve all copyright to this code, but grant use to use, modify, and distribute this code in accordance with the same license that accompanies tcl and Tk. A slightly modified version of that license accompanies this code, in the file "license.terms". Or, alternately, this code may also be distributed under the terms outlined in the Gnu General Public License. Take your pick. Why bother with a license at all? Well, if I've managed to do anything even remotely clever here, I want credit, by God. ------------------------------------------------ What I'd do different, because I know better now ------------------------------------------------ First, I'd move the form selection button routines from the individual forms to the main timesheet program, surrounding the "source ts.*.tk" lines. The idea is to make each form as independent as possible-- hopefully, completely independent. They could then be easily reused in other code. I'd probably sell it all for a zillion dollars and retire. I'd probably re-write the code to simplify turning it into a library, especially the date and merge routines.