rbcurse 1.3.0 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG +33 -0
- data/README.markdown +7 -1
- data/TODO2.txt +21 -15
- data/VERSION +1 -1
- data/examples/abasiclist.rb +2 -2
- data/examples/alpmenu.rb +1 -1
- data/examples/app.rb +0 -1
- data/examples/appdirtree.rb +4 -2
- data/examples/appemail.rb +7 -3
- data/examples/appemaillb.rb +1 -1
- data/examples/appgcompose.rb +2 -2
- data/examples/appgmail.rb +1 -1
- data/examples/appmethods.rb +20 -2
- data/examples/atree.rb +9 -1
- data/examples/dbdemo.rb +460 -0
- data/examples/dirtree.rb +1 -1
- data/examples/menu1.rb +37 -5
- data/examples/multispl.rb +1 -1
- data/examples/rfe.rb +9 -2
- data/examples/splitp.rb +1 -1
- data/examples/sqlc.rb +6 -10
- data/examples/sqlm.rb +2 -20
- data/examples/sqlt.rb +408 -0
- data/examples/term2.rb +1 -1
- data/examples/test2.rb +169 -97
- data/examples/testapp.rb +1 -1
- data/examples/testapp2.rb +1 -1
- data/examples/testkeypress.rb +4 -2
- data/examples/testtable.rb +6 -0
- data/examples/testtpane.rb +35 -23
- data/examples/testvimsplit.rb +3 -2
- data/lib/rbcurse.rb +1 -1
- data/lib/rbcurse/action.rb +8 -0
- data/lib/rbcurse/app.rb +39 -23
- data/lib/rbcurse/extras/bottomline.rb +101 -13
- data/lib/rbcurse/extras/directorylist.rb +14 -5
- data/lib/rbcurse/extras/divider.rb +1 -1
- data/lib/rbcurse/extras/listselectable.rb +42 -8
- data/lib/rbcurse/extras/masterdetail.rb +2 -2
- data/lib/rbcurse/extras/scrollbar.rb +11 -2
- data/lib/rbcurse/extras/statusline.rb +56 -0
- data/lib/rbcurse/extras/stdscrwindow.rb +11 -0
- data/lib/rbcurse/extras/tabular.rb +2 -1
- data/lib/rbcurse/extras/tabularwidget.rb +60 -17
- data/lib/rbcurse/extras/viewer.rb +16 -4
- data/lib/rbcurse/keylabelprinter.rb +34 -4
- data/lib/rbcurse/listeditable.rb +5 -1
- data/lib/rbcurse/listkeys.rb +1 -1
- data/lib/rbcurse/listscrollable.rb +15 -8
- data/lib/rbcurse/rbasiclistbox.rb +44 -23
- data/lib/rbcurse/rcommandwindow.rb +8 -14
- data/lib/rbcurse/rdialogs.rb +187 -2
- data/lib/rbcurse/rlistbox.rb +38 -19
- data/lib/rbcurse/rmenu.rb +313 -93
- data/lib/rbcurse/rmessagebox.rb +3 -2
- data/lib/rbcurse/rmulticontainer.rb +5 -3
- data/lib/rbcurse/rmultisplit.rb +2 -11
- data/lib/rbcurse/rmultitextview.rb +4 -5
- data/lib/rbcurse/rtabbedpane.rb +223 -69
- data/lib/rbcurse/rtable.rb +6 -10
- data/lib/rbcurse/rtextarea.rb +57 -36
- data/lib/rbcurse/rtextview.rb +12 -15
- data/lib/rbcurse/rtree.rb +79 -22
- data/lib/rbcurse/rvimsplit.rb +16 -25
- data/lib/rbcurse/rwidget.rb +376 -523
- data/lib/rbcurse/tree/treecellrenderer.rb +24 -11
- data/lib/rbcurse/tree/treemodel.rb +1 -1
- data/lib/ver/window.rb +130 -66
- metadata +5 -3
- data/examples/term.rb +0 -48
data/examples/dirtree.rb
CHANGED
@@ -11,7 +11,7 @@ def _directories wd
|
|
11
11
|
return ent
|
12
12
|
end
|
13
13
|
App.new do
|
14
|
-
header = app_header "rbcurse
|
14
|
+
header = app_header "rbcurse #{Rbcurse::VERSION}", :text_center => "Yet Another File Manager", :text_right =>"Directory Lister", :color => :black, :bgcolor => :white#, :attr => Ncurses::A_BLINK
|
15
15
|
message "Press Enter to expand/collapse"
|
16
16
|
|
17
17
|
pwd = Dir.getwd
|
data/examples/menu1.rb
CHANGED
@@ -4,7 +4,9 @@ require 'rbcurse/app'
|
|
4
4
|
App.new do
|
5
5
|
#title "Demo of Menu - rbcurse"
|
6
6
|
#subtitle "Hit F1 to quit, F2 for menubar toggle"
|
7
|
-
header = app_header "rbcurse
|
7
|
+
header = app_header "rbcurse #{Rbcurse::VERSION}", :text_center => "Menubar Demo", :text_right =>"enabled"
|
8
|
+
form = @form
|
9
|
+
mylabel = "a field"
|
8
10
|
|
9
11
|
# TODO accelerators and
|
10
12
|
# getting a handle for later use
|
@@ -12,13 +14,36 @@ require 'rbcurse/app'
|
|
12
14
|
#@toggle_key=KEY_F2
|
13
15
|
menu "File" do
|
14
16
|
item "Open", "O" do
|
15
|
-
|
17
|
+
accelerator "Ctrl-O"
|
18
|
+
command do
|
16
19
|
alert "HA!! you wanted to open a file?"
|
17
20
|
end
|
18
21
|
end
|
22
|
+
menu "QuickOpen" do
|
23
|
+
item_list do
|
24
|
+
Dir.glob("*.rb")
|
25
|
+
end
|
26
|
+
command do |menuitem, text|
|
27
|
+
#alert " We gots #{text} "
|
28
|
+
fld = form.by_name[mylabel]
|
29
|
+
fld.text =text
|
30
|
+
end
|
31
|
+
end
|
32
|
+
menu "Close" do
|
33
|
+
item_list do
|
34
|
+
Dir.glob("t*.rb")
|
35
|
+
end
|
36
|
+
end
|
19
37
|
item "New", "N"
|
20
38
|
separator
|
21
|
-
item "
|
39
|
+
item "Exit", "x" do
|
40
|
+
command do
|
41
|
+
throw(:close)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
item "Cancel Menu" do
|
45
|
+
accelerator "Ctrl-g"
|
46
|
+
end
|
22
47
|
|
23
48
|
end # menu
|
24
49
|
menu "Window" do
|
@@ -31,13 +56,20 @@ require 'rbcurse/app'
|
|
31
56
|
alert "You clickses on Less"
|
32
57
|
end
|
33
58
|
end
|
59
|
+
menu "Size" do
|
60
|
+
item "Zoom", "Z"
|
61
|
+
item "Maximize", "X"
|
62
|
+
item "Minimize", "N"
|
63
|
+
end
|
34
64
|
end
|
35
65
|
end
|
36
66
|
end # menubar
|
37
67
|
mb.toggle_key = FFI::NCurses::KEY_F2
|
68
|
+
mb.color = :white
|
69
|
+
mb.bgcolor = :blue
|
38
70
|
@form.set_menu_bar mb
|
39
71
|
stack :margin_top => 10, :margin => 5 do
|
40
|
-
field
|
72
|
+
field mylabel, :attr => 'reverse', :block_event => :CHANGE do |e|
|
41
73
|
message e.to_s
|
42
74
|
|
43
75
|
case e.text
|
@@ -53,7 +85,7 @@ require 'rbcurse/app'
|
|
53
85
|
end
|
54
86
|
@adock = nil
|
55
87
|
keyarray = [
|
56
|
-
["
|
88
|
+
["F10" , "Exit"], nil,
|
57
89
|
["F2", "Menu"], nil,
|
58
90
|
["M-e", "Disable"], ["M-x", "XXXX"],
|
59
91
|
["C-?", "Help"], nil
|
data/examples/multispl.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'rbcurse/app'
|
2
2
|
|
3
3
|
App.new do
|
4
|
-
header = app_header "rbcurse
|
4
|
+
header = app_header "rbcurse #{Rbcurse::VERSION}", :text_center => "MultiSplit Demo", :text_right =>"ColumnBrowse pattern"
|
5
5
|
message_row(27)
|
6
6
|
message "<TAB> and <BTAB> "
|
7
7
|
oo = :HORIZONTAL_SPLIT
|
data/examples/rfe.rb
CHANGED
@@ -468,15 +468,20 @@ class RFe
|
|
468
468
|
end
|
469
469
|
end
|
470
470
|
## TODO : make this separate and callable with its own keylabels
|
471
|
-
def view content=nil
|
471
|
+
def view content=nil # can throw IO errors
|
472
472
|
require 'rbcurse/rtextview'
|
473
473
|
wt = 0
|
474
474
|
wl = 0
|
475
475
|
wh = Ncurses.LINES-wt
|
476
476
|
ww = Ncurses.COLS-wl
|
477
477
|
if content.nil?
|
478
|
+
begin
|
478
479
|
fp = @current_list.filepath
|
479
480
|
content = get_contents(fp)
|
481
|
+
rescue => err
|
482
|
+
alert err.to_s
|
483
|
+
return
|
484
|
+
end
|
480
485
|
else
|
481
486
|
fp=""
|
482
487
|
end
|
@@ -506,6 +511,8 @@ class RFe
|
|
506
511
|
@v_form.repaint
|
507
512
|
##@v_window.wrefresh
|
508
513
|
end
|
514
|
+
rescue => err
|
515
|
+
alert err.to_s
|
509
516
|
ensure
|
510
517
|
@v_window.destroy if !@v_window.nil?
|
511
518
|
end
|
@@ -544,7 +551,7 @@ class RFe
|
|
544
551
|
str= "view #{fp}"
|
545
552
|
#if confirm("#{str}")==:YES
|
546
553
|
$log.debug " VIEW #{fp}"
|
547
|
-
view
|
554
|
+
view
|
548
555
|
#end
|
549
556
|
when 'r'
|
550
557
|
str= "ruby #{fn}"
|
data/examples/splitp.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'rbcurse/app'
|
2
2
|
|
3
3
|
App.new do
|
4
|
-
header = app_header "rbcurse
|
4
|
+
header = app_header "rbcurse #{Rbcurse::VERSION}", :text_center => "Splitpane Demo", :text_right =>""
|
5
5
|
message_row(27)
|
6
6
|
message "<TAB> between outer panes, Alt-W between inner tabs, Alt-TAb to exit Splitpane"
|
7
7
|
|
data/examples/sqlc.rb
CHANGED
@@ -1,13 +1,14 @@
|
|
1
1
|
## rkumar, 2009
|
2
|
-
#DEPRECATED. See sqlm.rb
|
2
|
+
#DEPRECATED. See sqlm.rb or sqlt.rb in which i use a TabularWidget instead of Table.
|
3
3
|
#AVOID USING TabbedPane till its rewritten 1.3.2 or so.
|
4
|
-
|
4
|
+
|
5
5
|
#
|
6
6
|
############ WARNING ##############################################################
|
7
7
|
# TabbedPanes seem to have stopped displaying at some points
|
8
8
|
# after moving to FFI-Ncurses. And i've not been able to locate the point.
|
9
9
|
# This is one subtle difference between ncurses and ffi-ncurses.
|
10
10
|
# So i will scrap this and do a fresh clean rewrite of TabbedPane class.
|
11
|
+
# OKAY I've got them fixed.
|
11
12
|
#
|
12
13
|
###################################################################################
|
13
14
|
# Sample demo of various widgets and their interaction.
|
@@ -17,11 +18,9 @@
|
|
17
18
|
# Please see bind_key statements in this app for some key bindings in table.
|
18
19
|
# There are also key bindings in tabbedpanes and textarea's that will help alot.
|
19
20
|
# This demo uses a tabbedpane so we can have the results of many sql statements and not
|
20
|
-
# need to keep reissuing.
|
21
|
-
#
|
21
|
+
# need to keep reissuing. Its better to use a multitextview or multicontainer
|
22
|
+
# than a tabbedpane for such use.
|
22
23
|
#
|
23
|
-
require 'rubygems'
|
24
|
-
#require 'ncurses' # FFI
|
25
24
|
require 'logger'
|
26
25
|
require 'sqlite3'
|
27
26
|
require 'rbcurse'
|
@@ -168,7 +167,7 @@ class Sqlc
|
|
168
167
|
end
|
169
168
|
def run
|
170
169
|
title = "rbcurse"
|
171
|
-
@header = ApplicationHeader.new @form, title, {:text2=>"Demo", :text_center=>"SQL Client
|
170
|
+
@header = ApplicationHeader.new @form, title, {:text2=>"Demo", :text_center=>"SQL Client using TabbedPane and Table (see sqlm.rb instead) "}
|
172
171
|
status_row = RubyCurses::Label.new @form, {'text' => "", :row => Ncurses.LINES-4, :col => 0, :display_length=>70}
|
173
172
|
@status_row = status_row
|
174
173
|
# setting ENTER across all objects on a form
|
@@ -405,9 +404,6 @@ class Sqlc
|
|
405
404
|
table_ht = 15
|
406
405
|
atable = Table.new do
|
407
406
|
name "sqltable#{counter}"
|
408
|
-
#cell_editing_allowed true
|
409
|
-
#editing_policy :EDITING_AUTO
|
410
|
-
#help_text "M-Tab for next field, M-8 amd M-7 for horiz scroll, + to resize, C-q quit"
|
411
407
|
help_text "M-Tab for next field, C-q quit"
|
412
408
|
end
|
413
409
|
atable.bind(:TABLE_TRAVERSAL_EVENT){|e| @header.text_right "Row #{e.newrow+1} of #{atable.row_count}" }
|
data/examples/sqlm.rb
CHANGED
@@ -125,24 +125,6 @@ class Datasource
|
|
125
125
|
end
|
126
126
|
|
127
127
|
end
|
128
|
-
def get_key_labels
|
129
|
-
key_labels = [
|
130
|
-
['C-q', 'Exit'], nil,
|
131
|
-
['M-s', 'Save'], ['M-m', 'Move']
|
132
|
-
]
|
133
|
-
return key_labels
|
134
|
-
end
|
135
|
-
def get_key_labels_table
|
136
|
-
key_labels = [
|
137
|
-
['M-n','NewRow'], ['M-d','DelRow'],
|
138
|
-
['C-x','Select'], nil,
|
139
|
-
['M-0', 'Top'], ['M-9', 'End'],
|
140
|
-
['C-p', 'PgUp'], ['C-n', 'PgDn'],
|
141
|
-
['M-Tab','Nxt Fld'], ['Tab','Nxt Col'],
|
142
|
-
['+','Widen'], ['-','Narrow']
|
143
|
-
]
|
144
|
-
return key_labels
|
145
|
-
end
|
146
128
|
class Sqlc
|
147
129
|
def initialize
|
148
130
|
@window = VER::Window.root_window
|
@@ -175,7 +157,7 @@ class Sqlc
|
|
175
157
|
height ta_ht
|
176
158
|
title "Sql Query"
|
177
159
|
title_attrib (Ncurses::A_REVERSE | Ncurses::A_BOLD)
|
178
|
-
help_text "Enter query and press Run or Meta-r"
|
160
|
+
help_text "Enter query and press Run or Meta-r. Ctrl-q to quit"
|
179
161
|
end
|
180
162
|
sqlarea << "select * from contacts"
|
181
163
|
buttrow = r+ta_ht+1 #Ncurses.LINES-4
|
@@ -352,7 +334,7 @@ class Sqlc
|
|
352
334
|
while((ch = @window.getchar()) != ?\C-q.getbyte(0) )
|
353
335
|
break if ch == KEY_F1
|
354
336
|
s = keycode_tos ch
|
355
|
-
status_row.text = "
|
337
|
+
status_row.text = "C-q to quit, Alt-Tab to exit table, Alt-: for buffers. Alt-N/P next/previous "
|
356
338
|
@form.handle_key(ch)
|
357
339
|
|
358
340
|
@form.repaint
|
data/examples/sqlt.rb
ADDED
@@ -0,0 +1,408 @@
|
|
1
|
+
## rkumar, 2009
|
2
|
+
#AVOID USING TabbedPane till its rewritten 1.3.2 or so.
|
3
|
+
#You will have to press a downarrow or any key if the pane goes blank.
|
4
|
+
#
|
5
|
+
# Sample demo of various widgets and their interaction.
|
6
|
+
# This is a simple sql client which allows table / column selection, construction
|
7
|
+
# of SQL queries, and multiple resultsets.
|
8
|
+
# Use C-q to quit, Alt-Tab to move out of Table to next field.
|
9
|
+
# Please see bind_key statements in this app for some key bindings in table.
|
10
|
+
# There are also key bindings in tabbedpanes and textarea's that will help alot.
|
11
|
+
# This demo uses a tabbedpane so we can have the results of many sql statements and not
|
12
|
+
# need to keep reissuing. The tabbed pane SUCKS, if you get in when not populated
|
13
|
+
# you GET STUCK so press Alt-C to get out.
|
14
|
+
#
|
15
|
+
require 'logger'
|
16
|
+
require 'sqlite3'
|
17
|
+
require 'rbcurse'
|
18
|
+
require 'rbcurse/rcombo'
|
19
|
+
require 'rbcurse/rtextarea'
|
20
|
+
require 'rbcurse/rtable'
|
21
|
+
#require 'rbcurse/table/tablecellrenderer'
|
22
|
+
#require 'rbcurse/comboboxcellrenderer'
|
23
|
+
#require 'rbcurse/keylabelprinter'
|
24
|
+
require 'rbcurse/applicationheader'
|
25
|
+
require 'rbcurse/action' # not used here
|
26
|
+
require 'rbcurse/rtabbedpane'
|
27
|
+
require 'rbcurse/extras/tabularwidget'
|
28
|
+
|
29
|
+
# pls get testd.db from
|
30
|
+
# http://www.benegal.org/files/screen/testd.db
|
31
|
+
# or put some other sqlite3 db name there.
|
32
|
+
# or create using sqlite3 testd.db < data.txt
|
33
|
+
|
34
|
+
## must give me @content, @columns, @datatypes (opt)
|
35
|
+
class Datasource
|
36
|
+
# attr_reader :field_length # specified by user, length of row in display table
|
37
|
+
attr_accessor :columns # names of columns in array
|
38
|
+
attr_accessor :datatypes # array of datatyps of columns required to align: int, real, float, smallint
|
39
|
+
attr_accessor :content # 2 dim data
|
40
|
+
attr_accessor :user_columns # columnnames provided by user, overrides what is generated for display
|
41
|
+
# attr_reader :sqlstring # specified by user
|
42
|
+
|
43
|
+
# constructor
|
44
|
+
def initialize(config={}, &block)
|
45
|
+
@content = []
|
46
|
+
@columns = nil # actual db columnnames -- needed to figure out datatypes
|
47
|
+
@user_columns = nil # user specified db columnnames, overrides what may be provided
|
48
|
+
@datatypes = nil
|
49
|
+
# @rows = nil
|
50
|
+
# @sqlstring = nil
|
51
|
+
# @command = nil
|
52
|
+
|
53
|
+
instance_eval(&block) if block_given?
|
54
|
+
end
|
55
|
+
def connect dbname
|
56
|
+
raise " #{dbname} does not exist. Please fetch from http://www.benegal.org/files/screen/testd.db" if !File.exists?(dbname)
|
57
|
+
@db = SQLite3::Database.new(dbname)
|
58
|
+
end
|
59
|
+
# get columns and datatypes, prefetch
|
60
|
+
def get_data command
|
61
|
+
@columns, *rows = @db.execute2(command)
|
62
|
+
$log.debug "XXX COLUMNS #{command} : #{@columns.count}: #{@columns} "
|
63
|
+
@content = rows
|
64
|
+
return nil if @content.nil? or @content[0].nil?
|
65
|
+
@datatypes = @content[0].types #if @datatypes.nil?
|
66
|
+
@command = command
|
67
|
+
return @content
|
68
|
+
end
|
69
|
+
def get_metadata table
|
70
|
+
get_data "select * from #{table} limit 1"
|
71
|
+
return @columns
|
72
|
+
end
|
73
|
+
##
|
74
|
+
# returns columns_widths, and updates that variable
|
75
|
+
def estimate_column_widths tablewidth, columns
|
76
|
+
colwidths = {}
|
77
|
+
min_column_width = (tablewidth/columns.length) -1
|
78
|
+
$log.debug("min: #{min_column_width}, #{tablewidth}")
|
79
|
+
@content.each_with_index do |row, cix|
|
80
|
+
break if cix >= 20
|
81
|
+
row.each_index do |ix|
|
82
|
+
col = row[ix]
|
83
|
+
colwidths[ix] ||= 0
|
84
|
+
colwidths[ix] = [colwidths[ix], col.length].max
|
85
|
+
end
|
86
|
+
end
|
87
|
+
total = 0
|
88
|
+
colwidths.each_pair do |k,v|
|
89
|
+
name = columns[k.to_i]
|
90
|
+
colwidths[name] = v
|
91
|
+
total += v
|
92
|
+
end
|
93
|
+
colwidths["__TOTAL__"] = total
|
94
|
+
column_widths = colwidths
|
95
|
+
@max_data_widths = column_widths.dup
|
96
|
+
|
97
|
+
columns.each_with_index do | col, i|
|
98
|
+
if @datatypes[i].match(/(real|int)/) != nil
|
99
|
+
wid = column_widths[i]
|
100
|
+
# cw = [column_widths[i], [8,min_column_width].min].max
|
101
|
+
$log.debug("XXX #{wid}. #{columns[i].length}")
|
102
|
+
cw = [wid, columns[i].length].max
|
103
|
+
$log.debug("int #{col} #{column_widths[i]}, #{cw}")
|
104
|
+
elsif @datatypes[i].match(/(date)/) != nil
|
105
|
+
cw = [column_widths[i], [12,min_column_width].min].max
|
106
|
+
#cw = [12,min_column_width].min
|
107
|
+
$log.debug("date #{col} #{column_widths[i]}, #{cw}")
|
108
|
+
else
|
109
|
+
cw = [column_widths[i], min_column_width].max
|
110
|
+
if column_widths[i] <= col.length and col.length <= min_column_width
|
111
|
+
cw = col.length
|
112
|
+
end
|
113
|
+
$log.debug("else #{col} #{column_widths[i]}, #{col.length} #{cw}")
|
114
|
+
end
|
115
|
+
column_widths[i] = cw
|
116
|
+
total += cw
|
117
|
+
end
|
118
|
+
column_widths["__TOTAL__"] = total
|
119
|
+
$log.debug("Estimated col widths: #{column_widths.inspect}")
|
120
|
+
@column_widths = column_widths
|
121
|
+
return column_widths
|
122
|
+
end
|
123
|
+
|
124
|
+
# added to enable query form to allow movement into table only if
|
125
|
+
# there is data 2008-10-08 17:46
|
126
|
+
# returns number of rows fetched
|
127
|
+
def data_length
|
128
|
+
return @content.length
|
129
|
+
end
|
130
|
+
|
131
|
+
end
|
132
|
+
def get_key_labels
|
133
|
+
key_labels = [
|
134
|
+
['C-q', 'Exit'], nil,
|
135
|
+
['M-s', 'Save'], ['M-m', 'Move']
|
136
|
+
]
|
137
|
+
return key_labels
|
138
|
+
end
|
139
|
+
def get_key_labels_table
|
140
|
+
key_labels = [
|
141
|
+
['M-n','NewRow'], ['M-d','DelRow'],
|
142
|
+
['C-x','Select'], nil,
|
143
|
+
['M-0', 'Top'], ['M-9', 'End'],
|
144
|
+
['C-p', 'PgUp'], ['C-n', 'PgDn'],
|
145
|
+
['M-Tab','Nxt Fld'], ['Tab','Nxt Col'],
|
146
|
+
['+','Widen'], ['-','Narrow']
|
147
|
+
]
|
148
|
+
return key_labels
|
149
|
+
end
|
150
|
+
class Sqlc
|
151
|
+
def initialize
|
152
|
+
@window = VER::Window.root_window
|
153
|
+
$catch_alt_digits = false # we want to use Alt-1, 2 for tabs.
|
154
|
+
@form = Form.new @window
|
155
|
+
@tab_ctr = 0
|
156
|
+
|
157
|
+
@db = Datasource.new
|
158
|
+
@db.connect "testd.db"
|
159
|
+
end
|
160
|
+
def run
|
161
|
+
title = "rbcurse"
|
162
|
+
@header = ApplicationHeader.new @form, title, {:text2=>"Demo", :text_center=>"SQL Client using TabbedPane and TabularWidget (see sqlm.rb also) "}
|
163
|
+
status_row = RubyCurses::Label.new @form, {'text' => "", :row => Ncurses.LINES-4, :col => 0, :display_length=>70}
|
164
|
+
@status_row = status_row
|
165
|
+
# setting ENTER across all objects on a form
|
166
|
+
@form.bind(:ENTER) {|f| status_row.text = f.help_text unless f.help_text.nil? }
|
167
|
+
r = 1; c = 1;
|
168
|
+
@data = [ ["No data"] ]
|
169
|
+
data = @data
|
170
|
+
colnames = %w[ Result ]
|
171
|
+
|
172
|
+
ta_ht = 5
|
173
|
+
t_width = 78
|
174
|
+
sqlarea = TextArea.new @form do
|
175
|
+
name "sqlarea"
|
176
|
+
row r
|
177
|
+
col c
|
178
|
+
width t_width
|
179
|
+
height ta_ht
|
180
|
+
title "Sql Query"
|
181
|
+
title_attrib (Ncurses::A_REVERSE | Ncurses::A_BOLD)
|
182
|
+
help_text "Enter query and press Run or Meta-r"
|
183
|
+
end
|
184
|
+
sqlarea << "select * from contacts"
|
185
|
+
buttrow = r+ta_ht+1 #Ncurses.LINES-4
|
186
|
+
b_run = Button.new @form do
|
187
|
+
text "&Run"
|
188
|
+
row buttrow
|
189
|
+
col c
|
190
|
+
help_text "Run query"
|
191
|
+
end
|
192
|
+
## We use Action to create a button: to test out ampersand with MI and Button
|
193
|
+
b_clear = Button.new @form do
|
194
|
+
#action new_act
|
195
|
+
text "&Clear"
|
196
|
+
row buttrow
|
197
|
+
col c+10
|
198
|
+
help_text "Clear query entry box "
|
199
|
+
end
|
200
|
+
b_clear.command {
|
201
|
+
sqlarea.remove_all
|
202
|
+
sqlarea.focus
|
203
|
+
}
|
204
|
+
|
205
|
+
# using ampersand to set mnemonic
|
206
|
+
|
207
|
+
b_construct = Button.new @form do
|
208
|
+
text "Constr&uct"
|
209
|
+
row buttrow
|
210
|
+
col c+25
|
211
|
+
help_text "Select a table, select columns and press this to construct an SQL"
|
212
|
+
end
|
213
|
+
|
214
|
+
Button.button_layout [b_run, b_clear, b_construct], buttrow, startcol=5, cols=Ncurses.COLS-1, gap=5
|
215
|
+
|
216
|
+
@tp = create_tabbed_pane @form, buttrow, t_width, c
|
217
|
+
@tp.show
|
218
|
+
@data = data
|
219
|
+
|
220
|
+
b_run.command {
|
221
|
+
query = sqlarea.get_text
|
222
|
+
run_query query
|
223
|
+
}
|
224
|
+
#
|
225
|
+
## key bindings fo atable
|
226
|
+
# column widths
|
227
|
+
app = self
|
228
|
+
|
229
|
+
|
230
|
+
tablist_ht = 6
|
231
|
+
mylist = @db.get_data "select name from sqlite_master"
|
232
|
+
# mylist is an Array of SQLite3::ResultSet::ArrayWithTypesAndFields
|
233
|
+
raise "Database contains no tables! I need some tables" unless mylist
|
234
|
+
mylist.collect!{|x| x[0] } ## 1.9 hack, but will it run on 1.8 ??
|
235
|
+
$listdata = Variable.new mylist
|
236
|
+
tablelist = Listbox.new @form do
|
237
|
+
name "tablelist"
|
238
|
+
row 1
|
239
|
+
col t_width+2
|
240
|
+
width 20
|
241
|
+
height tablist_ht
|
242
|
+
# list mylist
|
243
|
+
list_variable $listdata
|
244
|
+
#selection_mode :multiple
|
245
|
+
#show_selector true
|
246
|
+
title "Tables"
|
247
|
+
title_attrib 'reverse'
|
248
|
+
help_text "Press ENTER to run * query, Space to select columns"
|
249
|
+
end
|
250
|
+
#tablelist.bind(:PRESS) { |alist| @status_row.text = "Selected #{alist.current_index}" }
|
251
|
+
tablelist.list_selection_model().bind(:LIST_SELECTION_EVENT,tablelist) { |lsm, alist| @status_row.text = "Selected #{alist.current_index}" }
|
252
|
+
|
253
|
+
collist = []
|
254
|
+
$coldata = Variable.new collist
|
255
|
+
columnlist = Listbox.new @form do
|
256
|
+
name "columnlist"
|
257
|
+
row tablist_ht+2
|
258
|
+
col t_width+2
|
259
|
+
width 20
|
260
|
+
height 15
|
261
|
+
# list mylist
|
262
|
+
list_variable $coldata
|
263
|
+
selection_mode :multiple
|
264
|
+
#show_selector true
|
265
|
+
title "Columns"
|
266
|
+
title_attrib 'reverse'
|
267
|
+
help_text "Press ENTER to append columns to sqlarea, Space to select"
|
268
|
+
end
|
269
|
+
## pressing SPACE on a table populates column list with its columns so they can be selected
|
270
|
+
#tablelist.bind_key(32) {
|
271
|
+
# Now space trapped at listbox level, need to use event
|
272
|
+
tablelist.list_selection_model().bind(:LIST_SELECTION_EVENT,tablelist) { |lsm, alist| @status_row.text = "Selected #{alist.current_index}"
|
273
|
+
#@status_row.text = "Selected table #{tablelist.get_content()[tablelist.current_index]}"
|
274
|
+
table = "#{tablelist.get_content()[tablelist.current_index]}"
|
275
|
+
##table = table[0] if table.class==Array ## 1.9 ???
|
276
|
+
columnlist.list_data_model.remove_all
|
277
|
+
columnlist.list_data_model.insert 0, *@db.get_metadata(table)
|
278
|
+
}
|
279
|
+
## pressing ENTER on a table runs a query on it, no need to type and SQL
|
280
|
+
|
281
|
+
tablelist.bind(:PRESS) {
|
282
|
+
@status_row.text = "Selected #{tablelist.get_content()[tablelist.current_index]}"
|
283
|
+
table = "#{tablelist.get_content()[tablelist.current_index]}"
|
284
|
+
##table = table[0] if table.class==Array ## 1.9 ???
|
285
|
+
run_query "select * from #{table}"
|
286
|
+
}
|
287
|
+
|
288
|
+
columnlist.bind(:PRESS) {
|
289
|
+
## append column name to sqlarea if ENTER pressed
|
290
|
+
column = "#{columnlist.get_content()[columnlist.current_index]}"
|
291
|
+
sqlarea << "#{column},"
|
292
|
+
}
|
293
|
+
columnlist.bind_key(32) {
|
294
|
+
## select row - later can press Construct button
|
295
|
+
columnlist.toggle_row_selection
|
296
|
+
column = "#{columnlist.get_content()[columnlist.current_index]}"
|
297
|
+
}
|
298
|
+
## construct an SQL after selecting some columns in the column list
|
299
|
+
b_construct.command {
|
300
|
+
# current_index is wrong, we need selected_index
|
301
|
+
table = "#{tablelist.get_content()[tablelist.selected_index]}"
|
302
|
+
#table = table[0] if table.class==Array ## 1.9 ???
|
303
|
+
indexes = columnlist.selected_rows()
|
304
|
+
columns=[]
|
305
|
+
indexes.each do |i|
|
306
|
+
columns << columnlist.get_content()[i]
|
307
|
+
end
|
308
|
+
sql = "select #{columns.join(',')} from #{table}"
|
309
|
+
sqlarea << sql
|
310
|
+
}
|
311
|
+
|
312
|
+
|
313
|
+
@form.repaint
|
314
|
+
@window.wrefresh
|
315
|
+
Ncurses::Panel.update_panels
|
316
|
+
begin
|
317
|
+
while((ch = @window.getchar()) != ?\C-q.getbyte(0) )
|
318
|
+
break if ch == KEY_F1
|
319
|
+
s = keycode_tos ch
|
320
|
+
status_row.text = "Pressed #{ch} , #{s}. Press C-q to quit, Alt-Tab for exiting table "
|
321
|
+
@form.handle_key(ch)
|
322
|
+
|
323
|
+
@form.repaint
|
324
|
+
@window.wrefresh
|
325
|
+
end
|
326
|
+
ensure
|
327
|
+
@window.destroy if !@window.nil?
|
328
|
+
end
|
329
|
+
end
|
330
|
+
## execute the query in the textarea
|
331
|
+
# @param [String] sql string
|
332
|
+
def run_query sql
|
333
|
+
#query = sqlarea.get_text
|
334
|
+
query = sql
|
335
|
+
begin
|
336
|
+
@content = @db.get_data query
|
337
|
+
if @content.nil?
|
338
|
+
@status_row.text = "0 rows retrieved"
|
339
|
+
return
|
340
|
+
end
|
341
|
+
#cw = @db.estimate_column_widths @atable.width, @db.columns
|
342
|
+
atable, newtab = create_table @tp, @tab_ctr #, buttrow, t_width, c
|
343
|
+
#atable.set_data @content, @db.columns
|
344
|
+
atable.set_content @content
|
345
|
+
atable.columns=@db.columns
|
346
|
+
#cw = atable.estimate_column_widths @db.columns, @db.datatypes
|
347
|
+
#atable.set_column_widths cw
|
348
|
+
rescue => exc
|
349
|
+
$log.debug(exc.backtrace.join("\n"))
|
350
|
+
alert exc.to_s
|
351
|
+
return
|
352
|
+
end
|
353
|
+
@status_row.text = "#{@content.size} rows retrieved"
|
354
|
+
atable.repaint
|
355
|
+
newtab.repaint
|
356
|
+
end
|
357
|
+
## create a Table component for populating with data
|
358
|
+
def create_table tp, counter #, buttrow, t_width, c
|
359
|
+
table_ht = 15
|
360
|
+
atable = TabularWidget.new do
|
361
|
+
name "sqltable#{counter}"
|
362
|
+
help_text "M-Tab for next field, C-q quit"
|
363
|
+
end
|
364
|
+
#atable.bind(:TABLE_TRAVERSAL_EVENT){|e| @header.text_right "Row #{e.newrow+1} of #{atable.row_count}" }
|
365
|
+
@tab_ctr += 1
|
366
|
+
tab1 = tp.add_tab "Tab&#{@tab_ctr}" , atable
|
367
|
+
return atable, tab1
|
368
|
+
end
|
369
|
+
## create the single tabbedpane for populating with resultsets
|
370
|
+
def create_tabbed_pane form, buttrow, t_width, c
|
371
|
+
tp = RubyCurses::TabbedPane.new form do
|
372
|
+
height 16
|
373
|
+
width t_width
|
374
|
+
row buttrow +1
|
375
|
+
col c
|
376
|
+
button_type :ok
|
377
|
+
end
|
378
|
+
return tp
|
379
|
+
end
|
380
|
+
end
|
381
|
+
if $0 == __FILE__
|
382
|
+
include RubyCurses
|
383
|
+
include RubyCurses::Utils
|
384
|
+
|
385
|
+
begin
|
386
|
+
# Initialize curses
|
387
|
+
VER::start_ncurses # this is initializing colors via ColorMap.setup
|
388
|
+
#$log = Logger.new("rbc13.log")
|
389
|
+
$log = Logger.new(ENV['LOGDIR'] || "" + "rbc13.log")
|
390
|
+
|
391
|
+
$log.level = Logger::DEBUG
|
392
|
+
|
393
|
+
colors = Ncurses.COLORS
|
394
|
+
$log.debug "START #{colors} colors SQLC demo "
|
395
|
+
|
396
|
+
catch(:close) do
|
397
|
+
t = Sqlc.new
|
398
|
+
t.run
|
399
|
+
end
|
400
|
+
rescue => ex
|
401
|
+
ensure
|
402
|
+
VER::stop_ncurses
|
403
|
+
p ex if ex
|
404
|
+
p(ex.backtrace.join("\n")) if ex
|
405
|
+
$log.debug( ex) if ex
|
406
|
+
$log.debug(ex.backtrace.join("\n")) if ex
|
407
|
+
end
|
408
|
+
end
|