AndroWish and SQLite

GCS - 2014-02-18

My first use for AndroWish on my phone is to be able to check on data I keep in SQLite databases. I cannot use any of the available Android tools because one of my tables uses a custom collation defined in Tcl.

I will be using this wiki page to publish my code. Currently all it does is show the schema of an attached database file in a Tktable. The next step will involve examining the data in one of its tables.

The code does react to orientation changes via the <Configure> event. Here are screen captures: and , using an SQLite fossil database from a few months ago.

package require Tktable
# The [catch] below is a workaround for the bug in Galileo Galilei supplying 3.8.3.1 instead of 3.8.3
catch {package require sqlite3}

namespace path ::tcl::mathop

catch {font create myfont -family courier -size 10}

wm attributes . -fullscreen 1

# Create a Tktable for display of an attached file's schema
proc maketable {attachedname} {
        global tableinfo
        destroy {*}[winfo children .]
         set f [filename2widgetname $attachedname]
         set tableinfo(framename,$attachedname) $f
         pack [frame $f ] -padx 5 -pady 5
         set t $f.t
        table $t  -cols [expr {$::tableinfo(maxnumcols,$attachedname)+2}] -rows [expr {$::tableinfo(numtables,$attachedname)+1}] \
        -titlecols 1 -titlerows 1 -font myfont -command [list filltable %i %r %c %s $attachedname] -anchor w \
        -xscrollcommand [list ${t}sx set] -yscrollcommand [list ${t}sy set] -height 0 -width 0 -ipadx 4
        $t tag col entries 1
        $t tag configure entries -anchor e
        $t width 0 18
        scrollbar ${t}sy -orient vert -width 30 -command [list $t yview]
        scrollbar ${t}sx -orient horiz -width 30 -command [list $t xview]
        grid  $t  ${t}sy -sticky nsew
        grid ${t}sx -sticky new
        grid columnconfigure $f 0 -weight 1        
}

# Redraw the table (and enclosing frame) when the orientation is changed
#   Assumes the table widget is named xxxxxx.t and is enclosed in a frame
proc frameconfig tablewidget {
        if {[string range $tablewidget end-1 end] ne ".t"} return
                array set metrics [borg displaymetrics]
                set w [- $metrics(width) 10]
                set h [- $metrics(height) 10]
                [string range $tablewidget 0 end-2] configure -width $w -height  $h 
                $tablewidget configure -maxwidth [- $w 30] -maxheight [- $h 30] -width 0 -height 0
}

# Called by tktable innards to get values to show with display colnum & rownum
proc filltable { iswrite rownum colnum tblval attachedname}  {
    set retval {}
        if { ! $iswrite} {
        if {$rownum == 0} {
            switch $colnum \
                0 {set retval Table} \
                1 {set retval Entries} \
                default {set retval "F [expr $colnum - 1]"}
        } else {
            set rownum [expr {$rownum-1}]
            set tablename $::tableinfo(tablename,$attachedname,$rownum)
            if {$colnum == 0} {set retval $tablename}
            if {$colnum == 1} {set retval $::tableinfo(numentries,$attachedname,$tablename)}
            if {$colnum > 1 && $colnum <= $::tableinfo(numcols,$attachedname,$tablename)+1} {set retval $::tableinfo(colname,$attachedname,$tablename,[expr {$colnum - 1}]) }
            }
        }
    return $retval
}

# Attach a file and set up tableinfo global array
proc attachfile {filename attachedname} {
        global tableinfo
        db eval "attach \"$filename\"  as $attachedname"
        set tablesql_list [db eval "select sql from $attachedname.sqlite_master where type = 'table'"]
        set tableinfo(numtables,$attachedname) [llength $tablesql_list]
        set tablenum 0
        set tableinfo(maxnumcols,$attachedname) 0
        foreach tablesql $tablesql_list {
                regsub -nocase {create table } $tablesql {} tablesql
                regsub -all { +} $tablesql { } tablesql] 
                scan $tablesql {%[^(]%[^!]} tablename tabledef
                set tableinfo(tablename,$attachedname,$tablenum) $tablename
                set tableinfo(tablenum,$attachedname,$tablename) $tablenum
                set tableinfo(tabledef,$attachedname,$tablename) $tabledef
                set tableinfo(numentries,$attachedname,$tablename) [db eval "select count(*) from $attachedname.$tablename"]
            set colnum 0
            regexp {\((.*)\)} $tabledef -> tabledefguts
                foreach coldef [splitcols $tabledefguts] {
                        set isconstraint [regexp -nocase {^unique|^check|^primary key|^not null|^default|^collate|^references} $coldef]
                        if {$isconstraint} {
                                lappend tableinfo(constraint,$attachedname,$tablename) $coldef
                                
                        } else {
                                incr colnum
                                set colname [coldef2colname $coldef]
                                set tableinfo(colname,$attachedname,$tablename,$colnum) $colname
                                set tableinfo(colnum,$attachedname,$tablename,$colname) $colnum
                        }
                }
                set tableinfo(numcols,$attachedname,$tablename) $colnum
                set tableinfo(maxnumcols,$attachedname) [lindex [lsort -integer -decreasing [list $colnum $tableinfo(maxnumcols,$attachedname)]] 0]
            incr tablenum
        }
}

# Split a table definition at any comma not inside parentheses and return the list of column defs
proc splitcols tabledef {
    set collist [list]
    set colstring ""
    set parendepth 0
    foreach char [split $tabledef {}] {
        if {$char eq "("} {
            incr parendepth
            } elseif {$char eq ")"} {
                incr parendepth -1
            }
        if {$char ne "," || $parendepth > 0} {
            append colstring $char
        } else {
            lappend collist [string trim $colstring]
            set colstring ""
        }
    }
    lappend collist [string trim $colstring]
    return $collist
}   
        
# Ignore comments at the beginning of a column definition
proc coldef2colname coldef {
    foreach line [split $coldef \n] {
        if {[string range $line 0 1] ne "--"} {
            set colname [lindex $line 0]
            break
        }
    }
    return $colname
} 


# Convert attached name of file to frame name
proc filename2widgetname filename {
        return .$filename
}

global tableinfo

sqlite3 db main.sq3

set filename [tk_getOpenFile]

if {$filename eq ""} return

set attachedname _[file rootname [file tail $filename]]

attachfile $filename $attachedname

set t [filename2widgetname $attachedname]

maketable  $attachedname

bind . <Configure> {
        frameconfig %W
}

Superlinux - 2014-06-19 16:01:16

You may test the first published Androwish app on Google Play store named CashierTclTk It has some logical bugs which I might not fix in the near future. I made a Java/Android app instead named it "LebanesePos(Free)". You may find and download the code of CashierTclTk here