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/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
|