source: tol/tolbase/lib/markupviewer/markupviewer.tcl @ 4721b73

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

refs #1347, notebook data base manager & markup viewer widget

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

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