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/Manifest.txt +4 -1
- 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/testd.db +0 -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/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
- data/lib/rbcurse.rb +1 -1
- metadata +5 -3
- data/lib/rbcurse/rform.rb +0 -845
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
|
data/examples/testd.db
ADDED
Binary file
|
data/examples/testtable.rb
CHANGED
@@ -83,10 +83,6 @@ if $0 == __FILE__
|
|
83
83
|
#
|
84
84
|
## key bindings fo texta
|
85
85
|
# column widths
|
86
|
-
$log.debug " tcm #{tcm.inspect}"
|
87
|
-
$log.debug " tcms #{tcm.columns}"
|
88
|
-
$log.debug " tcm0 #{tcm.column(0).identifier}"
|
89
|
-
$log.debug " tcm0 #{tcm.column(0).width}"
|
90
86
|
tcm.column(0).width 24
|
91
87
|
tcm.column(1).width 5
|
92
88
|
tcm.column(2).width 18
|
data/examples/testtabp.rb
CHANGED
@@ -20,6 +20,7 @@ class TestTabbedPane
|
|
20
20
|
width 50
|
21
21
|
row 5
|
22
22
|
col 10
|
23
|
+
button_type :ok
|
23
24
|
end
|
24
25
|
@tab1 = @tp.add_tab "&Language"
|
25
26
|
f1 = @tab1.form
|
@@ -95,6 +96,7 @@ if $0 == __FILE__
|
|
95
96
|
$log = Logger.new("view.log")
|
96
97
|
$log.level = Logger::DEBUG
|
97
98
|
n = TestTabbedPane.new
|
99
|
+
n.run
|
98
100
|
rescue => ex
|
99
101
|
ensure
|
100
102
|
VER::stop_ncurses
|
data/examples/testtodo.rb
CHANGED
@@ -13,23 +13,53 @@ require 'rbcurse/keylabelprinter'
|
|
13
13
|
require 'rbcurse/applicationheader'
|
14
14
|
require 'rbcurse/action'
|
15
15
|
|
16
|
+
# TODO move the csv to a database so you can update. this sucketh.
|
17
|
+
#
|
16
18
|
class TodoList
|
17
19
|
def initialize file
|
18
20
|
@file = file
|
19
21
|
end
|
20
22
|
def load
|
21
|
-
|
23
|
+
#@todomap = YAML::load(File.open(@file));
|
24
|
+
@data =[]
|
25
|
+
@statuses=[]
|
26
|
+
@categories=[]
|
27
|
+
@modules=[]
|
28
|
+
require 'csv'
|
29
|
+
CSV::Reader.parse(File.open(@file, 'r')) do |row|
|
30
|
+
@data << row
|
31
|
+
$log.debug " #{row.inspect} "
|
32
|
+
@categories << row[0] unless @categories.include? row[0]
|
33
|
+
@statuses << row[4] unless @statuses.include? row[4]
|
34
|
+
@modules << row[1] unless @modules.include? row[1]
|
35
|
+
end
|
36
|
+
$log.debug " MOD #{@modules}"
|
22
37
|
end
|
23
38
|
def get_statuses
|
24
|
-
@todomap['__STATUSES']
|
39
|
+
# @todomap['__STATUSES']
|
40
|
+
@statuses
|
25
41
|
end
|
26
42
|
def get_modules
|
27
|
-
|
43
|
+
#@todomap['__MODULES'].sort
|
44
|
+
@modules.sort
|
28
45
|
end
|
29
46
|
def get_categories
|
30
|
-
|
47
|
+
#@todomap.keys.delete_if {|k| k.match(/^__/) }
|
48
|
+
@categories
|
31
49
|
end
|
32
50
|
def get_tasks_for_category categ
|
51
|
+
@data.select do |row|
|
52
|
+
row[0] == categ
|
53
|
+
end
|
54
|
+
end
|
55
|
+
def insert_task_for_category task, categ
|
56
|
+
task[0] = categ
|
57
|
+
@data << task
|
58
|
+
end
|
59
|
+
def delete_task task
|
60
|
+
@data.delete task
|
61
|
+
end
|
62
|
+
def oldget_tasks_for_category categ
|
33
63
|
c = @todomap[categ]
|
34
64
|
d = []
|
35
65
|
c.each_pair {|k,v|
|
@@ -44,6 +74,14 @@ class TodoList
|
|
44
74
|
return d
|
45
75
|
end
|
46
76
|
def set_tasks_for_category categ, data
|
77
|
+
$log.debug " def set_tasks_for_category #{categ}, #{data.size} old #{@data.size}"
|
78
|
+
@data.delete_if { |row| row[0] == categ }
|
79
|
+
$log.debug " 2 def set_tasks_for_category #{categ}, #{data.size} old #{@data.size}"
|
80
|
+
data.each { |row| row[0] = categ }
|
81
|
+
@data.insert -1, *data
|
82
|
+
$log.debug " 3 def set_tasks_for_category #{categ}, #{data.size} old #{@data.size}"
|
83
|
+
end
|
84
|
+
def old_set_tasks_for_category categ, data
|
47
85
|
d = {}
|
48
86
|
data.each do |row|
|
49
87
|
#key = row.delete_at 0
|
@@ -55,6 +93,7 @@ class TodoList
|
|
55
93
|
$log.debug " NEW DATA #{categ}: #{data}"
|
56
94
|
end
|
57
95
|
def convert_to_text
|
96
|
+
=begin
|
58
97
|
d = []
|
59
98
|
cats = get_categories
|
60
99
|
cats.each do |c|
|
@@ -65,8 +104,10 @@ class TodoList
|
|
65
104
|
d << n
|
66
105
|
end
|
67
106
|
end
|
68
|
-
File.open("todo.
|
107
|
+
#File.open("todo.yml", "w") { |f| YAML.dump( d, f )}
|
69
108
|
buf =''
|
109
|
+
=end
|
110
|
+
d = @data
|
70
111
|
require 'csv'
|
71
112
|
CSV.open('todocsv.csv', 'w') do |writer|
|
72
113
|
#writer << [nil, nil]
|
@@ -105,7 +146,7 @@ class TodoApp
|
|
105
146
|
@window = VER::Window.root_window
|
106
147
|
@form = Form.new @window
|
107
148
|
|
108
|
-
@todo = TodoList.new "
|
149
|
+
@todo = TodoList.new "todocsv.csv"
|
109
150
|
@todo.load
|
110
151
|
end
|
111
152
|
def make_popup table
|
@@ -218,14 +259,14 @@ class TodoApp
|
|
218
259
|
data = todo.get_tasks_for_category 'TODO'
|
219
260
|
@data = data
|
220
261
|
$log.debug " data is #{data}"
|
221
|
-
colnames = %w[ Module Prior Task Status]
|
262
|
+
colnames = %w[ Categ Module Prior Task Status]
|
222
263
|
|
223
264
|
table_ht = 15
|
224
265
|
atable = Table.new @form do
|
225
266
|
name "tasktable"
|
226
267
|
row r+2
|
227
268
|
col c
|
228
|
-
width
|
269
|
+
width 84
|
229
270
|
height table_ht
|
230
271
|
#title "A Table"
|
231
272
|
#title_attrib (Ncurses::A_REVERSE | Ncurses::A_BOLD)
|
@@ -238,8 +279,8 @@ class TodoApp
|
|
238
279
|
data = todo.get_tasks_for_category fld.getvalue;
|
239
280
|
@data = data
|
240
281
|
$log.debug " DATA is #{data.inspect} : #{data.length}"
|
241
|
-
data = [[nil, 5, "NEW ", "TODO", Time.now]] if data.nil? or data.empty? or data.size == 0
|
242
|
-
|
282
|
+
data = [['FIXME',nil, 5, "NEW ", "TODO", Time.now]] if data.nil? or data.empty? or data.size == 0
|
283
|
+
#$log.debug " DATA is #{data.inspect} : #{data.length}"
|
243
284
|
atable.table_model.data = data
|
244
285
|
end
|
245
286
|
|
@@ -247,12 +288,15 @@ class TodoApp
|
|
247
288
|
#
|
248
289
|
## key bindings fo atable
|
249
290
|
# column widths
|
250
|
-
|
251
|
-
|
252
|
-
tcm.column(0).width
|
253
|
-
tcm.column(
|
254
|
-
tcm.column(
|
255
|
-
tcm.column(
|
291
|
+
#$log.debug " tcm #{tcm.inspect}"
|
292
|
+
#$log.debug " tcms #{tcm.columns}"
|
293
|
+
tcm.column(0).width 5
|
294
|
+
tcm.column(0).editable false
|
295
|
+
tcm.column(1).width 8
|
296
|
+
tcm.column(2).width 5
|
297
|
+
tcm.column(3).width 50
|
298
|
+
tcm.column(3).edit_length 80
|
299
|
+
tcm.column(4).width 8
|
256
300
|
app = self
|
257
301
|
atable.configure() do
|
258
302
|
#bind_key(330) { atable.remove_column(tcm.column(atable.focussed_col)) rescue "" }
|
@@ -303,11 +347,11 @@ class TodoApp
|
|
303
347
|
atable.set_default_cell_renderer_for_class "Float", num_renderer
|
304
348
|
atable.set_default_cell_renderer_for_class "TrueClass", bool_renderer
|
305
349
|
atable.set_default_cell_renderer_for_class "FalseClass", bool_renderer
|
306
|
-
atable.get_table_column_model.column(
|
307
|
-
atable.get_table_column_model.column(
|
350
|
+
atable.get_table_column_model.column(4).cell_editor = combo_editor
|
351
|
+
atable.get_table_column_model.column(1).cell_editor = combo_editor1
|
308
352
|
ce = atable.get_default_cell_editor_for_class "String"
|
309
353
|
# increase the maxlen of task
|
310
|
-
ce.component.maxlen = 80
|
354
|
+
# ce.component.maxlen = 80 # this is obsolete, use edit_length
|
311
355
|
# I want up and down to go up and down rows inside the combo box, i can use M-down for changing.
|
312
356
|
combo_editor.component.unbind_key(KEY_UP)
|
313
357
|
combo_editor.component.unbind_key(KEY_DOWN)
|
@@ -416,17 +460,21 @@ class TodoApp
|
|
416
460
|
amod = mods[@mb.selected_index]
|
417
461
|
row = atable.focussed_row
|
418
462
|
d = todo.get_tasks_for_category amod
|
463
|
+
$log.debug " retrieved #{d.size} rows for #{amod}"
|
419
464
|
r = []
|
420
|
-
tcm = atable.
|
465
|
+
tcm = atable.table_column_model
|
421
466
|
tcm.each_with_index do |acol, colix|
|
422
467
|
r << atable.get_value_at(row, colix)
|
423
468
|
end
|
424
469
|
# here i ignore the 5th row tht coud have been added
|
425
470
|
r << Time.now
|
426
471
|
d << r
|
472
|
+
$log.debug " sending #{d.size} rows for #{amod}"
|
427
473
|
todo.set_tasks_for_category amod, d
|
474
|
+
$log.debug " MOVE #{data.size} rows for #{categ.getvalue}"
|
428
475
|
tm = atable.table_model
|
429
476
|
ret = tm.delete_at row
|
477
|
+
$log.debug " MOVE after del #{data.size} rows for #{categ.getvalue}"
|
430
478
|
todo.set_tasks_for_category categ.getvalue, data
|
431
479
|
alert("Moved row #{row} to #{amod}.")
|
432
480
|
}
|
@@ -469,15 +517,17 @@ class TodoApp
|
|
469
517
|
#@new_act = Action.new("New Row", "mnemonic"=>"N") {
|
470
518
|
@new_act = Action.new("&New Row") {
|
471
519
|
mod = nil
|
520
|
+
cat = 'TODO'
|
472
521
|
cc = atable.get_table_column_model.column_count
|
473
522
|
if atable.row_count < 1
|
474
523
|
frow = 0
|
475
524
|
else
|
476
525
|
frow = atable.focussed_row
|
477
526
|
#frow += 1 # why ?
|
478
|
-
|
527
|
+
cat = atable.get_value_at(frow,0) unless frow.nil?
|
528
|
+
mod = atable.get_value_at(frow,1) unless frow.nil?
|
479
529
|
end
|
480
|
-
tmp = [mod, 5, "", "TODO", Time.now]
|
530
|
+
tmp = [cat,mod, 5, "", "TODO", Time.now]
|
481
531
|
tm = atable.table_model
|
482
532
|
tm.insert frow, tmp
|
483
533
|
atable.set_focus_on frow
|
@@ -488,7 +538,7 @@ class TodoApp
|
|
488
538
|
@save_cmd = lambda {
|
489
539
|
todo.set_tasks_for_category categ, data
|
490
540
|
todo.dump
|
491
|
-
alert("Rewritten
|
541
|
+
alert("Rewritten csv file")
|
492
542
|
}
|
493
543
|
@del_cmd = lambda {
|
494
544
|
row = atable.focussed_row
|
@@ -0,0 +1,28 @@
|
|
1
|
+
FIXME,MSGBOX,5,Confirm dialog: box vertical line overwritten in 2 spots,TODO
|
2
|
+
FIXME,MSGBOX,5,Confirm dialog: use normal key as hotkey also,TODO,Tue Jan 20 11:44:49 +0530 2009
|
3
|
+
FIXME,MSGBOX,5,Confirm dialog: arrow keys not navigating anylonger,TODO,Tue Jan 20 11:45:27 +0530 2009
|
4
|
+
FIXME,GEN,9,Message Box sizing,TODO,Thu Jan 22 20:39:21 +0530 2009
|
5
|
+
DONE,LIST,5,case insensitive char search in list and combo,TESTED,Sat Feb 21 20:43:05 +0530 2009
|
6
|
+
DONE,TABLE,5,increase the maxlen of this field please. Let us see how it goes.,TESTED
|
7
|
+
DONE,TABLE,5,Can we disable down arrow in Chkbox in table?,TESTED,Mon Jan 19 00:00:00 +0530 2009
|
8
|
+
DONE,TABLE,0,editing on enter,TESTED,Mon Jan 19 01:37:00 +0530 2009
|
9
|
+
DONE,TABLE,5,cell editors pcol is not being reset each time,TESTED,Mon Jan 19 17:47:00 +0530 2009
|
10
|
+
DONE,TABLE,5,Use TAB for intercell navig. use M-TAB for next f,TESTED,Tue Jan 20 00:38:19 +0530 2009
|
11
|
+
DONE,TABLE,5,Searching,TESTED,Sat Feb 21 20:42:10 +0530 2009
|
12
|
+
DONE,TABLE,3,Columns editable or not,TESTED,Sat Feb 21 20:43:10 +0530 2009
|
13
|
+
DONE,TABLE,1,Any way to start a table with no data and pop late,TODO,Sat Feb 21 20:43:33 +0530 2009
|
14
|
+
DONE,GEN,5,Make widget of Keylabelprinter,TESTED,Tue Jan 20 00:38:43 +0530 2009
|
15
|
+
DONE,GEN,5,Added Action class shared by Button Menuitem ,TESTED,Thu Jan 22 18:08:28 +0530 2009
|
16
|
+
DONE,GEN,5,Added PopupMenu 2009-01-22 18:09 ,TESTED,Thu Jan 22 18:09:34 +0530 2009
|
17
|
+
DONE,LIST,0,call on_enter and on_leave of component,TOTEST,Sun Feb 22 12:19:38 +0530 2009
|
18
|
+
TODO,TABLE,1,table.set_data should check if models already created.,TODO
|
19
|
+
TODO,TABLE,5,"Set column_class in TableColumn, to avoid hassles",TODO
|
20
|
+
TODO,TABLE,2,Table sorting and filtering is required - using VIEW,TODO
|
21
|
+
TODO,TABLE,5,Table height and col widths auto sizing or FILLING extra space.,TODO
|
22
|
+
TODO,TEXTAREA,9,"Textarea: wrap options NONE, COLUMN",TODO,Tue Jan 20 01:04:15 +0530 2009
|
23
|
+
TODO,GEN,5,"Modified should check if value changed, not UP etc",TOTEST
|
24
|
+
TODO,GEN,5,Give a decent FileChooser and FileSaver,TODO
|
25
|
+
TODO,GEN,5,Focus Traversable vs focusable,TODO
|
26
|
+
TODO,GEN,5,Action class: fire event for listeners,TODO,Thu Jan 22 20:09:50 +0530 2009
|
27
|
+
TODO,FIELD,5,Field: OVERWRITE Mode,TODO
|
28
|
+
TODO,FIELD,5,Field: Auto-skip when reaching end of maxlen,TODO
|