domtext.tcl

Go to the documentation of this file.
00001 /*  domtext.tcl --*/
00002 /* */
00003 /*  Megawidget to display a DOM document in a Text widget.*/
00004 /* */
00005 /*  This widget both generates and reacts to DOM Events.*/
00006 /* */
00007 /*  Copyright (c) 2008 Explain*/
00008 /*  http://www.explain.com.au/*/
00009 /*  Copyright (c) 1999-2003 Zveno Pty Ltd*/
00010 /*  http://www.zveno.com/*/
00011 /* */
00012 /*  See the file "LICENSE" in this distribution for information on usage and*/
00013 /*  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.*/
00014 /* */
00015 /*  $Id: domtext.tcl,v 1.5 2003/12/09 04:56:40 balls Exp $*/
00016 
00017 package provide domtext 2.5
00018 
00019 /*  We need BWidgets*/
00020 
00021 package require BWidget 1.4
00022 
00023 /*  We need the DOM*/
00024 /*  V2.0 gives us Level 2 Events*/
00025 
00026 package require dom 3.2
00027 
00028 /*  Configuration options:*/
00029 /* */
00030 /*  -elementbgcolorlist {colour1 colour2 ...}*/
00031 /*      Specifies a list of colours to cycle through for*/
00032 /*      backgrounds of sucessive element content.*/
00033 /* */
00034 /*  -showtag text|tab|<empty>*/
00035 /*      "text" denotes that start and end tags are shown*/
00036 /*      as their XML text.  "tab" denotes that start and*/
00037 /*      end tags are shown as an image.  Empty value*/
00038 /*      denotes that start and end tags are not shown.*/
00039 
00040 namespace domtext {
00041     Widget::tkinclude domtext text .text \
00042         remove {-command -state}
00043 
00044     Widget::declare domtext {
00045     {-highlightcolor    String  "/* d9ffff" 0}*/
00046     {-rootnode      String  ""      0}
00047     {-state         String  "normal"    0}
00048     {-tagcolor      String  "/* 18605a" 0}*/
00049     {-commentcolor      String  "/* 660f91" 0}*/
00050     {-entityrefcolor    String  "/* 0080c0" 0}*/
00051     {-elementbgcolorlist    String  ""      0}
00052     {-showxmldecl       Boolean 1       0}
00053     {-showdoctypedecl   Boolean 1       0}
00054     {-showtag       String  "text"      0}
00055     }
00056 
00057     ret  ::domtext ( type path , type args ) { return [eval domtext::create $path $args] }
00058     ret  use () {}
00059 
00060     /*  Define bindings for domtext widget class*/
00061 
00062     /*  Certain mouse event bindings for the Text widget class must be overridden*/
00063 
00064     bind domtext <Button-1> [namespace code [list _tkevent_override %W %x %y]]
00065     bind domtext <Double-Button-1> [namespace code [list _tkevent_override %W %x %y]]
00066 
00067     /*  All of these bindings for the Text widget class cause characters*/
00068     /*  to be inserted or deleted.  These must be caught and prevented if the*/
00069     /*  characters are part of markup, otherwise the node value must be*/
00070     /*  updated*/
00071     /*  TODO: update with all bindings for Text widget*/
00072 
00073     foreach spec {
00074     <Meta-Key-d> <Meta-Key-Delete> <Meta-Key-BackSpace>
00075     <Control-Key-h> <Control-Key-t> <Control-Key-k> <Control-Key-d>
00076     <Control-Key-i> <Key>
00077     <<Cut>> <<Paste>> <<PasteSelection>> <<Clear>>
00078     <Key-BackSpace> <Key-Delete> <Key-Return>
00079     } {
00080     bind domtext $spec [list domtext::_tkevent_filter_$spec %W %A]
00081     }
00082     foreach spec {
00083     <Key-Up> <Key-Down> <Key-Left> <Key-Right>
00084     } {
00085     bind domtext $spec [list domtext::_key_select %W $spec]
00086     }
00087     foreach spec {
00088     <Meta-Key> <Control-Key>
00089     } {
00090     bind domtext $spec {/*  Do nothing - allow the normal Text class binding to take effect}*/
00091     }
00092 
00093     variable eventTypeMap
00094     array  eventTypeMap =  {
00095     ButtonPress mousedown
00096     ButtonRelease   mouseup
00097     Enter       mouseover
00098     Leave       mouseout
00099     Motion      mousemove
00100     FocusIn     DOMFocusIn
00101     FocusOut    DOMFocusOut
00102     }
00103 }
00104 
00105 /*  domtext::create --*/
00106 /* */
00107 /*  Widget class creation command*/
00108 /* */
00109 /*  Arguments:*/
00110 /*  path    widget path*/
00111 /*  args    configuration options*/
00112 /* */
00113 /*  Results:*/
00114 /*  Widget created, returns path*/
00115 
00116 ret  domtext::create (type path , type args) {
00117     upvar #0 [namespace current]::$path data
00118     array set maps [list Text {} :text {} .text {}]
00119 
00120     eval frame $path $maps(:text) -bd 0 -relief flat -takefocus 0 \
00121         -class domtext -highlightthickness 0
00122 
00123     Widget::initFromODB domtext $path $maps(Text)
00124 
00125     # Setup event bindings for generating DOM events
00126     bindtags $path [list $path Bwdomtext [winfo toplevel $path] all]
00127 
00128     set text [eval text $path.text $maps(.text) \
00129         -state [Widget::getMegawidgetOption $path -state] -wrap none \
00130         -takefocus 1]
00131     $text tag configure starttab -elide 1
00132     $text tag configure endtab -elide 1
00133     $text tag configure xmldecl -elide 1
00134     $text tag configure doctypedecl -elide 1
00135 
00136     bindtags $path [list $path domtext [winfo toplevel $path] all]
00137 
00138     grid $text -sticky news
00139     grid rowconfigure $path 0 -weight 1
00140     grid columnconfigure $path 0 -weight 1
00141 
00142     # Certain class bindings must be overridden
00143     bindtags $text [list $path domtext [winfo class $text] [winfo toplevel $path] all]
00144 
00145     rename $path ::$path:cmd
00146     proc ::$path { cmd args } "return \[eval domtext::\$cmd $path \$args\]"
00147 
00148     set root [Widget::getMegawidgetOption $path -rootnode]
00149     if {[string length $root]} {
00150     _refresh $path $root
00151     }
00152 
00153     set data(insert) end
00154     set data(nextElemBgColor) 0
00155 
00156     configure $path \
00157         -showtag [Widget::getMegawidgetOption $path -showtag] \
00158         -showxmldecl [Widget::getMegawidgetOption $path -showxmldecl] \
00159         -showdoctypedecl [Widget::getMegawidgetOption $path -showdoctypedecl]
00160 
00161     return $path
00162 }
00163 
00164 /*  domtext::cget --*/
00165 /* */
00166 /*  Implements the cget method*/
00167 /* */
00168 /*  Arguments:*/
00169 /*  path    widget path*/
00170 /*  option  configuration option*/
00171 /* */
00172 /*  Results:*/
00173 /*  Returns value of option*/
00174 
00175 ret  domtext::cget (type path , type option) {
00176     return [Widget::getoption $path $option]
00177 }
00178 
00179 /*  domtext::configure --*/
00180 /* */
00181 /*  Implements the configure method*/
00182 /* */
00183 /*  Arguments:*/
00184 /*  path    widget path*/
00185 /*  args    configuration options*/
00186 /* */
00187 /*  Results:*/
00188 /*  Sets values of options*/
00189 
00190 ret  domtext::configure (type path , type args) {
00191     upvar #0 [namespace current]::$path data
00192 
00193     set res [Widget::configure $path $args]
00194 
00195     set rn [Widget::hasChanged $path -rootnode root]
00196     if {$rn} {
00197 
00198     $path.text delete 1.0 end
00199     # Delete all marks and tags
00200     # This doesn't delete the standard marks and tags
00201     eval $path.text tag delete [$path.text tag names]
00202     eval $path.text mark unset [$path.text mark names]
00203     # Remove event listeners from previous DOM tree
00204 
00205     set data(insert) 1.0
00206 
00207     if {[string length $root]} {
00208         set docel [dom::document cget $root -documentElement]
00209 
00210         if {[string length $docel]} {
00211         # Listen for UI events
00212         dom::node addEventListener $root DOMActivate [namespace code [list _node_selected $path]] -usecapture 1
00213 
00214         # Listen for mutation events
00215         dom::node addEventListener $root DOMNodeInserted [namespace code [list _node_inserted $path]] -usecapture 1
00216         dom::node addEventListener $root DOMNodeRemoved [namespace code [list _node_removed $path]] -usecapture 1
00217         dom::node addEventListener $root DOMCharacterDataModified [namespace code [list _node_pcdata_modified $path]] -usecapture 1
00218         dom::node addEventListener $root DOMAttrModified [namespace code [list _node_attr_modified $path]] -usecapture 1
00219         dom::node addEventListener $root DOMAttrRemoved [namespace code [list _node_attr_removed $path]] -usecapture 1
00220 
00221         _refresh $path $root
00222         }
00223     }
00224     }
00225 
00226     set tc [Widget::hasChanged $path -tagcolor tagcolor]
00227     set hc [Widget::hasChanged $path -highlightcolor hlcolor]
00228     set cc [Widget::hasChanged $path -commentcolor commcolor]
00229     set ec [Widget::hasChanged $path -entityrefcolor ercolor]
00230     set ebg [Widget::hasChanged $path -elementbgcolorlist ebgcolor]
00231     if {($rn && [string length $root]) || $tc} {
00232     $path.text tag configure tags -foreground $tagcolor
00233     }
00234     if {($rn && [string length $root]) || $cc} {
00235     $path.text tag configure comment -foreground $commcolor
00236     }
00237     if {($rn && [string length $root]) || $ec} {
00238     $path.text tag configure entityreference -foreground $ercolor
00239     }
00240     if {($rn && [string length $root]) || $hc} {
00241     $path.text tag configure highlight -background $hlcolor
00242     }
00243     if {($rn && [string length $root]) || $ebg} {
00244     set data(nextElemBgColor) 0
00245     _elementbg_setall $path $root
00246     }
00247 
00248     if {[Widget::hasChanged $path -showtag showtag]} {
00249     switch -- $showtag {
00250         text {
00251         $path.text tag configure starttab -elide 1
00252         $path.text tag configure endtab -elide 1
00253         $path.text tag configure tags -elide 0
00254         }
00255         tab {
00256         $path.text tag configure tags -elide 1
00257         $path.text tag configure starttab -elide 0
00258         $path.text tag configure endtab -elide 0
00259         }
00260         {} {
00261         $path.text tag configure tags -elide 1
00262         $path.text tag configure starttab -elide 1
00263         $path.text tag configure endtab -elide 1
00264         }
00265         default {
00266         return -code error "invalid value \"$showtag\""
00267         }
00268     }
00269     }
00270 
00271     if {[Widget::hasChanged $path -showxmldecl showxmldecl]} {
00272     $path.text tag configure xmldecl -elide [expr !$showxmldecl]
00273     }
00274     if {[Widget::hasChanged $path -showdoctypedecl showdoctypedecl]} {
00275     $path.text tag configure doctypedecl -elide [expr !$showdoctypedecl]
00276     }
00277     return $res
00278 }
00279 
00280 /*  domtext::xview --*/
00281 /* */
00282 /*  Implements xview method*/
00283 /* */
00284 /*  Arguments:*/
00285 /*  path    widget path*/
00286 /*  args    additional arguments*/
00287 /* */
00288 /*  Results:*/
00289 /*  Depends on Text's xview method*/
00290 
00291 ret  domtext::xview (type path , type args) {
00292     eval $path.text xview $args
00293 }
00294 
00295 /*  domtext::yview --*/
00296 /* */
00297 /*  Implements yview method*/
00298 /* */
00299 /*  Arguments:*/
00300 /*  path    widget path*/
00301 /*  args    additional arguments*/
00302 /* */
00303 /*  Results:*/
00304 /*  Depends on Text's yview method*/
00305 
00306 ret  domtext::yview (type path , type args) {
00307     eval $path.text yview $args
00308 }
00309 
00310 /*  domtext::_refresh --*/
00311 /* */
00312 /*  Inserts serialized nodes into the Text widget,*/
00313 /*  while at the same time marking up the text to support*/
00314 /*  DOM-level editing functions.*/
00315 /* */
00316 /*  This function is similar to the DOM package's*/
00317 /*  serialization feature.  The code started by being copied*/
00318 /*  from there.*/
00319 /* */
00320 /*  Assumes that the widget is in normal state*/
00321 /* */
00322 /*  Arguments:*/
00323 /*  path    widget path*/
00324 /*  node    DOM node*/
00325 /* */
00326 /*  Results:*/
00327 /*  Text widget populated with serialized text.*/
00328 
00329 ret  domtext::_refresh (type path , type node) {
00330     upvar #0 [namespace current]::$path data
00331 
00332     $path.text mark set $node $data(insert)
00333     $path.text mark gravity $node left
00334 
00335     set end $data(insert)
00336 
00337     # For all nodes we bind Tk events to be able to generate DOM events
00338     $path.text tag bind $node <1> [namespace code [list _tkevent_select $path $node %x %y]]
00339     $path.text tag bind $node <Double-1> [namespace code [list _tkevent_open $path $node]]
00340 
00341     $path.text tag configure $node -background [_elementbg_cycle $path]
00342 
00343     switch [::dom::node cget $node -nodeType] {
00344     document -
00345     documentFragment {
00346 
00347         # Display the XML declaration
00348         if {0} {
00349         # OUCH!  Need an interface in the DOM package for this data
00350         array set nodeInfo [set $node]
00351         # XML Declaration attributes have a defined order, so can't use array directly
00352         array set xmldecl $nodeInfo(document:xmldecl)
00353         set xmldecllist [list version $xmldecl(version)]
00354         catch {lappend xmldecllist standalone $xmldecl(standalone)}
00355         catch {lappend xmldecllist encoding $xmldecl(encoding)}
00356         $path.text insert $data(insert) "<?xml[dom::Serialize:attributeList $xmldecllist]?>\n" [list $node xmldecl]
00357         set data(insert) [lindex [$path.text tag ranges $node] end]
00358     }
00359         foreach childToken [::dom::node children $node] {
00360         set end [_refresh $path $childToken]
00361         set data(insert) $end
00362         }
00363 
00364         $path.text tag add $node $node $end
00365         $path.text tag configure xmldecl -elide [expr ![Widget::cget $path -showxmldecl]]
00366         $path.text tag raise xmldecl
00367     }
00368 
00369     element {
00370 
00371         # Serialize the start tag
00372         $path.text insert $data(insert) <[::dom::node cget $node -nodeName] [list tags tag:start:$node] [_serialize:attributeList [array get [::dom::node cget $node -attributes]]] [list tags attrs:$node] > [list tags tag:start:$node]
00373 
00374         # Add the start tab icon
00375         $path.text image create $data(insert) -image ::domtext::starttab -align center -name tab:start:$node
00376         foreach t [list starttab tags tag:start:$node] {
00377         $path.text tag add $t tab:start:$node
00378         }
00379 
00380         set data(insert) [lindex [$path.text tag ranges tag:start:$node] end]
00381 
00382         # Serialize the content
00383         $path.text mark set content:$node $data(insert)
00384         $path.text mark gravity content:$node left
00385         foreach childToken [::dom::node children $node] {
00386         set end [_refresh $path $childToken]
00387         set data(insert) $end
00388         }
00389         $path.text tag add content:$node content:$node $end
00390 
00391         # Serialize the end tag
00392         $path.text insert $data(insert) </[::dom::node cget $node -nodeName]> [list tags tag:end:$node]
00393         set end [lindex [$path.text tag ranges tag:end:$node] end]
00394         # Add the end tab icon
00395         $path.text image create $end -image ::domtext::endtab -align center -name tab:end:$node
00396         foreach t [list endtab tags tag:end:$node] {
00397         $path.text tag add $t tab:end:$node
00398         }
00399         set end [lindex [$path.text tag ranges tag:end:$node] end]
00400 
00401         set data(insert) $end
00402         $path.text tag add $node $node $end
00403 
00404         $path.text tag raise starttab
00405         $path.text tag raise endtab
00406         $path.text tag configure starttab -elide [expr {[Widget::cget $path -showtag] != "tab"}]
00407         $path.text tag configure endtab -elide [expr {[Widget::cget $path -showtag] != "tab"}]
00408 
00409     }
00410 
00411     textNode {
00412         set text [_encode [dom::node cget $node -nodeValue]]
00413         if {[string length $text]} {
00414         $path.text insert $data(insert) $text $node
00415         set end [lindex [$path.text tag ranges $node] 1]
00416         set data(insert) $end
00417         } else {
00418         set end $data(insert)
00419         }
00420     }
00421 
00422     docType {
00423         array set nodeInfo [set $node]
00424         $path.text insert $data(insert) "<!DOCTYPE $nodeInfo(doctype:name)" [list $node doctypedecl]
00425         set data(insert) [lindex [$path.text tag ranges $node] end]
00426 
00427         if {[string length $nodeInfo(doctype:internaldtd)]} {
00428         $path.text insert $data(insert) " \[$nodeInfo(doctype:internaldtd)\]" [list $node doctypedecl]
00429         set data(insert) [lindex [$path.text tag ranges $node] end]
00430         }
00431 
00432         $path.text insert $data(insert) >\n [list $node doctypedecl]
00433         set end [lindex [$path.text tag ranges $node] end]
00434         set data(insert) $end
00435         $path.text tag configure doctypedecl -elide [expr ![Widget::cget $path -showdoctypedecl]]
00436         $path.text tag raise doctypedecl
00437     }
00438 
00439     comment {
00440         set text [::dom::node cget $node -nodeValue]
00441         $path.text insert $data(insert) <!-- [list comment markup $node] $text [list comment $node] --> [list comment markup $node]
00442         set end [lindex [$path.text tag ranges $node] 1]
00443         set data(insert) $end
00444     }
00445 
00446     entityReference {
00447         set text [::dom::node cget $node -nodeName]
00448         $path.text insert $data(insert) & [list entityreference markup $node] $text [list entityreference $node] \; [list entityreference markup $node]
00449         set end [lindex [$path.text tag ranges $node] 1]
00450         set data(insert) $end
00451     }
00452 
00453     processingInstruction {
00454         set text [::dom::node cget $node -nodeValue]
00455         if {[string length $text]} {
00456         set text " $text"
00457         }
00458         $path.text insert $data(insert) "<?[::dom::node cget $node -nodeName]$text?>" $node
00459         set end [lindex [$path.text tag ranges $node] 1]
00460         set data(insert) $end
00461     }
00462 
00463     default {
00464         # Ignore it
00465     }
00466 
00467     }
00468 
00469     return $end
00470 }
00471 
00472 /*  domtext::_serialize:attributeList --*/
00473 /* */
00474 /*  Produce textual representation of an attribute list.*/
00475 /* */
00476 /*  NB. This is copied from TclDOM's domimpl.tcl,*/
00477 /*  but with the namespace handling removed.*/
00478 /* */
00479 /*  Arguments:*/
00480 /*  atlist  name/value list of attributes*/
00481 /* */
00482 /*  Results:*/
00483 /*  Returns string*/
00484 
00485 ret  domtext::_serialize:attributeList atlist (
00486 
00487     type set , type result , optional 
00488     , type foreach , optional name =value $, type atlist , optional 
00489 
00490     append =result {  $, type name =
00491 
00492     # , type Handle , type special , type characters
00493     , type regsub -, type all & $, type value , optional \&amp; , type value
00494     , type regsub -, type all < $, type value , optional \&lt; , type value
00495 
00496     , type if , optional ![string =match *\"* =$value] , optional 
00497         append =result \"$value\"
00498      , type elseif , optional ![string =match *'* =$value] , optional 
00499         append =result '$value'
00500      , type else , optional 
00501         regsub =-all \" =$value {\&quot; , type value
00502         , type append , type result \"$, type value\"
00503     )
00504 
00505     }
00506 
00507     return $result
00508 }
00509 
00510 # domtext::_encode --
00511 #
00512 #   Protect XML special characters
00513 #
00514 #   NB. This is copied from TclDOM's domimpl.tcl.
00515 #
00516 # Arguments:
00517 #   value   text
00518 #
00519 # Results:
00520 #   Returns string
00521 
00522 proc domtext::_encode value {
00523     array set Entity {
00524     $ $
00525     < &lt;
00526     > &gt;
00527     & &amp;
00528     \" &quot;
00529     ' &apos;
00530     }
00531 
00532     regsub -all {([$<>&"'])} $value {$Entity(\1)} value
00533 
00534     return [subst -nocommand -nobackslash $value]
00535 }
00536 
00537 # domtext::_elementbg_setall --
00538 #
00539 #   Recurse node hierarchy setting element background color property
00540 #
00541 # Arguments:
00542 #   path    widget path
00543 #   node    DOM node
00544 #
00545 # Results:
00546 #   Text widget tag configured
00547 
00548 proc domtext::_elementbg_setall {path node} {
00549 
00550     $path.text tag configure $node -background [_elementbg_cycle $path]
00551 
00552     switch [dom::node cget $node -nodeType] {
00553     document -
00554     documentFragment -
00555     element {
00556         foreach child [dom::node children $node] {
00557         _elementbg_setall $path $child
00558         }
00559     }
00560     default {
00561         /*  No more to do here*/
00562     }
00563     }
00564 
00565     return {}
00566 }
00567 ret  domtext::_elementbg_cycle path (
00568     type upvar #0 [, type namespace , type current]::$, type path , type data
00569 
00570     , type set , type list [, type Widget::, type cget $, type path -, type elementbgcolorlist]
00571     , type set , type colour [, type lindex $, type list $, type data(, type nextElemBgColor)]
00572 
00573     , type set , type data(, type nextElemBgColor) [, type expr [, type incr , type data(, type nextElemBgColor)] % [, type llength $$, type list]]
00574 
00575     , type return $, type colour
00576 )
00577 
00578 # domtext::_node_inserted --
00579 #
00580 #   React to addition of a node
00581 #
00582 # Arguments:
00583 #   path    widget path
00584 #   evid    DOM event node
00585 #
00586 # Results:
00587 #   Display updated to reflect change to DOM structure
00588 
00589 proc domtext::_node_inserted {path evid} {
00590     upvar /* 0 [namespace current]::$path data*/
00591 
00592      node =  [dom::event cget $evid -target]
00593 
00594     /*  Remove parent's content and then render new content*/
00595      parent =  [dom::node parent $node]
00596      tags =  [$path.text tag ranges $parent]
00597      start =  [lindex $tags 0]
00598      end =  [lindex $tags end]
00599     if {[string length $start]} {
00600     $path.text delete $start $end
00601     } else {
00602      start =  end
00603     }
00604 
00605      data = (insert) $start
00606      end =  [_refresh $path $parent]
00607 
00608     /*  Restore grandparent element tags*/
00609      parent =  [::dom::node parent $parent]
00610     while {[string length $parent]} {
00611      ranges =  [$path.text tag ranges $parent]
00612     catch {eval [list $path.text] tag remove [list $parent] $ranges}
00613     catch {$path.text tag add $parent [lindex $ranges 0] [lindex $ranges end]}
00614     /*  Also do content tag for elements*/
00615     if {![string compare [::dom::node cget $parent -nodeType] "element"]} {
00616          ranges =  [$path.text tag ranges content:$parent]
00617         catch {eval [list $path.text] tag remove [list $parent] $ranges}
00618         catch {$path.text tag add content:$parent [lindex $ranges 0] [lindex $ranges end]}
00619     }
00620 
00621      parent =  [::dom::node parent $parent]
00622     }
00623 
00624     return {}
00625 }
00626 
00627 /*  domtext::_node_removed --*/
00628 /* */
00629 /*  React to removal of a node.*/
00630 /*  This is almost identical to node insertion,*/
00631 /*  except that we must get the parent from the event.*/
00632 /* */
00633 /*  Arguments:*/
00634 /*  path    widget path*/
00635 /*  evid    DOM event node*/
00636 /* */
00637 /*  Results:*/
00638 /*  Display updated to reflect change to DOM structure*/
00639 
00640 ret  domtext::_node_removed (type path , type evid) {
00641     upvar #0 [namespace current]::selected$path selected
00642 
00643     set node [dom::event cget $evid -target]
00644 
00645     if {[info exists selected] && ![string compare $node $selected]} {
00646     unset selected
00647     }
00648 
00649     # Remove parent's content and then render new content
00650     set parent [dom::event cget $evid -relatedNode]
00651     set tags [$path.text tag ranges $parent]
00652     set start [lindex $tags 0]
00653     set end [lindex $tags end]
00654     if {[string length $start]} {
00655     $path.text delete $start $end
00656     } else {
00657     set start end
00658     }
00659 
00660     set data(insert) $start
00661     set end [_refresh $path $parent]
00662 
00663     # Restore grandparent element tags
00664     set parent [::dom::node parent $parent]
00665     while {[string length $parent]} {
00666     set ranges [$path.text tag ranges $parent]
00667     catch {eval [list $path.text] tag remove [list $parent] $ranges}
00668     catch {$path.text tag add $parent [lindex $ranges 0] [lindex $ranges end]}
00669     # Also do content tag for elements
00670     if {![string compare [::dom::node cget $parent -nodeType] "element"]} {
00671         set ranges [$path.text tag ranges content:$parent]
00672         catch {eval [list $path.text] tag remove [list $parent] $ranges}
00673         catch {$path.text tag add content:$parent [lindex $ranges 0] [lindex $ranges end]}
00674     }
00675 
00676     set parent [::dom::node parent $parent]
00677     }
00678 
00679     return {}
00680 }
00681 
00682 /*  domtext::_node_attr_modified --*/
00683 /* */
00684 /*  React to a change in the attribute list for a node*/
00685 /* */
00686 /*  Arguments:*/
00687 /*  path    widget path*/
00688 /*  evid    DOM event node*/
00689 /* */
00690 /*  Results:*/
00691 /*  Display updated to reflect change to DOM structure*/
00692 
00693 ret  domtext::_node_attr_modified (type path , type evid) {
00694 
00695     set node [dom::event cget $evid -target]
00696 
00697     set tags [$path.text tag ranges attrs:$node]
00698     if {[llength $tags]} {
00699 
00700     # Remove previously defined attributes
00701 
00702     foreach {start end} $tags break
00703     set existingTags [$path.text tag names $start]
00704     $path.text delete $start $end
00705     $path.text tag delete attrs:$node
00706 
00707     } else {
00708     set tagStartEnd [lindex [$path.text tag ranges tag:start:$node] end]
00709     set start [$path.text index "$tagStartEnd - 1 char"]
00710     set existingTags [$path.text tag names $start]
00711     }
00712 
00713     # Replace with current attributes
00714 
00715     lappend existingTags attrs:$node
00716     $path.text insert $start [::dom::Serialize:attributeList [array get [::dom::node cget $node -attributes]]] $existingTags
00717 
00718     return {}
00719 }
00720 
00721 /*  domtext::_node_attr_removed --*/
00722 /* */
00723 /*  React to a change in the attribute list for a node*/
00724 /* */
00725 /*  Arguments:*/
00726 /*  path    widget path*/
00727 /*  evid    DOM event node*/
00728 /* */
00729 /*  Results:*/
00730 /*  Display updated to reflect change to DOM structure*/
00731 
00732 ret  domtext::_node_attr_removed (type path , type evid) {
00733     _node_attr_modified $path $evid
00734 }
00735 
00736 /*  domtext::_node_pcdata_modified --*/
00737 /* */
00738 /*  React to a change in character data*/
00739 /* */
00740 /*  Arguments:*/
00741 /*  path    widget path*/
00742 /*  evid    DOM event node*/
00743 /* */
00744 /*  Results:*/
00745 /*  Display updated to reflect change to DOM structure*/
00746 
00747 ret  domtext::_node_pcdata_modified (type path , type evid) {
00748 
00749     set node [dom::event cget $evid -target]
00750 
00751     if {[string compare [dom::node cget $node -nodeType] "textNode"]} {
00752     return -code error "node is not a text node"
00753     }
00754 
00755     # Remember where the insertion point is
00756     set insert [$path.text index insert]
00757 
00758     # Remove previous text
00759     set ranges [$path.text tag ranges $node]
00760     set tags [$path.text tag names [lindex $ranges 0]]
00761     eval [list $path.text] delete $ranges
00762 
00763     # Replace with new text
00764     $path.text insert [lindex $ranges 0] [dom::event cget $evid -newValue] $tags
00765 
00766     # Restore insertion point
00767     $path.text mark set insert $insert
00768 
00769     return {}
00770 }
00771 
00772 /*  domtext::_node_selected --*/
00773 /* */
00774 /*  A node has been selected.*/
00775 /* */
00776 /*  Arguments:*/
00777 /*  path    widget path*/
00778 /*  evid    DOM event node*/
00779 /* */
00780 /*  Results:*/
00781 /*  Node's text is selected*/
00782 
00783 ret  domtext::_node_selected (type path , type evid) {
00784     upvar #0 [namespace current]::selected$path selected
00785 
00786     set node [dom::event cget $evid -target]
00787     set selected $node
00788 
00789     catch {eval [list $path.text] tag remove sel [$path.text tag ranges sel]}
00790 
00791     set ranges [$path.text tag ranges $node]
00792     if {[llength $ranges]} {
00793     eval [list $path.text] tag add sel $ranges
00794     }
00795 
00796     $path.text mark set insert [lindex $ranges end]
00797 
00798     return {}
00799 }
00800 
00801 /*  domtext::_tkevent_override --*/
00802 /* */
00803 /*  Certain Text widget class bindings must be prevented from firing*/
00804 /* */
00805 /*  Arguments:*/
00806 /*  path    widget path*/
00807 /*  x   x coord*/
00808 /*  y   y coord*/
00809 /* */
00810 /*  Results:*/
00811 /*  Return break error code*/
00812 
00813 ret  domtext::_tkevent_override (type w , type x , type y) {
00814     return -code break
00815 }
00816 
00817 /*  domtext::_tkevent_select --*/
00818 /* */
00819 /*  Single click.  We only want the highest priority tag to fire.*/
00820 /* */
00821 /*  Arguments:*/
00822 /*  path    widget path*/
00823 /*  node    DOM node*/
00824 /*  x*/
00825 /*  y   Coordinates*/
00826 /* */
00827 /*  Results:*/
00828 /*  DOM event posted*/
00829 
00830 ret  domtext::_tkevent_select (type path , type node , type x , type y) {
00831     variable tkeventid
00832 
00833     catch {after cancel $tkeventid}
00834     set tkeventid [after idle "
00835     dom::event postUIEvent [list $node] DOMActivate -detail 1
00836     dom::event postMouseEvent [list $node] click -detail 1
00837     [namespace current]::_tkevent_select_setinsert [list $path] [list $node] [::tk::TextClosestGap $path.text $x $y]
00838 "]
00839     return {}
00840 }
00841 
00842 /*  Helper routine for above proc*/
00843 
00844 ret  domtext::_tkevent_select_setinsert (type path , type node , type idx) {
00845     switch [::dom::node cget $node -nodeType] {
00846     textNode {
00847         # No need to change where the insertion point is going
00848     }
00849     element {
00850         # Set the insertion point to the end of the first
00851         # child textNode, or if none to immediately following
00852         # the start tag.
00853         set fc [::dom::node cget $node -firstChild]
00854         if {[string length $fc] && [::dom::node cget $fc -nodeType] == "textNode"} {
00855         set idx [lindex [$path.text tag ranges $fc] end]
00856         } else {
00857         set idx [lindex [$path.text tag ranges tag:start:$node] end]
00858         }
00859     }
00860     default {
00861         # Set the insertion point following the node
00862         set idx [lindex [$path.text tag ranges $node] end]
00863     }
00864     }
00865 
00866     $path.text mark set insert $idx
00867     $path.text mark set anchor insert
00868     focus $path.text
00869 
00870     return {}
00871 }
00872 
00873 /*  domtext::_tkevent_open --*/
00874 /* */
00875 /*  Double click*/
00876 /* */
00877 /*  Arguments:*/
00878 /*  path    widget path*/
00879 /*  node    DOM node*/
00880 /* */
00881 /*  Results:*/
00882 /*  DOM event posted*/
00883 
00884 ret  domtext::_tkevent_open (type path , type node) {
00885     variable tkeventid
00886 
00887     catch {after cancel $tkeventid}
00888     set tkeventid [after idle "
00889     dom::event postUIEvent [list $node] DOMActivate -detail 2
00890     dom::event postMouseEvent [list $node] click -detail 2
00891 "]
00892     return {}
00893 }
00894 
00895 /*  domtext::_key_select --*/
00896 /* */
00897 /*  Select a node in which a key event has occurred.*/
00898 /* */
00899 /*  Arguments:*/
00900 /*  path    widget path*/
00901 /*  spec    the event specifier*/
00902 /* */
00903 /*  Results:*/
00904 /*  Appropriate node is selected.  Returns node id.*/
00905 
00906 ret  domtext::_key_select (type path , type spec) {
00907     # Once the Text widget gets the focus, it receives the event.
00908     # We compensate for this here
00909     if {[winfo class $path] == "Text"} {
00910     set path [winfo parent $path]
00911     }
00912     upvar #0 [namespace current]::selected$path selected
00913 
00914     set root [Widget::cget $path -rootnode]
00915 
00916     # If selected node is a textNode move around the text itself
00917     # Otherwise markup has been selected.
00918     # Move around the nodes
00919 
00920     switch -glob [dom::node cget $selected -nodeType],$spec {
00921     textNode,<Key-Up> {
00922         set ranges [$path.text tag ranges $selected]
00923         foreach {line char} [split [lindex $ranges 0] .] break
00924         set index [$path.text index insert]
00925         foreach {iline ichar} [split [lindex $index 0] .] break
00926         if {$line == $iline} {
00927         set new [dom::node parent $selected]
00928         } else {
00929         ::tk::TextSetCursor $path.text [::tk::TextUpDownLine $path.text -1]
00930         # The insertion point may now be in another node
00931         set newnode [_insert_to_node $path]
00932         if {[string compare $newnode $selected]} {
00933             dom::event postUIEvent $newnode DOMActivate -detail 1
00934         }
00935         return -code break
00936         }
00937     }
00938     textNode,<Key-Down> {
00939         set ranges [$path.text tag ranges $selected]
00940         foreach {line char} [split [lindex $ranges end] .] break
00941         set index [$path.text index insert]
00942         foreach {iline ichar} [split [lindex $index 0] .] break
00943         if {$line == $iline} {
00944         bell
00945         return {}
00946         } else {
00947         ::tk::TextSetCursor $path.text [::tk::TextUpDownLine $path.text 1]
00948         # The insertion point may now be in another node
00949         set newnode [_insert_to_node $path]
00950         if {[string compare $newnode $selected]} {
00951             dom::event postUIEvent $newnode DOMActivate -detail 1
00952         }
00953         return -code break
00954         }
00955     }
00956     textNode,<Key-Left> {
00957         set ranges [$path.text tag ranges $selected]
00958         set index [$path.text index insert]
00959         if {[$path.text compare $index == [lindex $ranges 0]]} {
00960         set new [dom::node cget $selected -previousSibling]
00961         if {![string length $new]} {
00962             set new [dom::node parent $selected]
00963         }
00964         } else {
00965         ::tk::TextSetCursor $path.text insert-1c
00966         return -code break
00967         }
00968     }
00969     textNode,<Key-Right> {
00970         set ranges [$path.text tag ranges $selected]
00971         set index [$path.text index insert]
00972         if {[$path.text compare $index == [lindex $ranges end]]} {
00973         set new [dom::node cget $selected -nextSibling]
00974         if {![string length $new]} {
00975             set new [dom::node parent $selected]
00976         }
00977         } else {
00978         ::tk::TextSetCursor $path.text insert+1c
00979         return -code break
00980         }
00981     }
00982 
00983     *,<Key-Up>  {
00984         set new [dom::node parent $selected]
00985     }
00986     *,<Key-Down>    {
00987         set new [dom::node cget $selected -firstChild]
00988         if {![string length $new]} {
00989         bell
00990         return {}
00991         }
00992     }
00993     *,<Key-Left>    {
00994         if {[dom::node parent $selected] == $root} {
00995         bell
00996         return {}
00997         }
00998         set new [dom::node cget $selected -previousSibling]
00999         if {![string length $new]} {
01000         set new [dom::node parent $selected]
01001         }
01002     }
01003     *,<Key-Right>   {
01004         set new [dom::node cget $selected -nextSibling]
01005         if {![string length $new]} {
01006         set new [dom::node parent $selected]
01007         }
01008     }
01009     }
01010     if {![string length $new]} {
01011     bell
01012     }
01013 
01014     dom::event postUIEvent $new DOMActivate -detail 1
01015 
01016     return -code break
01017 }
01018 
01019 /*  domtext::_tkevent_filter_* --*/
01020 /* */
01021 /*  React to editing events to keep the DOM structure*/
01022 /*  synchronised*/
01023 /* */
01024 /*  Arguments:*/
01025 /*  path    widget path*/
01026 /*  detail  key pressed*/
01027 /* */
01028 /*  Results:*/
01029 /*  Either event is blocked or passed through to the Text class binding*/
01030 /*  DOM events may be generated if text is inserted or deleted*/
01031 
01032 ret  domtext::_tkevent_filter_<Key> (type path , type detail) {
01033     # Once the Text widget gets the focus, it receives the event.
01034     # We compensate for this here
01035     set code ok
01036     if {[winfo class $path] == "Text"} {
01037     set path [winfo parent $path]
01038     set code break
01039     }
01040     upvar #0 [namespace current]::selected$path selected
01041 
01042     set index [$path.text index insert]
01043 
01044     $path.text tag remove sel 0.0 end
01045 
01046     # Take action depending upon which node type the event has occurred.
01047     # Possibilities are:
01048     #   text node           insert the text, update node
01049     #   element             If a text node exists as first child,
01050     #                   redirect event to it and make it active.
01051     #                   Otherwise create a text node
01052     #   Document Type Declaration   ignore
01053     #   XML Declaration         ignore
01054 
01055     switch [dom::node cget $selected -nodeType] {
01056     element {
01057         set child [dom::node cget $selected -firstChild]
01058         if {[string length $child]} {
01059         if {[dom::node cget $child -nodeType] == "textNode"} {
01060             dom::event postUIEvent $child DOMActivate -detail 1
01061             dom::node configure $child -nodeValue [dom::node cget $child -nodeValue]$detail
01062             ::tk::TextSetCursor $path.text insert+1c
01063             focus $path.text
01064             return -code $code {}
01065         } else {
01066             bell
01067             return -code $code {}
01068         }
01069         } else {
01070         set child [dom::document createTextNode $selected $detail]
01071         dom::event postUIEvent $child DOMActivate -detail 1
01072         # When we return the new text node will have been
01073         # inserted into the Text widget
01074         set end [lindex [$path.text tag ranges $child] 1]
01075         $path.text mark set insert $end
01076         $path.text tag remove sel 0.0 end
01077         focus $path.text
01078         return -code $code {}
01079         }
01080     }
01081     textNode {
01082 
01083         # We need to know where in the character data to insert the
01084         # character.  This is hard, so instead allow the Text widget
01085         # to do the insertion then take all of the text and
01086         # set that as the node's value
01087 
01088         $path.text insert insert $detail $selected
01089         $path.text see insert
01090         focus $path.text
01091         set ranges [$path.text tag ranges $selected]
01092         set newvalue [$path.text get [lindex $ranges 0] [lindex $ranges end]]
01093         dom::node configure $selected -nodeValue $newvalue
01094         return -code $code {}
01095 
01096     }
01097     default {
01098         bell
01099         return -code $code {}
01100     }
01101     }
01102 
01103     return -code $code {}
01104 }
01105 
01106 ret  domtext::_tkevent_filter_<Key-Return> (type path , type detail) {
01107     set code [catch {_tkevent_filter_<Key> $path \n} msg]
01108     return -code $code $msg
01109 }
01110 ret  domtext::_tkevent_filter_<Control-Key-i> (type path , type detail) {
01111     set code [catch {_tkevent_filter_<Key> $path \t} msg]
01112     return -code $code $msg
01113 }
01114 /*  Don't support transposition (yet)*/
01115 ret  domtext::_tkevent_filter_<Control-Key-t> (type path , type detail) {
01116     return -code break
01117 }
01118 
01119 ret  domtext::_tkevent_filter_<Control-Key-h> (type path , type detail) {
01120     set code [catch {_tkevent_filter_<Key-Backspace> $path $detail} msg]
01121     return -code $code $msg
01122 }
01123 ret  domtext::_tkevent_filter_<Key-BackSpace> (type path , type detail) {
01124     # Once the Text widget gets the focus, it receives the event.
01125     # We compensate for this here
01126     if {[winfo class $path] == "Text"} {
01127     set path [winfo parent $path]
01128     }
01129     upvar #0 [namespace current]::selected$path selected
01130 
01131     switch [dom::node cget $selected -nodeType] {
01132     textNode {
01133         # If we're at the beginning of the text node stop here
01134         set ranges [$path.text tag ranges $selected]
01135         if {![llength $ranges] || [$path.text compare insert <= [lindex $ranges 0]]} {
01136         bell
01137         return -code break
01138         }
01139     }
01140     default {
01141         switch [tk_messageBox -parent [winfo toplevel $path] -title [mc {Confirm Delete Node}] -message [format [mc {Are you sure you want to delete a node of type %s?}] [dom::node cget $selected -nodeType]] -type okcancel] {
01142         ok {
01143             dom::node removeNode [dom::node parent $selected] $selected
01144         }
01145         cancel {
01146             return -code break
01147         }
01148         }
01149     }
01150     }
01151 
01152     $path.text delete insert-1c
01153     $path.text see insert
01154 
01155     _tkevent_filter_update $path
01156 
01157     return -code break
01158 }
01159 ret  domtext::_tkevent_filter_<Key-Delete> (type path , type detail) {
01160     # Once the Text widget gets the focus, it receives the event.
01161     # We compensate for this here
01162     if {[winfo class $path] == "Text"} {
01163     set path [winfo parent $path]
01164     }
01165     upvar #0 [namespace current]::selected$path selected
01166 
01167     switch [dom::node cget $selected -nodeType] {
01168     textNode {
01169         # If we're at the beginning of the text node stop here
01170         set ranges [$path.text tag ranges $selected]
01171         if {[$path.text compare insert >= [lindex $ranges end]]} {
01172         bell
01173         return -code break
01174         }
01175     }
01176     default {
01177         switch [tk_messageBox -parent [winfo toplevel $path] -title [mc {Confirm Delete Node}] -message [format [mc {Are you sure you want to delete a node of type %s?}] [dom::node cget $selected -nodeType]] -type okcancel] {
01178         ok {
01179             dom::node removeNode [dom::node parent $selected] $selected
01180         }
01181         cancel {
01182             return -code break
01183         }
01184         }
01185     }
01186     }
01187 
01188     $path.text delete insert
01189     $path.text see insert
01190 
01191     _tkevent_filter_update $path
01192 
01193     return -code break
01194 }
01195 ret  domtext::_tkevent_filter_update path (
01196     type upvar #0 [, type namespace , type current]::, type selected$, type path , type selected
01197 
01198     # , type Now , type update , type the , type DOM , type node', type s , type value
01199 
01200     , type set , type ranges [$, type path., type text , type tag , type ranges $, type selected]
01201 
01202     # , type If , type all , type text , type has , type been , type deleted , type then , type remove , type the , type node
01203     , type if , optional [llength =$ranges] , optional 
01204     set =newtext [$path.text =get [lindex =$ranges 0] =[lindex $ranges =end]]
01205     dom::node =configure $selected =-nodeValue $newtext
01206      , type else , optional 
01207     set =parent [dom::node =parent $selected]
01208     =dom::node removeNode =[dom::node parent =$selected] $selected
01209     =# Move =selection to =parent element, =rather than =removing selection
01210     =#unset selected
01211     =dom::event postUIEvent =$parent DOMActivate =-detail 1
01212     
01213 
01214     , type return , optional 
01215 )
01216 
01217 # This will delete from the insertion point to the end of the line
01218 # or text node, whichever is shorter
01219 # TODO: implement this
01220 proc domtext::_tkevent_filter_<Control-Key-k> {path detail} {
01221     return -code break
01222 }
01223 /*  TODO: this will delete the word to the left of the insertion point*/
01224 /*  (only within the text node)*/
01225 ret  domtext::_tkevent_filter_<Meta-Key-Delete> (type path , type detail) {
01226     return -code break
01227 }
01228 ret  domtext::_tkevent_filter_<Meta-Key-BackSpace> (type path , type detail) {
01229     _tkevent_filter_<Meta-Key-Delete> $path $detail
01230 }
01231 
01232 /*  Utilities*/
01233 
01234 /*  domtext::_insert_to_node --*/
01235 /* */
01236 /*  Finds the DOM node for the insertion point*/
01237 /* */
01238 /*  Arguments:*/
01239 /*  path    widget path*/
01240 /* */
01241 /*  Results:*/
01242 /*  Returns DOM token*/
01243 
01244 ret  domtext::_insert_to_node path (
01245     type set , type tags [$, type path., type text , type tag , type names , type insert]
01246     , type set , type newnode [, type lindex $, type tags , type end]
01247     , type while , optional ![dom::DOMImplementation =isNode $newnode] , optional 
01248     set =tags [lreplace =$tags end =end]
01249     set =newnode [lindex =$tags end]
01250     
01251     , type return $, type newnode
01252 )
01253 
01254 ### Inlined images
01255 
01256 image create photo ::domtext::starttab -data {
01257 R0lGODlhEAAYAPcAAP//////zP//mf//Zv//M///AP/M///MzP/Mmf/MZv/M
01258 M//MAP+Z//+ZzP+Zmf+ZZv+ZM/+ZAP9m//9mzP9mmf9mZv9mM/9mAP8z//8z
01259 zP8zmf8zZv8zM/8zAP8A//8AzP8Amf8AZv8AM/8AAMz//8z/zMz/mcz/Zsz/
01260 M8z/AMzM/8zMzMzMmczMZszMM8zMAMyZ/8yZzMyZmcyZZsyZM8yZAMxm/8xm
01261 zMxmmcxmZsxmM8xmAMwz/8wzzMwzmcwzZswzM8wzAMwA/8wAzMwAmcwAZswA
01262 M8wAAJn//5n/zJn/mZn/Zpn/M5n/AJnM/5nMzJnMmZnMZpnMM5nMAJmZ/5mZ
01263 zJmZmZmZZpmZM5mZAJlm/5lmzJlmmZlmZplmM5lmAJkz/5kzzJkzmZkzZpkz
01264 M5kzAJkA/5kAzJkAmZkAZpkAM5kAAGb//2b/zGb/mWb/Zmb/M2b/AGbM/2bM
01265 zGbMmWbMZmbMM2bMAGaZ/2aZzGaZmWaZZmaZM2aZAGZm/2ZmzGZmmWZmZmZm
01266 M2ZmAGYz/2YzzGYzmWYzZmYzM2YzAGYA/2YAzGYAmWYAZmYAM2YAADP//zP/
01267 zDP/mTP/ZjP/MzP/ADPM/zPMzDPMmTPMZjPMMzPMADOZ/zOZzDOZmTOZZjOZ
01268 MzOZADNm/zNmzDNmmTNmZjNmMzNmADMz/zMzzDMzmTMzZjMzMzMzADMA/zMA
01269 zDMAmTMAZjMAMzMAAAD//wD/zAD/mQD/ZgD/MwD/AADM/wDMzADMmQDMZgDM
01270 MwDMAACZ/wCZzACZmQCZZgCZMwCZAABm/wBmzABmmQBmZgBmMwBmAAAz/wAz
01271 zAAzmQAzZgAzMwAzAAAA/wAAzAAAmQAAZgAAM+4AAN0AALsAAKoAAIgAAHcA
01272 AFUAAEQAACIAABEAAADuAADdAAC7AACqAACIAAB3AABVAABEAAAiAAARAAAA
01273 7gAA3QAAuwAAqgAAiAAAdwAAVQAARAAAIgAAEe7u7t3d3bu7u6qqqoiIiHd3
01274 d1VVVURERCIiIhEREQAAACwAAAAAEAAYAAcIgwABCBxIsKBAfAjx2TNYMCHC
01275 hQwPOrwHkaFDhRQjXtR3L6PBix3teSR4USRHexUlJuTY8WRFkBQ7dsQ3sOS9
01276 kzNrOmR5M6dKhCFl3qP5EyPOoTpXymRJFABMkTKb2sSZL19ShDz1WSU5MeZW
01277 rglNfgWL9d5YsvjMRgRQte3ZtXABAggIADs=
01278 }
01279 image create photo ::domtext::endtab -data {
01280 R0lGODlhEAAYAPcAAP//////zP//mf//Zv//M///AP/M///MzP/Mmf/MZv/M
01281 M//MAP+Z//+ZzP+Zmf+ZZv+ZM/+ZAP9m//9mzP9mmf9mZv9mM/9mAP8z//8z
01282 zP8zmf8zZv8zM/8zAP8A//8AzP8Amf8AZv8AM/8AAMz//8z/zMz/mcz/Zsz/
01283 M8z/AMzM/8zMzMzMmczMZszMM8zMAMyZ/8yZzMyZmcyZZsyZM8yZAMxm/8xm
01284 zMxmmcxmZsxmM8xmAMwz/8wzzMwzmcwzZswzM8wzAMwA/8wAzMwAmcwAZswA
01285 M8wAAJn//5n/zJn/mZn/Zpn/M5n/AJnM/5nMzJnMmZnMZpnMM5nMAJmZ/5mZ
01286 zJmZmZmZZpmZM5mZAJlm/5lmzJlmmZlmZplmM5lmAJkz/5kzzJkzmZkzZpkz
01287 M5kzAJkA/5kAzJkAmZkAZpkAM5kAAGb//2b/zGb/mWb/Zmb/M2b/AGbM/2bM
01288 zGbMmWbMZmbMM2bMAGaZ/2aZzGaZmWaZZmaZM2aZAGZm/2ZmzGZmmWZmZmZm
01289 M2ZmAGYz/2YzzGYzmWYzZmYzM2YzAGYA/2YAzGYAmWYAZmYAM2YAADP//zP/
01290 zDP/mTP/ZjP/MzP/ADPM/zPMzDPMmTPMZjPMMzPMADOZ/zOZzDOZmTOZZjOZ
01291 MzOZADNm/zNmzDNmmTNmZjNmMzNmADMz/zMzzDMzmTMzZjMzMzMzADMA/zMA
01292 zDMAmTMAZjMAMzMAAAD//wD/zAD/mQD/ZgD/MwD/AADM/wDMzADMmQDMZgDM
01293 MwDMAACZ/wCZzACZmQCZZgCZMwCZAABm/wBmzABmmQBmZgBmMwBmAAAz/wAz
01294 zAAzmQAzZgAzMwAzAAAA/wAAzAAAmQAAZgAAM+4AAN0AALsAAKoAAIgAAHcA
01295 AFUAAEQAACIAABEAAADuAADdAAC7AACqAACIAAB3AABVAABEAAAiAAARAAAA
01296 7gAA3QAAuwAAqgAAiAAAdwAAVQAARAAAIgAAEe7u7t3d3bu7u6qqqoiIiHd3
01297 d1VVVURERCIiIhEREQAAACwAAAAAEAAYAAcIgwABCBxIsKDBgvbwKcR3cGDC
01298 hQwb2rsHMaLBiQ8XHpx4T1/Fi/c4fiRob6K+kCMBlOx4r6VHiAPxtWwpEqZA
01299 mSFZZlQY0+XMlxpvzsxJ0SYAnCZRGsV50mVKnDRbpsyXL+fJnRYF5mvaMeXA
01300 qjWDFtyqVOzYrkYNVvWqlqrbhg0BAggIADs=
01301 }
01302 
01303 

Generated on 21 Sep 2010 for Gui by  doxygen 1.6.1