| # |
| # Hyperhelp |
| # ---------------------------------------------------------------------- |
| # Implements a help facility using html formatted hypertext files. |
| # |
| # ---------------------------------------------------------------------- |
| # AUTHOR: Kris Raney EMAIL: kraney@spd.dsccc.com |
| # |
| # @(#) $Id: hyperhelp.itk,v 1.5 2002/03/16 05:26:19 mgbacke Exp $ |
| # ---------------------------------------------------------------------- |
| # Copyright (c) 1996 DSC Technologies Corporation |
| # ====================================================================== |
| # Permission to use, copy, modify, distribute and license this software |
| # and its documentation for any purpose, and without fee or written |
| # agreement with DSC, is hereby granted, provided that the above copyright |
| # notice appears in all copies and that both the copyright notice and |
| # warranty disclaimer below appear in supporting documentation, and that |
| # the names of DSC Technologies Corporation or DSC Communications |
| # Corporation not be used in advertising or publicity pertaining to the |
| # software without specific, written prior permission. |
| # |
| # DSC DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING |
| # ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, AND NON- |
| # INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND THE |
| # AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE MAINTENANCE, |
| # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. IN NO EVENT SHALL |
| # DSC BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR |
| # ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, |
| # WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTUOUS ACTION, |
| # ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS |
| # SOFTWARE. |
| # ====================================================================== |
| |
| # |
| # Acknowledgements: |
| # |
| # Special thanks go to Sam Shen(SLShen@lbl.gov), as this code is based on his |
| # help.tcl code from tk inspect. |
| |
| # |
| # Default resources. |
| # |
| option add *Hyperhelp.width 575 widgetDefault |
| option add *Hyperhelp.height 450 widgetDefault |
| option add *Hyperhelp.modality none widgetDefault |
| option add *Hyperhelp.vscrollMode static widgetDefault |
| option add *Hyperhelp.hscrollMode static widgetDefault |
| option add *Hyperhelp.maxHistory 20 widgetDefault |
| |
| # |
| # Usual options. |
| # |
| itk::usual Hyperhelp { |
| keep -activebackground -activerelief -background -borderwidth -cursor \ |
| -foreground -highlightcolor -highlightthickness \ |
| -selectbackground -selectborderwidth -selectforeground \ |
| -textbackground |
| } |
| |
| # ------------------------------------------------------------------ |
| # HYPERHELP |
| # ------------------------------------------------------------------ |
| itcl::class iwidgets::Hyperhelp { |
| inherit iwidgets::Shell |
| |
| constructor {args} {} |
| |
| itk_option define -topics topics Topics {} |
| itk_option define -helpdir helpdir Directory . |
| itk_option define -title title Title "Help" |
| itk_option define -closecmd closeCmd CloseCmd {} |
| itk_option define -maxhistory maxHistory MaxHistory 20 |
| |
| public variable beforelink {} |
| public variable afterlink {} |
| |
| public method showtopic {topic} |
| public method followlink {link} |
| public method forward {} |
| public method back {} |
| public method updatefeedback {n} |
| |
| protected method _readtopic {file {anchorpoint {}}} |
| protected method _pageforward {} |
| protected method _pageback {} |
| protected method _lineforward {} |
| protected method _lineback {} |
| protected method _fill_go_menu {} |
| |
| protected variable _history {} ;# History list of viewed pages |
| protected variable _history_ndx -1 ;# current position in history list |
| protected variable _history_len 0 ;# length of history list |
| protected variable _histdir -1 ;# direction in history we just came |
| ;# from |
| protected variable _len 0 ;# length of text to be rendered |
| protected variable _file {} ;# current topic |
| |
| private variable _remaining 0 ;# remaining text to be rendered |
| private variable _rendering 0 ;# flag - in process of rendering |
| } |
| |
| # |
| # Provide a lowercased access method for the Scrolledlistbox class. |
| # |
| proc ::iwidgets::hyperhelp {pathName args} { |
| uplevel ::iwidgets::Hyperhelp $pathName $args |
| } |
| |
| # ------------------------------------------------------------------ |
| # CONSTRUCTOR |
| # ------------------------------------------------------------------ |
| itcl::body iwidgets::Hyperhelp::constructor {args} { |
| itk_option remove iwidgets::Shell::padx iwidgets::Shell::pady |
| |
| # |
| # Create a pulldown menu |
| # |
| itk_component add -private menubar { |
| frame $itk_interior.menu -relief raised -bd 2 |
| } { |
| keep -background -cursor |
| } |
| pack $itk_component(menubar) -side top -fill x |
| |
| itk_component add -private topicmb { |
| menubutton $itk_component(menubar).topicmb -text "Topics" \ |
| -menu $itk_component(menubar).topicmb.topicmenu \ |
| -underline 0 -padx 8 -pady 2 |
| } { |
| keep -background -cursor -font -foreground \ |
| -activebackground -activeforeground |
| } |
| pack $itk_component(topicmb) -side left |
| |
| itk_component add -private topicmenu { |
| menu $itk_component(topicmb).topicmenu -tearoff no |
| } { |
| keep -background -cursor -font -foreground \ |
| -activebackground -activeforeground |
| } |
| |
| itk_component add -private navmb { |
| menubutton $itk_component(menubar).navmb -text "Navigate" \ |
| -menu $itk_component(menubar).navmb.navmenu \ |
| -underline 0 -padx 8 -pady 2 |
| } { |
| keep -background -cursor -font -foreground \ |
| -activebackground -activeforeground |
| } |
| pack $itk_component(navmb) -side left |
| |
| itk_component add -private navmenu { |
| menu $itk_component(navmb).navmenu -tearoff no |
| } { |
| keep -background -cursor -font -foreground \ |
| -activebackground -activeforeground |
| } |
| set m $itk_component(navmenu) |
| $m add command -label "Forward" -underline 0 -state disabled \ |
| -command [itcl::code $this forward] -accelerator f |
| $m add command -label "Back" -underline 0 -state disabled \ |
| -command [itcl::code $this back] -accelerator b |
| $m add cascade -label "Go" -underline 0 -menu $m.go |
| |
| itk_component add -private navgo { |
| menu $itk_component(navmenu).go -postcommand [itcl::code $this _fill_go_menu] |
| } { |
| keep -background -cursor -font -foreground \ |
| -activebackground -activeforeground |
| } |
| |
| # |
| # Create a scrolledhtml object to display help pages |
| # |
| itk_component add scrtxt { |
| iwidgets::scrolledhtml $itk_interior.scrtxt \ |
| -linkcommand "$this followlink" -feedback "$this updatefeedback" |
| } { |
| keep -hscrollmode -vscrollmode -background -textbackground \ |
| -fontname -fontsize -fixedfont -link \ |
| -linkhighlight -borderwidth -cursor -sbwidth -scrollmargin \ |
| -width -height -foreground -highlightcolor -visibleitems \ |
| -highlightthickness -padx -pady -activerelief \ |
| -relief -selectbackground -selectborderwidth \ |
| -selectforeground -setgrid -wrap -unknownimage |
| } |
| pack $itk_component(scrtxt) -fill both -expand yes |
| |
| # |
| # Bind shortcut keys |
| # |
| bind $itk_component(hull) <Key-f> [itcl::code $this forward] |
| bind $itk_component(hull) <Key-b> [itcl::code $this back] |
| bind $itk_component(hull) <Alt-Right> [itcl::code $this forward] |
| bind $itk_component(hull) <Alt-Left> [itcl::code $this back] |
| bind $itk_component(hull) <Key-space> [itcl::code $this _pageforward] |
| bind $itk_component(hull) <Key-Next> [itcl::code $this _pageforward] |
| bind $itk_component(hull) <Key-BackSpace> [itcl::code $this _pageback] |
| bind $itk_component(hull) <Key-Prior> [itcl::code $this _pageback] |
| bind $itk_component(hull) <Key-Delete> [itcl::code $this _pageback] |
| bind $itk_component(hull) <Key-Down> [itcl::code $this _lineforward] |
| bind $itk_component(hull) <Key-Up> [itcl::code $this _lineback] |
| |
| wm title $itk_component(hull) "Help" |
| |
| eval itk_initialize $args |
| if {[lsearch -exact $args -closecmd] == -1} { |
| configure -closecmd [itcl::code $this deactivate] |
| } |
| } |
| |
| # ------------------------------------------------------------------ |
| # OPTIONS |
| # ------------------------------------------------------------------ |
| |
| # ------------------------------------------------------------------ |
| # OPTION: -topics |
| # |
| # Specifies the topics to display on the menu. For each topic, there should |
| # be a file named <helpdir>/<topic>.html |
| # ------------------------------------------------------------------ |
| itcl::configbody iwidgets::Hyperhelp::topics { |
| set m $itk_component(topicmenu) |
| $m delete 0 last |
| foreach topic $itk_option(-topics) { |
| if {[lindex $topic 1] == {} } { |
| $m add radiobutton -variable topic \ |
| -value $topic \ |
| -label $topic \ |
| -command [list $this showtopic $topic] |
| } else { |
| if {[string index [file dirname [lindex $topic 1]] 0] != "/" && \ |
| [string index [file dirname [lindex $topic 1]] 0] != "~"} { |
| set link $itk_option(-helpdir)/[lindex $topic 1] |
| } else { |
| set link [lindex $topic 1] |
| } |
| $m add radiobutton -variable topic \ |
| -value [lindex $topic 0] \ |
| -label [lindex $topic 0] \ |
| -command [list $this followlink $link] |
| } |
| } |
| $m add separator |
| $m add command -label "Close Help" -underline 0 \ |
| -command $itk_option(-closecmd) |
| } |
| |
| # ------------------------------------------------------------------ |
| # OPTION: -title |
| # |
| # Specify the window title. |
| # ------------------------------------------------------------------ |
| itcl::configbody iwidgets::Hyperhelp::title { |
| wm title $itk_component(hull) $itk_option(-title) |
| } |
| |
| # ------------------------------------------------------------------ |
| # OPTION: -helpdir |
| # |
| # Set location of help files |
| # ------------------------------------------------------------------ |
| itcl::configbody iwidgets::Hyperhelp::helpdir { |
| if {[file pathtype $itk_option(-helpdir)] == "relative"} { |
| configure -helpdir [file join [pwd] $itk_option(-helpdir)] |
| } else { |
| set _history {} |
| set _history_len 0 |
| set _history_ndx -1 |
| $itk_component(navmenu) entryconfig 0 -state disabled |
| $itk_component(navmenu) entryconfig 1 -state disabled |
| configure -topics $itk_option(-topics) |
| } |
| } |
| |
| # ------------------------------------------------------------------ |
| # OPTION: -closecmd |
| # |
| # Specify the command to execute when close is selected from the menu |
| # ------------------------------------------------------------------ |
| itcl::configbody iwidgets::Hyperhelp::closecmd { |
| $itk_component(topicmenu) entryconfigure last -command $itk_option(-closecmd) |
| } |
| |
| # ------------------------------------------------------------------ |
| # METHODS |
| # ------------------------------------------------------------------ |
| |
| # ------------------------------------------------------------------ |
| # METHOD: showtopic topic |
| # |
| # render text of help topic <topic>. The text is expected to be found in |
| # <helpdir>/<topic>.html |
| # ------------------------------------------------------------------ |
| itcl::body iwidgets::Hyperhelp::showtopic {topic} { |
| if ![regexp {(.*)#(.*)} $topic dummy topicname anchorpart] { |
| set topicname $topic |
| set anchorpart {} |
| } |
| if {$topicname == ""} { |
| set topicname $_file |
| set filepath $_file |
| } else { |
| set filepath $itk_option(-helpdir)/$topicname.html |
| } |
| if {[incr _history_ndx] < $itk_option(-maxhistory)} { |
| set _history [lrange $_history 0 [expr {$_history_ndx - 1}]] |
| set _history_len [expr {$_history_ndx + 1}] |
| } else { |
| incr _history_ndx -1 |
| set _history [lrange $_history 1 $_history_ndx] |
| set _history_len [expr {$_history_ndx + 1}] |
| } |
| lappend _history [list $topicname $filepath $anchorpart] |
| _readtopic $filepath $anchorpart |
| } |
| |
| # ------------------------------------------------------------------ |
| # METHOD: followlink link |
| # |
| # Callback for click on a link. Shows new topic. |
| # ------------------------------------------------------------------ |
| itcl::body iwidgets::Hyperhelp::followlink {link} { |
| if {[string compare $beforelink ""] != 0} { |
| eval $beforelink $link |
| } |
| if ![regexp {(.*)#(.*)} $link dummy filepart anchorpart] { |
| set filepart $link |
| set anchorpart {} |
| } |
| if {$filepart != "" && [string index [file dirname $filepart] 0] != "/" && \ |
| [string index [file dirname $filepart] 0] != "~"} { |
| set filepart [$itk_component(scrtxt) pwd]/$filepart |
| set hfile $filepart |
| } else { |
| set hfile $_file |
| } |
| incr _history_ndx |
| set _history [lrange $_history 0 [expr {$_history_ndx - 1}]] |
| set _history_len [expr {$_history_ndx + 1}] |
| lappend _history [list [file rootname [file tail $hfile]] $hfile $anchorpart] |
| set ret [_readtopic $filepart $anchorpart] |
| if {[string compare $afterlink ""] != 0} { |
| eval $afterlink $link |
| } |
| return $ret |
| } |
| |
| # ------------------------------------------------------------------ |
| # METHOD: forward |
| # |
| # Show topic one forward in history list |
| # ------------------------------------------------------------------ |
| itcl::body iwidgets::Hyperhelp::forward {} { |
| if {$_rendering || ($_history_ndx+1) >= $_history_len} return |
| incr _history_ndx |
| eval _readtopic [lrange [lindex $_history $_history_ndx] 1 end] |
| } |
| |
| # ------------------------------------------------------------------ |
| # METHOD: back |
| # |
| # Show topic one back in history list |
| # ------------------------------------------------------------------ |
| itcl::body iwidgets::Hyperhelp::back {} { |
| if {$_rendering || $_history_ndx <= 0} return |
| incr _history_ndx -1 |
| set _histdir 1 |
| eval _readtopic [lrange [lindex $_history $_history_ndx] 1 end] |
| } |
| |
| # ------------------------------------------------------------------ |
| # METHOD: updatefeedback remaining |
| # |
| # Callback from text to update feedback widget |
| # ------------------------------------------------------------------ |
| itcl::body iwidgets::Hyperhelp::updatefeedback {n} { |
| if {($_remaining - $n) > .1*$_len} { |
| [$itk_interior.feedbackshell childsite].helpfeedback step [expr {$_remaining - $n}] |
| update idletasks |
| set _remaining $n |
| } |
| } |
| |
| # ------------------------------------------------------------------ |
| # PRIVATE METHOD: _readtopic |
| # |
| # Read in file, render it in text area, and jump to anchorpoint |
| # ------------------------------------------------------------------ |
| itcl::body iwidgets::Hyperhelp::_readtopic {file {anchorpoint {}}} { |
| if {$file != ""} { |
| if {[string compare $file $_file] != 0} { |
| if {[catch {set f [open $file r]} err]} { |
| incr _history_ndx $_histdir |
| set _history_len [expr {$_history_ndx + 1}] |
| set _histdir -1 |
| set m $itk_component(navmenu) |
| if {($_history_ndx+1) < $_history_len} { |
| $m entryconfig 0 -state normal |
| } else { |
| $m entryconfig 0 -state disabled |
| } |
| if {$_history_ndx > 0} { |
| $m entryconfig 1 -state normal |
| } else { |
| $m entryconfig 1 -state disabled |
| } |
| return |
| } |
| set _file $file |
| set txt [read $f] |
| iwidgets::shell $itk_interior.feedbackshell -title \ |
| "Rendering HTML" -padx 1 -pady 1 |
| iwidgets::Feedback [$itk_interior.feedbackshell \ |
| childsite].helpfeedback \ |
| -steps [set _len [string length $txt]] \ |
| -labeltext "Rendering HTML" -labelpos n |
| pack [$itk_interior.feedbackshell childsite].helpfeedback |
| $itk_interior.feedbackshell center $itk_interior |
| $itk_interior.feedbackshell activate |
| set _remaining $_len |
| set _rendering 1 |
| if {[catch {$itk_component(scrtxt) render $txt [file dirname \ |
| $file]} err]} { |
| if [regexp "</pre>" $err] { |
| $itk_component(scrtxt) render "<tt>$err</tt>" |
| } else { |
| $itk_component(scrtxt) render "<pre>$err</pre>" |
| } |
| } |
| wm title $itk_component(hull) "Help: $file" |
| itcl::delete object [$itk_interior.feedbackshell \ |
| childsite].helpfeedback |
| itcl::delete object $itk_interior.feedbackshell |
| set _rendering 0 |
| } |
| } |
| set m $itk_component(navmenu) |
| if {($_history_ndx+1) < $_history_len} { |
| $m entryconfig 0 -state normal |
| } else { |
| $m entryconfig 0 -state disabled |
| } |
| if {$_history_ndx > 0} { |
| $m entryconfig 1 -state normal |
| } else { |
| $m entryconfig 1 -state disabled |
| } |
| if {$anchorpoint != {}} { |
| $itk_component(scrtxt) import -link #$anchorpoint |
| } else { |
| $itk_component(scrtxt) import -link # |
| } |
| set _histdir -1 |
| } |
| |
| # ------------------------------------------------------------------ |
| # PRIVATE METHOD: _fill_go_menu |
| # |
| # update go submenu with current history |
| # ------------------------------------------------------------------ |
| itcl::body iwidgets::Hyperhelp::_fill_go_menu {} { |
| set m $itk_component(navgo) |
| catch {$m delete 0 last} |
| for {set i [expr {$_history_len - 1}]} {$i >= 0} {incr i -1} { |
| set topic [lindex [lindex $_history $i] 0] |
| set filepath [lindex [lindex $_history $i] 1] |
| set anchor [lindex [lindex $_history $i] 2] |
| $m add command -label $topic \ |
| -command [list $this followlink $filepath#$anchor] |
| } |
| } |
| |
| # ------------------------------------------------------------------ |
| # PRIVATE METHOD: _pageforward |
| # |
| # Callback for page forward shortcut key |
| # ------------------------------------------------------------------ |
| itcl::body iwidgets::Hyperhelp::_pageforward {} { |
| $itk_component(scrtxt) yview scroll 1 pages |
| } |
| |
| # ------------------------------------------------------------------ |
| # PRIVATE METHOD: _pageback |
| # |
| # Callback for page back shortcut key |
| # ------------------------------------------------------------------ |
| itcl::body iwidgets::Hyperhelp::_pageback {} { |
| $itk_component(scrtxt) yview scroll -1 pages |
| } |
| |
| # ------------------------------------------------------------------ |
| # PRIVATE METHOD: _lineforward |
| # |
| # Callback for line forward shortcut key |
| # ------------------------------------------------------------------ |
| itcl::body iwidgets::Hyperhelp::_lineforward {} { |
| $itk_component(scrtxt) yview scroll 1 units |
| } |
| |
| # ------------------------------------------------------------------ |
| # PRIVATE METHOD: _lineback |
| # |
| # Callback for line back shortcut key |
| # ------------------------------------------------------------------ |
| itcl::body iwidgets::Hyperhelp::_lineback {} { |
| $itk_component(scrtxt) yview scroll -1 units |
| } |