File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / sqlite3 / contrib / sqlitecon.tcl
Revision 1.1: download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 17:04:16 2012 UTC (12 years, 4 months ago) by misho
CVS tags: MAIN, HEAD
Initial revision

    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>