File: htmlview.tcl

package info (click to toggle)
moomps 4.6-2
  • links: PTS
  • area: main
  • in suites: sarge
  • size: 2,444 kB
  • ctags: 2,307
  • sloc: tcl: 34,882; sh: 167; makefile: 91
file content (168 lines) | stat: -rw-r--r-- 8,377 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
# copyright (C) 1997-2005 Jean-Luc Fontaine (mailto:jfontain@free.fr)
# this program is free software: please read the COPYRIGHT file enclosed in this package or use the Help Copyright menu

# $Id: htmlview.tcl,v 2.28 2005/01/02 00:45:07 jfontain Exp $


set ::htmlLibraryAdditionalCode {

    # use bold and smaller sizes than the HTML library default ones for headers
    array set HMtag_map {
        h1 {size 22 weight bold}
        h2 {size 20 weight bold}
        h3 {size 18 weight bold}
        h4 {size 16 weight bold}
        h5 {size 14 weight bold}
        h6 {weight bold}
    }

    # make headers and preformatted text stand out better by adding new lines around them, extra new lines after lists are too much:
    array set HMinsert_map {
        h1 \n\n /h1 \n\n h2 \n\n /h2 \n\n h3 \n\n /h3 \n\n h4 \n\n /h4 \n\n h5 \n\n /h5 \n\n h6 \n\n /h6 \n\n pre \n\n /ul {} /ol {}
    }

    unset HMevents(Enter)                                                 ;# prevent links highlighting, try to behave like Netscape
    unset HMevents(Leave)
    unset HMevents(1)
    set HMevents(ButtonRelease-1) {-foreground darkblue}

    proc HMset_image {widget label source} {                                                      ;# supply image handling procedure
        if {![catch {image create photo -file $source} image]} {
            bind $label <Destroy> "image delete $image"              ;# setup binding so that image is deleted as label is destroyed
            HMgot_image $label $image                                                       ;# got the image for the specified label
            # suppress relief for better visibility and use parent text widget background for transparent areas to really look it
            $label configure -borderwidth 0 -background [[winfo parent $label] cget -background]
        }
    }

}

append ::htmlLibraryAdditionalCode "
    set HMtag_map(hmstart) {family [list $global::fontFamily]}
    lappend HMtag_map(hmstart) weight medium style r size $global::fontSize Tcenter {} Tlink {} Tnowrap {} Tunderline {} list list\
        fill 1 indent {} counter 0 adjust 0
"

proc HMlink_hit {path x y} {            ;# is invoked here at the global level by the Tk bind facility instead of in the interpreter
    $::htmlViewer::interpreterFromPath($path) eval "HMlink_hit $path $x $y"
}


class htmlViewer {

    proc htmlViewer {this parentPath args} composite {[new scroll text $parentPath] $args} {
        variable interpreterFromPath

        set path $composite::($composite::($this,base),scrolled,path)
        # borders are never shown on focus, padding so that lines do not start too close to the left border
        $path configure -highlightthickness 0 -state disabled -padx 2 -background white -cursor {}          ;# hide insertion cursor
        set interpreter [interp create]                      ;# use separate interpreter because HTML library uses global state data
        $interpreter eval "set ::auto_path [list $::auto_path]"                        ;# in case packages are needed by interpreter
        $interpreter eval $::htmlLibraryCode
        $interpreter eval $::htmlLibraryAdditionalCode
        $interpreter alias $path $path                                                    ;# make text widget visible in interpreter
        $interpreter alias formulasHelpWindow formulasHelpWindow
        foreach command {bind bindtags image pack update winfo} {                                           ;# and a few Tk commands
            $interpreter alias $command $command
        }
        foreach command {button frame label scrollbar text} {                                         ;# along with a few Tk widgets
            $interpreter alias $command ::htmlViewer::widget $command $interpreter
        }
        $interpreter eval "HMinit_win $path"
        # make HTML text widget behave more like Netscape
        $path tag configure mark -foreground black                                                    ;# override list markers color
        $path tag configure link -borderwidth 1 -foreground blue -underline 1       ;# override hypertext links border and underline
        $interpreter eval "set ::HM${path}(S_symbols) {oooooo\xd7\xb0>:\xb7}"         ;# use simple circles for list element markers
        set ($this,interpreter) $interpreter
        set ($this,textPath) $path
        set interpreterFromPath($path) $interpreter                           ;# required for link hit procedure to find interpreter

        composite::complete $this
    }

    proc ~htmlViewer {this} {
        variable interpreterFromPath

        # stop rendering in case we were interrupted by the user destroying the window for example
        $($this,interpreter) eval "HMset_state $($this,textPath) -stop 1"
        unset interpreterFromPath($($this,textPath))
        interp delete $($this,interpreter)
    }

    proc options {this} {
        # force initialization of linkto option
        return [list\
            [list -data {} {}]\
            [list -file {} {}]\
            [list -linkto $this]\
        ]
    }

    # can be set once completed so that widget can be managed (pack, bind, ...) and be visible for updates to occur
    proc set-data {this value} {
        if {[info exists ($this,loaded)]} {
            error {data can only be loaded once}
        }
        load $this $value
    }

    proc set-file {this value} {
        if {[info exists ($this,loaded)]} {
            error {data can only be loaded once}
        }
        set file [open $value]
        load $this [read $file]
        close $file
    }

    proc set-linkto {this viewer} {            ;# allow link hits to target another text widget (used in general help from contents)
        if {$viewer == $this} {
            $($this,interpreter) eval {
                proc HMlink_callback {widget reference} {                                          ;# supply link callback procedure
                    switch -glob -- [string tolower [file tail $reference]] {
                        formulas.htm - formulas-*.htm {
                            formulasHelpWindow                             ;# formulas help can be launched from general help window
                        }
                    }
                    if {![string match #* $reference]} return                                 ;# can only handle internal references
                    HMgoto $widget [string trimleft $reference #]                             ;# always update help data text widget
                }
            }
        } else {
            $($this,interpreter) alias HMlink_callback ::htmlViewer::linkCallbackRedirect $viewer
        }
    }

    proc load {this data} {
        set ($this,loaded) {}
        set path $($this,textPath)
        busy 1 $path                                                                      ;# show that we are busy for user feedback
        $path configure -state normal
        # the interpreter may no longer exists at this point
        # ignoring errors here is required in case we are interrupted while rendering by the user closing the window for example,
        # in which case the interpreter is destroyed causing the main interpreter to report the impossibility to evaluate the code
        catch {$($this,interpreter) eval "HMparse_html {$data} {HMrender $path}"}
        if {![winfo exists $path]} return              ;# user may have destroyed the window through the window manager, for example
        $($this,interpreter) eval "HMset_state $path -stop 1"                                ;# stop rendering previous page if busy
        $path configure -state disabled
        busy 0 $path
    }

    # create a widget of the specified type and make the resulting command available in the slave interpreter
    proc widget {type interpreter args} {
        set path [eval ::$type $args]
        $interpreter alias $path $path
        return $path
    }

    proc linkCallbackRedirect {viewer widget reference} {                  ;#  link callback procedure redirecting to another viewer
        $($viewer,interpreter) eval "HMlink_callback $($viewer,textPath) $reference"
    }

    ### public procedures below ###

    proc goTo {this url} {
        catch {$($this,interpreter) eval "HMlink_callback $($this,textPath) $url"}                     ;# ignore errors as in load{}
    }

}