examples/sqlc.rb in rbcurse-0.1.3 vs examples/sqlc.rb in rbcurse-1.1.1
- old
+ new
@@ -1,22 +1,29 @@
-## rahul kumar, 2009
-# to demonstrate usage of rbcurse
-# Use C-q to quit
+## rkumar, 2009
+# Sample demo of various widgets and their interaction.
+# This is a simple sql client which allows table / column selection, construction
+# of SQL queries, and multiple resultsets.
+# Use C-q to quit, Alt-Tab to move out of Table to next field.
+# Please see bind_key statements in this app for some key bindings in table.
+# There are also key bindings in tabbedpanes and textarea's that will help alot.
+# This demo uses a tabbedpane so we can have the results of many sql statements and not
+# need to keep reissuing.
#
require 'rubygems'
require 'ncurses'
require 'logger'
require 'sqlite3'
require 'rbcurse'
require 'rbcurse/rcombo'
require 'rbcurse/rtextarea'
require 'rbcurse/rtable'
#require 'rbcurse/table/tablecellrenderer'
-require 'rbcurse/comboboxcellrenderer'
-require 'rbcurse/keylabelprinter'
+#require 'rbcurse/comboboxcellrenderer'
+#require 'rbcurse/keylabelprinter'
require 'rbcurse/applicationheader'
-require 'rbcurse/action'
+require 'rbcurse/action' # not used here
+require 'rbcurse/rtabbedpane'
# pls get testd.db from
# http://www.benegal.org/files/screen/testd.db
# or put some other sqlite3 db name there.
@@ -135,14 +142,14 @@
return key_labels
end
class Sqlc
def initialize
@window = VER::Window.root_window
+ $catch_alt_digits = false # we want to use Alt-1, 2 for tabs.
@form = Form.new @window
+ @tab_ctr = 0
- #@todo = Sql.new "todo.yml"
- #@todo.load
@db = Datasource.new
@db.connect "testd.db"
end
def run
title = "rbcurse"
@@ -168,27 +175,23 @@
title_attrib (Ncurses::A_REVERSE | Ncurses::A_BOLD)
help_text "Enter query and press Run or Meta-r"
end
sqlarea << "select * from contacts"
buttrow = r+ta_ht+1 #Ncurses.LINES-4
- #create_table_actions atable, todo, data, categ.getvalue
- #save_cmd = @save_cmd
b_run = Button.new @form do
text "&Run"
row buttrow
col c
help_text "Run query"
end
## We use Action to create a button: to test out ampersand with MI and Button
- #clear_act = @clear_act
b_clear = Button.new @form do
#action new_act
text "&Clear"
row buttrow
col c+10
help_text "Clear query entry box "
- #bind(:ENTER) { status_row.text "New button adds a new row below current " }
end
b_clear.command {
sqlarea.remove_all
sqlarea.focus
}
@@ -197,82 +200,73 @@
b_construct = Button.new @form do
text "Constr&uct"
row buttrow
col c+25
- #bind(:ENTER) { status_row.text "Deletes focussed row" }
help_text "Select a table, select columns and press this to construct an SQL"
end
Button.button_layout [b_run, b_clear, b_construct], buttrow, startcol=5, cols=Ncurses.COLS-1, gap=5
- table_ht = 15
- atable = Table.new @form do
- name "sqltable"
- row buttrow+1
- col c
- width t_width
- height table_ht
- #title "A Table"
- #title_attrib (Ncurses::A_REVERSE | Ncurses::A_BOLD)
- #set_data data, colnames
- #cell_editing_allowed true
- #editing_policy :EDITING_AUTO
- help_text "M-Tab for next field"
- end
- @atable = atable
+ @tp = create_tabbed_pane @form, buttrow, t_width, c
+ @tp.show
@data = data
- #atable.table_model.data = data
- tcm = atable.get_table_column_model
b_run.command {
query = sqlarea.get_text
run_query query
}
#
## key bindings fo atable
# column widths
app = self
- atable.configure() do
- #bind_key(330) { atable.remove_column(tcm.column(atable.focussed_col)) rescue "" }
- bind_key(?+) {
- acolumn = atable.column atable.focussed_col()
- w = acolumn.width + 1
- acolumn.width w
- #atable.table_structure_changed
- }
- bind_key(?-) {
- acolumn = atable.column atable.focussed_col()
- w = acolumn.width - 1
- if w > 3
- acolumn.width w
- #atable.table_structure_changed
- end
- }
- bind_key(?>) {
- colcount = tcm.column_count-1
- #atable.move_column sel_col.value, sel_col.value+1 unless sel_col.value == colcount
- col = atable.focussed_col
- atable.move_column col, col+1 unless col == colcount
- }
- bind_key(?<) {
- col = atable.focussed_col
- atable.move_column col, col-1 unless col == 0
- #atable.move_column sel_col.value, sel_col.value-1 unless sel_col.value == 0
- }
- bind_key(?\M-h, app) {|tab,td| $log.debug " BIND... #{tab.class}, #{td.class}"; app.make_popup atable}
- end
+ #atable.configure() do
+ ##bind_key(330) { atable.remove_column(tcm.column(atable.focussed_col)) rescue "" }
+ #bind_key(?+) {
+ #acolumn = atable.column atable.focussed_col()
+ #w = acolumn.width + 1
+ #acolumn.width w
+ ##atable.table_structure_changed
+ #}
+ #bind_key(?-) {
+ #acolumn = atable.column atable.focussed_col()
+ #w = acolumn.width - 1
+ #if w > 3
+ #acolumn.width w
+ ##atable.table_structure_changed
+ #end
+ #}
+ ## added new method on 2009-10-08 00:47
+ #bind_key(?=) {
+ #atable.size_columns_to_fit
+ #}
+ #bind_key(?>) {
+ #tcm = atable.get_table_column_model
+ #colcount = tcm.column_count-1
+ ##atable.move_column sel_col.value, sel_col.value+1 unless sel_col.value == colcount
+ #col = atable.focussed_col
+ #atable.move_column col, col+1 unless col == colcount
+ #}
+ #bind_key(?<) {
+ #col = atable.focussed_col
+ #atable.move_column col, col-1 unless col == 0
+ ##atable.move_column sel_col.value, sel_col.value-1 unless sel_col.value == 0
+ #}
+ ## TODO popup and key labels
+ #bind_key(?\M-h, app) {|tab,td| $log.debug " BIND... #{tab.class}, #{td.class}"; app.make_popup atable}
+ #end
#keylabel = RubyCurses::Label.new @form, {'text' => "", "row" => r+table_ht+3, "col" => c, "color" => "yellow", "bgcolor"=>"blue", "display_length"=>60, "height"=>2}
#eventlabel = RubyCurses::Label.new @form, {'text' => "Events:", "row" => r+table_ht+6, "col" => c, "color" => "white", "bgcolor"=>"blue", "display_length"=>60, "height"=>2}
# report some events
#atable.table_model.bind(:TABLE_MODEL_EVENT){|e| #eventlabel.text = "Event: #{e}"}
#atable.get_table_column_model.bind(:TABLE_COLUMN_MODEL_EVENT){|e| eventlabel.text = "Event: #{e}"}
- atable.bind(:TABLE_TRAVERSAL_EVENT){|e| @header.text_right "Row #{e.newrow+1} of #{atable.row_count}" }
tablist_ht = 6
mylist = @db.get_data "select name from sqlite_master"
+ # mylist is an Array of SQLite3::ResultSet::ArrayWithTypesAndFields
+ mylist.collect!{|x| x[0] } ## 1.9 hack, but will it run on 1.8 ??
$listdata = Variable.new mylist
tablelist = Listbox.new @form do
name "tablelist"
row 1
col t_width+2
@@ -303,33 +297,39 @@
#show_selector true
title "Columns"
title_attrib 'reverse'
help_text "Press ENTER to append columns to sqlarea, Space to select"
end
+ ## pressing SPACE on a table populates column list with its columns so they can be selected
tablelist.bind_key(32) {
@status_row.text = "Selected #{tablelist.get_content()[tablelist.current_index]}"
table = "#{tablelist.get_content()[tablelist.current_index]}"
+ ##table = table[0] if table.class==Array ## 1.9 ???
columnlist.list_data_model.remove_all
columnlist.list_data_model.insert 0, *@db.get_metadata(table)
}
+ ## pressing ENTER on a table runs a query on it, no need to type and SQL
tablelist.bind_key(13) {
@status_row.text = "Selected #{tablelist.get_content()[tablelist.current_index]}"
table = "#{tablelist.get_content()[tablelist.current_index]}"
+ ##table = table[0] if table.class==Array ## 1.9 ???
run_query "select * from #{table}"
}
columnlist.bind_key(13) {
- # append column name to sqlarea if ENTER pressed
+ ## append column name to sqlarea if ENTER pressed
column = "#{columnlist.get_content()[columnlist.current_index]}"
sqlarea << "#{column},"
}
columnlist.bind_key(32) {
- # select row
+ ## select row - later can press Construct button
columnlist.toggle_row_selection
column = "#{columnlist.get_content()[columnlist.current_index]}"
}
+ ## construct an SQL after selecting some columns in the column list
b_construct.command {
table = "#{tablelist.get_content()[tablelist.current_index]}"
+ #table = table[0] if table.class==Array ## 1.9 ???
indexes = columnlist.selected_rows()
columns=[]
indexes.each do |i|
columns << columnlist.get_content()[i]
end
@@ -340,80 +340,71 @@
@form.repaint
@window.wrefresh
Ncurses::Panel.update_panels
begin
- while((ch = @window.getchar()) != ?\C-q )
- #colcount = tcm.column_count-1
+ while((ch = @window.getchar()) != ?\C-q.getbyte(0) )
s = keycode_tos ch
- #status_row.text = "Pressed #{ch} , #{s}"
+ status_row.text = "Pressed #{ch} , #{s}. Press C-q to quit, Alt-Tab for exiting table "
@form.handle_key(ch)
@form.repaint
@window.wrefresh
end
ensure
@window.destroy if !@window.nil?
end
end
+ ## execute the query in the textarea
+ # @param [String] sql string
def run_query sql
#query = sqlarea.get_text
query = sql
begin
@content = @db.get_data query
if @content.nil?
@status_row.text = "0 rows retrieved"
return
end
#cw = @db.estimate_column_widths @atable.width, @db.columns
- @atable.set_data @content, @db.columns
- cw = @atable.estimate_column_widths @db.columns, @db.datatypes
- @atable.set_column_widths cw
+ atable = create_table @tp, @tab_ctr #, buttrow, t_width, c
+ atable.set_data @content, @db.columns
+ cw = atable.estimate_column_widths @db.columns, @db.datatypes
+ atable.set_column_widths cw
rescue => exc
+ $log.debug(exc.backtrace.join("\n"))
alert exc.to_s
return
end
@status_row.text = "#{@content.size} rows retrieved"
- @atable.repaint
+ atable.repaint
end
- def create_table_actions atable, todo, data, categ
- #@new_act = Action.new("New Row", "mnemonic"=>"N") {
- @new_act = Action.new("&New Row") {
- mod = nil
- cc = atable.get_table_column_model.column_count
- if atable.row_count < 1
- frow = 0
- else
- frow = atable.focussed_row
- #frow += 1 # why ?
- mod = atable.get_value_at(frow,0) unless frow.nil?
+ ## create a Table component for populating with data
+ def create_table tp, counter #, buttrow, t_width, c
+ table_ht = 15
+ atable = Table.new do
+ name "sqltable#{counter}"
+ #cell_editing_allowed true
+ #editing_policy :EDITING_AUTO
+ #help_text "M-Tab for next field, M-8 amd M-7 for horiz scroll, + to resize, C-q quit"
+ help_text "M-Tab for next field, C-q quit"
+ end
+ atable.bind(:TABLE_TRAVERSAL_EVENT){|e| @header.text_right "Row #{e.newrow+1} of #{atable.row_count}" }
+ @tab_ctr += 1
+ tab1 = tp.add_tab "Tab&#{@tab_ctr}" , atable
+ return atable
+ end
+ ## create the single tabbedpane for populating with resultsets
+ def create_tabbed_pane form, buttrow, t_width, c
+ tp = RubyCurses::TabbedPane.new form do
+ height 16
+ width t_width
+ row buttrow +1
+ col c
+ button_type :ok
end
- tmp = [mod, 5, "", "TODO", Time.now]
- tm = atable.table_model
- tm.insert frow, tmp
- atable.set_focus_on frow
- @status_row.text = "Added a row. Please press Save before changing Category."
- alert("Added a row before current one. Use C-k to clear task.")
- }
- @new_act.accelerator "Alt-N"
- @save_cmd = lambda {
- todo.set_tasks_for_category categ, data
- todo.dump
- alert("Rewritten yaml file")
- }
- @del_cmd = lambda {
- row = atable.focussed_row
- if !row.nil?
- if confirm("Do your really want to delete row #{row+1}?")== :YES
- tm = atable.table_model
- tm.delete_at row
- else
- @status_row.text = "Delete cancelled"
- end
- end
- }
-
+ return tp
end
end
if $0 == __FILE__
include RubyCurses
include RubyCurses::Utils
@@ -423,10 +414,10 @@
VER::start_ncurses # this is initializing colors via ColorMap.setup
$log = Logger.new("view.log")
$log.level = Logger::DEBUG
colors = Ncurses.COLORS
- $log.debug "START #{colors} colors ---------"
+ $log.debug "START #{colors} colors SQLC demo "
catch(:close) do
t = Sqlc.new
t.run
end