1# 2# ftoc.tcl 3# 4# Folder table of contents display. 5# 6# Copyright (c) 1993 Xerox Corporation. 7# Use and copying of this software and preparation of derivative works based 8# upon this software are permitted. Any distribution of this software or 9# derivative works must comply with all applicable United States export 10# control laws. This software is made available AS IS, and Xerox Corporation 11# makes no warranty about the software, its performance or its conformity to 12# any specification. 13 14proc Ftoc_Init {} { 15 global ftoc 16 set ftoc(displayValid) 1 ;# 0 => pick results, not full scan 17 set ftoc(displayDirty) 0 ;# 1 => display differs from cache 18 set ftoc(mono) [expr {[winfo depth .] <= 4}] 19 # Parameters to the Next button 20 Preferences_Add "Scan Listing" \ 21"These settings affect the behavior of Exmh as you move through the scan listing to view and mark messages. 22While the default for Auto Commit is OFF, I suggest you try it out. 23Messages are still temporarily marked, but the commit is done when you need it." { 24 {exwin(ftextLines) ftextLines 15 {Scan listing lines} 25"Lines in the Scan listing window, which is 26also called Folder-Table-Of-Contents (FTOC)."} 27 {ftoc(implied) impliedDirection ON "Implied Direction" 28"If set, Exmh will remember your current direction, 29next or previous, and go that way after you mark a 30message for deletion or refiling."} 31 {ftoc(nextGuard) nextGuard OFF "Next Guard" 32"If set, Exmh will warn you that you are about to 33change folders when you hit Next. This means you 34end up hitting Next twice to chain the to next 35folder with unseen messages."} 36 {ftoc(autoCommit) autoCommit OFF "Auto Commit" 37"If set, Exmh will invoke the Commit operation to 38commit deletions and refiles when it would otherwise 39just complain that such a commit is required."} 40 {ftoc(commitDialog) commitDialog ON "Commit Dialog" 41"If set, you get a confirmation dialog when exmh wants 42you to commit pending changes. Otherwise you just 43get a warning message and have to hit the Commit button."} 44 {ftoc(autoPack) autoPack OFF "Auto Pack" 45"If set, Exmh will pack the folder every time a commit is performed."} 46 {ftoc(autoSort) autoSort OFF "Auto Sort" 47"If set, Exmh will sort the folder every time you change into it"} 48 {ftoc(autoSortType) autoSortType {CHOICE date subject sender custom} {Sorting criterion} 49"Sort by Date:/Subject:/From: or user-defined fields. Uses MH sortm command."} 50 {ftoc(autoSortCrit) autoSortCrit {-textfield keywords} {Custom criterion} 51"Custom parameters for sortm"} 52 {ftoc(showNew) ftocShowNew OFF "Show New Messages" 53"If set, Exmh will scroll the FTOC display to show 54new message that arrive because of an Inc."} 55 {ftoc(linkAdvance) advanceOnLink OFF "Advance after Link" 56"If set, Exmh will advance to the next message after a link."} 57 {ftoc(skipMarked) skipMarked ON "Next/Prev skip marked msgs" 58"If set, Next and Prev will skip over messages that have 59been marked for move or delete."} 60 {flist(cycleBack) cycleBack ON "Cycle back to first" 61"If there are no folders with unseen messages, then this 62option causes you to change to the first folder given by your 63Folder-Order MH profile entry."} 64 {ftoc(scanWidth) scanWidth 100 "Default scan width" 65"This value is passed as the -width argument to scan and in."} 66 {ftoc(scanSize) scanSize 100 "Default amount to scan" 67"Only the last N messages are scanned when you first enter a folder. 68The number is controlled by this setting."} 69 } 70} 71proc Ftoc_Reset { numMsgs msgid folder } { 72 global ftoc exwin 73 Exmh_Debug Ftoc_Reset $folder has $numMsgs msgs 74 set ftoc(numMsgs) $numMsgs ;# num msgs in the scan listing 75 set ftoc(changed) 0 ;# Number of moves/deletes marked 76 set ftoc(lineset) {} ;# set of selected messages 77 set ftoc(pickone) 1 ;# lineset is empty 78 set ftoc(folder) $folder ;# Currently displayed folder 79 set ftoc(direction) next ;# assumed next direction 80 set ftoc(softChange) [expr {! $ftoc(nextGuard)}] 81 set ftoc(lasthit) {} ;# search anchor 82 set ftoc(curLine) $msgid ;# current display line number 83 Ftoc_ClearMsgCache 84} 85proc Ftoc_Update { numMsgs } { 86 # Update size of message list after inc'ing into current folder 87 global ftoc 88 Exmh_Debug Ftoc_Update $ftoc(folder) has $numMsgs msgs (was $ftoc(numMsgs)) 89 if {$numMsgs > $ftoc(numMsgs)} { 90 set msgids {} 91 set lineno $ftoc(numMsgs) 92 while {$lineno < $numMsgs} { 93 incr lineno 94 lappend msgids [Ftoc_MsgNumber $lineno] 95 } 96 Ftoc_ShowSequences $msgids 97 } 98 set ftoc(numMsgs) $numMsgs 99} 100 101proc Ftoc_Bindings { w } { 102 # Bindings for the ftoc text widget 103 104 bind $w <Configure> FtocDeduceSize 105 106 # The TScroll binding to too general. 107 # We'll do our own scroll bindings here. 108 bindtags $w [list $w Command] 109 110 # Button-1 starts selection range 111 bind $w <Button-1> { 112 FtocRangeStart [lindex [split [%W index current] .] 0] 113 Exmh_Focus 114 } 115 bind $w <Shift-Button-1> { 116 FtocRangeAdd [lindex [split [%W index current] .] 0] 117 Exmh_Focus 118 } 119 bind $w <B1-Motion> { 120 FtocRangeExtendXY %x %y 121 } 122 bind $w <Shift-B1-Motion> { 123 FtocRangeExtendXY %x %y 124 } 125 bind $w <Any-ButtonRelease-1> { 126 FtocRangeEnd [lindex [split [%W index current] .] 0] 0 127 } 128 bind $w <Shift-ButtonRelease-1> { 129 FtocRangeEnd [lindex [split [%W index current] .] 0] 1 130 } 131 bind $w <Button-3> { 132 set lineNumber [lindex [split [%W index current] .] 0] 133 Msg_Pick $lineNumber noshow 134 Exmh_Focus 135 } 136 bind $w <Double-Button-1> { } 137 bind $w <Triple-Button-1> { } 138 139 bind $w <Button-2> {WidgetTextMark %W %y} 140 bind $w <B2-Motion> {WidgetTextDragto %W %y $exwin(scrollSpeed)} 141 142 Drag_Attach $w FtocDragSelect Shift 3 143 144} 145proc FtocDeduceSize {} { 146 global exwin 147 if {$exwin(toplevelMsg)} { 148 set top [lindex [split [$exwin(ftext) index @0,0] .] 0] 149 set h [winfo height $exwin(ftext)] 150 set w [winfo width $exwin(ftext)] 151 set ix [$exwin(ftext) index @[expr $h-1],[expr $w-1]] 152 set bottom [lindex [split $ix .] 0] 153 set exwin(ftextLines) [expr $bottom-$top] 154 } 155} 156proc FtocRangeStart { lineno } { 157 # For normal button-down "start a selection" 158 global ftoc 159 Ftoc_RangeUnHighlight 160 set ftoc(pickstart) $lineno 161 set ftoc(pickend) $lineno 162 set ftoc(pickstate) new 163 set ftoc(extend) 0 164 Ftoc_RangeHighlight $lineno $lineno 165} 166proc FtocRangeAdd { lineno } { 167 # For shift-select "add to selection" 168 global ftoc 169 set ftoc(pickstart) $lineno 170 set ftoc(pickend) $lineno 171 set ftoc(pickstate) invert 172 set ftoc(extend) 0 173 FtocRangeInvert $lineno $lineno 174} 175proc FtocRangeEnd { {lineno {}} {addcurrent 0} } { 176 # For end of button sweep 177 global ftoc exwin 178 catch {unset ftoc(extend)} 179 if ![info exists ftoc(pickend)] { 180 # Spurious button-release event 181 return 182 } 183 if {($lineno == $ftoc(pickstart)) && !$addcurrent} { 184 # regular button click optimization 185 unset ftoc(pickend) 186 Msg_Pick $lineno show 187 return 188 } 189 if {$lineno != {}} { 190 FtocRangeExtend $lineno 191 } 192 FtocPickRange $addcurrent 193 catch {unset ftoc(pickend)} 194} 195proc Ftoc_PickMsgs { msgids addtosel } { 196 # For adding to the selection by message number 197 global ftoc 198 Exmh_Status "Marking [llength $msgids] hits" 199 Ftoc_LinesHighlight [Ftoc_FindMsgs $msgids] 200 FtocPickRange $addtosel 201} 202proc FtocRangeExtendXY { x y } { 203 global ftoc exwin widgetText 204 205 if ![info exists ftoc(extend)] { 206 return 207 } 208 set active $ftoc(extend) 209 210 set h [winfo height $exwin(ftext)] 211 if {$y > $h} { 212 set ftoc(extend) [expr $y-$h] 213 } else { 214 if {$y < 0} { 215 set ftoc(extend) $y 216 } else { 217 set ftoc(extend) 0 218 } 219 } 220 221 if {$ftoc(extend) == 0} { 222 FtocRangeExtend [lindex [split [$exwin(ftext) index @$x,$y] .] 0] 223 } else { 224 if {! $active} { 225 set ftoc(lastmark) [lindex [ split [$exwin(ftext) index @$x,$y] .] 0] 226 after $widgetText(selectDelay) [list FtocSelExtend] 227 } 228 } 229} 230proc FtocSelExtend {} { 231 global ftoc exwin widgetText 232 set w $exwin(ftext) 233 if {![info exists ftoc(extend)] || 234 ($ftoc(extend) == 0)} { 235 return 236 } 237 catch { 238 set delta [expr {$ftoc(extend) / 16}] 239 if {$delta == 0} { 240 set delta [expr { ($ftoc(extend) < 0) ? -1 : 1 }] 241 } 242 set newmark [expr {$ftoc(lastmark) + $delta}] 243 FtocRangeExtend $newmark 244 set ftoc(lastmark) $newmark 245 $w yview -pickplace $newmark.0 246 after $widgetText(selectDelay) [list FtocSelExtend] 247 } 248} 249proc FtocRangeExtend { lineno } { 250 global ftoc 251 if ![info exists ftoc(pickend)] { 252 return 253 } 254 if {$lineno <= 0} { 255 set lineno 1 256 } 257 if {$lineno > $ftoc(numMsgs)} { 258 set lineno $ftoc(numMsgs) 259 } 260 if {$lineno == $ftoc(pickend)} { 261 # Invariant, previously defined selection is fine. 262 return 263 } 264 if {$lineno == 0} { 265 # no messages in folder 266 return 267 } 268 if {$ftoc(pickstate) != "invert"} { 269 if {$ftoc(pickstart) < $ftoc(pickend)} { 270 # Growing downward 271 if {$lineno > $ftoc(pickend)} { 272 Ftoc_RangeHighlight [expr $ftoc(pickend)+1] $lineno 273 } else { 274 if {$lineno < $ftoc(pickstart)} { 275 if {$ftoc(pickstart) != $ftoc(pickend)} { 276 # Change direction 277 FtocRangeClear [expr $ftoc(pickstart)+1] \ 278 $ftoc(pickend) 279 } 280 Ftoc_RangeHighlight [expr $ftoc(pickstart)-1] $lineno 281 } else { 282 # Shrink selection 283 FtocRangeClear [expr $lineno+1] $ftoc(pickend) 284 } 285 } 286 } else { 287 # Growing upward 288 if {$lineno < $ftoc(pickend)} { 289 Ftoc_RangeHighlight [expr $ftoc(pickend)-1] $lineno 290 } else { 291 if {$lineno > $ftoc(pickstart)} { 292 if {$ftoc(pickstart) != $ftoc(pickend)} { 293 # Change direction 294 FtocRangeClear [expr $ftoc(pickstart)-1] \ 295 $ftoc(pickend) 296 } 297 Ftoc_RangeHighlight [expr $ftoc(pickstart)+1] $lineno 298 } else { 299 # Shrink selection 300 FtocRangeClear [expr $lineno-1] $ftoc(pickend) 301 } 302 } 303 } 304 } else { 305 if {$ftoc(pickstart) < $ftoc(pickend)} { 306 # Growing downward 307 if {$lineno > $ftoc(pickend)} { 308 FtocRangeInvert [expr $ftoc(pickend)+1] $lineno 309 } else { 310 if {$lineno < $ftoc(pickstart)} { 311 if {$ftoc(pickstart) != $ftoc(pickend)} { 312 # Change direction 313 FtocRangeInvert [expr $ftoc(pickstart)+1] \ 314 $ftoc(pickend) 315 } 316 FtocRangeInvert [expr $ftoc(pickstart)-1] $lineno 317 } else { 318 # Shrink selection 319 FtocRangeInvert [expr $lineno+1] $ftoc(pickend) 320 } 321 } 322 } else { 323 # Growing upward 324 if {$lineno < $ftoc(pickend)} { 325 FtocRangeInvert [expr $ftoc(pickend)-1] $lineno 326 } else { 327 if {$lineno > $ftoc(pickstart)} { 328 if {$ftoc(pickstart) != $ftoc(pickend)} { 329 # Change direction 330 FtocRangeInvert [expr $ftoc(pickstart)-1] \ 331 $ftoc(pickend) 332 } 333 FtocRangeInvert [expr $ftoc(pickstart)+1] $lineno 334 } else { 335 # Shrink selection 336 FtocRangeInvert [expr $lineno-1] $ftoc(pickend) 337 } 338 } 339 } 340 } 341 set ftoc(pickend) $lineno 342} 343proc FtocRangeInvert { start end } { 344 global exwin 345 set win $exwin(ftext) 346 if {$start > $end} { 347 set tmp $start ; set start $end ; set end $tmp 348 } 349 for {set lineno $start} {$lineno <= $end} {incr lineno} { 350 catch { 351 set newtag range 352 set oldtag {} 353 set nuke 0 354 foreach tag [$win tag names $lineno.0] { 355 case $tag { 356 deleted { set newtag drange ; set oldtag $tag ; break; } 357 moved { set newtag mrange ; set oldtag $tag ; break; } 358 range { set newtag {} ; set oldtag $tag ; break; } 359 drange { set newtag deleted ; set oldtag $tag ; 360 set nuke 1; break} 361 mrange { set newtag moved ; set oldtag $tag ; 362 set nuke 1; break; } 363 } 364 } 365 if {$nuke} { 366 set ix [lsearch $ftoc(lineset) $lineno] 367 if {$ix >= 0} { 368 set ftoc(lineset) [lreplace $ftoc(lineset) $ix $ix] 369 } 370 } 371 if {$oldtag != {}} { 372 $win tag remove $oldtag $lineno.0 $lineno.end 373 } 374 if {$newtag != {}} { 375 $win tag add $newtag $lineno.0 $lineno.end 376 } 377 } 378 } 379} 380proc Ftoc_RangeHighlight { start end } { 381 global exwin 382 set win $exwin(ftext) 383 if {$start > $end} { 384 set tmp $start ; set start $end ; set end $tmp 385 } 386 for {set lineno $start} {$lineno <= $end} {incr lineno} { 387 set newtag range 388 foreach tag [$win tag names $lineno.0] { 389 case $tag { 390 {drange deleted} { set newtag drange ; break; } 391 {mrange moved} { set newtag mrange ; break; } 392 } 393 } 394 $win tag add $newtag $lineno.0 $lineno.end 395 } 396} 397proc Ftoc_LinesHighlight { linenos } { 398 global exwin 399 set win $exwin(ftext) 400 if {$linenos == {}} { 401 return 402 } 403 WidgetTextYview $exwin(ftext) -pickplace [lindex $linenos 0].0 404# update idletasks 405 foreach lineno $linenos { 406 set newtag range 407 foreach tag [$win tag names $lineno.0] { 408 case $tag { 409 {drange deleted} { set newtag drange ; break; } 410 {mrange moved} { set newtag mrange ; break; } 411 } 412 } 413 $win tag add $newtag $lineno.0 $lineno.end 414 } 415} 416proc FtocRangeClear { start end } { 417 global exwin 418 set win $exwin(ftext) 419 if {$start > $end} { 420 set tmp $start ; set start $end ; set end $tmp 421 } 422 for {set lineno $start} {$lineno <= $end} {incr lineno} { 423 catch { 424 set newtag {} 425 set oldtag range 426 foreach tag [$win tag names $lineno.0] { 427 case $tag { 428 drange { set newtag deleted ; set oldtag drange; break; } 429 mrange { set newtag moved ; set oldtag mrange; break; } 430 range { break } 431 } 432 } 433 $win tag remove $oldtag $lineno.0 $lineno.end 434 if {$newtag != {}} { 435 $win tag add $newtag $lineno.0 $lineno.end 436 } 437 } 438 } 439} 440proc Ftoc_RangeUnHighlight { } { 441 global exwin exmh 442 set win $exwin(ftext) 443 foreach tag {range drange mrange} { 444 foreach range [FtocMakePairs [$win tag ranges $tag]] { 445 eval $win tag remove $tag $range 446 if {$tag == "drange"} { 447 eval $win tag add deleted $range 448 } 449 if {$tag == "mrange"} { 450 eval $win tag add moved $range 451 } 452 } 453 } 454} 455 456# For user programming 457proc Ftoc_BindDouble { cmd } { 458 global exwin 459 bind $exwin(ftext) <Double-1> $cmd 460} 461proc Ftoc_BindRight { cmd } { 462 global exwin 463 bind $exwin(ftext) <3> $cmd 464} 465 466proc Ftoc_FindMsgs {msgids} { 467 global ftoc msgtolinecache 468 set linenos {} 469 foreach msg $msgids { 470 set lineno [Ftoc_FindMsg $msg] 471 if {$lineno != {}} { 472 lappend linenos $lineno 473 } 474 } 475 return $linenos 476} 477proc Ftoc_FindMsg { msgid } { 478 global ftoc msgtolinecache 479 if {$msgid == {}} { 480 return {} 481 } 482 if {[info exist msgtolinecache($msgid)]} { 483 return $msgtolinecache($msgid) 484 } 485 if !$ftoc(displayValid) { 486 # 487 # Linear search for pick and thread FTOCs (pseudo-displays) 488 # 489 for {set lineno 1} {$lineno <= $ftoc(numMsgs)} {incr lineno} { 490 if {[Ftoc_MsgNumber $lineno] == $msgid} { 491 return $lineno 492 } 493 } 494 return {} 495 } 496 497 # 498 # Binary search for other FTOCs 499 # 500 set minlineno 1 501 set minmsgid [Ftoc_MsgNumber $minlineno] 502 if {$msgid == $minmsgid} { 503 return $minlineno 504 } 505 set maxlineno $ftoc(numMsgs) ;# Ignore trailing blank line 506 set maxmsgid [Ftoc_MsgNumber $maxlineno] 507 if {$msgid == $maxmsgid} { 508 return $maxlineno 509 } 510 while (1) { 511 if {$msgid > $maxmsgid || $msgid < $minmsgid} { 512 Exmh_Status "Cannot find $msgid ($minmsgid,$maxmsgid)" warn 513 if {[info exist msgtolinecache($msgid)]} { 514 unset msgtolinecache($msgid) 515 } 516 return {} ;# new message not listed 517 } 518 if {$maxlineno == $minlineno} { 519 if {[info exist msgtolinecache($msgid)]} { 520 unset msgtolinecache($msgid) 521 } 522 return {} ;# not found 523 } 524 # Original binary search 525 #set nextlineno [expr int(($maxlineno+$minlineno)/2)] 526 # Don't divide in two, guestimate where the line might be instead 527 set nextlineno [expr int($minlineno+1+($msgid-$minmsgid)*($maxlineno-$minlineno-2)/($maxmsgid-$minmsgid))] 528 if {$nextlineno < $minlineno} { 529 set nextlineno $minlineno 530 } 531 if {$nextlineno > $maxlineno} { 532 set nextlineno $maxlineno 533 } 534 set nextmsgid [Ftoc_MsgNumber $nextlineno] 535 # Note that a side effect of Ftoc_MsgNumber was to put this entry in 536 # the cache,so we don't have to do it here. 537 if {$nextmsgid == $msgid} { 538 return $nextlineno 539 } elseif {$nextmsgid > $msgid} { 540 set maxlineno $nextlineno 541 set maxmsgid $nextmsgid 542 } elseif {$minlineno == $nextlineno} { 543 Exmh_Status "Cannot find $msgid" warn 544 if {[info exist msgtolinecache($msgid)]} { 545 unset msgtolinecache($msgid) 546 } 547 return {} ;# new message not listed 548 } elseif {$nextmsgid == ""} { 549 error "Failed to find a message number on line $nextlineno, end is [$::exwin(ftext) index end]\n[$::exwin(ftext) get $nextlineno.0 $nextlineno.end]" 550 } else { 551 set minlineno $nextlineno 552 set minmsgid $nextmsgid 553 } 554 } 555 # not reached 556} 557proc Ftoc_ClearMsgCache {} { 558 global linetomsgcache msgtolinecache 559 foreach x {linetomsgcache msgtolinecache} { 560 if {[info exists $x]} { 561 unset $x 562 } 563 } 564} 565proc Ftoc_MsgNumbers { linenos } { 566 global exwin 567 set msgids {} 568 foreach lineno $linenos { 569 set msgid [Ftoc_MsgNumber $lineno] 570 if {$msgid != {}} { 571 lappend msgids $msgid 572 } 573 } 574 return $msgids 575} 576proc Ftoc_MsgNumber { lineno } { 577 global exwin linetomsgcache msgtolinecache 578 if {[info exist linetomsgcache($lineno]} { 579 return $linetomsgcache($lineno) 580 } 581 if [catch {$exwin(ftext) get $lineno.0 $lineno.end} line] { 582 return {} 583 } 584 set msgid [Ftoc_MsgNumberRaw $line] 585 if {$msgid != {}} { 586 set msgtolinecache($msgid) $lineno 587 set linetomsgcache($lineno) $msgid 588 } 589 return $msgid 590} 591proc Ftoc_MsgNumberRaw { line } { 592 if [regexp {^( *)([0-9]+)} $line foo foo2 number] { 593 return $number 594 } else { 595 return "" 596 } 597} 598proc FtocPickRange { {addcurrent 0} } { 599 # Select a range of messages, or add to the current range 600 # Because of toggle/inverted selections, we pretty much 601 # have to recompute the select set from range tags 602 global exwin ftoc 603 set lineset {} 604 if {$ftoc(curLine) != {}} { 605 if {$addcurrent} { 606 Ftoc_RangeHighlight $ftoc(curLine) $ftoc(curLine) 607 } 608 Ftoc_ClearCurrent 609 Msg_ClearCurrent 610 set ftoc(curLine) {} 611 } 612 foreach range [concat \ 613 [FtocMakePairs [$exwin(ftext) tag ranges range]] \ 614 [FtocMakePairs [$exwin(ftext) tag ranges drange]] \ 615 [FtocMakePairs [$exwin(ftext) tag ranges mrange]]] { 616 set mark1 [lindex $range 0] 617 set lineno [lindex [split $mark1 .] 0] 618 lappend lineset $lineno 619 } 620 if {$lineset == {}} { 621 return ;# spurious <ButtonRelease-1> events 622 } 623 set ftoc(lineset) $lineset 624 set ftoc(pickone) 0 625 if {[llength $ftoc(lineset)] == 1} { 626 # This calls Msg_Change, 627 # which calls Ftoc_ClearCurrent, which sets pickone to 1, 628 # and calls Ftoc_Change, which sets curline 629 Msg_Pick [lindex $ftoc(lineset) 0] show 630 } else { 631 Buttons_Range ;# Enable actions on ranges 632 } 633} 634proc Ftoc_PickSize {} { 635 global ftoc 636 if {$ftoc(curLine) != {}} { 637 return [llength $ftoc(curLine)] 638 } else { 639 return [llength $ftoc(lineset)] 640 } 641} 642proc Ftoc_NewFtoc {{linenos ftoclineset}} { 643 global ftoc 644 if {$linenos == "ftoclineset"} { 645 set linenos $ftoc(lineset) 646 } 647 set msgids [Ftoc_MsgNumbers $linenos] 648 if {[llength $msgids] <= 1} { 649 Exmh_Status "Select more than one message first" warn 650 return 651 } 652 if {[Ftoc_Changes "new ftoc"] == 0} { 653 Exmh_Status $msgids 654 Scan_ProjectSelection $msgids 655 } 656} 657 658# Ftoc_ClearCurrent and Ftoc_Change are two parts of 659# dinking the ftoc display when advancing a message. 660 661proc Ftoc_ClearCurrent {} { 662 # Clear display of current message 663 global ftoc exwin 664 set ftoc(pickone) 1 665 set ftoc(lineset) {} 666 667 if {$ftoc(curLine) == {}} { 668 set ftoc(curLine) [Mh_Cur $ftoc(folder)] 669 } 670 if {$ftoc(curLine) != {}} { 671 $exwin(ftext) tag remove cur $ftoc(curLine).0 $ftoc(curLine).end 672 Ftoc_RescanLine $ftoc(curLine) 673 } 674 return $ftoc(curLine) 675} 676proc Ftoc_Change { lineno {show show} } { 677 global ftoc exwin mhProfile 678 set ftoc(curLine) $lineno 679 if {$ftoc(curLine) == {}} { 680 set ok 0 681 } else { 682 if {$show == "show"} { 683 $exwin(ftext) tag remove $mhProfile(unseen-sequence) $ftoc(curLine).0 $ftoc(curLine).end 684 } 685 Ftoc_RescanLine $ftoc(curLine) + 686 $exwin(ftext) tag add cur $ftoc(curLine).0 $ftoc(curLine).end 687 set top [$exwin(ftext) index @0,4] 688 if [catch {expr {$top+1}}] {set top 0} ;# trap 100.-1 format, iconic 689 if {$ftoc(curLine) == $top || 690 $ftoc(curLine) == $top+$exwin(ftextLines)-1} { 691 WidgetTextYview $exwin(ftext) [expr $ftoc(curLine)-$exwin(ftextLines)/2].0 692 } else { 693 WidgetTextYview $exwin(ftext) -pickplace $ftoc(curLine).0 694 } 695 set ok 1 696 } 697 return $ok 698} 699proc Ftoc_InitSequences { w } { 700 global exwin 701 set seqs [option get . sequences {}] 702 foreach seq $seqs { 703 eval $w tag configure $seq \ 704 [option get . sequence_$seq {}] 705 $w tag raise $seq 706 } 707} 708 709# Highlight a set of messages (or all in the folder) that belong 710# to a sequence. If msgsids is null, then we only work on that 711# subset of the folder. Otherwise we highlight all the messages 712# in the folder that are in the sequence. 713 714proc Ftoc_ShowSequence { seq {msgids {}} } { 715 global exwin exmh mhProfile 716Exmh_Debug Ftoc_ShowSequence $seq msgids $msgids 717 set seqids [Seq_Msgs $exmh(folder) $seq] 718 if {$msgids != {}} { 719 foreach msg $msgids { 720 set lineno [Ftoc_FindMsg $msg] 721 if {$lineno != {}} { 722 if {[lsearch -exact $seqids $msg] == -1} { 723 $exwin(ftext) tag remove $seq $lineno.0 $lineno.end 724 } else { 725 $exwin(ftext) tag add $seq $lineno.0 $lineno.end 726 } 727 } 728 } 729 } else { 730 $exwin(ftext) tag remove $seq 1.0 end 731 if {$seq == $mhProfile(unseen-sequence)} { 732 FtocShowUnseen $seqids 733 } else { 734 foreach lineno [Ftoc_FindMsgs $seqids] { 735 $exwin(ftext) tag add $seq $lineno.0 $lineno.end 736 } 737 } 738 } 739} 740 741proc Ftoc_ShowSequences { {msgids {}} } { 742 global exwin exmh 743 if {$msgids == {}} { 744Exmh_Debug Ftoc_ShowSequences msgids null 745 set seqs [option get . sequences {}] 746 set hiddenseqs [option get . hiddensequences {}] 747 foreach seq $seqs { 748 if {[lsearch -exact $hiddenseqs $seq] == -1} { 749 $exwin(ftext) tag remove $seq 1.0 end 750 } 751 } 752 } else { 753Exmh_Debug Ftoc_ShowSequences msgids $msgids 754 } 755 foreach seq [Mh_Sequences $exmh(folder)] { 756 Ftoc_ShowSequence $seq $msgids 757 } 758} 759 760# This is optimized for the unseen sequence, which tends to 761# cluster at the end of a folder, and get big 762 763proc FtocShowUnseen { unseen } { 764 global exwin flist 765 if {[llength $unseen] > 0} { 766Exmh_Debug FtocShowUnseen $unseen 767 set end [$exwin(ftext) index end] 768 set line [lindex [split $end .] 0] 769 set msgNum 0 770 for {} {$line > 0} {incr line -1} { 771 set msgNum [Ftoc_MsgNumber $line] 772 set i [lsearch $unseen $msgNum] 773 if {$i >= 0} { 774 $exwin(ftext) tag add unseen $line.0 $line.end 775 set unseen [lreplace $unseen $i $i] 776 if {[llength $unseen] == 0} { 777 return 1 778 } 779 } 780 } 781 # Here is some code from the old Ftoc_ShowUnseen that 782 # I don't think we need any more 783 if {0} { 784 # Repair bogus unseen sequences 785 # msgNum is the smallest message number, but it might not be 786 # the first message in the folder because of short scans 787 # Anything in the unseen sequence above msgNum is probably wrong 788 # and can result from races with the background process 789 foreach id $unseen { 790 if {$id > $msgNum} { 791 # This API doen't exist anymore 792 Flist_MsgSeenXXX $id 793 } 794 } 795 } 796 } 797} 798 799proc Ftoc_RescanLine { ix {plus none} } { 800 global exmh exwin ftoc 801 if [catch { 802 set text [$exwin(ftext) get ${ix}.0 ${ix}.end] 803 set ok 0 804 case $plus { 805 "none" { 806 # Replace + (current marker) with blank 807 set ok [regsub {^( *[0-9]+)(\+)} $text {\1 } newtext] 808 } 809 "+" { 810 # Stick a + after the number, if needed 811 if ![regexp {^( *)([0-9]+)(\+)} $text] { 812 set ok [regsub {^( *[0-9]+)( )} $text {\1+} newtext] 813 } 814 } 815 "dash" { 816 # Stick a - after the number, if needed 817 if ![regexp {^( *)([0-9]+).-} $text] { 818 set ok [regsub {^( *[0-9]+.)(.)} $text {\1-} newtext] 819 } 820 # Annotations result in writes to the directory. 821 # Here we mark the display dirty to force an update 822 # of the cache and prevent later rescans. 823 set ftoc(displayDirty) 1 824 Ftoc_ClearMsgCache 825 } 826 } 827 if {$ok} { 828 set tags [$exwin(ftext) tag names ${ix}.0] 829 $exwin(ftext) configure -state normal 830 $exwin(ftext) delete ${ix}.0 ${ix}.end 831 $exwin(ftext) insert ${ix}.0 $newtext 832 $exwin(ftext) configure -state disabled 833 foreach tag $tags { 834 $exwin(ftext) tag add $tag ${ix}.0 ${ix}.end 835 } 836 } 837 } msg] { 838 Exmh_Error "FtocRescanLine $ix : $msg" 839 } 840} 841proc Ftoc_NextImplied { {show show} {implied implied} } { 842 global ftoc 843 if {$ftoc(implied) && $ftoc(direction) == "prev"} { 844 Ftoc_Prev $show 845 } else { 846 Ftoc_Next $show $implied 847 } 848} 849proc Ftoc_Next { show {implied no} } { 850 # Go to the next message in the scan display 851 global exmh flist ftoc mhProfile 852 853 set ftoc(direction) "next" 854 if {$ftoc(curLine) == {}} { 855 if [Msg_Show $mhProfile(unseen-sequence)] { 856 return 857 } 858 } 859 set next [FtocSkipMarked $ftoc(curLine) 1] 860 if {($ftoc(curLine) == $next) || \ 861 ($ftoc(curLine) >= $ftoc(numMsgs)) || \ 862 ($ftoc(curLine) <= 0)} { 863 # End of folder 864 Ftoc_NextFolder $implied 865 } else { 866 # Simple case - go to the next message. 867 Msg_Pick $next $show 868 } 869} 870proc Ftoc_Prev { {show show} } { 871 global ftoc 872 873 Exmh_Debug Ftoc_Prev 874 if {$ftoc(curLine) == {}} { 875 if {$ftoc(numMsgs) > 0} { 876 Msg_Pick $ftoc(numMsgs) $show 877 } 878 return 879 } 880 if {$ftoc(curLine) > 1} then { 881 set ftoc(direction) "prev" 882 Msg_Pick [FtocSkipMarked $ftoc(curLine) -1] $show 883 } else { 884 Ftoc_Next $show implied 885 } 886} 887proc Ftoc_NextFolder { {implied no} } { 888 global ftoc exmh mhProfile 889 # Try to chain to the next folder with unread messages. 890 if {$implied != "no"} { 891 # Implied - chained with some other operation - be lenient 892 if {$ftoc(changed) > 0} { 893 # Dirty folder - do not change. 894 # If on last message, clear display because the 895 # message is moved or deleted 896 if {$ftoc(curLine) != {}} { 897 Ftoc_ClearCurrent 898 Msg_ClearCurrent 899 } 900 Exmh_Status "" 901 Exmh_Status "Changes pending; End of folder" warn 902 return 903 } 904 } 905 set folder [Flist_NextUnvisited] 906 if {[string length $folder] != 0} { 907 if {$ftoc(softChange)} { 908 set ftoc(lastFolder) $exmh(folder) 909 Folder_Change $folder [list Msg_Show $mhProfile(unseen-sequence)] 910 return 911 } else { 912 set ftoc(softChange) 1 913 Ftoc_ClearCurrent 914 Msg_ClearCurrent 915 Exmh_Status "" 916 Exmh_Status "End of folder; <Next> => $folder" warn 917 return 918 } 919 } 920 Exmh_Status "" 921 Exmh_Status "End of folder" warn 922} 923proc Ftoc_LastFolder {} { 924 global ftoc 925 if {[info exist ftoc(lastFolder)]} { 926 return $ftoc(lastFolder) 927 } else { 928 return "" 929 } 930} 931proc Ftoc_PrevMarked { {show show} } { 932 global ftoc 933 set skip $ftoc(skipMarked) 934 set ftoc(skipMarked) 0 935 Ftoc_Prev $show 936 set ftoc(skipMarked) $skip 937} 938proc Ftoc_Marked { msgid } { 939 global ftoc exwin 940 if {$ftoc(skipMarked) == 0} { 941 return 0 ;# Pretend it isn't marked 942 } 943 set lineno [Ftoc_FindMsg $msgid] 944 if {[string length $lineno] == 0} { 945 return 1 ;# Can't find it, pretend it's marked 946 } 947 set marked 0 948 foreach tag [$exwin(ftext) tag names $lineno.0] { 949 if [regexp {(deleted|moved|drange|mrange)} $tag] { 950 set marked 1 ; break; 951 } 952 } 953 return $marked 954} 955proc FtocSkipMarked {start inc} { 956 global exwin ftoc 957 958 if {$start == {}} { 959 return {} 960 } 961 for {set i [expr $start+$inc]} {$i > 0 && $i <= $ftoc(numMsgs)} {incr i $inc} { 962 if {$ftoc(skipMarked) == 0} { 963 return $i 964 } 965 set marked 0 966 foreach tag [$exwin(ftext) tag names $i.0] { 967 if [regexp {(deleted|moved|drange|mrange)} $tag] { 968 set marked 1 ; break; 969 } 970 } 971 if {! $marked} { 972 return $i 973 } 974 } 975 return $start 976} 977 978proc Ftoc_Changes {type {allowAuto 1} } { 979 global ftoc 980 981 if {$ftoc(changed) != 0} then { 982 Exmh_Debug Ftoc_Changes $type 983 if {("$allowAuto" == "1") && $ftoc(autoCommit)} { 984 Folder_CommitType $type 985 return 0 986 } 987 if {$type != {}} { 988 if {[string compare $type iconified] == 0} { 989 set msg "$ftoc(changed) changes pending" 990 } else { 991 if {$ftoc(commitDialog) && 992 [FtocDialog $ftoc(changed) $type]} { 993 Folder_CommitType $type 994 Exmh_Focus 995 return 0 996 } else { 997 set msg "$ftoc(changed) changes pending: $type cancelled" 998 } 999 } 1000 Exmh_Focus 1001 Exmh_Status $msg warn 1002 Sound_Error 1003 } else { 1004 Exmh_Status "Oops, $ftoc(changed) left over changes" error 1005 set ftoc(changed) 0 1006 return 1 1007 } 1008 } 1009 return $ftoc(changed) 1010} 1011proc FtocDialog { changes type } { 1012 global exwin ftoc 1013 if [winfo exists $exwin(mtext).commit] { 1014 destroy $exwin(mtext).commit 1015 } 1016 set f [frame $exwin(mtext).commit -class Dialog -bd 4 -relief ridge] 1017 set blurb [expr {($changes > 1) ? "are $changes changes" : "is one change"}] 1018 Widget_Message $f msg -text \ 1019"There $blurb pending. 1020(Press Return to Commit) 1021(Press <Control-c> to Cancel)" -aspect 1000 1022 set but [Widget_Frame $f but Dialog {top expand fill} -bd 10] 1023 set ftoc(okToCommit) 0 1024 Widget_AddBut $but cancel "Cancel" {set ftoc(okToCommit) 0} 1025 Widget_AddBut $but ok "Commit and $type" {set ftoc(okToCommit) 1} 1026 focus $but 1027 bind $but <Return> "$but.ok flash ; $but.ok invoke" 1028 bind $but <KP_Enter> "$but.ok flash ; $but.ok invoke" 1029 bind $but <Control-c> "$but.cancel flash ; $but.cancel invoke" 1030 Widget_PlaceDialog $exwin(mtext) $exwin(mtext).commit 1031 Visibility_Wait $but 1032 catch {grab $but} 1033 tkwait variable ftoc(okToCommit) 1034 catch {grab release $but} 1035 destroy $exwin(mtext).commit 1036 return $ftoc(okToCommit) 1037} 1038 1039proc Ftoc_CurLines {} { 1040 global ftoc 1041 if {$ftoc(curLine) != {}} { 1042 return $ftoc(curLine) 1043 } elseif {!$ftoc(pickone)} { 1044 return $ftoc(lineset); 1045 } else { 1046 return {} 1047 } 1048} 1049 1050proc Ftoc_CurMsgs {} { 1051 Ftoc_MsgNumbers [Ftoc_CurLines] 1052} 1053 1054proc Ftoc_Iterate { linenoVar body } { 1055 global ftoc 1056 upvar $linenoVar lineno 1057 foreach lineno [Ftoc_CurLines] { 1058 uplevel 1 $body 1059 } 1060} 1061proc Ftoc_MsgIterate { msgidVar body } { 1062 global ftoc 1063 upvar $msgidVar msgid 1064 foreach msgid [Ftoc_CurMsgs] { 1065 uplevel 1 $body 1066 } 1067} 1068proc Ftoc_Unmark {} { 1069 global ftoc 1070 1071 set hits 0 1072 Ftoc_Iterate lineno { 1073 if [FtocUnmarkInner $lineno] { incr hits } 1074 } 1075 Exmh_Status "Unmarked $hits msgs" 1076 incr ftoc(changed) -$hits 1077} 1078proc FtocUnmarkInner { lineno {all 0}} { 1079 global exwin 1080 set res 0 1081 if {$all} { 1082 set pat (deleted|moved|drange|mrange|copied) 1083 } else { 1084 set pat (deleted|moved|drange|mrange) 1085 } 1086 foreach tag [$exwin(ftext) tag names $lineno.0] { 1087 if [regexp $pat $tag] { 1088 $exwin(ftext) tag remove $tag $lineno.0 $lineno.end 1089 if [regexp {(drange|mrange|crange)} $tag] { 1090 eval $exwin(ftext) tag add range $lineno.0 $lineno.end 1091 } 1092 set res 1 1093 } 1094 } 1095 return $res 1096} 1097proc Ftoc_Delete { lineno } { 1098 global exwin ftoc 1099 $exwin(ftext) configure -state normal 1100 $exwin(ftext) delete $lineno.0 "$lineno.end + 1 chars" 1101 $exwin(ftext) configure -state disabled 1102 set ftoc(displayDirty) 1 1103 Ftoc_ClearMsgCache 1104} 1105proc Ftoc_RemoveMark { lineno } { 1106 # Flag the current message(s) for deletion 1107 global ftoc exwin 1108 if ![FtocUnmarkInner $lineno 1] { 1109 incr ftoc(changed) 1110 } 1111 1112 if {$ftoc(pickone)} { 1113 $exwin(ftext) tag add deleted $lineno.0 $lineno.end 1114 } else { 1115 $exwin(ftext) tag remove range $lineno.0 $lineno.end 1116 $exwin(ftext) tag add drange $lineno.0 $lineno.end 1117 } 1118} 1119proc Ftoc_MoveMark { lineno } { 1120 global ftoc exwin exmh 1121 if ![FtocUnmarkInner $lineno] { 1122 incr ftoc(changed) 1123 } 1124 # This tag records the target folder 1125 $exwin(ftext) tag add [list moved $exmh(target)] $lineno.0 $lineno.end 1126 1127 if {$ftoc(pickone)} { 1128 $exwin(ftext) tag add moved $lineno.0 $lineno.end 1129 } else { 1130 $exwin(ftext) tag remove range $lineno.0 $lineno.end 1131 $exwin(ftext) tag add mrange $lineno.0 $lineno.end 1132 } 1133} 1134proc Ftoc_CopyMark { lineno } { 1135 global ftoc exwin exmh 1136 if ![FtocUnmarkInner $lineno] { 1137 incr ftoc(changed) 1138 } 1139 # This tag records the target folder 1140 $exwin(ftext) tag add [list copied $exmh(target)] $lineno.0 $lineno.end 1141 1142 if {$ftoc(pickone)} { 1143 $exwin(ftext) tag add moved $lineno.0 $lineno.end 1144 } else { 1145 $exwin(ftext) tag remove range $lineno.0 $lineno.end 1146 $exwin(ftext) tag add mrange $lineno.0 $lineno.end 1147 } 1148} 1149proc Ftoc_Commit { rmmCommit moveCommit copyCommit } { 1150 global ftoc exwin 1151 1152 # Disable operations on ranges 1153 Ftoc_RangeUnHighlight 1154 if {! $ftoc(pickone)} { 1155 Buttons_Range 0 1156 set ftoc(lineset) {} 1157 set ftoc(pickone) 1 1158 } 1159 1160 Exmh_Status "Committing $ftoc(changed) changes..." 1161 $exwin(ftext) configure -state normal 1162 FtocCommit deleted $rmmCommit 1163 FtocCommit moved $moveCommit $copyCommit 1164 $exwin(ftext) configure -state disabled 1165 set l $ftoc(curLine) 1166 if {$l == {}} { 1167 set l $ftoc(numMsgs) 1168 } 1169 if {$l > 0} { 1170 WidgetTextYview $exwin(ftext) $l 1171 } 1172 if {! [Ftoc_Changes {} noautocommit]} { 1173 Exmh_Status "ok" 1174 } 1175} 1176proc FtocCommit {tagname commitProc {copyCommitProc {}} } { 1177 global ftoc exmh exwin msg mhProfile 1178 1179 set delmsgs {} 1180 set curid [file tail $msg(path)] 1181 set pairs [FtocMakeReversePairs [$exwin(ftext) tag ranges $tagname]] 1182 set seqdelmsgs {} 1183 foreach range $pairs { 1184 set c0 [lindex $range 0] 1185 set ce [lindex $range 1] 1186 scan $c0 "%d" lineno 1187 set msgid [Ftoc_MsgNumber $lineno] 1188 set F {} 1189 set delline 0 ;# Nuke display line 1190 foreach tag [$exwin(ftext) tag names $c0] { 1191 # Build up a list of moved or copied messages 1192 # Note that the original order of the messages is maintained, 1193 # (We are going from bottom to top thru the display.) 1194 # The scan lines are reversed, which is handled by Scan_Move. 1195 if {([llength $tag] == 2) && ([lindex $tag 0] == "moved")} { 1196 set F [lindex $tag 1] 1197 if ![info exists movemsgs($F)] { 1198 set movemsgs($F) $msgid 1199 } else { 1200 set movemsgs($F) [concat $msgid " " $movemsgs($F)] 1201 } 1202 lappend movescan($F) [$exwin(ftext) get $c0 "$ce + 1 chars"] 1203 set delline 1 1204 } 1205 if {([llength $tag] == 2) && ([lindex $tag 0] == "copied")} { 1206 set F [lindex $tag 1] 1207 if ![info exists copymsgs($F)] { 1208 set copymsgs($F) $msgid 1209 } else { 1210 set copymsgs($F) [concat $msgid " " $copymsgs($F)] 1211 } 1212 lappend movescan($F) [$exwin(ftext) get $c0 "$ce + 1 chars"] 1213 } 1214 } 1215 if {$tagname == "deleted"} { 1216 # Batch up deletes 1217 lappend delmsgs $msgid 1218 set delline 1 1219 } 1220 lappend seqdelmsgs $msgid ;# in case deleted or moved w/out viewing 1221 #Exmh_Debug FtocCommit added $msgid to be deleted from unseen-sequence 1222 1223 if {$delline} { 1224 $exwin(ftext) delete $c0 "$ce + 1 chars" 1225 set ftoc(displayDirty) 1 1226 Ftoc_ClearMsgCache 1227 if {$msgid == $curid} { 1228 Ftoc_ClearCurrent 1229 Msg_ClearCurrent 1230 } 1231 if {$lineno == $ftoc(curLine)} { 1232 set ftoc(curLine) {} 1233 } elseif {$ftoc(curLine) != {}} { 1234 if {$lineno < $ftoc(curLine)} { 1235 incr ftoc(curLine) -1 1236 if {$ftoc(curLine) == 0} { 1237 set ftoc(curLine) {} 1238 } 1239 } 1240 } 1241 incr ftoc(numMsgs) -1 1242 } else { 1243 FtocUnmarkInner $lineno 1244 } 1245 incr ftoc(changed) -1 1246 } 1247 1248 if {$seqdelmsgs != {}} { 1249 Exmh_Debug FtocCommit deleting msgs from $mhProfile(unseen-sequence) $seqdelmsgs 1250 Seq_Del $exmh(folder) $mhProfile(unseen-sequence) $seqdelmsgs 1251 } 1252 1253 if {$delmsgs != {}} { 1254 Exmh_Status "$commitProc $delmsgs" 1255 if [catch { 1256 BgAction "Rmm $exmh(folder)" $commitProc $exmh(folder) $delmsgs 1257 } err] { 1258 Exmh_Status $err error 1259 } 1260 } 1261 # Do copies before links so you can both move and copy a message. 1262 if {[catch {array names copymsgs} flist] == 0} { 1263 foreach f $flist { 1264 Exmh_Status "Copying to $f, $copymsgs($f)" 1265 if [catch { 1266 BgAction "Refile $f" $copyCommitProc $exmh(folder) $copymsgs($f) $f 1267 } err] { 1268 Exmh_Status $err error 1269 } 1270 } 1271 } 1272 if {[catch {array names movemsgs} flist] == 0} { 1273 foreach f $flist { 1274 Exmh_Status "Refiling to $f, $movemsgs($f)" 1275 if [catch { 1276 BgAction "Refile $f" $commitProc $exmh(folder) $movemsgs($f) $f 1277 } err] { 1278 Exmh_Status $err error 1279 } 1280 } 1281 } 1282} 1283proc FtocMakePairs { list } { 1284 set result {} 1285 for {set i 0} {$i < [expr [llength $list]-1]} {incr i +2} { 1286 set first [lindex $list $i] 1287 set second [lindex $list [expr $i+1]] 1288 lappend result [list $first $second] 1289 } 1290 if {$result == {}} { 1291 return $list 1292 } else { 1293 return $result 1294 } 1295} 1296proc FtocMakeReversePairs { list } { 1297 set result {} 1298 for {set i [expr [llength $list]-1]} {$i >= 0} {incr i -2} { 1299 set second [lindex $list $i] 1300 set first [lindex $list [expr $i-1]] 1301 lappend result [list $first $second] 1302 } 1303 if {$result == {}} { 1304 return $list 1305 } else { 1306 return $result 1307 } 1308} 1309 1310proc Ftoc_MoveFeedback { msgid } { 1311 global exwin ftoc 1312 set lineno [Ftoc_FindMsg $msgid] 1313 if {$lineno == ""} { 1314 return 1315 } 1316 set msg [Exmh_OldStatus] 1317 foreach tag [$exwin(ftext) tag names $lineno.0] { 1318 if [regexp {moved (.+)} $tag match folder] { 1319 Exmh_Status "$msgid => +$folder" 1320 return 1321 } elseif [regexp deleted $tag] { 1322 Exmh_Status "$msgid Pending Delete" 1323 return 1324 } 1325 } 1326 Exmh_Status $msg 1327} 1328proc Ftoc_FindNext {} { 1329 Find_It forw 1330} 1331proc Ftoc_FindPrev {} { 1332 Find_It back 1333} 1334proc Ftoc_FindAll {string} { 1335 global exwin find ftoc 1336 if {[string length $string] == 0} { 1337 Exmh_Status "No search string" warn 1338 return -1 1339 } 1340 set msgids {} 1341 for {set L 1} 1 {incr L} { 1342 if [$exwin(ftext) compare $L.end >= end] { 1343 break 1344 } 1345 if [catch {$exwin(ftext) get $L.0 $L.end} text] { 1346 break 1347 } 1348 if [regexp -nocase -- $string $text] { 1349 lappend msgids [Ftoc_MsgNumberRaw $text] 1350 } 1351 } 1352 if {[llength $msgids] == 0} { 1353 Exmh_Status "No match" warn 1354 return 0 1355 } else { 1356 Ftoc_PickMsgs $msgids 0 1357 return 1 1358 } 1359 1360} 1361proc Ftoc_FindMatch {L string} { 1362 global exwin ftoc 1363 if {$L == $ftoc(lasthit)} { 1364 return 0 1365 } 1366 if [catch {$exwin(ftext) get $L.0 $L.end} text] { 1367 return -1 ;# off the end or beginning 1368 } 1369 if [regexp -nocase -- $string $text] { 1370 set ftoc(lasthit) $L 1371 Msg_Pick $L show 1372 return 1 1373 } 1374 return 0 1375} 1376proc Ftoc_Yview {args} { 1377 global exwin 1378 eval {WidgetTextYview $exwin(ftext)} $args 1379} 1380proc Ftoc_Advance { advance } { 1381 global ftoc 1382 if {[string compare $advance "advance?"] == 0} { 1383 return $ftoc(linkAdvance) 1384 } else { 1385 return $advance 1386 } 1387} 1388proc Ftoc_PageUp {} { 1389 global exwin 1390 Widget_TextPageUp $exwin(ftext) 1391} 1392proc Ftoc_PageDown {} { 1393 global exwin 1394 Widget_TextPageDown $exwin(ftext) 1395} 1396 1397proc Ftoc_Sort {} { 1398 global ftoc 1399 case $ftoc(autoSortType) { 1400 {date} { Folder_Sort -datefield date } 1401 {subject} { Folder_Sort -textfield subject } 1402 {sender} { Folder_Sort -textfield from } 1403 {custom} { eval Folder_Sort $ftoc(autoSortCrit) } 1404 } 1405} 1406proc Ftoc_SelectAll {} { 1407 global ftoc 1408 FtocRangeStart 1 1409 FtocRangeEnd $ftoc(numMsgs) 1410} 1411proc Ftoc_SelectAllToEnd {} { 1412 global ftoc 1413 if {$ftoc(curLine) != {}} { 1414 FtocRangeStart $ftoc(curLine) 1415 } else { 1416 if {$ftoc(direction) == "next"} { 1417 FtocRangeStart 1 1418 } else { 1419 FtocRangeStart $ftoc(numMsgs) 1420 } 1421 } 1422 if {$ftoc(direction) == "next"} { 1423 FtocRangeEnd $ftoc(numMsgs) 1424 } else { 1425 FtocRangeEnd 1 1426 } 1427} 1428proc Ftoc_CatchUp {} { 1429 global ftoc 1430 Ftoc_SelectAll 1431 Msg_Remove 1432 Folder_Commit 1433 Msg_PageOrNext 1434} 1435proc Ftoc_CatchUpToEnd {} { 1436 global ftoc 1437 Ftoc_SelectAllToEnd 1438 Msg_Remove 1439 Folder_Commit 1440 Msg_PageOrNext 1441} 1442# 1443# Interface to Drag & Drop 1444# 1445set ftocDrag(types) {foldermsg} 1446set ftocDrag(formats) {string filename} 1447set ftocDrag(format,foldermsg) string 1448set ftocDrag(format,filename) string 1449set ftocDrag(type,string) foldermsg 1450 1451# Drag Selected 1452proc FtocDragSelect {w x y wx wy} { 1453 global exmh ftoc ftocDrag mhProfile 1454 1455 set folder $ftoc(folder) 1456 if !$ftoc(displayValid) { 1457 set folder $exmh(folder) 1458 } 1459 if $ftoc(pickone) { 1460 set lineno [lindex [split [$w index cur] .] 0] 1461 set msgids [Ftoc_MsgNumber $lineno] 1462 if {$msgids == {} || $msgids == 0} return 1463 set ftocDrag(data,filename) $mhProfile(path)/$folder/$msgids 1464 } else { 1465 set msgids [Ftoc_MsgNumber $ftoc(lineset)] 1466 catch {unset ftocDrag(data,filename)} 1467 } 1468 1469 # Hand off to Drag code 1470 set ftocDrag(source) $w 1471 set ftocDrag(data,foldermsg) "+$folder $msgids" 1472 Drag_Source ftocDrag $x $y 1473} 1474proc FtocToggleSequence { seq } { 1475 global ftoc exmh 1476 set folder $exmh(folder) 1477 set origmsgids [Seq_Msgs $folder $seq] 1478 set selmsgids [Ftoc_CurMsgs] 1479 if {$selmsgids == {}} { 1480 Exmh_Status "No messages were selected" 1481 } else { 1482 # If any selected message is not already in the sequence, then add 1483 # messages to the sequence. 1484 # If all selected messages are already in the sequence, then remove 1485 # messages from the sequence. 1486 set flag del 1487 foreach msgid $selmsgids { 1488 if {[lsearch -exact $origmsgids $msgid] == -1} { 1489 set flag add 1490 } 1491 } 1492 if {$flag == "del"} { 1493 Seq_Del $folder $seq $selmsgids 1494 } else { 1495 Seq_Add $folder $seq $selmsgids 1496 } 1497 Ftoc_ShowSequence $seq $selmsgids 1498 } 1499} 1500 1501# exmh-2.5 APIs 1502# Ftoc_ColorConfigure 1503# Ftoc_MarkSeen 1504# Ftoc_ShowUnseen 1505