Annotation of embedaddon/sqlite3/contrib/sqlitecon.tcl, revision 1.1.1.1

1.1       misho       1: # A Tk console widget for SQLite.  Invoke sqlitecon::create with a window name,
                      2: # a prompt string, a title to set a new top-level window, and the SQLite
                      3: # database handle.  For example:
                      4: #
                      5: #     sqlitecon::create .sqlcon {sql:- } {SQL Console} db
                      6: #
                      7: # A toplevel window is created that allows you to type in SQL commands to
                      8: # be processed on the spot.
                      9: #
                     10: # A limited set of dot-commands are supported:
                     11: #
                     12: #     .table
                     13: #     .schema ?TABLE?
                     14: #     .mode list|column|multicolumn|line
                     15: #     .exit
                     16: #
                     17: # In addition, a new SQL function named "edit()" is created.  This function
                     18: # takes a single text argument and returns a text result.  Whenever the
                     19: # the function is called, it pops up a new toplevel window containing a
                     20: # text editor screen initialized to the argument.  When the "OK" button
                     21: # is pressed, whatever revised text is in the text editor is returned as
                     22: # the result of the edit() function.  This allows text fields of SQL tables
                     23: # to be edited quickly and easily as follows:
                     24: #
                     25: #    UPDATE table1 SET dscr = edit(dscr) WHERE rowid=15;
                     26: #
                     27: 
                     28: 
                     29: # Create a namespace to work in
                     30: #
                     31: namespace eval ::sqlitecon {
                     32:   # do nothing
                     33: }
                     34: 
                     35: # Create a console widget named $w.  The prompt string is $prompt.
                     36: # The title at the top of the window is $title.  The database connection
                     37: # object is $db
                     38: #
                     39: proc sqlitecon::create {w prompt title db} {
                     40:   upvar #0 $w.t v
                     41:   if {[winfo exists $w]} {destroy $w}
                     42:   if {[info exists v]} {unset v}
                     43:   toplevel $w
                     44:   wm title $w $title
                     45:   wm iconname $w $title
                     46:   frame $w.mb -bd 2 -relief raised
                     47:   pack $w.mb -side top -fill x
                     48:   menubutton $w.mb.file -text File -menu $w.mb.file.m
                     49:   menubutton $w.mb.edit -text Edit -menu $w.mb.edit.m
                     50:   pack $w.mb.file $w.mb.edit -side left -padx 8 -pady 1
                     51:   set m [menu $w.mb.file.m -tearoff 0]
                     52:   $m add command -label {Close} -command "destroy $w"
                     53:   sqlitecon::create_child $w $prompt $w.mb.edit.m
                     54:   set v(db) $db
                     55:   $db function edit ::sqlitecon::_edit
                     56: }
                     57: 
                     58: # This routine creates a console as a child window within a larger
                     59: # window.  It also creates an edit menu named "$editmenu" if $editmenu!="".
                     60: # The calling function is responsible for posting the edit menu.
                     61: #
                     62: proc sqlitecon::create_child {w prompt editmenu} {
                     63:   upvar #0 $w.t v
                     64:   if {$editmenu!=""} {
                     65:     set m [menu $editmenu -tearoff 0]
                     66:     $m add command -label Cut -command "sqlitecon::Cut $w.t"
                     67:     $m add command -label Copy -command "sqlitecon::Copy $w.t"
                     68:     $m add command -label Paste -command "sqlitecon::Paste $w.t"
                     69:     $m add command -label {Clear Screen} -command "sqlitecon::Clear $w.t"
                     70:     $m add separator
                     71:     $m add command -label {Save As...} -command "sqlitecon::SaveFile $w.t"
                     72:     catch {$editmenu config -postcommand "sqlitecon::EnableEditMenu $w"}
                     73:   }
                     74:   scrollbar $w.sb -orient vertical -command "$w.t yview"
                     75:   pack $w.sb -side right -fill y
                     76:   text $w.t -font fixed -yscrollcommand "$w.sb set"
                     77:   pack $w.t -side right -fill both -expand 1
                     78:   bindtags $w.t Sqlitecon
                     79:   set v(editmenu) $editmenu
                     80:   set v(history) 0
                     81:   set v(historycnt) 0
                     82:   set v(current) -1
                     83:   set v(prompt) $prompt
                     84:   set v(prior) {}
                     85:   set v(plength) [string length $v(prompt)]
                     86:   set v(x) 0
                     87:   set v(y) 0
                     88:   set v(mode) column
                     89:   set v(header) on
                     90:   $w.t mark set insert end
                     91:   $w.t tag config ok -foreground blue
                     92:   $w.t tag config err -foreground red
                     93:   $w.t insert end $v(prompt)
                     94:   $w.t mark set out 1.0
                     95:   after idle "focus $w.t"
                     96: }
                     97: 
                     98: bind Sqlitecon <1> {sqlitecon::Button1 %W %x %y}
                     99: bind Sqlitecon <B1-Motion> {sqlitecon::B1Motion %W %x %y}
                    100: bind Sqlitecon <B1-Leave> {sqlitecon::B1Leave %W %x %y}
                    101: bind Sqlitecon <B1-Enter> {sqlitecon::cancelMotor %W}
                    102: bind Sqlitecon <ButtonRelease-1> {sqlitecon::cancelMotor %W}
                    103: bind Sqlitecon <KeyPress> {sqlitecon::Insert %W %A}
                    104: bind Sqlitecon <Left> {sqlitecon::Left %W}
                    105: bind Sqlitecon <Control-b> {sqlitecon::Left %W}
                    106: bind Sqlitecon <Right> {sqlitecon::Right %W}
                    107: bind Sqlitecon <Control-f> {sqlitecon::Right %W}
                    108: bind Sqlitecon <BackSpace> {sqlitecon::Backspace %W}
                    109: bind Sqlitecon <Control-h> {sqlitecon::Backspace %W}
                    110: bind Sqlitecon <Delete> {sqlitecon::Delete %W}
                    111: bind Sqlitecon <Control-d> {sqlitecon::Delete %W}
                    112: bind Sqlitecon <Home> {sqlitecon::Home %W}
                    113: bind Sqlitecon <Control-a> {sqlitecon::Home %W}
                    114: bind Sqlitecon <End> {sqlitecon::End %W}
                    115: bind Sqlitecon <Control-e> {sqlitecon::End %W}
                    116: bind Sqlitecon <Return> {sqlitecon::Enter %W}
                    117: bind Sqlitecon <KP_Enter> {sqlitecon::Enter %W}
                    118: bind Sqlitecon <Up> {sqlitecon::Prior %W}
                    119: bind Sqlitecon <Control-p> {sqlitecon::Prior %W}
                    120: bind Sqlitecon <Down> {sqlitecon::Next %W}
                    121: bind Sqlitecon <Control-n> {sqlitecon::Next %W}
                    122: bind Sqlitecon <Control-k> {sqlitecon::EraseEOL %W}
                    123: bind Sqlitecon <<Cut>> {sqlitecon::Cut %W}
                    124: bind Sqlitecon <<Copy>> {sqlitecon::Copy %W}
                    125: bind Sqlitecon <<Paste>> {sqlitecon::Paste %W}
                    126: bind Sqlitecon <<Clear>> {sqlitecon::Clear %W}
                    127: 
                    128: # Insert a single character at the insertion cursor
                    129: #
                    130: proc sqlitecon::Insert {w a} {
                    131:   $w insert insert $a
                    132:   $w yview insert
                    133: }
                    134: 
                    135: # Move the cursor one character to the left
                    136: #
                    137: proc sqlitecon::Left {w} {
                    138:   upvar #0 $w v
                    139:   scan [$w index insert] %d.%d row col
                    140:   if {$col>$v(plength)} {
                    141:     $w mark set insert "insert -1c"
                    142:   }
                    143: }
                    144: 
                    145: # Erase the character to the left of the cursor
                    146: #
                    147: proc sqlitecon::Backspace {w} {
                    148:   upvar #0 $w v
                    149:   scan [$w index insert] %d.%d row col
                    150:   if {$col>$v(plength)} {
                    151:     $w delete {insert -1c}
                    152:   }
                    153: }
                    154: 
                    155: # Erase to the end of the line
                    156: #
                    157: proc sqlitecon::EraseEOL {w} {
                    158:   upvar #0 $w v
                    159:   scan [$w index insert] %d.%d row col
                    160:   if {$col>=$v(plength)} {
                    161:     $w delete insert {insert lineend}
                    162:   }
                    163: }
                    164: 
                    165: # Move the cursor one character to the right
                    166: #
                    167: proc sqlitecon::Right {w} {
                    168:   $w mark set insert "insert +1c"
                    169: }
                    170: 
                    171: # Erase the character to the right of the cursor
                    172: #
                    173: proc sqlitecon::Delete w {
                    174:   $w delete insert
                    175: }
                    176: 
                    177: # Move the cursor to the beginning of the current line
                    178: #
                    179: proc sqlitecon::Home w {
                    180:   upvar #0 $w v
                    181:   scan [$w index insert] %d.%d row col
                    182:   $w mark set insert $row.$v(plength)
                    183: }
                    184: 
                    185: # Move the cursor to the end of the current line
                    186: #
                    187: proc sqlitecon::End w {
                    188:   $w mark set insert {insert lineend}
                    189: }
                    190: 
                    191: # Add a line to the history
                    192: #
                    193: proc sqlitecon::addHistory {w line} {
                    194:   upvar #0 $w v
                    195:   if {$v(historycnt)>0} {
                    196:     set last [lindex $v(history) [expr $v(historycnt)-1]]
                    197:     if {[string compare $last $line]} {
                    198:       lappend v(history) $line
                    199:       incr v(historycnt)
                    200:     }
                    201:   } else {
                    202:     set v(history) [list $line]
                    203:     set v(historycnt) 1
                    204:   }
                    205:   set v(current) $v(historycnt)
                    206: }
                    207: 
                    208: # Called when "Enter" is pressed.  Do something with the line
                    209: # of text that was entered.
                    210: #
                    211: proc sqlitecon::Enter w {
                    212:   upvar #0 $w v
                    213:   scan [$w index insert] %d.%d row col
                    214:   set start $row.$v(plength)
                    215:   set line [$w get $start "$start lineend"]
                    216:   $w insert end \n
                    217:   $w mark set out end
                    218:   if {$v(prior)==""} {
                    219:     set cmd $line
                    220:   } else {
                    221:     set cmd $v(prior)\n$line
                    222:   }
                    223:   if {[string index $cmd 0]=="." || [$v(db) complete $cmd]} {
                    224:     regsub -all {\n} [string trim $cmd] { } cmd2
                    225:     addHistory $w $cmd2
                    226:     set rc [catch {DoCommand $w $cmd} res]
                    227:     if {![winfo exists $w]} return
                    228:     if {$rc} {
                    229:       $w insert end $res\n err
                    230:     } elseif {[string length $res]>0} {
                    231:       $w insert end $res\n ok
                    232:     }
                    233:     set v(prior) {}
                    234:     $w insert end $v(prompt)
                    235:   } else {
                    236:     set v(prior) $cmd
                    237:     regsub -all {[^ ]} $v(prompt) . x
                    238:     $w insert end $x
                    239:   }
                    240:   $w mark set insert end
                    241:   $w mark set out {insert linestart}
                    242:   $w yview insert
                    243: }
                    244: 
                    245: # Execute a single SQL command.  Pay special attention to control
                    246: # directives that begin with "."
                    247: #
                    248: # The return value is the text output from the command, properly
                    249: # formatted.
                    250: #
                    251: proc sqlitecon::DoCommand {w cmd} {
                    252:   upvar #0 $w v
                    253:   set mode $v(mode)
                    254:   set header $v(header)
                    255:   if {[regexp {^(\.[a-z]+)} $cmd all word]} {
                    256:     if {$word==".mode"} {
                    257:       regexp {^.[a-z]+ +([a-z]+)} $cmd all v(mode)
                    258:       return {}
                    259:     } elseif {$word==".exit"} {
                    260:       destroy [winfo toplevel $w]
                    261:       return {}
                    262:     } elseif {$word==".header"} {
                    263:       regexp {^.[a-z]+ +([a-z]+)} $cmd all v(header)
                    264:       return {}
                    265:     } elseif {$word==".tables"} {
                    266:       set mode multicolumn
                    267:       set cmd {SELECT name FROM sqlite_master WHERE type='table'
                    268:                UNION ALL
                    269:                SELECT name FROM sqlite_temp_master WHERE type='table'}
                    270:       $v(db) eval {PRAGMA database_list} {
                    271:          if {$name!="temp" && $name!="main"} {
                    272:             append cmd "UNION ALL SELECT name FROM $name.sqlite_master\
                    273:                         WHERE type='table'"
                    274:          }
                    275:       }
                    276:       append cmd  { ORDER BY 1}
                    277:     } elseif {$word==".fullschema"} {
                    278:       set pattern %
                    279:       regexp {^.[a-z]+ +([^ ]+)} $cmd all pattern
                    280:       set mode list
                    281:       set header 0
                    282:       set cmd "SELECT sql FROM sqlite_master WHERE tbl_name LIKE '$pattern'
                    283:                AND sql NOT NULL UNION ALL SELECT sql FROM sqlite_temp_master
                    284:                WHERE tbl_name LIKE '$pattern' AND sql NOT NULL"
                    285:       $v(db) eval {PRAGMA database_list} {
                    286:          if {$name!="temp" && $name!="main"} {
                    287:             append cmd " UNION ALL SELECT sql FROM $name.sqlite_master\
                    288:                         WHERE tbl_name LIKE '$pattern' AND sql NOT NULL"
                    289:          }
                    290:       }
                    291:     } elseif {$word==".schema"} {
                    292:       set pattern %
                    293:       regexp {^.[a-z]+ +([^ ]+)} $cmd all pattern
                    294:       set mode list
                    295:       set header 0
                    296:       set cmd "SELECT sql FROM sqlite_master WHERE name LIKE '$pattern'
                    297:                AND sql NOT NULL UNION ALL SELECT sql FROM sqlite_temp_master
                    298:                WHERE name LIKE '$pattern' AND sql NOT NULL"
                    299:       $v(db) eval {PRAGMA database_list} {
                    300:          if {$name!="temp" && $name!="main"} {
                    301:             append cmd " UNION ALL SELECT sql FROM $name.sqlite_master\
                    302:                         WHERE name LIKE '$pattern' AND sql NOT NULL"
                    303:          }
                    304:       }
                    305:     } else {
                    306:       return \
                    307:         ".exit\n.mode line|list|column\n.schema ?TABLENAME?\n.tables"
                    308:     }
                    309:   }
                    310:   set res {}
                    311:   if {$mode=="list"} {
                    312:     $v(db) eval $cmd x {
                    313:       set sep {}
                    314:       foreach col $x(*) {
                    315:         append res $sep$x($col)
                    316:         set sep |
                    317:       }
                    318:       append res \n
                    319:     }
                    320:     if {[info exists x(*)] && $header} {
                    321:       set sep {}
                    322:       set hdr {}
                    323:       foreach col $x(*) {
                    324:         append hdr $sep$col
                    325:         set sep |
                    326:       }
                    327:       set res $hdr\n$res
                    328:     }
                    329:   } elseif {[string range $mode 0 2]=="col"} {
                    330:     set y {}
                    331:     $v(db) eval $cmd x {
                    332:       foreach col $x(*) {
                    333:         if {![info exists cw($col)] || $cw($col)<[string length $x($col)]} {
                    334:            set cw($col) [string length $x($col)]
                    335:         }
                    336:         lappend y $x($col)
                    337:       }
                    338:     }
                    339:     if {[info exists x(*)] && $header} {
                    340:       set hdr {}
                    341:       set ln {}
                    342:       set dash ---------------------------------------------------------------
                    343:       append dash ------------------------------------------------------------
                    344:       foreach col $x(*) {
                    345:         if {![info exists cw($col)] || $cw($col)<[string length $col]} {
                    346:            set cw($col) [string length $col]
                    347:         }
                    348:         lappend hdr $col
                    349:         lappend ln [string range $dash 1 $cw($col)]
                    350:       }
                    351:       set y [concat $hdr $ln $y]
                    352:     }
                    353:     if {[info exists x(*)]} {
                    354:       set format {}
                    355:       set arglist {}
                    356:       set arglist2 {}
                    357:       set i 0
                    358:       foreach col $x(*) {
                    359:         lappend arglist x$i
                    360:         append arglist2 " \$x$i"
                    361:         incr i
                    362:         append format "  %-$cw($col)s"
                    363:       }
                    364:       set format [string trimleft $format]\n
                    365:       if {[llength $arglist]>0} {
                    366:         foreach $arglist $y "append res \[format [list $format] $arglist2\]"
                    367:       }
                    368:     }
                    369:   } elseif {$mode=="multicolumn"} {
                    370:     set y [$v(db) eval $cmd]
                    371:     set max 0
                    372:     foreach e $y {
                    373:       if {$max<[string length $e]} {set max [string length $e]}
                    374:     }
                    375:     set ncol [expr {int(80/($max+2))}]
                    376:     if {$ncol<1} {set ncol 1}
                    377:     set nelem [llength $y]
                    378:     set nrow [expr {($nelem+$ncol-1)/$ncol}]
                    379:     set format "%-${max}s"
                    380:     for {set i 0} {$i<$nrow} {incr i} {
                    381:       set j $i
                    382:       while 1 {
                    383:         append res [format $format [lindex $y $j]]
                    384:         incr j $nrow
                    385:         if {$j>=$nelem} break
                    386:         append res {  }
                    387:       }
                    388:       append res \n
                    389:     }
                    390:   } else {
                    391:     $v(db) eval $cmd x {
                    392:       foreach col $x(*) {append res "$col = $x($col)\n"}
                    393:       append res \n
                    394:     }
                    395:   }
                    396:   return [string trimright $res]
                    397: }
                    398: 
                    399: # Change the line to the previous line
                    400: #
                    401: proc sqlitecon::Prior w {
                    402:   upvar #0 $w v
                    403:   if {$v(current)<=0} return
                    404:   incr v(current) -1
                    405:   set line [lindex $v(history) $v(current)]
                    406:   sqlitecon::SetLine $w $line
                    407: }
                    408: 
                    409: # Change the line to the next line
                    410: #
                    411: proc sqlitecon::Next w {
                    412:   upvar #0 $w v
                    413:   if {$v(current)>=$v(historycnt)} return
                    414:   incr v(current) 1
                    415:   set line [lindex $v(history) $v(current)]
                    416:   sqlitecon::SetLine $w $line
                    417: }
                    418: 
                    419: # Change the contents of the entry line
                    420: #
                    421: proc sqlitecon::SetLine {w line} {
                    422:   upvar #0 $w v
                    423:   scan [$w index insert] %d.%d row col
                    424:   set start $row.$v(plength)
                    425:   $w delete $start end
                    426:   $w insert end $line
                    427:   $w mark set insert end
                    428:   $w yview insert
                    429: }
                    430: 
                    431: # Called when the mouse button is pressed at position $x,$y on
                    432: # the console widget.
                    433: #
                    434: proc sqlitecon::Button1 {w x y} {
                    435:   global tkPriv
                    436:   upvar #0 $w v
                    437:   set v(mouseMoved) 0
                    438:   set v(pressX) $x
                    439:   set p [sqlitecon::nearestBoundry $w $x $y]
                    440:   scan [$w index insert] %d.%d ix iy
                    441:   scan $p %d.%d px py
                    442:   if {$px==$ix} {
                    443:     $w mark set insert $p
                    444:   }
                    445:   $w mark set anchor $p
                    446:   focus $w
                    447: }
                    448: 
                    449: # Find the boundry between characters that is nearest
                    450: # to $x,$y
                    451: #
                    452: proc sqlitecon::nearestBoundry {w x y} {
                    453:   set p [$w index @$x,$y]
                    454:   set bb [$w bbox $p]
                    455:   if {![string compare $bb ""]} {return $p}
                    456:   if {($x-[lindex $bb 0])<([lindex $bb 2]/2)} {return $p}
                    457:   $w index "$p + 1 char"
                    458: }
                    459: 
                    460: # This routine extends the selection to the point specified by $x,$y
                    461: #
                    462: proc sqlitecon::SelectTo {w x y} {
                    463:   upvar #0 $w v
                    464:   set cur [sqlitecon::nearestBoundry $w $x $y]
                    465:   if {[catch {$w index anchor}]} {
                    466:     $w mark set anchor $cur
                    467:   }
                    468:   set anchor [$w index anchor]
                    469:   if {[$w compare $cur != $anchor] || (abs($v(pressX) - $x) >= 3)} {
                    470:     if {$v(mouseMoved)==0} {
                    471:       $w tag remove sel 0.0 end
                    472:     }
                    473:     set v(mouseMoved) 1
                    474:   }
                    475:   if {[$w compare $cur < anchor]} {
                    476:     set first $cur
                    477:     set last anchor
                    478:   } else {
                    479:     set first anchor
                    480:     set last $cur
                    481:   }
                    482:   if {$v(mouseMoved)} {
                    483:     $w tag remove sel 0.0 $first
                    484:     $w tag add sel $first $last
                    485:     $w tag remove sel $last end
                    486:     update idletasks
                    487:   }
                    488: }
                    489: 
                    490: # Called whenever the mouse moves while button-1 is held down.
                    491: #
                    492: proc sqlitecon::B1Motion {w x y} {
                    493:   upvar #0 $w v
                    494:   set v(y) $y
                    495:   set v(x) $x
                    496:   sqlitecon::SelectTo $w $x $y
                    497: }
                    498: 
                    499: # Called whenever the mouse leaves the boundries of the widget
                    500: # while button 1 is held down.
                    501: #
                    502: proc sqlitecon::B1Leave {w x y} {
                    503:   upvar #0 $w v
                    504:   set v(y) $y
                    505:   set v(x) $x
                    506:   sqlitecon::motor $w
                    507: }
                    508: 
                    509: # This routine is called to automatically scroll the window when
                    510: # the mouse drags offscreen.
                    511: #
                    512: proc sqlitecon::motor w {
                    513:   upvar #0 $w v
                    514:   if {![winfo exists $w]} return
                    515:   if {$v(y)>=[winfo height $w]} {
                    516:     $w yview scroll 1 units
                    517:   } elseif {$v(y)<0} {
                    518:     $w yview scroll -1 units
                    519:   } else {
                    520:     return
                    521:   }
                    522:   sqlitecon::SelectTo $w $v(x) $v(y)
                    523:   set v(timer) [after 50 sqlitecon::motor $w]
                    524: }
                    525: 
                    526: # This routine cancels the scrolling motor if it is active
                    527: #
                    528: proc sqlitecon::cancelMotor w {
                    529:   upvar #0 $w v
                    530:   catch {after cancel $v(timer)}
                    531:   catch {unset v(timer)}
                    532: }
                    533: 
                    534: # Do a Copy operation on the stuff currently selected.
                    535: #
                    536: proc sqlitecon::Copy w {
                    537:   if {![catch {set text [$w get sel.first sel.last]}]} {
                    538:      clipboard clear -displayof $w
                    539:      clipboard append -displayof $w $text
                    540:   }
                    541: }
                    542: 
                    543: # Return 1 if the selection exists and is contained
                    544: # entirely on the input line.  Return 2 if the selection
                    545: # exists but is not entirely on the input line.  Return 0
                    546: # if the selection does not exist.
                    547: #
                    548: proc sqlitecon::canCut w {
                    549:   set r [catch {
                    550:     scan [$w index sel.first] %d.%d s1x s1y
                    551:     scan [$w index sel.last] %d.%d s2x s2y
                    552:     scan [$w index insert] %d.%d ix iy
                    553:   }]
                    554:   if {$r==1} {return 0}
                    555:   if {$s1x==$ix && $s2x==$ix} {return 1}
                    556:   return 2
                    557: }
                    558: 
                    559: # Do a Cut operation if possible.  Cuts are only allowed
                    560: # if the current selection is entirely contained on the
                    561: # current input line.
                    562: #
                    563: proc sqlitecon::Cut w {
                    564:   if {[sqlitecon::canCut $w]==1} {
                    565:     sqlitecon::Copy $w
                    566:     $w delete sel.first sel.last
                    567:   }
                    568: }
                    569: 
                    570: # Do a paste opeation.
                    571: #
                    572: proc sqlitecon::Paste w {
                    573:   if {[sqlitecon::canCut $w]==1} {
                    574:     $w delete sel.first sel.last
                    575:   }
                    576:   if {[catch {selection get -displayof $w -selection CLIPBOARD} topaste]
                    577:     && [catch {selection get -displayof $w -selection PRIMARY} topaste]} {
                    578:     return
                    579:   }
                    580:   if {[info exists ::$w]} {
                    581:     set prior 0
                    582:     foreach line [split $topaste \n] {
                    583:       if {$prior} {
                    584:         sqlitecon::Enter $w
                    585:         update
                    586:       }
                    587:       set prior 1
                    588:       $w insert insert $line
                    589:     }
                    590:   } else {
                    591:     $w insert insert $topaste
                    592:   }
                    593: }
                    594: 
                    595: # Enable or disable entries in the Edit menu
                    596: #
                    597: proc sqlitecon::EnableEditMenu w {
                    598:   upvar #0 $w.t v
                    599:   set m $v(editmenu)
                    600:   if {$m=="" || ![winfo exists $m]} return
                    601:   switch [sqlitecon::canCut $w.t] {
                    602:     0 {
                    603:       $m entryconf Copy -state disabled
                    604:       $m entryconf Cut -state disabled
                    605:     }
                    606:     1 {
                    607:       $m entryconf Copy -state normal
                    608:       $m entryconf Cut -state normal
                    609:     }
                    610:     2 {
                    611:       $m entryconf Copy -state normal
                    612:       $m entryconf Cut -state disabled
                    613:     }
                    614:   }
                    615: }
                    616: 
                    617: # Prompt the user for the name of a writable file.  Then write the
                    618: # entire contents of the console screen to that file.
                    619: #
                    620: proc sqlitecon::SaveFile w {
                    621:   set types {
                    622:     {{Text Files}  {.txt}}
                    623:     {{All Files}    *}
                    624:   }
                    625:   set f [tk_getSaveFile -filetypes $types -title "Write Screen To..."]
                    626:   if {$f!=""} {
                    627:     if {[catch {open $f w} fd]} {
                    628:       tk_messageBox -type ok -icon error -message $fd
                    629:     } else {
                    630:       puts $fd [string trimright [$w get 1.0 end] \n]
                    631:       close $fd
                    632:     }
                    633:   }
                    634: }
                    635: 
                    636: # Erase everything from the console above the insertion line.
                    637: #
                    638: proc sqlitecon::Clear w {
                    639:   $w delete 1.0 {insert linestart}
                    640: }
                    641: 
                    642: # An in-line editor for SQL
                    643: #
                    644: proc sqlitecon::_edit {origtxt {title {}}} {
                    645:   for {set i 0} {[winfo exists .ed$i]} {incr i} continue
                    646:   set w .ed$i
                    647:   toplevel $w
                    648:   wm protocol $w WM_DELETE_WINDOW "$w.b.can invoke"
                    649:   wm title $w {Inline SQL Editor}
                    650:   frame $w.b
                    651:   pack $w.b -side bottom -fill x
                    652:   button $w.b.can -text Cancel -width 6 -command [list set ::$w 0]
                    653:   button $w.b.ok -text OK -width 6 -command [list set ::$w 1]
                    654:   button $w.b.cut -text Cut -width 6 -command [list ::sqlitecon::Cut $w.t]
                    655:   button $w.b.copy -text Copy -width 6 -command [list ::sqlitecon::Copy $w.t]
                    656:   button $w.b.paste -text Paste -width 6 -command [list ::sqlitecon::Paste $w.t]
                    657:   set ::$w {}
                    658:   pack $w.b.cut $w.b.copy $w.b.paste $w.b.can $w.b.ok\
                    659:      -side left -padx 5 -pady 5 -expand 1
                    660:   if {$title!=""} {
                    661:     label $w.title -text $title
                    662:     pack $w.title -side top -padx 5 -pady 5
                    663:   }
                    664:   text $w.t -bg white -fg black -yscrollcommand [list $w.sb set]
                    665:   pack $w.t -side left -fill both -expand 1
                    666:   scrollbar $w.sb -orient vertical -command [list $w.t yview]
                    667:   pack $w.sb -side left -fill y
                    668:   $w.t insert end $origtxt
                    669: 
                    670:   vwait ::$w
                    671: 
                    672:   if {[set ::$w]} {
                    673:     set txt [string trimright [$w.t get 1.0 end]]
                    674:   } else {
                    675:     set txt $origtxt
                    676:   }
                    677:   destroy $w
                    678:   return $txt
                    679: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>