rkumar-rbcurse 0.1.1 → 0.1.2
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 +40 -0
- data/History.txt +13 -0
- data/README.txt +13 -12
- data/examples/rfe.rb +150 -34
- data/examples/rfe_renderer.rb +6 -0
- data/examples/sqlc.rb +419 -0
- data/examples/testtable.rb +0 -4
- data/examples/testtabp.rb +2 -0
- data/examples/testtodo.rb +73 -23
- data/examples/todocsv.csv +28 -0
- data/lib/rbcurse.rb +1 -1
- data/lib/rbcurse/defaultlistselectionmodel.rb +14 -0
- data/lib/rbcurse/listcellrenderer.rb +7 -0
- data/lib/rbcurse/listkeys.rb +7 -4
- data/lib/rbcurse/listscrollable.rb +144 -7
- data/lib/rbcurse/listselectable.rb +23 -2
- data/lib/rbcurse/rlistbox.rb +69 -15
- data/lib/rbcurse/rmessagebox.rb +14 -5
- data/lib/rbcurse/rtabbedpane.rb +64 -2
- data/lib/rbcurse/rtable.rb +223 -18
- data/lib/rbcurse/rtextarea.rb +34 -2
- data/lib/rbcurse/rtextview.rb +27 -4
- data/lib/rbcurse/rwidget.rb +9 -3
- data/lib/rbcurse/table/tablecellrenderer.rb +1 -0
- metadata +4 -1
data/CHANGELOG
CHANGED
@@ -1,3 +1,43 @@
|
|
1
|
+
** 2009-02-17 12:10 **
|
2
|
+
## added table markers for data and columns before and after on border ##
|
3
|
+
|
4
|
+
also added putting space in intercell area, but today i am not getting any
|
5
|
+
junk there anywaym while scrolling etc.
|
6
|
+
|
7
|
+
* * *
|
8
|
+
** 2009-02-16 22:10 **
|
9
|
+
## added edit_length to TableColumn ##
|
10
|
+
|
11
|
+
This is max editable length of editor component in tables.
|
12
|
+
|
13
|
+
* * *
|
14
|
+
** 2009-02-13 13:48 **
|
15
|
+
## added button_type to tabbed pane ##
|
16
|
+
|
17
|
+
Now buttons at bottom of tabbed pane. Will return selected_index
|
18
|
+
to caller.
|
19
|
+
Uploaded to github, will be included in 0.1.2.
|
20
|
+
|
21
|
+
* * *
|
22
|
+
** 2009-02-12 22:48 **
|
23
|
+
## Code to stop table from printing a column if exceeding bounds ##
|
24
|
+
|
25
|
+
Uploaded to github, will be included in 0.1.2.
|
26
|
+
|
27
|
+
EXPERIMENTAL CODE: Affects only tables. Now table will not print a column or header
|
28
|
+
if columns width causes it to exceed width of table.
|
29
|
+
|
30
|
+
This means if you have a single column which is wider than table
|
31
|
+
then it wont print. In Listboxes we always truncate data and pass to
|
32
|
+
renderer. We could do that here, but it could get messy.
|
33
|
+
|
34
|
+
* * *
|
35
|
+
**2009-02-12 **
|
36
|
+
## Missed one parameter in Table's repaint, and some Table Cell Renderers
|
37
|
+
|
38
|
+
Fixed and uploaded as 0.1.1
|
39
|
+
|
40
|
+
* * *
|
1
41
|
**2009-02-11 00:57**
|
2
42
|
## Path changes in order to make first gem ##
|
3
43
|
|
data/History.txt
ADDED
data/README.txt
CHANGED
@@ -13,13 +13,19 @@
|
|
13
13
|
|
14
14
|
* rfe.rb is a ruby file explorer
|
15
15
|
|
16
|
+
* sqlc.rb is a ruby sql client demo (using testd.db at
|
17
|
+
http://www.benegal.org/files/screen/testd.db)
|
18
|
+
|
16
19
|
* testtodo.rb is a test TODO application
|
17
20
|
|
18
|
-
* Screenshots on
|
19
|
-
|
20
|
-
and http://www.benegal.org/files/screen/?M=D (new)
|
21
|
+
* Screenshots on
|
22
|
+
http://www.benegal.org/files/screen/?M=D (new)
|
21
23
|
and on blog, http://totalrecall.wordpress.com
|
24
|
+
and http://github.com/rkumar/rbcurse/wikis/screenshots (old)
|
25
|
+
|
26
|
+
* Todo (for 0.1.2): http://rubyforge.org/pm/task.php?group_id=7775&group_project_id=13812&func=browse
|
22
27
|
|
28
|
+
* Next Major Release: http://rubyforge.org/pm/task.php?group_project_id=13813&group_id=7775&func=browse
|
23
29
|
|
24
30
|
== DESCRIPTION:
|
25
31
|
|
@@ -127,7 +133,7 @@ code below. See test programs for latest, working code.
|
|
127
133
|
end
|
128
134
|
field.insert 5, "hello ruby", "so long python", "farewell java", "RIP .Net"
|
129
135
|
|
130
|
-
=== create a textarea for entry
|
136
|
+
=== create a textarea for entry
|
131
137
|
|
132
138
|
texta = TextArea.new @form do
|
133
139
|
name "mytext"
|
@@ -287,21 +293,16 @@ code below. See test programs for latest, working code.
|
|
287
293
|
|
288
294
|
(following is provided with source)
|
289
295
|
|
290
|
-
* uses the window class created by "manveru" (michael)
|
291
|
-
removed if not needed. (lib/ver/window)
|
296
|
+
* uses the window class created by "manveru" (michael)
|
292
297
|
It is provided with this package, and has some alterations from the
|
293
298
|
original. I have added a method getchar() which traps and returns
|
294
299
|
ALT/META, META+CTRL, META+SHIFT+CONTROL, ALT+Fn etc.
|
295
300
|
|
296
|
-
So basically do not remove it unless you have very different
|
297
|
-
requirements.
|
298
301
|
|
299
302
|
== INSTALL:
|
300
303
|
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
(Please advice me how i can improve installation procedure)
|
304
|
+
sudo gem install ncurses-ruby
|
305
|
+
sudo gem install rbcurse
|
305
306
|
|
306
307
|
== LICENSE:
|
307
308
|
|
data/examples/rfe.rb
CHANGED
@@ -13,9 +13,14 @@ require 'fileutils'
|
|
13
13
|
#$LOAD_PATH << "/Users/rahul/work/projects/rbcurse/"
|
14
14
|
|
15
15
|
# TODO
|
16
|
-
# operations on selected files: move, delete, zip
|
16
|
+
# operations on selected files: move, delete, zip, copy
|
17
|
+
# - delete should move to Trash if exists - DONE
|
18
|
+
# global - don't ask confirm
|
19
|
+
# Select based on pattern.
|
17
20
|
# This class represents the finder pane. There are 2
|
18
21
|
# on this sample app
|
22
|
+
# NOTE: rfe_renderer uses entries so you may need to sync it with list_data_model
|
23
|
+
# actually, renderer should refer back to list data model!
|
19
24
|
class FileExplorer
|
20
25
|
include FileUtils
|
21
26
|
attr_reader :wdir
|
@@ -34,6 +39,8 @@ class FileExplorer
|
|
34
39
|
@wdir = @dir.path
|
35
40
|
@filter_pattern = '*'
|
36
41
|
@prev_dirs=[]
|
42
|
+
@inside_block = false
|
43
|
+
|
37
44
|
end
|
38
45
|
def title str
|
39
46
|
@list.title = str
|
@@ -234,19 +241,41 @@ class FileExplorer
|
|
234
241
|
def current_index
|
235
242
|
@list.current_index
|
236
243
|
end
|
237
|
-
def filename
|
244
|
+
def filename ix=current_index()
|
238
245
|
#@entries[@list.current_index]
|
239
|
-
list_data()[
|
246
|
+
list_data()[ix]
|
240
247
|
end
|
241
|
-
def filepath
|
242
|
-
f = filename()
|
248
|
+
def filepath ix=current_index()
|
249
|
+
f = filename(ix)
|
243
250
|
if f[0,1]=='/'
|
244
251
|
f
|
245
252
|
else
|
246
|
-
cur_dir() + "/" +
|
253
|
+
cur_dir() + "/" + f
|
254
|
+
end
|
255
|
+
end
|
256
|
+
# delete the item at position i
|
257
|
+
def delete_at i=@list.current_index
|
258
|
+
ret = @list.list_data_model.delete_at i
|
259
|
+
ret = @entries.delete_at i
|
260
|
+
end
|
261
|
+
def delete obj
|
262
|
+
ret = @list.list_data_model.delete obj
|
263
|
+
ret = @entries.delete_at obj
|
264
|
+
end
|
265
|
+
def insert_at obj, ix = @list.current_index
|
266
|
+
@list.list_data_model.insert ix, f
|
267
|
+
@entries.insert ix, obj
|
268
|
+
end
|
269
|
+
def remove_selected_rows
|
270
|
+
rows = @list.selected_rows
|
271
|
+
rows=rows.sort! {|x,y| y <=> x }
|
272
|
+
rows.each do |i|
|
273
|
+
ret = @list.list_data_model.delete_at i
|
274
|
+
ret = @entries.delete_at i
|
247
275
|
end
|
248
276
|
end
|
249
277
|
|
278
|
+
# ADD
|
250
279
|
end
|
251
280
|
class RFe
|
252
281
|
attr_reader :status_row
|
@@ -258,6 +287,9 @@ class RFe
|
|
258
287
|
colb = Ncurses.COLS/2
|
259
288
|
ht = Ncurses.LINES - 7
|
260
289
|
wid = Ncurses.COLS/2 - 0
|
290
|
+
@trash_path = File.expand_path("~/.Trash")
|
291
|
+
@trash_exists = File.directory? @trash_path
|
292
|
+
$log.debug " trash_path #{@trash_path}, #{@trash_exists}"
|
261
293
|
@lista = FileExplorer.new @form, self, row=2, col=1, ht, wid
|
262
294
|
@listb = FileExplorer.new @form, self, row=2, col=colb, ht, wid
|
263
295
|
|
@@ -280,33 +312,116 @@ class RFe
|
|
280
312
|
File.open(@config_name, "w") { | f | YAML.dump( @config, f )}
|
281
313
|
end
|
282
314
|
def move
|
283
|
-
fp = @current_list.filepath
|
315
|
+
fp = @current_list.filepath #.gsub(' ',"\ ")
|
284
316
|
fn = @current_list.filename
|
285
317
|
$log.debug " FP #{fp}"
|
286
318
|
other_list = [@lista, @listb].index(@current_list)==0 ? @listb : @lista
|
287
319
|
other_dir = other_list.cur_dir
|
288
320
|
$log.debug " OL #{other_list.cur_dir}"
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
321
|
+
if @current_list.list.selected_row_count == 0
|
322
|
+
str= "#{fn}"
|
323
|
+
else
|
324
|
+
str= "#{@current_list.list.selected_row_count} files "
|
325
|
+
end
|
326
|
+
mb = RubyCurses::MessageBox.new do
|
327
|
+
title "Move"
|
328
|
+
message "Move #{str} to"
|
329
|
+
type :input
|
330
|
+
width 80
|
331
|
+
default_value other_dir
|
332
|
+
button_type :ok_cancel
|
333
|
+
default_button 0
|
334
|
+
end
|
301
335
|
#confirm "selected :#{mb.input_value}, #{mb.selected_index}"
|
302
336
|
if mb.selected_index == 0
|
303
|
-
|
304
|
-
|
305
|
-
|
337
|
+
if @current_list.list.selected_row_count == 0
|
338
|
+
FileUtils.move(fp, mb.input_value)
|
339
|
+
#ret = @current_list.list.list().delete_at @current_list.list.current_index # ???
|
340
|
+
# @current_list.entries.delete_at @current_list.current_index
|
341
|
+
@current_list.delete_at
|
342
|
+
else
|
343
|
+
each_selected_row do |f|
|
344
|
+
FileUtils.move(f, mb.input_value)
|
345
|
+
end
|
346
|
+
@current_list.remove_selected_rows
|
347
|
+
@current_list.list.clear_selection
|
348
|
+
end
|
306
349
|
other_list.rescan
|
307
350
|
end
|
308
351
|
end
|
352
|
+
def each_selected_row #title, message, default_value
|
353
|
+
rows = @current_list.list.selected_rows
|
354
|
+
rows = rows.dup
|
355
|
+
rows.each do |i|
|
356
|
+
fp = @current_list.filepath i
|
357
|
+
#$log.debug " moving #{i}: #{fp}"
|
358
|
+
#FileUtils.move(fp, mb.input_value)
|
359
|
+
yield fp
|
360
|
+
end
|
361
|
+
end
|
309
362
|
def copy
|
363
|
+
fp = @current_list.filepath #.gsub(' ',"\ ")
|
364
|
+
fn = @current_list.filename
|
365
|
+
$log.debug " FP #{fp}"
|
366
|
+
other_list = [@lista, @listb].index(@current_list)==0 ? @listb : @lista
|
367
|
+
other_dir = other_list.cur_dir
|
368
|
+
$log.debug " OL #{other_list.cur_dir}"
|
369
|
+
if @current_list.list.selected_row_count == 0
|
370
|
+
str= "#{fn}"
|
371
|
+
else
|
372
|
+
str= "#{@current_list.list.selected_row_count} files "
|
373
|
+
end
|
374
|
+
mb = RubyCurses::MessageBox.new do
|
375
|
+
title "Copy"
|
376
|
+
message "Copy #{str} to"
|
377
|
+
type :input
|
378
|
+
width 80
|
379
|
+
default_value other_dir
|
380
|
+
button_type :ok_cancel
|
381
|
+
default_button 0
|
382
|
+
end
|
383
|
+
if mb.selected_index == 0
|
384
|
+
if @current_list.list.selected_row_count == 0
|
385
|
+
FileUtils.copy(fp, mb.input_value)
|
386
|
+
else
|
387
|
+
each_selected_row do |f|
|
388
|
+
FileUtils.copy(f, mb.input_value)
|
389
|
+
end
|
390
|
+
@current_list.list.clear_selection
|
391
|
+
end
|
392
|
+
other_list.rescan
|
393
|
+
end
|
394
|
+
end
|
395
|
+
def delete
|
396
|
+
fp = @current_list.filepath #.gsub(' ',"\ ")
|
397
|
+
fn = @current_list.filename
|
398
|
+
if @current_list.list.selected_row_count == 0
|
399
|
+
str= "#{fn}"
|
400
|
+
else
|
401
|
+
str= "#{@current_list.list.selected_row_count} files "
|
402
|
+
end
|
403
|
+
if confirm("delete #{str}")==:YES
|
404
|
+
if @current_list.list.selected_row_count == 0
|
405
|
+
if @trash_exists
|
406
|
+
FileUtils.mv fp, @trash_path
|
407
|
+
else
|
408
|
+
FileUtils.rm fp
|
409
|
+
end
|
410
|
+
ret=@current_list.delete_at
|
411
|
+
else
|
412
|
+
each_selected_row do |f|
|
413
|
+
if @trash_exists
|
414
|
+
FileUtils.mv f, @trash_path
|
415
|
+
else
|
416
|
+
FileUtils.rm f
|
417
|
+
end
|
418
|
+
end
|
419
|
+
@current_list.remove_selected_rows
|
420
|
+
@current_list.list.clear_selection
|
421
|
+
end
|
422
|
+
end
|
423
|
+
end
|
424
|
+
def copy1
|
310
425
|
fp = @current_list.filepath
|
311
426
|
fn = @current_list.filename
|
312
427
|
$log.debug " FP #{fp}"
|
@@ -392,22 +507,11 @@ class RFe
|
|
392
507
|
other_list = [@lista, @listb].index(@current_list)==0 ? @listb : @lista
|
393
508
|
case c
|
394
509
|
when 'c'
|
395
|
-
# str= "copy #{fn} to #{other_list.cur_dir}"
|
396
510
|
copy
|
397
511
|
when 'm'
|
398
|
-
str= "move #{fn} to #{other_list.cur_dir}"
|
399
512
|
move
|
400
|
-
#if confirm("#{str}")==:YES
|
401
|
-
#$log.debug " MOVE #{str}"
|
402
|
-
#end
|
403
513
|
when 'd'
|
404
|
-
|
405
|
-
if confirm("#{str}")==:YES
|
406
|
-
$log.debug " delete #{fp}"
|
407
|
-
FileUtils.rm fp
|
408
|
-
ret=@current_list.list.list_data_model.delete_at @current_list.list.current_index # ???
|
409
|
-
$log.debug " DEL RET #{ret},#{@current_list.list.current_index}"
|
410
|
-
end
|
514
|
+
delete
|
411
515
|
when 'u'
|
412
516
|
str= "move #{fn} to #{other_list.cur_dir}"
|
413
517
|
if confirm("#{str}")==:YES
|
@@ -475,6 +579,14 @@ class RFe
|
|
475
579
|
str= "edit #{fp}"
|
476
580
|
#if confirm("#{str}")==:YES
|
477
581
|
edit fp
|
582
|
+
when 'm'
|
583
|
+
f = get_string("Enter a directory to create", 20 )
|
584
|
+
if f != ""
|
585
|
+
FileUtils.mkdir f
|
586
|
+
@current_list.list.list_data_model.insert @current_list.list.current_index, f # ???
|
587
|
+
@current_list.entries.insert @current_list.list.current_index, f # ???
|
588
|
+
end
|
589
|
+
|
478
590
|
when 'x'
|
479
591
|
str= "exec #{fp}"
|
480
592
|
exec_popup fp
|
@@ -508,6 +620,9 @@ class RFe
|
|
508
620
|
@lista.draw_screen lasta
|
509
621
|
@listb.draw_screen lastb
|
510
622
|
|
623
|
+
# @form.bind_key(?\M-x){
|
624
|
+
# @current_list.mark_block
|
625
|
+
# }
|
511
626
|
@form.bind_key(?@){
|
512
627
|
@current_list.change_dir File.expand_path("~/")
|
513
628
|
}
|
@@ -653,6 +768,7 @@ def get_key_labels categ=nil
|
|
653
768
|
['t', 'tree'], ['p', 'Previous'],
|
654
769
|
['b', 'Bookmark'], ['u', 'Unbookmark'],
|
655
770
|
['l', 'List'], ['s', 'Save'],
|
771
|
+
['m', 'mkdir'], nil,
|
656
772
|
['C-c', 'Cancel']
|
657
773
|
]
|
658
774
|
end
|
data/examples/rfe_renderer.rb
CHANGED
@@ -19,12 +19,14 @@ module RubyCurses
|
|
19
19
|
@bgcolor = @orig_bgcolor
|
20
20
|
@color = @orig_color
|
21
21
|
@row_attr = @orig_attr
|
22
|
+
# XXX ouch, when we delete from list, must delete from here too.
|
22
23
|
value = @parent.entries[row_index]
|
23
24
|
if value[0,1]=="/"
|
24
25
|
path = value.dup
|
25
26
|
else
|
26
27
|
path = @parent.cur_dir()+"/"+value
|
27
28
|
end
|
29
|
+
begin
|
28
30
|
stat = File.stat(path)
|
29
31
|
if File.directory? path
|
30
32
|
@row_attr = Ncurses::A_BOLD
|
@@ -33,6 +35,10 @@ module RubyCurses
|
|
33
35
|
value = format_string(value, path, stat)
|
34
36
|
super
|
35
37
|
|
38
|
+
rescue => err
|
39
|
+
$log.debug " rfe_renderer: #{err}"
|
40
|
+
end
|
41
|
+
|
36
42
|
end
|
37
43
|
GIGA_SIZE = 1073741824.0
|
38
44
|
MEGA_SIZE = 1048576.0
|
data/examples/sqlc.rb
ADDED
@@ -0,0 +1,419 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'ncurses'
|
3
|
+
require 'logger'
|
4
|
+
require 'sqlite3'
|
5
|
+
require 'rbcurse'
|
6
|
+
require 'rbcurse/rcombo'
|
7
|
+
require 'rbcurse/rtextarea'
|
8
|
+
require 'rbcurse/rtable'
|
9
|
+
#require 'rbcurse/table/tablecellrenderer'
|
10
|
+
require 'rbcurse/comboboxcellrenderer'
|
11
|
+
require 'rbcurse/keylabelprinter'
|
12
|
+
require 'rbcurse/applicationheader'
|
13
|
+
require 'rbcurse/action'
|
14
|
+
|
15
|
+
# pls get testd.db from
|
16
|
+
# http://www.benegal.org/files/screen/testd.db
|
17
|
+
# or put some other sqlite3 db name there.
|
18
|
+
|
19
|
+
## must give me @content, @columns, @datatypes (opt)
|
20
|
+
class Datasource
|
21
|
+
# attr_reader :field_length # specified by user, length of row in display table
|
22
|
+
attr_accessor :columns # names of columns in array
|
23
|
+
attr_accessor :datatypes # array of datatyps of columns required to align: int, real, float, smallint
|
24
|
+
attr_accessor :content # 2 dim data
|
25
|
+
attr_accessor :user_columns # columnnames provided by user, overrides what is generated for display
|
26
|
+
# attr_reader :sqlstring # specified by user
|
27
|
+
|
28
|
+
# constructor
|
29
|
+
def initialize(config={}, &block)
|
30
|
+
@content = []
|
31
|
+
@columns = nil # actual db columnnames -- needed to figure out datatypes
|
32
|
+
@user_columns = nil # user specified db columnnames, overrides what may be provided
|
33
|
+
@datatypes = nil
|
34
|
+
# @rows = nil
|
35
|
+
# @sqlstring = nil
|
36
|
+
# @command = nil
|
37
|
+
|
38
|
+
instance_eval(&block) if block_given?
|
39
|
+
end
|
40
|
+
def connect dbname
|
41
|
+
@db = SQLite3::Database.new(dbname)
|
42
|
+
end
|
43
|
+
# get columns and datatypes, prefetch
|
44
|
+
def get_data command
|
45
|
+
@columns, *rows = @db.execute2(command)
|
46
|
+
@content = rows
|
47
|
+
return nil if @content.nil? or @content[0].nil?
|
48
|
+
@datatypes = @content[0].types #if @datatypes.nil?
|
49
|
+
@command = command
|
50
|
+
return @content
|
51
|
+
end
|
52
|
+
def get_metadata table
|
53
|
+
get_data "select * from #{table} limit 1"
|
54
|
+
return @columns
|
55
|
+
end
|
56
|
+
##
|
57
|
+
# returns columns_widths, and updates that variable
|
58
|
+
def estimate_column_widths tablewidth, columns
|
59
|
+
colwidths = {}
|
60
|
+
min_column_width = (tablewidth/columns.length) -1
|
61
|
+
$log.debug("min: #{min_column_width}, #{tablewidth}")
|
62
|
+
@content.each_with_index do |row, cix|
|
63
|
+
break if cix >= 20
|
64
|
+
row.each_index do |ix|
|
65
|
+
col = row[ix]
|
66
|
+
colwidths[ix] ||= 0
|
67
|
+
colwidths[ix] = [colwidths[ix], col.length].max
|
68
|
+
end
|
69
|
+
end
|
70
|
+
total = 0
|
71
|
+
colwidths.each_pair do |k,v|
|
72
|
+
name = columns[k.to_i]
|
73
|
+
colwidths[name] = v
|
74
|
+
total += v
|
75
|
+
end
|
76
|
+
colwidths["__TOTAL__"] = total
|
77
|
+
column_widths = colwidths
|
78
|
+
@max_data_widths = column_widths.dup
|
79
|
+
|
80
|
+
columns.each_with_index do | col, i|
|
81
|
+
if @datatypes[i].match(/(real|int)/) != nil
|
82
|
+
wid = column_widths[i]
|
83
|
+
# cw = [column_widths[i], [8,min_column_width].min].max
|
84
|
+
$log.debug("XXX #{wid}. #{columns[i].length}")
|
85
|
+
cw = [wid, columns[i].length].max
|
86
|
+
$log.debug("int #{col} #{column_widths[i]}, #{cw}")
|
87
|
+
elsif @datatypes[i].match(/(date)/) != nil
|
88
|
+
cw = [column_widths[i], [12,min_column_width].min].max
|
89
|
+
#cw = [12,min_column_width].min
|
90
|
+
$log.debug("date #{col} #{column_widths[i]}, #{cw}")
|
91
|
+
else
|
92
|
+
cw = [column_widths[i], min_column_width].max
|
93
|
+
if column_widths[i] <= col.length and col.length <= min_column_width
|
94
|
+
cw = col.length
|
95
|
+
end
|
96
|
+
$log.debug("else #{col} #{column_widths[i]}, #{col.length} #{cw}")
|
97
|
+
end
|
98
|
+
column_widths[i] = cw
|
99
|
+
total += cw
|
100
|
+
end
|
101
|
+
column_widths["__TOTAL__"] = total
|
102
|
+
$log.debug("Estimated col widths: #{column_widths.inspect}")
|
103
|
+
@column_widths = column_widths
|
104
|
+
return column_widths
|
105
|
+
end
|
106
|
+
|
107
|
+
# added to enable query form to allow movement into table only if
|
108
|
+
# there is data 2008-10-08 17:46
|
109
|
+
# returns number of rows fetched
|
110
|
+
def data_length
|
111
|
+
return @content.length
|
112
|
+
end
|
113
|
+
|
114
|
+
end
|
115
|
+
def get_key_labels
|
116
|
+
key_labels = [
|
117
|
+
['C-q', 'Exit'], nil,
|
118
|
+
['M-s', 'Save'], ['M-m', 'Move']
|
119
|
+
]
|
120
|
+
return key_labels
|
121
|
+
end
|
122
|
+
def get_key_labels_table
|
123
|
+
key_labels = [
|
124
|
+
['M-n','NewRow'], ['M-d','DelRow'],
|
125
|
+
['C-x','Select'], nil,
|
126
|
+
['M-0', 'Top'], ['M-9', 'End'],
|
127
|
+
['C-p', 'PgUp'], ['C-n', 'PgDn'],
|
128
|
+
['M-Tab','Nxt Fld'], ['Tab','Nxt Col'],
|
129
|
+
['+','Widen'], ['-','Narrow']
|
130
|
+
]
|
131
|
+
return key_labels
|
132
|
+
end
|
133
|
+
class Sqlc
|
134
|
+
def initialize
|
135
|
+
@window = VER::Window.root_window
|
136
|
+
@form = Form.new @window
|
137
|
+
|
138
|
+
#@todo = Sql.new "todo.yml"
|
139
|
+
#@todo.load
|
140
|
+
@db = Datasource.new
|
141
|
+
@db.connect "testd.db"
|
142
|
+
end
|
143
|
+
def run
|
144
|
+
title = "rbcurse"
|
145
|
+
@header = ApplicationHeader.new @form, title, {:text2=>"Demo", :text_center=>"SQL Client"}
|
146
|
+
status_row = RubyCurses::Label.new @form, {'text' => "", :row => Ncurses.LINES-4, :col => 0, :display_length=>60}
|
147
|
+
@status_row = status_row
|
148
|
+
# setting ENTER across all objects on a form
|
149
|
+
@form.bind(:ENTER) {|f| status_row.text = f.help_text unless f.help_text.nil? }
|
150
|
+
r = 1; c = 1;
|
151
|
+
@data = [ ["No data"] ]
|
152
|
+
data = @data
|
153
|
+
colnames = %w[ Result ]
|
154
|
+
|
155
|
+
ta_ht = 5
|
156
|
+
t_width = 78
|
157
|
+
sqlarea = TextArea.new @form do
|
158
|
+
name "sqlarea"
|
159
|
+
row r
|
160
|
+
col c
|
161
|
+
width t_width
|
162
|
+
height ta_ht
|
163
|
+
title "Sql Query"
|
164
|
+
title_attrib (Ncurses::A_REVERSE | Ncurses::A_BOLD)
|
165
|
+
help_text "Enter query and press Run or Meta-r"
|
166
|
+
end
|
167
|
+
sqlarea << "select * from contacts"
|
168
|
+
buttrow = r+ta_ht+1 #Ncurses.LINES-4
|
169
|
+
#create_table_actions atable, todo, data, categ.getvalue
|
170
|
+
#save_cmd = @save_cmd
|
171
|
+
b_run = Button.new @form do
|
172
|
+
text "&Run"
|
173
|
+
row buttrow
|
174
|
+
col c
|
175
|
+
help_text "Run query"
|
176
|
+
end
|
177
|
+
## We use Action to create a button: to test out ampersand with MI and Button
|
178
|
+
#clear_act = @clear_act
|
179
|
+
b_clear = Button.new @form do
|
180
|
+
#action new_act
|
181
|
+
text "&Clear"
|
182
|
+
row buttrow
|
183
|
+
col c+10
|
184
|
+
help_text "Clear query entry box "
|
185
|
+
#bind(:ENTER) { status_row.text "New button adds a new row below current " }
|
186
|
+
end
|
187
|
+
b_clear.command {
|
188
|
+
sqlarea.remove_all
|
189
|
+
sqlarea.focus
|
190
|
+
}
|
191
|
+
|
192
|
+
# using ampersand to set mnemonic
|
193
|
+
=begin
|
194
|
+
b_delrow = Button.new @form do
|
195
|
+
text "&Delete"
|
196
|
+
row buttrow
|
197
|
+
col c+25
|
198
|
+
#bind(:ENTER) { status_row.text "Deletes focussed row" }
|
199
|
+
help_text ""
|
200
|
+
end
|
201
|
+
b_delrow.command {
|
202
|
+
#@del_cmd.call
|
203
|
+
}
|
204
|
+
=end
|
205
|
+
Button.button_layout [b_run, b_clear], buttrow, startcol=5, cols=Ncurses.COLS-1, gap=5
|
206
|
+
|
207
|
+
table_ht = 15
|
208
|
+
atable = Table.new @form do
|
209
|
+
name "tasktable"
|
210
|
+
row buttrow+1
|
211
|
+
col c
|
212
|
+
width t_width
|
213
|
+
height table_ht
|
214
|
+
#title "A Table"
|
215
|
+
#title_attrib (Ncurses::A_REVERSE | Ncurses::A_BOLD)
|
216
|
+
#set_data data, colnames
|
217
|
+
#cell_editing_allowed true
|
218
|
+
#editing_policy :EDITING_AUTO
|
219
|
+
help_text "M-Tab for next field"
|
220
|
+
end
|
221
|
+
@atable = atable
|
222
|
+
@data = data
|
223
|
+
#atable.table_model.data = data
|
224
|
+
|
225
|
+
tcm = atable.get_table_column_model
|
226
|
+
b_run.command {
|
227
|
+
query = sqlarea.get_text
|
228
|
+
run_query query
|
229
|
+
}
|
230
|
+
#
|
231
|
+
## key bindings fo atable
|
232
|
+
# column widths
|
233
|
+
app = self
|
234
|
+
atable.configure() do
|
235
|
+
#bind_key(330) { atable.remove_column(tcm.column(atable.focussed_col)) rescue "" }
|
236
|
+
bind_key(?+) {
|
237
|
+
acolumn = atable.column atable.focussed_col()
|
238
|
+
w = acolumn.width + 1
|
239
|
+
acolumn.width w
|
240
|
+
#atable.table_structure_changed
|
241
|
+
}
|
242
|
+
bind_key(?-) {
|
243
|
+
acolumn = atable.column atable.focussed_col()
|
244
|
+
w = acolumn.width - 1
|
245
|
+
if w > 3
|
246
|
+
acolumn.width w
|
247
|
+
#atable.table_structure_changed
|
248
|
+
end
|
249
|
+
}
|
250
|
+
bind_key(?>) {
|
251
|
+
colcount = tcm.column_count-1
|
252
|
+
#atable.move_column sel_col.value, sel_col.value+1 unless sel_col.value == colcount
|
253
|
+
col = atable.focussed_col
|
254
|
+
atable.move_column col, col+1 unless col == colcount
|
255
|
+
}
|
256
|
+
bind_key(?<) {
|
257
|
+
col = atable.focussed_col
|
258
|
+
atable.move_column col, col-1 unless col == 0
|
259
|
+
#atable.move_column sel_col.value, sel_col.value-1 unless sel_col.value == 0
|
260
|
+
}
|
261
|
+
bind_key(?\M-h, app) {|tab,td| $log.debug " BIND... #{tab.class}, #{td.class}"; app.make_popup atable}
|
262
|
+
end
|
263
|
+
#keylabel = RubyCurses::Label.new @form, {'text' => "", "row" => r+table_ht+3, "col" => c, "color" => "yellow", "bgcolor"=>"blue", "display_length"=>60, "height"=>2}
|
264
|
+
#eventlabel = RubyCurses::Label.new @form, {'text' => "Events:", "row" => r+table_ht+6, "col" => c, "color" => "white", "bgcolor"=>"blue", "display_length"=>60, "height"=>2}
|
265
|
+
|
266
|
+
# report some events
|
267
|
+
#atable.table_model.bind(:TABLE_MODEL_EVENT){|e| #eventlabel.text = "Event: #{e}"}
|
268
|
+
#atable.get_table_column_model.bind(:TABLE_COLUMN_MODEL_EVENT){|e| eventlabel.text = "Event: #{e}"}
|
269
|
+
atable.bind(:TABLE_TRAVERSAL_EVENT){|e| @header.text_right "Row #{e.newrow+1} of #{atable.row_count}" }
|
270
|
+
|
271
|
+
tablist_ht = 6
|
272
|
+
mylist = @db.get_data "select name from sqlite_master"
|
273
|
+
$listdata = Variable.new mylist
|
274
|
+
tablelist = Listbox.new @form do
|
275
|
+
name "tablelist"
|
276
|
+
row 1
|
277
|
+
col t_width+2
|
278
|
+
width 20
|
279
|
+
height tablist_ht
|
280
|
+
# list mylist
|
281
|
+
list_variable $listdata
|
282
|
+
#selection_mode :SINGLE
|
283
|
+
#show_selector true
|
284
|
+
title "Tables"
|
285
|
+
title_attrib 'reverse'
|
286
|
+
end
|
287
|
+
#tablelist.bind(:PRESS) { |alist| @status_row.text = "Selected #{alist.current_index}" }
|
288
|
+
tablelist.list_selection_model().bind(:LIST_SELECTION_EVENT,tablelist) { |lsm, alist| @status_row.text = "Selected #{alist.current_index}" }
|
289
|
+
|
290
|
+
collist = []
|
291
|
+
$coldata = Variable.new collist
|
292
|
+
columnlist = Listbox.new @form do
|
293
|
+
name "columnlist"
|
294
|
+
row tablist_ht+2
|
295
|
+
col t_width+2
|
296
|
+
width 20
|
297
|
+
height 15
|
298
|
+
# list mylist
|
299
|
+
list_variable $coldata
|
300
|
+
#selection_mode :SINGLE
|
301
|
+
#show_selector true
|
302
|
+
title "Columns"
|
303
|
+
title_attrib 'reverse'
|
304
|
+
end
|
305
|
+
tablelist.bind_key(32) {
|
306
|
+
@status_row.text = "Selected #{tablelist.get_content()[tablelist.current_index]}"
|
307
|
+
table = "#{tablelist.get_content()[tablelist.current_index]}"
|
308
|
+
columnlist.list_data_model.remove_all
|
309
|
+
columnlist.list_data_model.insert 0, *@db.get_metadata(table)
|
310
|
+
}
|
311
|
+
tablelist.bind_key(13) {
|
312
|
+
@status_row.text = "Selected #{tablelist.get_content()[tablelist.current_index]}"
|
313
|
+
table = "#{tablelist.get_content()[tablelist.current_index]}"
|
314
|
+
run_query "select * from #{table}"
|
315
|
+
}
|
316
|
+
|
317
|
+
|
318
|
+
@form.repaint
|
319
|
+
@window.wrefresh
|
320
|
+
Ncurses::Panel.update_panels
|
321
|
+
begin
|
322
|
+
while((ch = @window.getchar()) != ?\C-q )
|
323
|
+
#colcount = tcm.column_count-1
|
324
|
+
s = keycode_tos ch
|
325
|
+
#status_row.text = "Pressed #{ch} , #{s}"
|
326
|
+
@form.handle_key(ch)
|
327
|
+
|
328
|
+
@form.repaint
|
329
|
+
@window.wrefresh
|
330
|
+
end
|
331
|
+
ensure
|
332
|
+
@window.destroy if !@window.nil?
|
333
|
+
end
|
334
|
+
end
|
335
|
+
def run_query sql
|
336
|
+
#query = sqlarea.get_text
|
337
|
+
query = sql
|
338
|
+
begin
|
339
|
+
@content = @db.get_data query
|
340
|
+
if @content.nil?
|
341
|
+
@status_row.text = "0 rows retrieved"
|
342
|
+
return
|
343
|
+
end
|
344
|
+
#cw = @db.estimate_column_widths @atable.width, @db.columns
|
345
|
+
@atable.set_data @content, @db.columns
|
346
|
+
cw = @atable.estimate_column_widths @db.columns, @db.datatypes
|
347
|
+
@atable.set_column_widths cw
|
348
|
+
rescue => exc
|
349
|
+
alert exc.to_s
|
350
|
+
return
|
351
|
+
end
|
352
|
+
@status_row.text = "#{@content.size} rows retrieved"
|
353
|
+
@atable.repaint
|
354
|
+
end
|
355
|
+
def create_table_actions atable, todo, data, categ
|
356
|
+
#@new_act = Action.new("New Row", "mnemonic"=>"N") {
|
357
|
+
@new_act = Action.new("&New Row") {
|
358
|
+
mod = nil
|
359
|
+
cc = atable.get_table_column_model.column_count
|
360
|
+
if atable.row_count < 1
|
361
|
+
frow = 0
|
362
|
+
else
|
363
|
+
frow = atable.focussed_row
|
364
|
+
#frow += 1 # why ?
|
365
|
+
mod = atable.get_value_at(frow,0) unless frow.nil?
|
366
|
+
end
|
367
|
+
tmp = [mod, 5, "", "TODO", Time.now]
|
368
|
+
tm = atable.table_model
|
369
|
+
tm.insert frow, tmp
|
370
|
+
atable.set_focus_on frow
|
371
|
+
@status_row.text = "Added a row. Please press Save before changing Category."
|
372
|
+
alert("Added a row before current one. Use C-k to clear task.")
|
373
|
+
}
|
374
|
+
@new_act.accelerator "Alt-N"
|
375
|
+
@save_cmd = lambda {
|
376
|
+
todo.set_tasks_for_category categ, data
|
377
|
+
todo.dump
|
378
|
+
alert("Rewritten yaml file")
|
379
|
+
}
|
380
|
+
@del_cmd = lambda {
|
381
|
+
row = atable.focussed_row
|
382
|
+
if !row.nil?
|
383
|
+
if confirm("Do your really want to delete row #{row+1}?")== :YES
|
384
|
+
tm = atable.table_model
|
385
|
+
tm.delete_at row
|
386
|
+
else
|
387
|
+
@status_row.text = "Delete cancelled"
|
388
|
+
end
|
389
|
+
end
|
390
|
+
}
|
391
|
+
|
392
|
+
end
|
393
|
+
end
|
394
|
+
if $0 == __FILE__
|
395
|
+
include RubyCurses
|
396
|
+
include RubyCurses::Utils
|
397
|
+
|
398
|
+
begin
|
399
|
+
# Initialize curses
|
400
|
+
VER::start_ncurses # this is initializing colors via ColorMap.setup
|
401
|
+
$log = Logger.new("view.log")
|
402
|
+
$log.level = Logger::DEBUG
|
403
|
+
|
404
|
+
colors = Ncurses.COLORS
|
405
|
+
$log.debug "START #{colors} colors ---------"
|
406
|
+
|
407
|
+
catch(:close) do
|
408
|
+
t = Sqlc.new
|
409
|
+
t.run
|
410
|
+
end
|
411
|
+
rescue => ex
|
412
|
+
ensure
|
413
|
+
VER::stop_ncurses
|
414
|
+
p ex if ex
|
415
|
+
p(ex.backtrace.join("\n")) if ex
|
416
|
+
$log.debug( ex) if ex
|
417
|
+
$log.debug(ex.backtrace.join("\n")) if ex
|
418
|
+
end
|
419
|
+
end
|