1# Copyright (c) 2002-2011 Tim Baker 2 3# 4# Demo: Outlook Express newsgroup messages 5# 6namespace eval DemoOutlookNewsgroup {} 7proc DemoOutlookNewsgroup::Init {T} { 8 9 variable Priv 10 11 InitPics outlook-* 12 13 set height [font metrics [$T cget -font] -linespace] 14 if {$height < 18} { 15 set height 18 16 } 17 18 # 19 # Configure the treectrl widget 20 # 21 22 $T configure -itemheight $height -selectmode browse \ 23 -showroot no -showrootbutton no -showbuttons yes -showlines no \ 24 -xscrollincrement 20 -xscrollsmoothing yes 25 26 switch -- [$T theme platform] { 27 visualstyles { 28 $T theme setwindowtheme "Explorer" 29 } 30 } 31 32 # 33 # Create columns 34 # 35 36 $T column create -image outlook-clip -tags clip 37 $T column create -image outlook-arrow -tags arrow 38 $T column create -image outlook-watch -tags watch 39 $T column create -text Subject -width 250 -tags subject 40 $T column create -text From -width 150 -tags from 41 $T column create -text Sent -width 150 -tags sent 42 $T column create -text Size -width 60 -justify right -tags size 43 44# $T column configure all -gridrightcolor #ebf4fe 45 46 # Would be nice if I could specify a column -tag too 47 # *blink* The amazing code Genie makes it so!!! 48 $T configure -treecolumn subject 49 50 # State for a read message 51 $T item state define read 52 53 # State for a message with unread descendants 54 $T item state define unread 55 56 # States for "open" rectangles. This is an ugly hack to get the 57 # active outline to span multiple columns. 58 $T item state define openWE 59 $T item state define openE 60 $T item state define openW 61 62 # 63 # Create elements 64 # 65 66 $T element create elemImg image -image { 67 outlook-read-2Sel {selected read unread !open} 68 outlook-read-2 {read unread !open} 69 outlook-readSel {selected read} 70 outlook-read {read} 71 outlook-unreadSel {selected} 72 outlook-unread {} 73 } 74 75 $T element create elemTxt text -fill [list $::SystemHighlightText {selected focus}] \ 76 -font [list DemoFontBold {read unread !open} DemoFontBold {!read}] -lines 1 77 78 $T element create sel rect \ 79 -fill [list $::SystemHighlight {selected focus} gray {selected !focus}] \ 80 -open {we openWE e openE w openW} -showfocus yes 81 82 # 83 # Create styles using the elements 84 # 85 86 # Image + text 87 set S [$T style create s1] 88 $T style elements $S {sel elemImg elemTxt} 89 $T style layout $S elemImg -expand ns 90 $T style layout $S elemTxt -padx {2 6} -squeeze x -expand ns 91 $T style layout $S sel -union [list elemTxt] -iexpand nes -ipadx {2 0} 92 93 # Text 94 set S [$T style create s2] 95 $T style elements $S {sel elemTxt} 96 $T style layout $S elemTxt -padx 6 -squeeze x -expand ns 97 $T style layout $S sel -detach yes -iexpand xy 98 99 # Set default item styles 100 $T column configure subject -itemstyle s1 101 $T column configure from -itemstyle s2 102 $T column configure sent -itemstyle s2 103 $T column configure size -itemstyle s2 104 105 # 106 # Create items and assign styles 107 # 108 109 set msgCnt 100 110 111 set thread 0 112 set Priv(count,0) 0 113 set items [$T item id root] 114 for {set i 1} {$i < $msgCnt} {incr i} { 115 set itemi [$T item create] 116 while 1 { 117 set j [expr {int(rand() * $i)}] 118 set itemj [lindex $items $j] 119 if {$j == 0} break 120 if {[$T depth $itemj] == 5} continue 121 if {$Priv(count,$Priv(thread,$itemj)) == 15} continue 122 break 123 } 124 $T item lastchild $itemj $itemi 125 126 set Priv(read,$itemi) [expr rand() * 2 > 1] 127 if {$j == 0} { 128 set Priv(thread,$itemi) [incr thread] 129 set Priv(seconds,$itemi) [expr {[clock seconds] - int(rand() * 500000)}] 130 set Priv(seconds2,$itemi) $Priv(seconds,$itemi) 131 set Priv(count,$thread) 1 132 } else { 133 set Priv(thread,$itemi) $Priv(thread,$itemj) 134 set Priv(seconds,$itemi) [expr {$Priv(seconds2,$itemj) + int(rand() * 10000)}] 135 set Priv(seconds2,$itemi) $Priv(seconds,$itemi) 136 set Priv(seconds2,$itemj) $Priv(seconds,$itemi) 137 incr Priv(count,$Priv(thread,$itemj)) 138 } 139 lappend items $itemi 140 } 141 142 for {set i 1} {$i < $msgCnt} {incr i} { 143 set itemi [lindex $items $i] 144 set subject "This is thread number $Priv(thread,$itemi)" 145 set from somebody@somewhere.net 146 set sent [clock format $Priv(seconds,$itemi) -format "%d/%m/%y %I:%M %p"] 147 set size [expr {1 + int(rand() * 10)}]KB 148 149 # This message has been read 150 if {$Priv(read,$itemi)} { 151 $T item state set $itemi read 152 } 153 154 # This message has unread descendants 155 if {[AnyUnreadDescendants $T $itemi]} { 156 $T item state set $itemi unread 157 } 158 159 if {[$T item numchildren $itemi]} { 160 $T item configure $itemi -button yes 161 162 # Collapse some messages 163 if {rand() * 2 > 1} { 164 $T item collapse $itemi 165 } 166 } 167 168# $T item style set $i 3 s1 4 s2.we 5 s2.we 6 s2.w 169 $T item text $itemi subject $subject from $from sent $sent size $size 170 171 $T item state forcolumn $itemi subject openE 172 $T item state forcolumn $itemi from openWE 173 $T item state forcolumn $itemi sent openWE 174 $T item state forcolumn $itemi size openW 175 } 176 177 # Do something when the selection changes 178 $T notify bind $T <Selection> { 179 DemoOutlookNewsgroup::Selection %T 180 } 181 182 # Fix the display when a column is dragged 183 $T notify bind $T <ColumnDrag-receive> { 184 %T column move %C %b 185 DemoOutlookNewsgroup::FixItemStyles %T 186 } 187 188 # Fix the display when a column's visibility changes 189 $T notify bind $T <DemoColumnVisibility> { 190 DemoOutlookNewsgroup::FixItemStyles %T 191 } 192 193 return 194} 195 196proc DemoOutlookNewsgroup::Selection {T} { 197 variable Priv 198 # One item is selected 199 if {[$T selection count] == 1} { 200 if {[info exists Priv(afterId)]} { 201 after cancel $Priv(afterId) 202 } 203 set Priv(afterId,item) [$T selection get 0] 204 set Priv(afterId) [after 500 DemoOutlookNewsgroup::MessageReadDelayed] 205 } 206 return 207} 208 209proc DemoOutlookNewsgroup::MessageReadDelayed {} { 210 211 variable Priv 212 213 set T [DemoList] 214 215 unset Priv(afterId) 216 set I $Priv(afterId,item) 217 if {![$T selection includes $I]} return 218 219 # This message is not read 220 if {!$Priv(read,$I)} { 221 222 # Read the message 223 $T item state set $I read 224 set Priv(read,$I) 1 225 226 # Check ancestors (except root) 227 foreach I2 [lrange [$T item ancestors $I] 0 end-1] { 228 229 # This ancestor has no more unread descendants 230 if {![AnyUnreadDescendants $T $I2]} { 231 $T item state set $I2 !unread 232 } 233 } 234 } 235 return 236} 237 238# Alternate implementation that does not rely on run-time states 239proc DemoOutlookNewsgroup::Init_2 {T} { 240 241 global Message 242 243 InitPics outlook-* 244 245 set height [font metrics [$T cget -font] -linespace] 246 if {$height < 18} { 247 set height 18 248 } 249 250 # 251 # Configure the treectrl widget 252 # 253 254 $T configure -itemheight $height -selectmode browse \ 255 -showroot no -showrootbutton no -showbuttons yes -showlines no 256 257 # 258 # Create columns 259 # 260 261 $T column create -image outlook-clip -tags clip 262 $T column create -image outlook-arrow -tags arrow 263 $T column create -image outlook-watch -tags watch 264 $T column create -text Subject -width 250 -tags subject 265 $T column create -text From -width 150 -tags from 266 $T column create -text Sent -width 150 -tags sent 267 $T column create -text Size -width 60 -justify right -tags size 268 269 $T configure -treecolumn 3 270 271 # 272 # Create elements 273 # 274 275 $T element create image.unread image -image outlook-unread 276 $T element create image.read image -image outlook-read 277 $T element create image.read2 image -image outlook-read-2 278 $T element create text.read text -fill [list $::SystemHighlightText {selected focus}] \ 279 -lines 1 280 $T element create text.unread text -fill [list $::SystemHighlightText {selected focus}] \ 281 -font [list DemoFontBold] -lines 1 282 $T element create sel.e rect -fill [list $::SystemHighlight {selected focus} gray {selected !focus}] -open e -showfocus yes 283 $T element create sel.w rect -fill [list $::SystemHighlight {selected focus} gray {selected !focus}] -open w -showfocus yes 284 $T element create sel.we rect -fill [list $::SystemHighlight {selected focus} gray {selected !focus}] -open we -showfocus yes 285 286 # 287 # Create styles using the elements 288 # 289 290 # Image + text 291 set S [$T style create unread] 292 $T style elements $S {sel.e image.unread text.unread} 293 $T style layout $S image.unread -expand ns 294 $T style layout $S text.unread -padx {2 6} -squeeze x -expand ns 295 $T style layout $S sel.e -union [list text.unread] -iexpand nes -ipadx {2 0} 296 297 # Image + text 298 set S [$T style create read] 299 $T style elements $S {sel.e image.read text.read} 300 $T style layout $S image.read -expand ns 301 $T style layout $S text.read -padx {2 6} -squeeze x -expand ns 302 $T style layout $S sel.e -union [list text.read] -iexpand nes -ipadx {2 0} 303 304 # Image + text 305 set S [$T style create read2] 306 $T style elements $S {sel.e image.read2 text.unread} 307 $T style layout $S image.read2 -expand ns 308 $T style layout $S text.unread -padx {2 6} -squeeze x -expand ns 309 $T style layout $S sel.e -union [list text.unread] -iexpand nes -ipadx {2 0} 310 311 # Text 312 set S [$T style create unread.we] 313 $T style elements $S {sel.we text.unread} 314 $T style layout $S text.unread -padx 6 -squeeze x -expand ns 315 $T style layout $S sel.we -detach yes -iexpand xy 316 317 # Text 318 set S [$T style create read.we] 319 $T style elements $S {sel.we text.read} 320 $T style layout $S text.read -padx 6 -squeeze x -expand ns 321 $T style layout $S sel.we -detach yes -iexpand xy 322 323 # Text 324 set S [$T style create unread.w] 325 $T style elements $S {sel.w text.unread} 326 $T style layout $S text.unread -padx 6 -squeeze x -expand ns 327 $T style layout $S sel.w -detach yes -iexpand xy 328 329 # Text 330 set S [$T style create read.w] 331 $T style elements $S {sel.w text.read} 332 $T style layout $S text.read -padx 6 -squeeze x -expand ns 333 $T style layout $S sel.w -detach yes -iexpand xy 334 335 # 336 # Create items and assign styles 337 # 338 339 set msgCnt 100 340 341 set thread 0 342 set Priv(count,0) 0 343 for {set i 1} {$i < $msgCnt} {incr i} { 344 $T item create 345 while 1 { 346 set j [expr {int(rand() * $i)}] 347 if {$j == 0} break 348 if {[$T depth $j] == 5} continue 349 if {$Priv(count,$Priv(thread,$j)) == 15} continue 350 break 351 } 352 $T item lastchild $j $i 353 354 set Priv(read,$i) [expr rand() * 2 > 1] 355 if {$j == 0} { 356 set Priv(thread,$i) [incr thread] 357 set Priv(seconds,$i) [expr {[clock seconds] - int(rand() * 500000)}] 358 set Priv(seconds2,$i) $Priv(seconds,$i) 359 set Priv(count,$thread) 1 360 } else { 361 set Priv(thread,$i) $Priv(thread,$j) 362 set Priv(seconds,$i) [expr {$Priv(seconds2,$j) + int(rand() * 10000)}] 363 set Priv(seconds2,$i) $Priv(seconds,$i) 364 set Priv(seconds2,$j) $Priv(seconds,$i) 365 incr Priv(count,$Priv(thread,$j)) 366 } 367 } 368 369 for {set i 1} {$i < $msgCnt} {incr i} { 370 set subject "This is thread number $Priv(thread,$i)" 371 set from somebody@somewhere.net 372 set sent [clock format $Priv(seconds,$i) -format "%d/%m/%y %I:%M %p"] 373 set size [expr {1 + int(rand() * 10)}]KB 374 if {$Priv(read,$i)} { 375 set style read 376 set style2 read 377 } else { 378 set style unread 379 set style2 unread 380 } 381 $T item style set $i 3 $style 4 $style2.we 5 $style2.we 6 $style2.w 382 $T item text $i 3 $subject 4 $from 5 $sent 6 $size 383 if {[$T item numchildren $i]} { 384 $T item configure $i -button yes 385 } 386 } 387 388 $T notify bind $T <Selection> { 389 if {[%T selection count] == 1} { 390 set I [%T selection get 0] 391 if {!$Priv(read,$I)} { 392 if {[%T item isopen $I] || ![AnyUnreadDescendants %T $I]} { 393 # unread ->read 394 %T item style map $I subject read {text.unread text.read} 395 %T item style map $I from read.we {text.unread text.read} 396 %T item style map $I sent read.we {text.unread text.read} 397 %T item style map $I size read.w {text.unread text.read} 398 } else { 399 # unread -> read2 400 %T item style map $I subject read2 {text.unread text.unread} 401 } 402 set Priv(read,$I) 1 403 DisplayStylesInItem $I 404 } 405 } 406 } 407 408 $T notify bind $T <Expand-after> { 409 if {$Priv(read,%I) && [AnyUnreadDescendants %T %I]} { 410 # read2 -> read 411 %T item style map %I subject read {text.unread text.read} 412 # unread -> read 413 %T item style map %I from read.we {text.unread text.read} 414 %T item style map %I sent read.we {text.unread text.read} 415 %T item style map %I size read.w {text.unread text.read} 416 } 417 } 418 419 $T notify bind $T <Collapse-after> { 420 if {$Priv(read,%I) && [AnyUnreadDescendants %T %I]} { 421 # read -> read2 422 %T item style map %I subject read2 {text.read text.unread} 423 # read -> unread 424 %T item style map %I from unread.we {text.read text.unread} 425 %T item style map %I sent unread.we {text.read text.unread} 426 %T item style map %I size unread.w {text.read text.unread} 427 } 428 } 429 430 for {set i 1} {$i < $msgCnt} {incr i} { 431 if {rand() * 2 > 1} { 432 if {[$T item numchildren $i]} { 433 $T item collapse $i 434 } 435 } 436 } 437 438 return 439} 440 441proc DemoOutlookNewsgroup::AnyUnreadDescendants {T I} { 442 443 variable Priv 444 445 foreach item [$T item descendants $I] { 446 if {!$Priv(read,$item)} { 447 return 1 448 } 449 } 450 return 0 451} 452 453proc DemoOutlookNewsgroup::FixItemStyles {T} { 454 455 set columns1 [$T column id "visible tag clip||arrow||watch !tail"] 456 set columns2 [$T column id "visible tag !(clip||arrow||watch) !tail"] 457 458 foreach C [$T column id "visible !tail"] { 459 460 # The clip/arrow/watch columns only get a style when they are 461 # between the first and last text-containing columns. 462 if {[lsearch -exact $columns1 $C] != -1} { 463 if {[$T column compare $C > [lindex $columns2 0]] && 464 [$T column compare $C < [lindex $columns2 end]]} { 465 $T item style set all $C s2 466 $T item state forcolumn all $C {!openW !openE openWE} 467 } else { 468 $T item style set all $C "" 469 } 470 continue 471 } 472 473 # The text-containing columns need their styles set such that the 474 # active outline of the selected item extends from left to right. 475 # Also, the left-most text-containing column is the tree column 476 # and displays the icon. 477 if {$C eq [lindex $columns2 0]} { 478 $T configure -treecolumn $C 479 set S s1 480 set state openE 481 } elseif {$C eq [lindex $columns2 end]} { 482 set S s2 483 set state openW 484 } else { 485 set S s2 486 set state openWE 487 } 488 $T item state forcolumn all $C [list !openWE !openE !openW $state] 489 490 # Change the style, but keep the text so we don't have to reset it. 491 $T item style map all $C $S {elemTxt elemTxt} 492 } 493 return 494} 495