rbcurse 1.3.0 → 1.4.0
Sign up to get free protection for your applications and to get access to all the features.
- 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/CHANGELOG
CHANGED
@@ -1,3 +1,36 @@
|
|
1
|
+
**2011-10-06**
|
2
|
+
## 1.3.1 or 1.4.0
|
3
|
+
|
4
|
+
### Major cleanup of widget class
|
5
|
+
Scrollpane support (buffering stuff all removed)
|
6
|
+
|
7
|
+
### TabbedPane
|
8
|
+
Corrected, major changes
|
9
|
+
|
10
|
+
### dsl_accessor and dsl_property
|
11
|
+
Now return self so we can chain.
|
12
|
+
|
13
|
+
### return values of some keys (Class Form)
|
14
|
+
Earlier not returning anything meaningful or returning last_key
|
15
|
+
Now return NO_NEXT_FIELD or NO_PREVIOUS_FIELD
|
16
|
+
|
17
|
+
### j and k keys used for down and up where possible
|
18
|
+
e.g. button and its children including checkbox
|
19
|
+
|
20
|
+
### Miscellaneous
|
21
|
+
|
22
|
+
* Dynamic menuitems in menu (see menu1.tb)
|
23
|
+
* rework on menu and menubar, and keys using them
|
24
|
+
* FieldVetoException (see test2.rb)
|
25
|
+
* valid_range for Field (see test2.rb)
|
26
|
+
* fixed field's type method, earlier non-functional
|
27
|
+
* array and 4 integer constructor for Window
|
28
|
+
* StatusWindow class - 2 line window for alert, confirm and statuses as an
|
29
|
+
alternative to dialogs.
|
30
|
+
* status_dialog returning a handle so we can keep updating status then
|
31
|
+
close.
|
32
|
+
* many more minor adjustments, tweaks, issues
|
33
|
+
|
1
34
|
**2011-09-26**
|
2
35
|
## 1.3.0
|
3
36
|
|
data/README.markdown
CHANGED
@@ -2,7 +2,11 @@
|
|
2
2
|
|
3
3
|
* Migrating from ncurses-ruby to ffi-ncurses
|
4
4
|
|
5
|
-
I have moved rbcurse to ffi-ncurses (earlier ncurses gem).
|
5
|
+
I have moved rbcurse to ffi-ncurses (earlier ncurses gem) since 1.3.0.
|
6
|
+
|
7
|
+
Please report bugs on github/rkumar/rbcurse mentioning version. Your program dependency
|
8
|
+
should be an explicit rbcurse version since I am doing a lot of improvements, cleaning up
|
9
|
+
etc in the code base.
|
6
10
|
|
7
11
|
If you are looking for the ncurses version, please goto
|
8
12
|
branch rbcurse1.2.0. I am not likely to support that henceforth due to the difficulty in installing ncurses gem.
|
@@ -17,6 +21,8 @@ then do a final after some testing.
|
|
17
21
|
|
18
22
|
* Version that works with ruby 1.9 (backward compatible with 1.8.7)
|
19
23
|
|
24
|
+
* 1.3.1: Rework of some classes - see CHANGELOG
|
25
|
+
* 1.3.0: ffi-ification of rbcurses with some minor bug-fixes, deprecations
|
20
26
|
* 1.2.0: many additions (See CHANGELOG for details)
|
21
27
|
- App class that wraps the environment and makes application development very easy
|
22
28
|
- New controls such as:
|
data/TODO2.txt
CHANGED
@@ -41,7 +41,6 @@
|
|
41
41
|
28 [x] (A) TextArea: borders get overwritten * chomp was required when using << (2010-01-14) (x2010-01-14)
|
42
42
|
29 [x] what if we don't want to print borders, since that eats an extraline and col. Can we switch off and reclaim the line and col (2010-01-15) (x2010-02-18)
|
43
43
|
31 [x] move create_buffer to repaintin TA and TV and others, so that enduser does not have to bother. scroll and split can set internally * All create_buffer calls moved to repaint. Maybe table pending (2010-01-16) (x2010-02-18)
|
44
|
-
36 [ ] should parent set scrollatrows for lb and tv and ta ? (2010-01-17)
|
45
44
|
37 [x] (B) test rtable in splitpane and scrollpanes * done rtable in scrollpane (2010-01-18) (x2010-02-24)
|
46
45
|
38 [x] (B) test various widgets inside rtabbedpane (2010-01-19) (x2010-02-22)
|
47
46
|
41 [x] Textareas: C-a C-e does not repain which is good, but footer not updated (2010-01-23) (x2010-01-25)
|
@@ -69,7 +68,6 @@
|
|
69
68
|
72 [ ] (F) TextView: keymaps. p 699 (2010-03-07)
|
70
69
|
73 [ ] (F) TextView: freezing an area horiz vertically (2010-03-07)
|
71
70
|
74 [x] General: move key bindings to bind_key so user can see what's bound (2010-03-07)
|
72
|
-
76 [ ] a Box class = would that help? (2010-03-08)
|
73
71
|
78 [x] (A) Undo: refactor undomanager and undohandler (2010-03-08) (x2010-03-10)
|
74
72
|
79 [x] (A) Demo: get sqlc.rb demo running (2010-03-09) (x2010-03-14)
|
75
73
|
80 [x] firehandler: can we combine consecutive ones into one, passing an array? (2010-03-09) (x2010-03-12)
|
@@ -80,22 +78,18 @@
|
|
80
78
|
85 [x] (F) how about getting ascii tables in here for sql stuff (2010-03-12)
|
81
79
|
87 [x] (E) MultiTextView: list buffers to do (2010-03-12) (x2010-03-15)
|
82
80
|
88 [x] (E) TextV+A, when printing a screenful, store actual maxlen for scrolling left (2010-03-12) (x2010-03-13)
|
83
|
-
89 [ ] (Z) Scrollpane is just wrong with textobjects, searching doesnt work properly - it doesnt show up (2010-03-13)
|
84
|
-
90 [ ] (Z) tabbedpane buttons focus sometimes mixes with table first row focuses (2010-03-14)
|
85
81
|
91 [x] (B) tabbedpane: adding new tab dyn, not immediately shown (2010-03-14) (x2010-03-15)
|
86
|
-
93 [ ] (Z) tabbedpane: new tabs not really getting focus??? (2010-03-15)
|
87
82
|
94 [x] (F) MultiContainer: takes n objects, fills, one can cycle, just as in MultiTextView except that any component can be put. (2010-03-15) (x2010-03-15)
|
88
|
-
95 [ ] (Z) TabbedWindow is totally off - redo ? (2010-03-16)
|
89
83
|
97 [x] (A) Scrollform : dont we need some indicators or bars (2010-03-17) (x2010-03-18)
|
90
84
|
98 [x] (A) SCrollFOrm: cursor not on first field to start with (2010-03-17) (x2010-03-18)
|
91
85
|
99 [ ] scrollform demo: add larger objects like textview and test (2010-03-18)
|
92
86
|
100 [x] (A) sqlm.rb finish this with multicontainer and table (2010-03-19) (x2010-03-19)
|
93
|
-
101 [
|
94
|
-
102 [
|
87
|
+
101 [x] Menu: simpler rewrite ?? (2010-03-20)
|
88
|
+
102 [x] (A) TabbedPane: rewrite (2011-09-21)
|
95
89
|
103 [ ] Messagebox: rewrite (2011-09-21)
|
96
|
-
104 [
|
97
|
-
105 [
|
98
|
-
106 [
|
90
|
+
104 [x] (E) Gen: catching extended keys C-left, S-F10 (2011-09-21)
|
91
|
+
105 [x] (A) Window: combine array into existing constructor (2011-09-21)
|
92
|
+
106 [x] (A) gen: check if that buffering nonsense is still being used? (2011-09-21)
|
99
93
|
107 [ ] (F) find_file like microemacs (2011-09-21)
|
100
94
|
108 [ ] (F) color schemes (applying at form or app level) (2011-09-21)
|
101
95
|
109 [ ] (E) App: stack and flow to be objects so RESIZE can happen (2011-09-21)
|
@@ -105,8 +99,20 @@
|
|
105
99
|
110.3 [ ] (E) Text objects: execute ex commands ??? * printf '%cs/change this/to that/nwq' '%' | ex file.name (2010-03-05)
|
106
100
|
110.4 [ ] (E) TextView etal: store path so save can be done? (2010-03-12)
|
107
101
|
110.5 [ ] (E) table: yank one or more rows into kill ring as comma delim (2010-03-17)
|
108
|
-
110.6 [ ]
|
109
|
-
110.7 [ ] TabbedPane: move fun stuff to Util class - dont crowd main classes (2010-03-14)
|
102
|
+
110.6 [ ] Table needs multiplier for resizing cols (2010-02-24)
|
110
103
|
110.8 [ ] (O) maybe we should combine set_form_row and col since we call them one after another nowadays (2010-01-16)
|
111
|
-
110.
|
112
|
-
110.
|
104
|
+
110.11 [ ] should parent set scrollatrows for lb and tv and ta ? (2010-01-17)
|
105
|
+
110.12 [ ] a Box class = would that help? (2010-03-08)
|
106
|
+
111 [ ] (B) me: arrow down and up moves vertically not to next field (2011-09-21)
|
107
|
+
112 [ ] (E) app: add popup (2011-09-21)
|
108
|
+
113 [ ] (F) basic html view like alpine help with link, underline (2011-09-21)
|
109
|
+
115 [ ] (F) widgets shd add major keys to keylabel if present (2011-09-28)
|
110
|
+
116 [ ] (F) colormap can check for colorscheme before setting colors (2011-10-01)
|
111
|
+
117 [ ] make readme and homepage simple and clean like urwid (2011-10-01)
|
112
|
+
118 [x] return self from dsl_property and dsl_accessor (2011-10-02)
|
113
|
+
119 [x] PropertyVetoException to disallow change (2011-10-02)
|
114
|
+
120 [x] StatusWindow: 2 line bottom window for alert, confirm and status (2011-10-02)
|
115
|
+
121 [x] cleanup Widget and others, remove buffering nonsense (2011-10-02)
|
116
|
+
122 [x] Add valid_range to Field (2011-10-02)
|
117
|
+
123 [x] (A) Make listbox data more accessible from lb class (2011-10-02)
|
118
|
+
124 [ ] look at sandy,ne,pygments source for ncurses syntax highlighting (2011-10-07)
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.
|
1
|
+
1.4.0
|
data/examples/abasiclist.rb
CHANGED
@@ -3,8 +3,8 @@ require 'rbcurse/rbasiclistbox'
|
|
3
3
|
|
4
4
|
# just a simple test to ensure that rbasiclistbox is running inside a container.
|
5
5
|
App.new do
|
6
|
-
header = app_header "rbcurse
|
7
|
-
message "Press
|
6
|
+
header = app_header "rbcurse #{Rbcurse::VERSION}", :text_center => "Basic List Demo", :text_right =>"New Improved!", :color => :black, :bgcolor => :white, :attr => :bold
|
7
|
+
message "Press F10 to escape from here"
|
8
8
|
|
9
9
|
list = %W{ bhikshu boddisattva avalokiteswara mu mun kwan paramita prajna samadhi sutra shakyamuni }
|
10
10
|
vimsplit :row => 1, :col => 0, :suppress_borders => false, :width => 60, :height => Ncurses.LINES-2, :weight => 0.4, :orientation => :VERTICAL do |s|
|
data/examples/alpmenu.rb
CHANGED
@@ -3,7 +3,7 @@ require 'rbcurse/app'
|
|
3
3
|
App.new do
|
4
4
|
#title "Demo of Menu - rbcurse"
|
5
5
|
#subtitle "Hit F1 to quit, F2 for menubar toggle"
|
6
|
-
header = app_header "rbcurse
|
6
|
+
header = app_header "rbcurse #{Rbcurse::VERSION}", :text_center => "Alpine Menu Demo", :text_right =>""
|
7
7
|
message_row(27)
|
8
8
|
|
9
9
|
stack :margin_top => 10, :margin => 15 do
|
data/examples/app.rb
CHANGED
data/examples/appdirtree.rb
CHANGED
@@ -39,7 +39,7 @@ App.new do
|
|
39
39
|
last = nodes.last
|
40
40
|
nodes.last.add entries
|
41
41
|
model = DefaultTreeModel.new nodes.first
|
42
|
-
header = app_header "rbcurse
|
42
|
+
header = app_header "rbcurse #{Rbcurse::VERSION}", :text_center => "Yet Another File Manager", :text_right =>"Directory Lister", :color => :black, :bgcolor => :white#, :attr => Ncurses::A_BLINK
|
43
43
|
message "Press Enter to expand/collapse"
|
44
44
|
|
45
45
|
|
@@ -69,5 +69,7 @@ App.new do
|
|
69
69
|
#@l = list_box :height => ht, :border_attrib => borderattrib, :selection_mode => :multiple
|
70
70
|
s.add dl, :SECOND
|
71
71
|
end # vimsplit
|
72
|
-
end #
|
72
|
+
end # stack
|
73
|
+
sl = status_line :row => Ncurses.LINES-1
|
74
|
+
sl.command { "%-20s | %-20s | v View" % [Time.now, File.absolute_path(dl.current_path)] }
|
73
75
|
end # app
|
data/examples/appemail.rb
CHANGED
@@ -8,8 +8,10 @@ require './rmail'
|
|
8
8
|
# this will go into top namespace so will conflict with other apps!
|
9
9
|
def testchoose
|
10
10
|
# list filters as you type
|
11
|
-
$log.debug "called
|
12
|
-
|
11
|
+
$log.debug "called CHOOSE " if $log.debug?
|
12
|
+
filter = "*"
|
13
|
+
filter = ENV['PWD']+"/*"
|
14
|
+
str = choose filter, :title => "Files", :prompt => "Choose a file: "
|
13
15
|
end
|
14
16
|
def testnumberedmenu
|
15
17
|
list1 = %w{ ruby perl python erlang rake java lisp scheme chicken }
|
@@ -70,7 +72,7 @@ App.new do
|
|
70
72
|
$unread_hash = {}
|
71
73
|
@tv = nil
|
72
74
|
borderattrib = :reverse
|
73
|
-
@header = app_header "rbcurse
|
75
|
+
@header = app_header "rbcurse #{Rbcurse::VERSION}", :text_center => "Yet Another Email Client that sucks", :text_right =>"", :color => :black, :bgcolor => :white
|
74
76
|
message "Press F10 to exit ...................................................."
|
75
77
|
|
76
78
|
|
@@ -186,6 +188,8 @@ App.new do
|
|
186
188
|
@tv.suppress_borders true
|
187
189
|
@tv.border_attrib = borderattrib
|
188
190
|
end # stack
|
191
|
+
@statusline = status_line :row => Ncurses.LINES-1
|
192
|
+
#@statusline.command { }
|
189
193
|
@form.bind_key(?\M-v) { test11() }
|
190
194
|
@form.bind_key(?\M-V) { testme() }
|
191
195
|
@form.bind_key(?\M-c) { test1() }
|
data/examples/appemaillb.rb
CHANGED
@@ -244,7 +244,7 @@ App.new do
|
|
244
244
|
@messages = nil
|
245
245
|
@tv = nil
|
246
246
|
borderattrib = :reverse
|
247
|
-
@header = app_header "rbcurse
|
247
|
+
@header = app_header "rbcurse #{Rbcurse::VERSION}", :text_center => "Yet Another Email Client that sucks", :text_right =>"", :color => :black, :bgcolor => :white#, :attr => Ncurses::A_BLINK
|
248
248
|
message "Press F10 to exit ...................................................."
|
249
249
|
|
250
250
|
|
data/examples/appgcompose.rb
CHANGED
@@ -196,8 +196,8 @@ module AppgCompose
|
|
196
196
|
def get_commands
|
197
197
|
%w{ insert_file}
|
198
198
|
end
|
199
|
-
header = app.app_header "rbcurse
|
200
|
-
app.message "Press
|
199
|
+
header = app.app_header "rbcurse #{Rbcurse::VERSION}", :text_center => "Compose Mail", :text_right =>"27% Stronger", :color => :black, :bgcolor => :white, :attr => :bold
|
200
|
+
app.message "Press F10 to exit from here"
|
201
201
|
app.stack :margin_top => 2, :margin => 5, :width => 15 do |xxx|
|
202
202
|
fg = :white
|
203
203
|
bg = :blue
|
data/examples/appgmail.rb
CHANGED
@@ -672,7 +672,7 @@ App.new do
|
|
672
672
|
@default_mailbox = "INBOX"
|
673
673
|
@gmail = nil
|
674
674
|
borderattrib = :reverse
|
675
|
-
@header = app_header "rbcurse
|
675
|
+
@header = app_header "rbcurse #{Rbcurse::VERSION}", :text_center => "Yet Another Gmail Client that sucks", :text_right =>"", :color => :black, :bgcolor => :white#, :attr => Ncurses::A_BLINK
|
676
676
|
message "Press F1 to exit ...................................................."
|
677
677
|
|
678
678
|
|
data/examples/appmethods.rb
CHANGED
@@ -18,8 +18,8 @@ module RubyCurses
|
|
18
18
|
VER::start_ncurses
|
19
19
|
#@form.reset_all # not required
|
20
20
|
end
|
21
|
-
@form.repaint
|
22
|
-
@window.wrefresh
|
21
|
+
@form.repaint if @form
|
22
|
+
@window.wrefresh if @window
|
23
23
|
Ncurses::Panel.update_panels
|
24
24
|
end
|
25
25
|
def suspend
|
@@ -64,6 +64,24 @@ module RubyCurses
|
|
64
64
|
t.attr = :reverse
|
65
65
|
end
|
66
66
|
end
|
67
|
+
def shell_output
|
68
|
+
cmd = get_string("Enter shell command:", 50)
|
69
|
+
if cmd && !cmd.empty?
|
70
|
+
run_command cmd
|
71
|
+
end
|
72
|
+
end
|
73
|
+
def run_command cmd
|
74
|
+
# http://whynotwiki.com/Ruby_/_Process_management#What_happens_to_standard_error_.28stderr.29.3F
|
75
|
+
require 'rbcurse/extras/viewer'
|
76
|
+
begin
|
77
|
+
res = `#{cmd} 2>&1`
|
78
|
+
rescue => ex
|
79
|
+
res = ex.to_s
|
80
|
+
res << ex.backtrace.join("\n")
|
81
|
+
end
|
82
|
+
res.gsub!("\t"," ")
|
83
|
+
RubyCurses::Viewer.view(res.split("\n"), :close_key => KEY_RETURN, :title => "<Enter> to close, M-l M-h to scroll")
|
84
|
+
end
|
67
85
|
end # utils
|
68
86
|
end # module RubyC
|
69
87
|
include RubyCurses::Utils
|
data/examples/atree.rb
CHANGED
@@ -1,8 +1,12 @@
|
|
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 => "Tree Demo", :text_right =>"New Improved!", :color => :black, :bgcolor => :white, :attr => :bold
|
5
5
|
message "Press Enter to expand/collapse"
|
6
|
+
@form.bind_key(FFI::NCurses::KEY_F3) {
|
7
|
+
require 'rbcurse/extras/viewer'
|
8
|
+
RubyCurses::Viewer.view("rbc13.log", :close_key => KEY_RETURN, :title => "<Enter> to close")
|
9
|
+
}
|
6
10
|
|
7
11
|
stack :margin_top => 2, :margin => 5, :width => 30 do
|
8
12
|
tm = nil
|
@@ -17,6 +21,9 @@ App.new do
|
|
17
21
|
end
|
18
22
|
end
|
19
23
|
end
|
24
|
+
found=atree.get_node_for_path "goodbye"
|
25
|
+
atree.set_expanded_state(atree.root, true)
|
26
|
+
atree.set_expanded_state(found,true)
|
20
27
|
|
21
28
|
# using a Hash
|
22
29
|
model = { :ruby => [ "jruby", {:mri => %W[ 1.8.6 1.8.7]}, {:yarv => %W[1.9.1 1.9.2]}, "rubinius", "macruby" ], :python => %W[ cpython jython laden-swallow ] }
|
@@ -52,5 +59,6 @@ App.new do
|
|
52
59
|
end
|
53
60
|
|
54
61
|
tree :data => model, :title => "legacy way"
|
62
|
+
|
55
63
|
end
|
56
64
|
end # app
|
data/examples/dbdemo.rb
ADDED
@@ -0,0 +1,460 @@
|
|
1
|
+
require 'rbcurse/app'
|
2
|
+
require 'sqlite3'
|
3
|
+
require 'rbcurse/undomanager'
|
4
|
+
|
5
|
+
# @return array of table names from selected db file
|
6
|
+
def get_table_names
|
7
|
+
raise "No database file selected." unless $current_db
|
8
|
+
|
9
|
+
$tables = get_data "select name from sqlite_master"
|
10
|
+
$tables.collect!{|x| x[0] } ## 1.9 hack, but will it run on 1.8 ??
|
11
|
+
$tables
|
12
|
+
end
|
13
|
+
def get_column_names tbname
|
14
|
+
get_metadata tbname
|
15
|
+
end
|
16
|
+
def connect dbname
|
17
|
+
$current_db = dbname
|
18
|
+
$db = SQLite3::Database.new(dbname)
|
19
|
+
|
20
|
+
return $db
|
21
|
+
end
|
22
|
+
def get_data sql
|
23
|
+
$log.debug "SQL: #{sql} "
|
24
|
+
$columns, *rows = $db.execute2(sql)
|
25
|
+
$log.debug "XXX COLUMNS #{sql} "
|
26
|
+
content = rows
|
27
|
+
return nil if content.nil? or content[0].nil?
|
28
|
+
$datatypes = content[0].types #if @datatypes.nil?
|
29
|
+
return content
|
30
|
+
end
|
31
|
+
def get_metadata table
|
32
|
+
get_data "select * from #{table} limit 1"
|
33
|
+
#$columns.collect!{|x| x[0] } ## 1.9 hack, but will it run on 1.8 ??
|
34
|
+
return $columns
|
35
|
+
end
|
36
|
+
#
|
37
|
+
# creates a popup for selection given the data, and executes given block with
|
38
|
+
# following return value.
|
39
|
+
# @return [String] if mode is :single
|
40
|
+
# @return [Array] if mode is :multiple
|
41
|
+
#
|
42
|
+
def create_popup array, selection_mode=:single, &blk
|
43
|
+
require 'rbcurse/rlistbox'
|
44
|
+
#raise "no block given " unless block_given?
|
45
|
+
listconfig = {'bgcolor' => 'blue', 'color' => 'white'}
|
46
|
+
url_list= RubyCurses::ListDataModel.new(array)
|
47
|
+
ht = 16
|
48
|
+
if array.length < 16
|
49
|
+
ht = array.length+1
|
50
|
+
end
|
51
|
+
pl = RubyCurses::PopupList.new do
|
52
|
+
row 4
|
53
|
+
col 10
|
54
|
+
width 30
|
55
|
+
height ht
|
56
|
+
#list url_list
|
57
|
+
list_data_model url_list
|
58
|
+
list_selection_mode selection_mode
|
59
|
+
#relative_to f
|
60
|
+
list_config listconfig
|
61
|
+
bind :PRESS do |lb|
|
62
|
+
#field.set_buffer url_list[index]
|
63
|
+
#blk.call(url_list[index]) #if &blk
|
64
|
+
#selected = []; indices.each{|i| selected << url_list[i] }
|
65
|
+
#blk.call(selected.join(", "))
|
66
|
+
if selection_mode == :single
|
67
|
+
blk.call(url_list[lb]) #if &blk
|
68
|
+
else
|
69
|
+
blk.call(lb.selected_values)
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def view_data fields="*", name
|
77
|
+
stmt = "select #{fields} from #{name}"
|
78
|
+
stmt << $where_string if $where_string
|
79
|
+
stmt << $order_string if $order_string
|
80
|
+
@form.by_name['tarea'] << stmt
|
81
|
+
view_sql stmt
|
82
|
+
end
|
83
|
+
def view_sql stmt
|
84
|
+
begin
|
85
|
+
content = get_data stmt
|
86
|
+
if content.nil?
|
87
|
+
else
|
88
|
+
require 'rbcurse/extras/tabular'
|
89
|
+
t = Tabular.new do |t|
|
90
|
+
t.headings = $columns
|
91
|
+
t.data=content
|
92
|
+
end
|
93
|
+
view t.render
|
94
|
+
end
|
95
|
+
rescue => err
|
96
|
+
$log.error err.to_s
|
97
|
+
$log.error(err.backtrace.join("\n"))
|
98
|
+
alert err.to_s
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
App.new do
|
103
|
+
header = app_header "rbcurse #{Rbcurse::VERSION}", :text_center => "Database Demo", :text_right =>"enabled"
|
104
|
+
form = @form
|
105
|
+
mylabel = "a field"
|
106
|
+
$catch_alt_digits = true # use M-1..9 in textarea
|
107
|
+
$current_table = nil
|
108
|
+
$current_db = nil # "testd.db"
|
109
|
+
connect $current_db if $current_db
|
110
|
+
|
111
|
+
def help_text
|
112
|
+
<<-eos
|
113
|
+
APPEMAIL HELP
|
114
|
+
|
115
|
+
This is some help text for appemail.
|
116
|
+
We are testing out this feature.
|
117
|
+
|
118
|
+
Alt-d - Select a database
|
119
|
+
<Enter> on a table, view data (q to close window)
|
120
|
+
<Space> on a table, display columns in lower list
|
121
|
+
|
122
|
+
COLUMN LIST KEYS
|
123
|
+
<Space> on a column for multiple select
|
124
|
+
<Ctrl-Space> on a column for range select/deselect from previous selection
|
125
|
+
<Enter> on column table to view data for selected columns
|
126
|
+
u unselect all
|
127
|
+
a select all
|
128
|
+
* invert selection
|
129
|
+
F4 View data for selected table (or columns if selected)
|
130
|
+
|
131
|
+
q or C-q Close the data window that comes on Enter or F4
|
132
|
+
|
133
|
+
Alt-x - Command mode (<tab> to see commands and select)
|
134
|
+
: - Command mode
|
135
|
+
F10 - Quit application
|
136
|
+
|
137
|
+
|
138
|
+
|
139
|
+
-----------------------------------------------------------------------
|
140
|
+
Hope you enjoyed this help.
|
141
|
+
eos
|
142
|
+
end
|
143
|
+
def ask_databases
|
144
|
+
names = Dir.glob("*.{sqlite,db}")
|
145
|
+
if names
|
146
|
+
create_popup( names,:single) {|value| connect(value);
|
147
|
+
@form.by_name["tlist"].list(get_table_names)
|
148
|
+
}
|
149
|
+
else
|
150
|
+
alert "Can't find a .db or .sqlite file"
|
151
|
+
end
|
152
|
+
end
|
153
|
+
# TODO accelerators and
|
154
|
+
# getting a handle for later use
|
155
|
+
mb = menubar do
|
156
|
+
keep_visible true
|
157
|
+
#@toggle_key=KEY_F2
|
158
|
+
menu "File" do
|
159
|
+
item "Open", "O" do
|
160
|
+
accelerator "Ctrl-O"
|
161
|
+
command do
|
162
|
+
alert "HA!! you wanted to open a file?"
|
163
|
+
end
|
164
|
+
end
|
165
|
+
menu "Database" do
|
166
|
+
item_list do
|
167
|
+
Dir.glob("**/*.{sqlite,db}")
|
168
|
+
end
|
169
|
+
command do |menuitem, text|
|
170
|
+
connect text
|
171
|
+
form.by_name["tlist"].list(get_table_names)
|
172
|
+
end
|
173
|
+
end
|
174
|
+
menu "Tables" do
|
175
|
+
item_list do
|
176
|
+
if $current_db
|
177
|
+
get_table_names
|
178
|
+
end
|
179
|
+
end
|
180
|
+
command do |menuitem, text|
|
181
|
+
$current_table = text
|
182
|
+
#alert(get_column_names(text).join(", "))
|
183
|
+
create_popup(get_column_names(text), :multiple) { |value| view_data( value.join(","), text) }
|
184
|
+
end
|
185
|
+
end
|
186
|
+
item "New", "N"
|
187
|
+
separator
|
188
|
+
item "Exit", "x" do
|
189
|
+
command do
|
190
|
+
throw(:close)
|
191
|
+
end
|
192
|
+
end
|
193
|
+
item "Cancel Menu" do
|
194
|
+
accelerator "Ctrl-g"
|
195
|
+
end
|
196
|
+
|
197
|
+
end # menu
|
198
|
+
menu "Window" do
|
199
|
+
item "Tile", "T"
|
200
|
+
menu "Find" do
|
201
|
+
item "More", "M"
|
202
|
+
$x = item "Less", "L" do
|
203
|
+
#accelerator "Ctrl-X"
|
204
|
+
command do
|
205
|
+
alert "You clickses on Less"
|
206
|
+
end
|
207
|
+
end
|
208
|
+
menu "Size" do
|
209
|
+
item "Zoom", "Z"
|
210
|
+
item "Maximize", "X"
|
211
|
+
item "Minimize", "N"
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
215
|
+
menu "Others" do
|
216
|
+
require './appmethods.rb'
|
217
|
+
item "Shell Output" do
|
218
|
+
command { shell_output }
|
219
|
+
end
|
220
|
+
item "Suspend" do
|
221
|
+
command { suspend }
|
222
|
+
end
|
223
|
+
end
|
224
|
+
end # menubar
|
225
|
+
mb.toggle_key = FFI::NCurses::KEY_F2
|
226
|
+
mb.color = :white
|
227
|
+
mb.bgcolor = :blue
|
228
|
+
@form.set_menu_bar mb
|
229
|
+
stack :margin => 0 do
|
230
|
+
text = "No tables"
|
231
|
+
if !$current_db
|
232
|
+
text = "Select DB first. Press Alt-D"
|
233
|
+
end
|
234
|
+
tlist = basiclist :name => "tlist", :list => [text], :title => "Tables", :height => 10
|
235
|
+
tlist.bind(:PRESS) do |eve|
|
236
|
+
if $current_db
|
237
|
+
# get data of table
|
238
|
+
view_data eve.text
|
239
|
+
else
|
240
|
+
ask_databases
|
241
|
+
end
|
242
|
+
end
|
243
|
+
tlist.bind(:ENTER_ROW) do |eve|
|
244
|
+
# too much confusion between selected and focussed row
|
245
|
+
#$current_table = eve.text if $db
|
246
|
+
end
|
247
|
+
clist = basiclist :name => "clist", :list => ["No columns"], :title => "Columns", :height => 14,
|
248
|
+
:selection_mode => :multiple
|
249
|
+
tlist.bind(:LIST_SELECTION_EVENT) do |eve|
|
250
|
+
$selected_table = eve.source[eve.firstrow]
|
251
|
+
$current_table = $selected_table
|
252
|
+
clist.data = get_column_names $selected_table
|
253
|
+
end
|
254
|
+
clist.bind(:PRESS) do |eve|
|
255
|
+
# get data of table
|
256
|
+
if $selected_table
|
257
|
+
cols = "*"
|
258
|
+
c = clist.get_selected_values
|
259
|
+
unless c.empty?
|
260
|
+
cols = c.join(",")
|
261
|
+
end
|
262
|
+
view_data cols, $selected_table
|
263
|
+
else
|
264
|
+
alert "Select a table first."
|
265
|
+
end
|
266
|
+
end
|
267
|
+
clist.bind_key('w') {
|
268
|
+
c = clist.current_value
|
269
|
+
$where_columns ||= []
|
270
|
+
hist = ["#{c} = "]
|
271
|
+
w = ask("(UP arrow to edit) where "){ |q| q.default = "#{c} = "; q.history = hist }
|
272
|
+
$where_columns << w if w
|
273
|
+
message "where: #{$where_columns.last}. Press F4 when done"
|
274
|
+
$log.debug "XXX: WHERE: #{$where_columns} "
|
275
|
+
}
|
276
|
+
clist.bind_key('o') {
|
277
|
+
c = clist.current_value
|
278
|
+
$order_columns ||= []
|
279
|
+
$order_columns << c if c
|
280
|
+
message "order (asc): #{$order_columns.last}. Press F4 when done"
|
281
|
+
$log.debug "XXX: ORDER: #{$order_columns} "
|
282
|
+
}
|
283
|
+
clist.bind_key('O') {
|
284
|
+
c = clist.current_value
|
285
|
+
$order_columns ||= []
|
286
|
+
$order_columns << " #{c} desc " if c
|
287
|
+
message "order: #{$order_columns.last}"
|
288
|
+
$log.debug "XXX: ORDER: #{$order_columns}. Press F4 when done"
|
289
|
+
}
|
290
|
+
@statusline = status_line
|
291
|
+
@statusline.command {
|
292
|
+
# trying this out. If you want a persistent message that remains till the next on
|
293
|
+
# then send it in as $status_message
|
294
|
+
text = $status_message.value || ""
|
295
|
+
if !$current_db
|
296
|
+
"%-20s [%-s] %s" % [ Time.now, "Select a Database", text]
|
297
|
+
elsif !$current_table
|
298
|
+
"%-20s [DB: %-s | %-s ] %s" % [ Time.now, $current_db || "None", $current_table || "Select a table", text]
|
299
|
+
else
|
300
|
+
"%-20s [DB: %-s | %-s ] %s" % [ Time.now, $current_db || "None", $current_table || "----", text]
|
301
|
+
end
|
302
|
+
}
|
303
|
+
@adock = nil
|
304
|
+
keyarray = [
|
305
|
+
["F1" , "Help"], ["F10" , "Exit"],
|
306
|
+
["F2", "Menu"], ["F4", "View"],
|
307
|
+
["M-d", "Datebase"], ["M-t", "Table"],
|
308
|
+
["M-x", "Command"], nil
|
309
|
+
]
|
310
|
+
tlist_keyarray = keyarray + [ ["Sp", "Select"], nil, ["Enter","View"] ]
|
311
|
+
|
312
|
+
clist_keyarray = keyarray + [ ["Sp", "Select"], ["C-sp", "Range Sel"],
|
313
|
+
["Enter","View"], ['w', 'where'],
|
314
|
+
["o","order by"], ['O', 'order desc']
|
315
|
+
]
|
316
|
+
tarea_keyarray = keyarray + [ ["M-z", "Commands"], nil ]
|
317
|
+
#tarea_sub_keyarray = [ ["r", "Run"], ["c", "clear"], ["w","Save"], ["a", "Append next"],
|
318
|
+
#["y", "Yank"], ["Y", "yank pop"] ]
|
319
|
+
tarea_sub_keyarray = [ ["r", "Run"], ["c", "clear"], ["w","Kill Ring Save (M-w)"], ["a", "Append Next"],
|
320
|
+
["y", "Yank (C-y)"], ["Y", "yank pop (M-y)"],
|
321
|
+
["u", "Undo (C-_)"], ["R", "Redo (C-r)"],
|
322
|
+
]
|
323
|
+
|
324
|
+
gw = get_color($reversecolor, 'green', 'black')
|
325
|
+
@adock = dock keyarray, { :row => Ncurses.LINES-2, :footer_color_pair => $datacolor,
|
326
|
+
:footer_mnemonic_color_pair => gw }
|
327
|
+
@adock.set_key_labels tlist_keyarray, :tables
|
328
|
+
@adock.set_key_labels clist_keyarray, :columns
|
329
|
+
@adock.set_key_labels tarea_sub_keyarray, :tarea_sub
|
330
|
+
@adock.set_key_labels tarea_keyarray, :tarea
|
331
|
+
tlist.bind(:ENTER) { @adock.mode :tables }
|
332
|
+
clist.bind(:ENTER) { @adock.mode :columns }
|
333
|
+
|
334
|
+
reduce = lambda { |obj|
|
335
|
+
obj.height -= 1 if obj.height > 3
|
336
|
+
}
|
337
|
+
increase = lambda { |obj|
|
338
|
+
obj.height += 1 if obj.height + obj.row < Ncurses.LINES-2
|
339
|
+
}
|
340
|
+
_lower = lambda { |obj|
|
341
|
+
obj.row += 1 if obj.height + obj.row < Ncurses.LINES-2
|
342
|
+
}
|
343
|
+
_raise = lambda { |obj|
|
344
|
+
obj.row -= 1 if obj.row > 2
|
345
|
+
}
|
346
|
+
[clist, tlist].each do |o|
|
347
|
+
o.bind_key([?\C-x, ?-]){ |o| reduce.call(o) }
|
348
|
+
o.bind_key([?\C-x, ?+]){ |o| increase.call(o) }
|
349
|
+
o.bind_key([?\C-x, ?v]){ |o| _lower.call(o) }
|
350
|
+
o.bind_key([?\C-x, ?6]){ |o| _raise.call(o) }
|
351
|
+
end
|
352
|
+
|
353
|
+
|
354
|
+
@form.bind_key([?q,?q]) { throw :close }
|
355
|
+
@form.bind_key(?\M-t) do
|
356
|
+
if $current_db.nil?
|
357
|
+
alert "Please select database first"
|
358
|
+
else
|
359
|
+
create_popup( get_table_names,:single) {|value| $selected_table = $current_table = value}
|
360
|
+
end
|
361
|
+
end
|
362
|
+
@form.bind_key(?\M-d) do
|
363
|
+
ask_databases
|
364
|
+
end
|
365
|
+
@form.bind_key(Ncurses::KEY_F4) do
|
366
|
+
$where_string = nil
|
367
|
+
$order_string = nil
|
368
|
+
if $where_columns
|
369
|
+
$where_string = " where " + $where_columns.join(" and ")
|
370
|
+
end
|
371
|
+
if $order_columns
|
372
|
+
$order_string = " order by " + $order_columns.join(" , ")
|
373
|
+
end
|
374
|
+
# mismatch between current and selected table
|
375
|
+
if $current_table
|
376
|
+
cols = "*"
|
377
|
+
c = clist.get_selected_values
|
378
|
+
unless c.empty?
|
379
|
+
cols = c.join(",")
|
380
|
+
end
|
381
|
+
view_data cols, $current_table
|
382
|
+
else
|
383
|
+
alert "Select a table first."
|
384
|
+
end
|
385
|
+
end
|
386
|
+
end # stack
|
387
|
+
stack :margin => 50, :width => :EXPAND do
|
388
|
+
tarea = textarea :name => 'tarea', :height => 20, :title => 'Sql Statement'
|
389
|
+
undom = SimpleUndo.new tarea
|
390
|
+
tarea.bind_key(Ncurses::KEY_F4) do
|
391
|
+
text = tarea.get_text
|
392
|
+
if text == ""
|
393
|
+
alert "Please enter a query and then hit F4. Or press F4 over column list"
|
394
|
+
else
|
395
|
+
view_sql tarea.get_text
|
396
|
+
end
|
397
|
+
end
|
398
|
+
tarea.bind(:ENTER) { @adock.mode :tarea }
|
399
|
+
tarea.bind_key(?\M-z){
|
400
|
+
|
401
|
+
hash = { 'c' => lambda{ tarea.remove_all },
|
402
|
+
'w' => lambda{ tarea.kill_ring_save },
|
403
|
+
'a' => lambda{ tarea.append_next_kill },
|
404
|
+
'y' => lambda{ tarea.yank },
|
405
|
+
'Y' => lambda{ tarea.yank_pop },
|
406
|
+
'r' => lambda{ view_sql tarea.get_text },
|
407
|
+
'u' => lambda{ tarea.undo },
|
408
|
+
'R' => lambda{ tarea.redo },
|
409
|
+
}
|
410
|
+
|
411
|
+
|
412
|
+
@adock.mode :tarea_sub
|
413
|
+
@adock.repaint
|
414
|
+
keys = @adock.get_current_keys
|
415
|
+
while((ch = @window.getchar()) != ?\C-c.getbyte(0) )
|
416
|
+
if ch < 33 || ch > 126
|
417
|
+
Ncurses.beep
|
418
|
+
elsif !keys.include?(ch.chr)
|
419
|
+
Ncurses.beep
|
420
|
+
else
|
421
|
+
hash.fetch(ch.chr).call
|
422
|
+
#opt_file ch.chr
|
423
|
+
break
|
424
|
+
end
|
425
|
+
end
|
426
|
+
@adock.mode :normal
|
427
|
+
} # M-z
|
428
|
+
flow do
|
429
|
+
button_row = 17
|
430
|
+
button "Save" do
|
431
|
+
@cmd_history ||= []
|
432
|
+
filename = ask("File to append contents to: ") { |q| q.default = @oldfilename; q.history = @cmd_history }
|
433
|
+
|
434
|
+
if filename
|
435
|
+
str = tarea.get_text
|
436
|
+
File.open(filename, 'a') {|f| f.write(str) }
|
437
|
+
@oldfilename = filename
|
438
|
+
@cmd_history << filename unless @cmd_history.include? filename
|
439
|
+
|
440
|
+
message "Appended data to #{filename}"
|
441
|
+
else
|
442
|
+
message "Aborted operation"
|
443
|
+
end
|
444
|
+
hide_bottomline
|
445
|
+
end
|
446
|
+
button "Read" do
|
447
|
+
filter = "*"
|
448
|
+
str = choose filter, :title => "Files", :prompt => "Choose a file: "
|
449
|
+
begin
|
450
|
+
tarea.set_content(str)
|
451
|
+
message "Read content from #{str} "
|
452
|
+
rescue => err
|
453
|
+
say_with_pause "No file named: #{str}: #{err.to_s} "
|
454
|
+
end
|
455
|
+
end
|
456
|
+
#ok_button = button( [button_row,30], "OK", {:mnemonic => 'O'}) do
|
457
|
+
#end
|
458
|
+
end
|
459
|
+
end
|
460
|
+
end # app
|