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