source: tol/tolbase/lib/markupviewer/markupviewer.tcl @ 5c67e4e

1941-docker-image-to-testdevel
Last change on this file since 5c67e4e was 5c67e4e, checked in by Jorge Pérez <josp.jorge@…>, 15 years ago

refs #1347, fixing some bugs after including notebook markup in tolbase

git-svn-id: ​https://www.tol-project.org/svn/tolp/trunk@3883 be4846ae-f051-483a-831f-b64e7d08527f

  • Property mode set to 100644
File size: 13.9 KB
Line 
1#-----------------------------------------------------------------------
2# TITLE:
3#       markupviewer.tcl
4#
5# AUTHOR:
6#       inspired in Will Duquette
7#
8# DESCRIPTION:
9#       A viewer for browsing Notebook pages. Simplified version of
10#       pageviewer.tcl
11#
12# LICENSE:
13#
14#-----------------------------------------------------------------------
15
16package require snit
17package require renderpane
18
19package require autoscroll 1.1
20
21snit::widget markupviewer {
22    # A command to use for outputting messages.  The message will be
23    # appended.
24    option -messagecommand {}
25 
26    #-------------------------------------------------------------------
27    # Other options
28
29    # A command that's called when the displayed page changes. The
30    # command gets one argument, the page name.
31    option -pagecommand {}
32
33    # A command that's called when we try to display a page that
34    # doesn't exist.
35    option -unknowncommand {}
36
37    # The notebook database
38    option -db -default {} -readonly 1
39
40    # control if the title is rendered on the renderpane
41    option -showtitle -default 1
42
43    #-------------------------------------------------------------------
44    # Components
45
46    variable db
47
48    # The renderpane is the component that actually displays the
49    # rendered page.
50    variable rp
51
52    #--------------------------------------------------------------------
53    # Other variables
54
55    # The history list is a list of {PageName PagePos} pairs.
56    variable history {}
57
58    # The histPos is the index of the currently displayed page in the
59    # history list.  It's initially -1 because there's nothing in the
60    # list.
61    variable histPos -1
62
63    # A list of recently displayed pages.  Each page appears only once,
64    # regardless of how often (and where) it appears in the history list.
65    # There will be ten pages listed, maximum; no more than one of them
66    # are guaranteed to still exist.
67    variable recentPages {}
68
69    #--------------------------------------------------------------------
70    # Constructor
71
72    constructor {args} {
73        # As yet we have no option delegation, so go ahead and get the
74        # args
75        $self configurelist $args
76
77        if { $options(-db) eq "" } {
78          error "Invalid database option: '$options(-db)'"
79        }
80        set db $options(-db)
81
82        # Create the renderpane.
83
84        install rp using renderpane $win.rp \
85            -yscrollcommand "$win.scroll set" \
86            -querycommand      [mymethod pageexists] \
87            -titlecommand      [mymethod TitleHandler] \
88            -linkcommand       [mymethod LinkHandler] \
89            -buttoncommand     [mymethod ButtonHandler] \
90            -macroerrorcommand [mymethod MacroErrorHandler] \
91            -messagecommand    $options(-messagecommand)
92
93        scrollbar $win.scroll \
94            -command "$win.rp yview"
95
96        # grid them in.
97        # josp: use grid and autoscroll
98        if { 0 } {
99          pack $win.scroll  -side right -fill y    -expand false
100          pack $rp          -side top   -fill both -expand true
101        }
102
103        grid $rp -row 0 -column 0 -sticky "snew"
104        grid $win.scroll -row 0 -column 1 -sticky "ns"
105        grid rowconfigure $win 0 -weight 1
106        grid columnconfigure $win 0 -weight 1
107        ::autoscroll::autoscroll $win.scroll
108
109        #---------------------------------------------------------------
110        # User Interactions
111
112        # Add the pageviewer window itself to the renderpane's bindtags,
113        # so that keys bound to the pageviewer will take effect when the
114        # renderpane has focus
115        set tags [bindtags $rp]
116        lappend tags $win
117        bindtags $rp $tags
118
119        # Go to the previous page when <BackSpace> is pressed.
120        bind $rp <BackSpace> [list $self backpage]
121
122        # User Menu.
123        # josp: no user menu considered
124        if { 0 } {
125          menu $rp.user -tearoff no -postcommand [mymethod PostUserMenu]
126         
127          $rp.user add command -label "User Menu"
128          $rp.user add separator
129          $rp.user add command -label "Dummy"
130         
131          bind $rp <Control-1> [list tk_popup $rp.user %X %Y 2]
132          bind $rp <3>         [list tk_popup $rp.user %X %Y 2]
133         
134          # Recent Pages Menu.
135          menu $rp.recent -tearoff no -postcommand [mymethod PostRecent]
136         
137          $rp.recent add command -label "Recent Pages"
138          $rp.recent add separator
139          $rp.recent add command -label "Dummy"
140         
141          bind $rp <Shift-1> [list tk_popup $rp.recent %X %Y 2]
142        }
143        #---------------------------------------------------------------
144        # Prepare to receive preferences events; unregister on
145        # destroy.
146        prefs register $selfns [mymethod UsePreferences]
147    }
148
149    destructor {
150        catch {prefs unregister $selfns}
151    }
152
153    delegate method UsePreferences to rp
154    # josp: delegate UsePreferences on renderpane
155    if { 0 } {
156      method UsePreferences {} {
157        # Update the display when the preferences change.
158        $self showpage
159      }
160    }
161
162    #-------------------------------------------------------------------
163    # Public Methods
164
165    delegate method searchfor to rp
166
167    delegate method pagetime     to db
168    delegate method pagename     to db      as name
169
170    method pageexists { name } {
171      if { [ $db exists $name ] } {
172        return 1
173      } else {
174        return [ regexp "(http|https)://" $name ]
175      }
176    }
177
178    # Returns the expanded text of the page, which must exist.
179    method pageexpand {name} {
180      try {
181        set result [$db expand [$db get $name]]
182      }
183      return $result
184    }
185
186    # Returns the name of the currently displayed page, or "" if none.
187    # Note that during a deletion or page renaming the named page
188    # is not guaranteed to exist.
189    method current {} {
190      return [lindex $history $histPos 0]
191    }
192
193    # Tells the pageviewer to take the keyboard focus.
194    # If -friendly, we take the focus only if our toplevel already
195    # has it (e.g., we take the focus back from the search box).
196    method focus {{option {}}} {
197      set focusWin [focus]
198     
199      if {$focusWin eq ""} {
200        return
201      }
202     
203      if {$option ne "-friendly" ||
204          [winfo toplevel $win] eq [winfo toplevel $focusWin]} {
205        focus $rp
206      }
207    }
208   
209    # Shows the named page.  The -unknowncommand is called if the
210    # page doesn't exist.
211    method showpage {{name ""}} {
212        # FIRST, remember the position for the page we're showing now.
213        if {$histPos >= 0} {
214            lset history $histPos 1 [$self GetPos]
215        }
216
217        # NEXT, default to the current page.
218        if {$name eq ""} {
219            set name [$self current]
220
221            if {$name eq ""} {
222                error "no current page."
223            }
224        }
225
226        # NEXT, if the page doesn't exist, call the -unknowncommand.
227        if {![$self pageexists $name]} {
228            if {$options(-unknowncommand) ne {}} {
229                set command $options(-unknowncommand)
230                lappend command $name
231                uplevel \#0 $command
232            } else {
233                return -code error -errorcode USER "No such page: '$name'"
234            }
235
236            return
237        }
238
239        # NEXT, save the new page in the history list.  When we show
240        # a new page, any pages forward of our position go away.
241        set history [lrange $history 0 $histPos]
242        lappend history [list [$self pagename $name] 0]
243        incr histPos
244
245        # NEXT, display it.
246        $self DisplayPage
247    }
248    # Steps back one page, if possible
249    method backpage {} {
250        # FIRST, remember the position for the page we're showing now.
251        if {$histPos >= 0} {
252            lset history $histPos 1 [$self GetPos]
253        }
254
255        # NEXT, Look back through the history list for a page that exists,
256        # and is also different than the current page.
257        set current [lindex $history $histPos 0]
258        set pos [expr {$histPos - 1}]
259
260        while {$pos >= 0} {
261            set candidate [lindex $history $pos 0]
262
263            if {[$self pageexists $candidate]} {
264
265                if {![string equal -nocase $candidate $current]} {
266                    break
267                }
268            }
269
270            incr pos -1
271        }
272
273        if {$pos < 0} {
274            bell
275            return
276        }
277
278        set histPos $pos
279
280        $self DisplayPage
281    }
282
283    # Steps forward one page, if possible
284    method forwardpage {} {
285        # FIRST, remember the position for the page we're showing now.
286        if {$histPos >= 0} {
287            lset history $histPos 1 [$self GetPos]
288        }
289
290        # NEXT, Look forward through the history list for a page that exists,
291        # and is also different than the current page.
292        set current [lindex $history $histPos 0]
293        set pos [expr {$histPos + 1}]
294        set len [llength $history]
295
296        while {$pos < $len} {
297            set candidate [lindex $history $pos 0]
298
299            if {[$self pageexists $candidate]} {
300
301                if {![string equal -nocase $candidate $current]} {
302                    break
303                }
304            }
305
306            incr pos
307        }
308
309        if {$pos >= $len} {
310            bell
311            return
312        }
313
314        set histPos $pos
315
316        $self DisplayPage
317    }
318
319    # Shows the page from the beginning of the Recent Pages list, if it exists.
320    method cyclerecent {} {
321        foreach id $recentPages {
322            if {[$self pageexists $id]} {
323                $self showpage $id
324                break
325            }
326        }
327    }
328
329    #-------------------------------------------------------------------
330    # Private Methods
331
332    # Display the current page
333    method DisplayPage { } {
334        # FIRST, Get the current page specs
335        set name [$self pagename [lindex $history $histPos 0]]
336        set ypos [lindex $history $histPos 1]
337
338        # NEXT, add the name to the list of recent pages
339        $self SaveRecentPage $name
340
341        # NEXT, Expand the requested page and display it.
342        set pagetext [$self pageexpand $name]
343
344        if { $options(-showtitle) } {
345          $rp render $name $pagetext
346        } else {
347          $rp render "" $pagetext
348        }
349       
350        # josp: don't known what is it for
351        if { 0 } {
352          $rp searchfor [$self searchtext]
353        }
354        # NEXT, give the renderpane the focus so that we don't
355        # need to click in it.
356
357        #$self focus -friendly
358
359        $self setpos $ypos
360
361        # NEXT, notify those concerned.
362        if {$options(-pagecommand) ne {}} {
363            set command $options(-pagecommand)
364            lappend command $name
365            uplevel \#0 $command
366        }
367    }
368
369    # Save the specified page to the recent pages list, removing
370    # any previous entry with the same name.  Names are stored
371    # in lower case.  No more than ten names are stored.
372    method SaveRecentPage {name} {
373        set name [string tolower $name]
374
375        set ndx [lsearch -exact $recentPages $name]
376
377        if {$ndx != -1} {
378            set recentPages [lreplace $recentPages $ndx $ndx]
379        }
380
381        lappend recentPages $name
382       
383        # Cut down back to ten, if need be
384        if {[llength $recentPages] == 11} {
385            set recentPages [lreplace $recentPages 0 0]
386        }
387    }
388   
389
390    # Get the y-position of the text at the top of the window.
391    method GetPos {} {
392        lindex [$rp yview] 0
393    }
394
395    # Set the y-position of the text at the top of the window.
396    method setpos  {ypos} {
397        $rp yview moveto $ypos
398    }
399
400    # Called when the user clicks on the title text.
401    method TitleHandler {title} {
402        $self showsearch $title
403    }
404
405    # Called when the user clicks on a link; shows the linked page.
406    method LinkHandler {linkName} {
407      if { [ regexp "(http|https)://" $linkName ] } {
408        LaunchBrowser $linkName
409      } else {
410        $self showpage $linkName
411      }
412    }
413
414    # Called when the user clicks on a magic button; calls the button's script
415    method ButtonHandler {script} {
416        $self evaluser $script
417    }
418
419    # Finds the macro error text and displays the error message.
420    method MacroErrorHandler {macro} {
421        $self evaluser $macro
422        # TBD: If macros are disabled, then clicking on this won't
423        # display an error.  We need to handle this somehow.
424    }
425
426    # procs
427
428    proc LaunchBrowser { url } {
429      global tcl_platform
430     
431      # It *is* generally a mistake to switch on $tcl_platform(os), particularly
432      # in comparison to $tcl_platform(platform).  For now, let's just regard it
433      # as a stylistic variation subject to debate.
434      switch $tcl_platform(os) {
435        Darwin {
436          set command [list open $url]
437        }
438        HP-UX -
439        Linux  -
440        SunOS {
441          foreach executable {firefox mozilla netscape iexplorer opera lynx
442            w3m links epiphany galeon konqueror mosaic amaya
443            browsex elinks} {
444            set executable [auto_execok $executable]
445            if [string length $executable] {
446              # Do you want to mess with -remote?  How about other browsers?
447              # Frank Darby says the '&' leads on his Ubuntu to attempts to
448              # open 'www.&.com', and so on.
449              set command [list $executable $url &]
450              set command [list $executable $url]
451              break
452            }
453          }
454        }
455        {Windows 95} -
456        {Windows NT} {
457          set command "[auto_execok start] {} [list $url]"
458        }
459      }
460      if [info exists command] {
461        # Replace {*}$command by eval "$command" if you want < tcl 8.5 compatibility ([RA])
462        # Added the '&' to launch the browser as background process. [Duoas]
463        if [catch {eval exec $command &} err] {
464          tk_messageBox -icon error -message "error '$err' with '$command'"
465        }
466      } else {
467        tk_messageBox -icon error -message \
468            "Please tell CL that ($tcl_platform(os), $tcl_platform(platform)) is not yet ready for browsing."
469      }
470    }
471}
472
473package provide markupviewer 1.0
Note: See TracBrowser for help on using the repository browser.