rbcurse-extras 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. data/README.md +75 -0
  2. data/VERSION +1 -0
  3. data/examples/data/list.txt +300 -0
  4. data/examples/data/lotr.txt +12 -0
  5. data/examples/data/table.txt +36 -0
  6. data/examples/data/tasks.txt +27 -0
  7. data/examples/data/unix1.txt +21 -0
  8. data/examples/inc/qdfilechooser.rb +70 -0
  9. data/examples/inc/rfe_renderer.rb +121 -0
  10. data/examples/newtabbedwindow.rb +100 -0
  11. data/examples/rfe.rb +1236 -0
  12. data/examples/test2.rb +670 -0
  13. data/examples/testeditlist.rb +78 -0
  14. data/examples/testtable.rb +270 -0
  15. data/examples/testvimsplit.rb +141 -0
  16. data/lib/rbcurse/extras/include/celleditor.rb +112 -0
  17. data/lib/rbcurse/extras/include/checkboxcellrenderer.rb +57 -0
  18. data/lib/rbcurse/extras/include/comboboxcellrenderer.rb +30 -0
  19. data/lib/rbcurse/extras/include/defaultlistselectionmodel.rb +79 -0
  20. data/lib/rbcurse/extras/include/listkeys.rb +37 -0
  21. data/lib/rbcurse/extras/include/listselectable.rb +144 -0
  22. data/lib/rbcurse/extras/include/tableextended.rb +40 -0
  23. data/lib/rbcurse/extras/widgets/horizlist.rb +203 -0
  24. data/lib/rbcurse/extras/widgets/menutree.rb +63 -0
  25. data/lib/rbcurse/extras/widgets/multilinelabel.rb +142 -0
  26. data/lib/rbcurse/extras/widgets/rcomboedit.rb +256 -0
  27. data/lib/rbcurse/extras/widgets/rlink.rb.moved +27 -0
  28. data/lib/rbcurse/extras/widgets/rlistbox.rb +1247 -0
  29. data/lib/rbcurse/extras/widgets/rmenulink.rb.moved +21 -0
  30. data/lib/rbcurse/extras/widgets/rmulticontainer.rb +304 -0
  31. data/lib/rbcurse/extras/widgets/rmultisplit.rb +722 -0
  32. data/lib/rbcurse/extras/widgets/rmultitextview.rb +306 -0
  33. data/lib/rbcurse/extras/widgets/rpopupmenu.rb +755 -0
  34. data/lib/rbcurse/extras/widgets/rtable.rb +1758 -0
  35. data/lib/rbcurse/extras/widgets/rvimsplit.rb +800 -0
  36. data/lib/rbcurse/extras/widgets/table/tablecellrenderer.rb +86 -0
  37. data/lib/rbcurse/extras/widgets/table/tabledatecellrenderer.rb +98 -0
  38. metadata +94 -0
@@ -0,0 +1,1758 @@
1
+ =begin
2
+ * Name: table widget
3
+ * Description:
4
+ * Author: rkumar
5
+
6
+
7
+ TODO: NOTE:
8
+ A few higher level methods check for no data but lower level ones do not.
9
+ XXX FIXME if M-tab to exit table then editing_stopped should be called.
10
+ currenty valus is lost if exiting table using Mtab or M-S-tab 2009-10-06 15:10
11
+ FIXME if a field is not printed since it is going out, tab still goes there, and celleditor
12
+ still prints there. - DONE
13
+
14
+ FIXME Increasing a column shoud decrease others till min size but not push off.
15
+ Should we have a method for changing column width online that recomputes others?
16
+ See testtable.rb - TODO a bit later
17
+ FIXME - tabbing in a row, should auto scroll to columns not displayed ?
18
+ currently it moves to next row. (examples/sqlc.rb) - DONE
19
+
20
+ * 2010-01-18 19:54 - BUFFERING related changes.
21
+ * 2011-09-30 - removed all buffer related stuff
22
+ --------
23
+ * Date: 2008-12-27 21:33
24
+ * License:
25
+ Same as Ruby's License (http://www.ruby-lang.org/LICENSE.txt)
26
+
27
+ =end
28
+ require 'logger'
29
+ require 'rbcurse'
30
+ require 'rbcurse/extras/widgets/table/tablecellrenderer'
31
+ require 'rbcurse/extras/widgets/table/tabledatecellrenderer'
32
+ require 'rbcurse/extras/include/checkboxcellrenderer'
33
+ require 'rbcurse/extras/include/listselectable'
34
+ require 'rbcurse/extras/include/listkeys'
35
+
36
+ #include Ncurses # FFI 2011-09-8
37
+ include RubyCurses
38
+ module RubyCurses
39
+ extend self
40
+
41
+ # ------ NOTE ------------------ #
42
+ # Table contains a TableModel
43
+ # Table contains a TableColumnModel (which contains TableColumn instances)
44
+ # TableColumn contains 2 TableCellRenderer: column and header
45
+ # ------------------------ #
46
+ #
47
+ #
48
+ # Due to not having method overloading, after usig new, use set_data or set_model
49
+ #
50
+ # This is a widget that displays tabular data. We will get into editing after this works out.
51
+ # This uses the MVC architecture and is WIP as of 2009-01-04 18:37
52
+ # TODO cellrenderers should be able to get parents bgcolor and color (Jtables) if none defined for them.
53
+ class Table < Widget
54
+ #include RubyCurses::EventHandler # widget does 2009-01-15 15:38
55
+ include RubyCurses::ListSelectable
56
+ include RubyCurses::ListKeys
57
+
58
+ dsl_accessor :title
59
+ dsl_accessor :title_attrib
60
+ dsl_accessor :selected_color, :selected_bgcolor, :selected_attr
61
+ attr_accessor :current_index # the row index universally
62
+ #attr_accessor :current_column # index of column (usually in current row )
63
+ # a changed event of an editor component can utitlize this if it wishes to know
64
+ # the row or col that was exited.
65
+ attr_reader :editing_col, :editing_row # r and col being edited, set to nil on leave
66
+ attr_accessor :is_editing # boolean is only true if cell_editing_allowed
67
+ # if set editing starts when you enter a cell, otherwise you would
68
+ # have to toggle to start editing.
69
+ dsl_accessor :editing_policy # :EDITING_AUTO
70
+ dsl_accessor :size_to_fit # boolean, will size columns upon set data just to fit
71
+ dsl_accessor :estimate_widths # boolean, will size columns upon set data
72
+
73
+ # A table should only be editable if this is true regardless of other variables
74
+ # In addition, A column to be editable must either have editable as nil or true
75
+ dsl_accessor :cell_editing_allowed # 2009-01-16 22:55
76
+
77
+ def initialize form = nil, config={}, &block
78
+ _data = config.delete :data
79
+ _columns = config.delete :columns
80
+ @_column_widths = config.delete :column_widths
81
+ # if user leaves width blank but gives us col widths, that means calculate total width
82
+ if @_column_widths && config[:width].nil?
83
+ total = @_column_widths.inject(0) { |total, w| total+=w }
84
+ @width = total+2
85
+ end
86
+ @suppress_borders = false
87
+ @col_offset = @row_offset = 1
88
+
89
+ super
90
+ # added LIST event since bombing when selecting a row in table 2011-09-8 FFI
91
+ @_events.push(*[:TABLE_TRAVERSAL_EVENT,:TABLE_EDITING_EVENT, :LIST_SELECTION_EVENT])
92
+ init_vars
93
+ install_list_keys
94
+ map_keys
95
+ if _data && _columns
96
+ set_data _data, _columns
97
+ end
98
+ init_actions
99
+ end
100
+
101
+ def init_vars
102
+ @focusable= true
103
+ @current_index = 0
104
+ @current_column = 0
105
+ @oldrow = @oldcol = 0
106
+ @current_column_offset ||= 0 # added 2009-01-12 19:06 current_column's offset
107
+ @toprow = 0
108
+ @show_grid ||= 1
109
+ @_first_column_print = 0 # intro for horiz scrolling 2009-02-14 16:20
110
+ @_last_column_print = 0 # 2009-02-16 23:57 so we don't tab further etc.
111
+ # table needs to know what columns are being printed.
112
+ @curpos = 0
113
+ @inter_column_spacing = 1
114
+ # @selected_color ||= 'yellow'
115
+ # @selected_bgcolor ||= 'black'
116
+ @col_offset = @row_offset = 0 if @suppress_borders
117
+ @table_changed = true
118
+ @repaint_required = true
119
+ end
120
+ def map_keys
121
+
122
+ # alt-tab next column
123
+ # alt-shift-tab prev column
124
+ #bind_key(?\M-\C-i) { next_column }
125
+ #bind_key(481) { previous_column }
126
+ bind_key(KEY_TAB, :next_column )
127
+ bind_key(KEY_BTAB, :previous_column )
128
+ bind_key(KEY_RIGHT, :next_column )
129
+ bind_key(KEY_LEFT, :previous_column )
130
+ bind_key(@KEY_ASK_FIND_FORWARD, :ask_search_forward )
131
+ bind_key(@KEY_ASK_FIND_BACKWARD, :ask_search_backward )
132
+ bind_key(@KEY_FIND_NEXT, :find_next )
133
+ bind_key(@KEY_FIND_PREV, :find_prev ) if @KEY_FIND_PREV
134
+ # added 2010-05-12 21:41 for vim keys, will work if cell editing allowed is false
135
+ # user should be able to switch to editable and off so he can use keys TODO
136
+ # TODO vim_editable mode: C dd etc . to repeat change, how about range commands like vim
137
+ # TODO use numeric to widen, so we can distribute spacing
138
+ bind_key(?j, :next_row )
139
+ bind_key(?k, :previous_row )
140
+ bind_key(?G, :goto_bottom )
141
+ bind_key([?g,?g], :goto_top )
142
+ bind_key(?l, :next_column )
143
+ bind_key(?h, :previous_column )
144
+ bind_key(KEY_ENTER, :toggle_cell_editing )
145
+ bind_keys([?\C-n, KEY_DOWN], 'next_row') {
146
+ editing_stopped if @is_editing # 2009-01-16 16:06
147
+ next_row #scroll_forward
148
+ }
149
+ bind_keys([KEY_UP, ?\C-p], 'prev_row') {
150
+ editing_stopped if @is_editing # 2009-01-16 16:06
151
+ previous_row #scroll_forward
152
+ }
153
+ bind_key(@KEY_SCROLL_FORWARD, 'scroll_down') {
154
+ editing_stopped if @is_editing # 2009-01-16 16:06
155
+ scroll_forward
156
+ }
157
+ bind_key(@KEY_SCROLL_BACKWARD, 'scroll_backward') {
158
+ editing_stopped if @is_editing # 2009-01-16 16:06
159
+ scroll_backward
160
+ }
161
+ bind_key( @KEY_SCROLL_RIGHT, 'scroll right'){
162
+ editing_stopped if @is_editing # dts 2009-02-17 00:35
163
+ scroll_right
164
+ }
165
+ bind_key( @KEY_SCROLL_LEFT, 'scroll left') {
166
+ editing_stopped if @is_editing # dts 2009-02-17 00:35
167
+ scroll_left
168
+ }
169
+ end
170
+
171
+ def focussed_row
172
+ #raise "No data in table" if row_count < 1
173
+ return nil if row_count < 1
174
+ return @current_index if @current_index < row_count
175
+ @current_index = row_count-1
176
+ end
177
+ def focussed_col
178
+ return nil if row_count < 1
179
+ #raise "No data in table" if row_count < 1
180
+ @current_column
181
+ end
182
+ # added 2009-01-07 13:05 so new scrollable can use
183
+ def row_count
184
+ return 0 if @table_model.nil?
185
+ @table_model.row_count
186
+ end
187
+ # added 2009-01-07 13:05 so new scrollable can use
188
+ def scrollatrow
189
+ if @suppress_borders # NOT TESTED XXX
190
+ @height - 2 # we forgot to remove 1 from height in border.
191
+ else
192
+ @height - 4 # we forgot to remove 1 from height in border.
193
+ end
194
+ end
195
+
196
+ #
197
+ # Sets the data in models
198
+ # Should replace if these are created. TODO FIXME
199
+ def set_data data, colnames_array
200
+ # next 2 added in case set_data called again
201
+ @table_changed = true
202
+ @repaint_required = true
203
+ data ||= [[]]
204
+ colnames_array ||= [""]
205
+ if data.is_a? Array
206
+ model = RubyCurses::DefaultTableModel.new data, colnames_array
207
+ table_model model
208
+ elsif data.is_a? RubyCurses::TableModel
209
+ table_model data
210
+ else
211
+ raise "set_data: don't know how to handle data: #{data.class.to_s}"
212
+ end
213
+ if colnames_array.is_a? Array
214
+ model = DefaultTableColumnModel.new colnames_array
215
+ table_column_model model
216
+ elsif colnames_array.is_a? RubyCurses::TableColumnModel
217
+ table_column_model colnames_array
218
+ else
219
+ raise "set_data: don't know how to handle column data: #{colnames_array.class.to_s}"
220
+ end
221
+ create_default_list_selection_model
222
+ create_table_header
223
+ # added 2010-09-09 19:57 if user provides col widths in hash, or size_to_fit
224
+ $log.debug " XXX @size_to_fit: #{@size_to_fit} "
225
+ if @_column_widths
226
+ $log.debug "XXXX inside set column widths "
227
+ set_column_widths @_column_widths
228
+ elsif @estimate_widths
229
+ $log.debug "XXXX inside estimate column widths "
230
+ cw = estimate_column_widths data
231
+ set_column_widths cw
232
+ elsif @size_to_fit
233
+ $log.debug " XXX inside @size_to_fit: #{@size_to_fit} "
234
+ size_columns_to_fit
235
+ end
236
+ end
237
+ def set_model tm, tcm=nil, lsm=nil
238
+ table_model tm
239
+ if tcm.nil?
240
+ create_default_table_column_model
241
+ else
242
+ table_column_model tcm
243
+ end
244
+ if lsm.nil?
245
+ create_default_list_selection_model
246
+ else
247
+ list_selection_model lsm
248
+ end
249
+ create_table_header
250
+ end
251
+
252
+ # getter and setter for table_model
253
+ def table_model(*val)
254
+ if val.empty?
255
+ @table_model
256
+ else
257
+ raise "data error" if !val[0].is_a? RubyCurses::TableModel
258
+ @table_model = val[0]
259
+ ## table registers as a listener, or rather binds to event
260
+ @table_model.bind(:TABLE_MODEL_EVENT){|lde| table_data_changed(lde) }
261
+ end
262
+ end
263
+ # updated this so no param will return the tcm 2009-02-14 12:31
264
+ def table_column_model(*val)
265
+ if val.empty?
266
+ return @table_column_model
267
+ end
268
+ tcm = val[0]
269
+ raise "data error: table_column_model wrong class" if !tcm.is_a? RubyCurses::TableColumnModel
270
+ @table_column_model = tcm
271
+ @table_column_model.bind(:TABLE_COLUMN_MODEL_EVENT) {|e|
272
+ table_structure_changed e
273
+ }
274
+ @table_column_model.bind(:PROPERTY_CHANGE){|e| column_property_changed(e)}
275
+
276
+ #@table_header.column_model(tcm) unless @table_header.nil?
277
+ @table_header.table_column_model=(tcm) unless @table_header.nil?
278
+ end
279
+ # @deprecated, avoid usage
280
+ def get_table_column_model
281
+ $log.warn " DEPRECATED. Pls use table_column_model()"
282
+ @table_column_model
283
+ end
284
+ #
285
+ def create_default_table_column_model
286
+ table_column_model DefaultTableColumnModel.new
287
+ end
288
+ def create_table_header
289
+ @table_header = TableHeader.new @table_column_model
290
+ end
291
+
292
+ #--- selection methods ---#
293
+ def is_column_selected col
294
+ raise "TODO "
295
+ end
296
+ def is_cell_selected row, col
297
+ raise "TODO "
298
+ end
299
+ def add_column_selection_interval ix0, ix1
300
+ raise "TODO "
301
+ # if column_selection_allowed
302
+ end
303
+ def remove_column_selection_interval ix0, ix1
304
+ raise "TODO "
305
+ end
306
+
307
+ def selected_column
308
+ @table_column_model.selected_columns[0]
309
+ end
310
+ def selected_columns
311
+ @table_column_model.selected_columns
312
+ end
313
+ def selected_column_count
314
+ @table_column_model.selected_column_count
315
+ end
316
+
317
+ #--- row and column methods ---#
318
+
319
+ ##
320
+ # getter and setter for current_column index
321
+ def current_column(*val)
322
+ if val.empty?
323
+ @current_column || 0
324
+ else
325
+ @oldcol = @current_column
326
+ v = val[0]
327
+ v = 0 if v < 0
328
+ v = @table_column_model.column_count-1 if v > @table_column_model.column_count-1
329
+ @current_column = v
330
+ if @current_column != @oldcol
331
+ on_leave_column @oldcol
332
+ on_enter_column @current_column
333
+ end
334
+ set_form_col
335
+ @oldcol = @current_column # added on 2009-01-16 19:40 for next_col
336
+ end
337
+ end
338
+
339
+
340
+ def add_column tc
341
+ @table_column_model << tc
342
+ #table_structure_changed # this should be called by tcm TODO with object
343
+ end
344
+ def remove_column tc
345
+ @table_column_model.remove_column tc
346
+ #table_structure_changed # this should be called by tcm TODO with object
347
+ end
348
+ def get_column identifier
349
+ ix = @table_column_model.column_index identifier
350
+ return @table_column_model.column ix
351
+ end
352
+ ##
353
+ # returns col by col ix added on 2009-01-16 23:45
354
+ def column ix
355
+ @table_column_model.column(ix)
356
+ end
357
+ def get_column_name ix
358
+ @table_column_model.column(ix).identifier
359
+ end
360
+ def move_column ix, newix
361
+ @table_column_model.move_column ix, newix
362
+ #table_structure_changed # this should be called by tcm TODO with object
363
+ end
364
+
365
+ #--- row and column methods of Table ---#
366
+ # must not give wrong results when columns switched!
367
+ def get_value_at row, col
368
+ return nil if row.nil? || col.nil? # 2011-09-29
369
+ model_index = @table_column_model.column(col).model_index
370
+ @table_model.get_value_at row, model_index
371
+ end
372
+ # must not give wrong results when columns switched!
373
+ def set_value_at row, col, value
374
+ model_index = @table_column_model.column(col).model_index
375
+ @table_model.set_value_at row, model_index, value
376
+ end
377
+
378
+ #--- event listener support methods (p521) TODO ---#
379
+
380
+ def table_data_changed tabmodev
381
+ #$log.debug " def table_data_changed got #{tabmodev}"
382
+ @repaint_required = true
383
+ # next was required otherwise on_enter would bomb if data changed from outside
384
+ if row_count == 0
385
+ init_vars
386
+ set_form_col # added 2009-01-24 14:32 since cursor was still showing on existing col
387
+ return # added 2009-01-23 15:15
388
+ end
389
+ # the next block to be only called if user is inside editing. Often data will be refreshed by
390
+ # a search field and this gets called.
391
+ if @is_editing
392
+ @is_editing = false # 2009-01-19 18:18 testing this out XXX
393
+ # we need to refresh the editor if you deleted a row while sitting on it
394
+ # otherwise it shows the old value
395
+ editing_started
396
+ end
397
+ end
398
+ def table_structure_changed tablecolmodelevent
399
+ $log.debug " def table_structure_changed #{tablecolmodelevent}"
400
+ @table_changed = true
401
+ @repaint_required = true
402
+ init_vars
403
+ end
404
+ def column_property_changed evt
405
+ $log.debug "JT def column_property_changed #{evt} "
406
+ @table_changed = true
407
+ @repaint_required = true
408
+ end
409
+ =begin
410
+ # this could be complicating things. I don't need it in here.
411
+ def column_added tabcolmodev
412
+ @repaint_required = true
413
+ end
414
+ def column_removed tabcolmodev
415
+ @repaint_required = true
416
+ end
417
+ def column_moved tabcolmodev
418
+ @repaint_required = true
419
+ end
420
+ =end
421
+ ## to do for TrueClass and FalseClass
422
+ def prepare_renderers
423
+ @crh = Hash.new
424
+ @crh['String'] = TableCellRenderer.new "", {"parent" => self }
425
+ @crh['Fixnum'] = TableCellRenderer.new "", { "justify" => :right, "parent" => self}
426
+ @crh['Float'] = TableCellRenderer.new "", {"justify" => :right, "parent" => self}
427
+ @crh['TrueClass'] = CheckBoxCellRenderer.new "", {"parent" => self, "display_length"=>7}
428
+ @crh['FalseClass'] = CheckBoxCellRenderer.new "", {"parent" => self, "display_length"=>7}
429
+ @crh['Time'] = TableDateCellRenderer.new "", {"parent" => self, "display_length"=>16}
430
+ #@crh['String'] = TableCellRenderer.new "", {"bgcolor" => "cyan", "color"=>"white", "parent" => self}
431
+ #@crh['Fixnum'] = TableCellRenderer.new "", {"display_length" => 6, "justify" => :right, "color"=>"blue","bgcolor"=>"cyan" }
432
+ #@crh['Float'] = TableCellRenderer.new "", {"display_length" => 6, "justify" => :right, "color"=>"blue", "bgcolor"=>"cyan" }
433
+ end
434
+ # this is vry temporary and will change as we begin to use models - i need to pick
435
+ # columns renderer
436
+ def get_default_cell_renderer_for_class cname
437
+ @crh || prepare_renderers
438
+ @crh[cname] || @crh['String']
439
+ end
440
+ def set_default_cell_renderer_for_class cname, rend
441
+ @crh ||= {}
442
+ @crh[cname]=rend
443
+ end
444
+ ## override for cell or row behaviour
445
+ def get_cell_renderer row, col
446
+ # get columns renderer else class default
447
+ column = @table_column_model.column(col)
448
+ rend = column.cell_renderer
449
+ return rend # can be nil
450
+ end
451
+ #
452
+ # ------- editing methods---------- #
453
+ def get_cell_editor row, col
454
+ $log.debug " def get_cell_editor #{row}, #{col}"
455
+ column = @table_column_model.column(col)
456
+ return nil if column.editable == false or (column.editable.nil? and @cell_editing_allowed!=true)
457
+ editor = column.cell_editor
458
+ return editor # can be nil
459
+ end
460
+ def edit_cell_at row, col
461
+ acolumn = column(col)
462
+ if acolumn.editable == false or (acolumn.editable.nil? and @cell_editing_allowed!=true)
463
+ $log.debug " editing not allowed in #{col}"
464
+ @is_editing = false
465
+ return nil
466
+ end
467
+ return nil if row >= row_count
468
+ value = get_value_at row, col
469
+ editor = get_cell_editor row, col
470
+ @old_cell_value = value # for event
471
+ if editor.nil?
472
+
473
+ cls = value.nil? ? get_value_at(0,col).class.to_s : value.class.to_s
474
+ if value.nil?
475
+ case cls
476
+ when 'String'
477
+ value = value.to_s
478
+ when 'Fixnum'
479
+ value = value.to_i
480
+ when 'Float'
481
+ value = value.to_f
482
+ else
483
+ value = value.to_s
484
+ end
485
+ end
486
+ editor = get_default_cell_editor_for_class cls
487
+ #$log.debug "EDIT_CELL_AT:1 #{cls} #{editor.component.display_length} = #{@table_column_model.column(col).width}i maxlen #{editor.component.maxlen}"
488
+ editor.component.display_length = @table_column_model.column(col).width
489
+ # maxlen won't be nil ! This used to work earlier
490
+ #editor.component.maxlen = editor.component.display_length if editor.component.respond_to? :maxlen and editor.component.maxlen.nil? # 2009-01-18 00:59 XXX don't overwrite if user has set
491
+ if editor.component.respond_to? :maxlen
492
+ editor.component.maxlen = @table_column_model.column(col).edit_length || editor.component.display_length
493
+ end
494
+ #$log.debug "EDIT_CELL_AT: #{cls} #{editor.component.display_length} = #{@table_column_model.column(col).width}i maxlen #{editor.component.maxlen}"
495
+ end
496
+ #$log.debug " got an EDITOR #{editor} :: #{editor.component} "
497
+ # by now we should have something to edit with. We just need to prepare the widgey.
498
+ prepare_editor editor, row, col, value
499
+
500
+ end
501
+ def prepare_editor editor, row, col, value
502
+ r,c = rowcol
503
+ row = r + (row - @toprow) +1 # @form.row , 1 added for header row!
504
+ col = c+get_column_offset()
505
+ editor.prepare_editor self, row, col, value
506
+ # added on 2009-02-16 23:49
507
+ # if data is longer than can be displayed then update editors disp len too
508
+ if (col+editor.component.display_length)>= @col+@width
509
+ editor.component.display_length = @width-1-col
510
+ $log.debug "DDDXXX #{editor.component.display_length} = @width-1-col"
511
+ else
512
+ $log.debug "EEE if (#{col+editor.component.display_length})> #{@col+@width}"
513
+ end
514
+ @cell_editor = editor
515
+ @repaint_required = true
516
+ # copied from rlistbox, so that editors write on parent's graphic, otherwise
517
+ # their screen updates get overwritten by parent. 2010-01-19 20:17
518
+ set_form_col
519
+ end
520
+ ## Its too late to call components on_leave here
521
+ # since cursor would have moved elsewhere.
522
+ # Prior to moving out of a field, the on_leave should be called and exceptions caught FIXME
523
+ def cancel_editor
524
+ # not really required, the refresh was required. Ok, now i call components on_leave inside
525
+ #@cell_editor.cancel_editor
526
+ @editing_row, @editing_col = nil, nil
527
+ @is_editing = false
528
+ @repaint_required = true
529
+ end
530
+ def get_default_cell_editor_for_class cname
531
+ @ceh ||= {}
532
+ cname = 'Boolean' if cname == 'TrueClass' or cname == 'FalseClass'
533
+ if @ceh.include? cname
534
+ return @ceh[cname]
535
+ else
536
+ case cname
537
+ when 'String'
538
+ # I do not know cell width here, you will have toset display_length NOTE
539
+ ce = RubyCurses::CellEditor.new RubyCurses::Field.new nil, {"focusable"=>false, "visible"=>false, "display_length"=> 8, :name => "tb_field_str"}
540
+ @ceh['String'] = ce
541
+ return ce
542
+ when 'Fixnum'
543
+ ce = RubyCurses::CellEditor.new RubyCurses::Field.new nil, {"focusable"=>false, "visible"=>false, "display_length"=> 5, :name => "tb_field_num"}
544
+ @ceh[cname] = ce
545
+ return ce
546
+ when 'Float'
547
+ ce = RubyCurses::CellEditor.new RubyCurses::Field.new nil, {"focusable"=>false, "visible"=>false, "display_length"=> 5, :name => "tb_field_flt"}
548
+ @ceh[cname] = ce
549
+ return ce
550
+ when "Boolean" #'TrueClass', 'FalseClass'
551
+ ce = RubyCurses::CellEditor.new(RubyCurses::CheckBox.new nil, {"display_length"=> 0})
552
+ @ceh[cname] = ce
553
+ return ce
554
+ else
555
+ $log.debug " get_default_cell_editor_for_class UNKNOWN #{cname}"
556
+ ce = RubyCurses::CellEditor.new RubyCurses::Field.new nil, {"focusable"=>false, "visible"=>false, "display_length"=> 6, :name => "tb_field_unk"}
557
+ @ceh[cname] = ce
558
+ return ce
559
+ end
560
+ end
561
+ end
562
+ # returns true if editing is occurring
563
+ #def is_editing?
564
+ # @editing
565
+ #end
566
+
567
+ # ----------------- #
568
+
569
+ ##
570
+ # key handling
571
+ # make separate methods so callable programmatically
572
+ def handle_key(ch)
573
+ return :UNHANDLED if @table_model.nil?
574
+ @current_index ||= 0
575
+ @toprow ||= 0
576
+ h = scrollatrow()
577
+ rc = @table_model.row_count
578
+ # if we are editing let the component handle the key
579
+ # - unless its ESC, ENTER or C-c in which case we do our own
580
+ # processing, or coming out of edit mode
581
+ if @is_editing && (ch != 27 && ch != ?\C-c && ch != 13)
582
+ $log.debug " sending ch #{ch} to cell editor"
583
+ ret = @cell_editor.component.handle_key(ch)
584
+ @repaint_required = true
585
+ $log.debug "RET #{ret} got from to cell editor"
586
+ #set_form_col if ret != :UNHANDLED # added 2010-01-30 20:17 CURSOR POS TABBEDPANE
587
+ return if ret != :UNHANDLED
588
+ end
589
+ case ch
590
+ when ?\C-c, ?\C-g # earlier ESC was here, but in vim ESC completes edit
591
+ editing_canceled
592
+ #when KEY_ENTER, 10, 13
593
+ ## actually it should fall through to the else
594
+ #return :UNHANDLED unless @cell_editing_allowed
595
+ #toggle_cell_editing
596
+
597
+ when @KEY_ROW_SELECTOR # ?\C-x #32
598
+ #add_row_selection_interval @current_index, @current_index
599
+ toggle_row_selection @current_index #, @current_index
600
+ @repaint_required = true
601
+ #when ?\C-n.getbyte(0)
602
+ #editing_stopped if @is_editing # 2009-01-16 16:06
603
+ #scroll_forward
604
+ #when ?\C-p.getbyte(0)
605
+ #editing_stopped if @is_editing # 2009-01-16 16:06
606
+ #scroll_backward
607
+ when @KEY_GOTO_TOP # removed 48 (0) from here so we can trap numbers
608
+ # please note that C-[ gives 27, same as esc so will respond after ages
609
+ editing_stopped if @is_editing # 2009-01-16 16:06
610
+ goto_top
611
+ when @KEY_GOTO_BOTTOM
612
+ editing_stopped if @is_editing # 2009-01-16 16:06
613
+ goto_bottom
614
+ #when @KEY_SCROLL_RIGHT
615
+ #editing_stopped if @is_editing # dts 2009-02-17 00:35
616
+ #scroll_right
617
+ #when @KEY_SCROLL_LEFT
618
+ #editing_stopped if @is_editing # dts 2009-02-17 00:35
619
+ #scroll_left
620
+ when ?0.getbyte(0)..?9.getbyte(0)
621
+ $multiplier *= 10 ; $multiplier += (ch-48)
622
+ #$log.debug " setting mult to #{$multiplier} in list "
623
+ return 0
624
+ else
625
+ # there could be a case of editing here too!
626
+ ret = process_key ch, self
627
+ $multiplier = 0
628
+ return :UNHANDLED if ret == :UNHANDLED
629
+ end
630
+ return 0 # added 2010-03-14 13:27
631
+ end
632
+ def editing_canceled
633
+ return unless @cell_editing_allowed
634
+ @is_editing = false if @is_editing
635
+ cancel_editor
636
+ end
637
+ def toggle_cell_editing
638
+ return unless @cell_editing_allowed
639
+ @is_editing = !@is_editing
640
+ if @is_editing
641
+ editing_started
642
+ else
643
+ editing_stopped
644
+ end
645
+ end
646
+ def editing_started
647
+ return if !@cell_editing_allowed or row_count < 1
648
+ @is_editing = true # 2009-01-16 16:14
649
+ $log.debug " turning on editing cell at #{focussed_row}, #{focussed_col}"
650
+ # on deleting last row, we need to go back 2009-01-19 18:31
651
+ if focussed_row >= row_count
652
+ bounds_check
653
+ end
654
+ @editing_row, @editing_col = focussed_row(), focussed_col()
655
+ edit_cell_at focussed_row(), focussed_col()
656
+ end
657
+ # EDST
658
+ # the defualt values are useful when user is ON the field and pressed ENTER
659
+ # when leaving a cell, this should have oldrow and oldcol, not default values
660
+ # this throws an exception if validation on field fails NOTE
661
+ def editing_stopped row=focussed_row(), col=focussed_col()
662
+ return unless @cell_editing_allowed or @is_editing == false or column(col).editable == false
663
+ return if row_count < 1
664
+ $log.debug "editing_stopped set_value_at(#{row}, #{col}: #{@cell_editor.getvalue}"
665
+ # next line should be in on_leave_cell but that's not being called FIXME from everywhere
666
+ @cell_editor.on_leave row,col # added here since this is called whenever a cell is exited
667
+
668
+ value = @cell_editor.getvalue
669
+ if value != @old_cell_value
670
+ set_value_at(row, col, @cell_editor.getvalue) #.dup 2009-01-10 21:42 boolean can't duplicate
671
+ if @table_editing_event.nil?
672
+ @table_editing_event ||= TableEditingEvent.new row, col, self, @old_cell_value, value, :EDITING_STOPPED
673
+ else
674
+ @table_editing_event.set row, col, self, @old_cell_value, value, :EDITING_STOPPED
675
+ end
676
+ fire_handler :TABLE_EDITING_EVENT, @table_editing_event
677
+ end
678
+ cancel_editor
679
+ end
680
+ ##
681
+ #def previous_row
682
+ def previous_row num=(($multiplier.nil? or $multiplier == 0) ? 1 : $multiplier)
683
+ @oldrow = @current_index
684
+ # @current_index -= 1 if @current_index > 0
685
+ num.times {
686
+ @current_index -= 1 if @current_index > 0
687
+ }
688
+ $multiplier = 0
689
+ bounds_check
690
+ end
691
+ # goto next row
692
+ # added multipler 2010-05-12 20:51
693
+ def next_row num=(($multiplier.nil? or $multiplier == 0) ? 1 : $multiplier)
694
+ rc = row_count
695
+ @oldrow = @current_index
696
+ # don't go on if rc 2009-01-16 19:55 XXX
697
+ if @current_index < rc
698
+ @current_index += 1*num if @current_index < rc
699
+ bounds_check
700
+ end
701
+ $multiplier = 0
702
+ end
703
+ # move focus to next column
704
+ # 2009-10-07 12:47 behavior change. earlier this would move to next row
705
+ # if focus was on last visible field. Now it scrolls so that first invisible
706
+ # field becomes the first column.
707
+ # # 2010-05-13 12:42 added multiplier
708
+ #def next_column
709
+ def next_column num=(($multiplier.nil? or $multiplier == 0) ? 1 : $multiplier)
710
+ $multiplier = 0 # so not used again in next row
711
+ #v = @current_column+1
712
+ v = @current_column + num
713
+ # normal situation, there is a next column go to
714
+ if v < @table_column_model.column_count
715
+ if v <= @_last_column_print
716
+ $log.debug " if v < #{@table_column_model.column_count} nd lastcolprint "
717
+ current_column v
718
+ else
719
+ # there is a col but its not visible
720
+ # XXX inefficient but i scroll completely to next column (putting it at start)
721
+ # otherwise sometimes it was still not visible if last column
722
+ (v-@_first_column_print).times(){scroll_right}
723
+ current_column v
724
+ set_form_col
725
+ end
726
+
727
+ else
728
+ if @current_index < row_count()-1
729
+ $log.debug " GOING TO NEXT ROW FROM NEXT COL : #{@current_index} : #{row_count}"
730
+ @current_column = 0
731
+ #@current_column = @_first_column_print # added 2009-02-17 00:01
732
+ @_first_column_print = 0 # added 2009-10-07 11:25
733
+ next_row 1
734
+ set_form_col
735
+ @repaint_required = true
736
+ @table_changed = true # so columns are modified by print_header
737
+ else
738
+ return :UNHANDLED
739
+ end
740
+ end
741
+ end
742
+ # move focus to previous column
743
+ # if you are on first column, check if scrolling required, else move up to
744
+ # last *visible* column of prev row
745
+ #def previous_column
746
+ def previous_column num=(($multiplier.nil? or $multiplier == 0) ? 1 : $multiplier)
747
+ v = @current_column - num # 2010-05-13 12:44 1 to num
748
+ # returning unhandled so focus can go to prev field auto
749
+ if v < @_first_column_print and @current_index <= 0
750
+ return :UNHANDLED
751
+ end
752
+ if v < @_first_column_print
753
+ if v > 0
754
+ scroll_left
755
+ current_column v
756
+ elsif @current_index > 0
757
+ @current_column = @table_column_model.column_count-1
758
+ @current_column = @_last_column_print # added 2009-02-17 00:01
759
+ $log.debug " XXXXXX prev col #{@current_column}, las #{@_last_column_print}, fi: #{@_first_column_print}"
760
+ set_form_col
761
+ previous_row 1
762
+ end
763
+ else
764
+ current_column v
765
+ end
766
+ end
767
+ def goto_bottom
768
+ @oldrow = @current_index
769
+ rc = row_count
770
+ @current_index = rc -1
771
+ bounds_check
772
+ end
773
+ def goto_top
774
+ @oldrow = @current_index
775
+ # actually goto_top should onl;y goto top but I am making a change
776
+ # for vim's gg behaviour which will take you to line number if
777
+ # given, actually this should only happen on gg not some othey key
778
+ # that may specifically be for goto_top. 2012-01-2
779
+ @current_index = $multiplier || 0
780
+ #@current_index = 0
781
+ bounds_check
782
+ end
783
+ def scroll_backward
784
+ @oldrow = @current_index
785
+ h = scrollatrow()
786
+ @current_index -= h
787
+ bounds_check
788
+ end
789
+ def scroll_forward
790
+ @oldrow = @current_index
791
+ h = scrollatrow()
792
+ rc = row_count
793
+ # more rows than box
794
+ if h < rc
795
+ @toprow += h+1 #if @current_index+h < rc
796
+ @current_index = @toprow
797
+ else
798
+ # fewer rows than box
799
+ @current_index = rc -1
800
+ end
801
+ #@current_index += h+1 #if @current_index+h < rc
802
+ bounds_check
803
+ end
804
+
805
+ def bounds_check
806
+ h = scrollatrow()
807
+ rc = row_count
808
+
809
+ @current_index = 0 if @current_index < 0 # not lt 0
810
+ @current_index = rc-1 if @current_index >= rc # not gt rowcount
811
+ @toprow = rc-h-1 if rc > h and @toprow > rc - h - 1 # toprow shows full page if possible
812
+ # curr has gone below table, move toprow forward
813
+ if @current_index - @toprow > h
814
+ @toprow = @current_index - h
815
+ elsif @current_index < @toprow
816
+ # curr has gone above table, move toprow up
817
+ @toprow = @current_index
818
+ end
819
+
820
+ if @oldrow != @current_index
821
+ #$log.debug "going to call on leave and on enter"
822
+ on_leave_row @oldrow #if respond_to? :on_leave_row # to be defined by widget that has included this
823
+ on_enter_row @current_index #if respond_to? :on_enter_row # to be defined by widget that has included this
824
+ end
825
+ set_form_row
826
+ @oldrow = @current_index
827
+ @repaint_required = true
828
+ end
829
+ def on_leave_row arow
830
+ #$log.debug " def on_leave_row #{arow}"
831
+ #on_leave_cell arow, @current_column
832
+ on_leave_cell arow, @oldcol # 2009-01-16 19:41 XXX trying outt
833
+ end
834
+ def on_leave_column acol
835
+ #$log.debug " def on_leave_column #{acol}"
836
+ #on_leave_cell @current_index, acol
837
+ on_leave_cell @oldrow, acol
838
+ end
839
+ def on_enter_row arow
840
+ #$log.debug " def on_enter_row #{arow}"
841
+ on_enter_cell arow, @current_column
842
+ end
843
+ def on_enter_column acol
844
+ #$log.debug " def on_enter_column #{acol}"
845
+ on_enter_cell @current_index, acol
846
+ end
847
+ ## OLCE
848
+ def on_leave_cell arow, acol
849
+ $log.debug " def on_leave_cell #{arow}, #{acol}"
850
+ #if @editing_policy == :EDITING_AUTO # actually this should happen in all cases
851
+ if @is_editing # 2009-01-17 00:49
852
+ editing_stopped arow, acol
853
+ end
854
+ end
855
+ ## OECE
856
+ def on_enter_cell arow, acol
857
+ $log.debug " def on_enter_cell #{arow}, #{acol}"
858
+ if @table_traversal_event.nil?
859
+ @table_traversal_event ||= TableTraversalEvent.new @oldrow, @oldcol, arow, acol, self
860
+ else
861
+ @table_traversal_event.set(@oldrow, @oldcol, arow, acol, self)
862
+ end
863
+ fire_handler :TABLE_TRAVERSAL_EVENT, @table_traversal_event
864
+ if @editing_policy == :EDITING_AUTO
865
+ editing_started
866
+ end
867
+ end
868
+ # on enter of widget
869
+ # the cursor should be appropriately positioned
870
+ def on_enter
871
+ super
872
+ set_form_row
873
+ set_form_col # 2009-01-17 01:35
874
+ on_enter_cell focussed_row(), focussed_col() unless focussed_row().nil? or focussed_col().nil?
875
+ end
876
+ def on_leave
877
+ super
878
+ $log.debug " on leave of table 2009-01-16 21:58 "
879
+ editing_stopped if @is_editing # 2009-01-16 21:58
880
+ end
881
+ def set_form_row
882
+ r,c = rowcol
883
+ @rows_panned ||= 0 # RFED16 2010-02-19 10:00
884
+ win_row = 0
885
+ #win_row=@form.window.top # 2010-01-18 20:28 added
886
+ # +1 is due to header
887
+ #@form.row = r + (@current_index-@toprow) + 1
888
+ frow = r + (@current_index-@toprow) + 1 + win_row + @rows_panned
889
+ setrowcol(frow, nil) # 2010-01-18 20:04
890
+ end
891
+ # set cursor on correct column, widget
892
+ def set_form_col col=@curpos
893
+ @curpos = col
894
+ @cols_panned ||= 0 # RFED16 2010-02-19 10:00
895
+ @current_column_offset = get_column_offset
896
+ #@form.col = @col + @col_offset + @curpos + @current_column_offset
897
+ #win_col=@form.window.left
898
+ win_col = 0 # RFED16 2010-02-19 10:00
899
+ fcol = @col + @col_offset + @curpos + @current_column_offset + @cols_panned + win_col
900
+ setrowcol(nil, fcol) # 2010-01-18 20:04
901
+ end
902
+ # protected
903
+ def get_column_offset columnid=@current_column
904
+ return 0 if @table_column_model.nil?
905
+ return @table_column_model.column(columnid).column_offset || 0
906
+ end
907
+
908
+
909
+ def repaint
910
+ return unless @repaint_required
911
+ my_win = @form ? @form.window : @target_window
912
+ @graphic = my_win unless @graphic
913
+ #$log.warn "neither form not target window given!!! TV paint 368" unless my_win
914
+ raise " #{@name} neither form, nor target window given TV paint " unless my_win
915
+ raise " #{@name} NO GRAPHIC set as yet TV paint " unless @graphic
916
+ @win_left = my_win.left # unused remove TODO
917
+ @win_top = my_win.top
918
+
919
+ print_border @graphic if !@suppress_borders # do this once only, unless everything changes
920
+ return if @table_model.nil? # added 2009-02-17 12:45
921
+ @_first_column_print ||= 0
922
+ cc = @table_model.column_count
923
+ rc = @table_model.row_count
924
+ inter_column_padding = " " * @inter_column_spacing
925
+ @_last_column_print = cc-1
926
+ tcm = @table_column_model
927
+ tm = @table_model
928
+ tr = @toprow
929
+ _column_scrolling = false
930
+ acolor = get_color $datacolor
931
+ h = scrollatrow()
932
+ r,c = rowcol
933
+ # each cell should print itself, however there is a width issue.
934
+ # Then thee
935
+ print_header # do this once, unless columns changed
936
+ # TCM should give modelindex of col which is used to fetch data from TM
937
+ r += 1 # save for header
938
+ 0.upto(h) do |hh|
939
+ crow = tr+hh # crow is the row
940
+ if crow < rc
941
+ offset = 0 # offset of column
942
+ # 0.upto(cc-1) do |colix|
943
+ focussed = @current_index == crow ? true : false
944
+ selected = is_row_selected crow
945
+ # we loop through column_model and fetch data based on model index
946
+ # FIXED better to call table.get_value_at since we may now
947
+ # introduce a view - 2009-01-18 18:21
948
+ tcm.each_with_index do |acolumn, colix|
949
+ next if colix < @_first_column_print
950
+ #acolumn = tcm.column(colix)
951
+ #model_index = acolumn.model_index
952
+ content = get_value_at(crow, colix) # tables
953
+ renderer = get_cell_renderer(crow, colix)
954
+ if renderer.nil?
955
+ renderer = get_default_cell_renderer_for_class(content.class.to_s) if renderer.nil?
956
+ renderer.display_length acolumn.width unless acolumn.nil?
957
+ end
958
+ width = renderer.display_length + @inter_column_spacing
959
+ acolumn.column_offset = offset
960
+ # trying to ensure that no overprinting
961
+ if c+offset+width > @col+@width
962
+ _column_scrolling = true
963
+ @_last_column_print = colix
964
+ # experimental to print subset of last
965
+ space_left = (@width-3)-(offset) # 3 due to boundaries
966
+ space_left = 0 if space_left < 0
967
+ # length bombed for trueclass 2009-10-05 19:34
968
+ contentlen = content.length rescue content.to_s.length
969
+ #if content.length > space_left
970
+ if contentlen > space_left
971
+ clen = space_left
972
+ renderer.display_length clen
973
+ else
974
+ clen = -1
975
+ renderer.display_length space_left # content.length
976
+ end
977
+ # added 2009-10-05 20:29 since non strings were bombing
978
+ # in other cases should be just pass the content as-is. XXX
979
+ contenttrim = content[0..clen] rescue content # .to_s[0..clen]
980
+ # print the inter cell padding just in case things mess up while scrolling
981
+ @graphic.mvprintw r+hh, c+offset-@inter_column_spacing, inter_column_padding
982
+ #renderer.repaint @graphic, r+hh, c+offset, crow, content[0..clen], focussed, selected
983
+ #renderer.repaint @graphic, r+hh, c+offset, crow, contenttrim, focussed, selected
984
+ # 2009-10-05 20:35 XXX passing self so we check it doesn't print outside
985
+ renderer.repaint self, r+hh, c+offset, crow, contenttrim, focussed, selected
986
+ break
987
+ end
988
+ # added crow on 2009-02-11 22:46
989
+ #renderer.repaint @graphic, r+hh, c+(offset), crow, content, focussed, selected
990
+ # 2009-10-05 20:35 XXX
991
+ renderer.repaint self, r+hh, c+(offset), crow, content, focussed, selected
992
+ offset += width
993
+ end
994
+ else
995
+ #@graphic.printstring r+hh, c, " " * (@width-2), acolor,@attr
996
+ printstring r+hh, c, " " * (@width-2), acolor,@attr
997
+ # clear rows
998
+ end
999
+ end
1000
+ if @is_editing
1001
+ @cell_editor.component.repaint unless @cell_editor.nil? or @cell_editor.component.form.nil?
1002
+ end
1003
+ _print_more_columns_marker _column_scrolling
1004
+ _print_more_data_marker(rc-1 > tr + h)
1005
+ $log.debug " _print_more_data_marker(#{rc} >= #{tr} + #{h})"
1006
+ @table_changed = false
1007
+ @repaint_required = false
1008
+ #@buffer_modified = true # 2011-09-30 CLEANUP
1009
+ end
1010
+ # NEW to correct overflow
1011
+ # 2009-10-05 21:34
1012
+ # when resizing columns a renderer can go outside the table bounds
1013
+ # so printing should be done by parent not window
1014
+ def printstring(r,c,string, color, att)
1015
+ # 3 is table borders
1016
+ # if renderer trying to print outside don't let it
1017
+ if c > @col+@width-3
1018
+ return
1019
+ end
1020
+ # if date exceeds boundary truncate
1021
+ if c+string.length > (@col+@width)-3
1022
+ len = string.length-((c+string.length)-(@col+@width-3))
1023
+ @graphic.printstring(r,c,string[0..len], color,att)
1024
+ else
1025
+ @graphic.printstring(r,c,string, color,att)
1026
+ end
1027
+ end
1028
+ def print_border g
1029
+ return unless @table_changed
1030
+ g.print_border @row, @col, @height-1, @width, $datacolor
1031
+ return if @table_model.nil?
1032
+ rc = @table_model.row_count
1033
+ h = scrollatrow()
1034
+ _print_more_data_marker (rc>h)
1035
+ end
1036
+ # private
1037
+ def _print_more_data_marker tf
1038
+ marker = tf ? Ncurses::ACS_CKBOARD : Ncurses::ACS_VLINE
1039
+ @graphic.mvwaddch @row+@height-2, @col+@width-1, marker
1040
+ marker = @toprow > 0 ? Ncurses::ACS_CKBOARD : Ncurses::ACS_VLINE
1041
+ @graphic.mvwaddch @row+1, @col+@width-1, marker
1042
+ end
1043
+ def _print_more_columns_marker tf
1044
+ marker = tf ? Ncurses::ACS_CKBOARD : Ncurses::ACS_HLINE
1045
+ @graphic.mvwaddch @row+@height-1, @col+@width-2, marker
1046
+ # show if columns to left or not
1047
+ marker = @_first_column_print > 0 ? Ncurses::ACS_CKBOARD : Ncurses::ACS_HLINE
1048
+ @graphic.mvwaddch @row+@height-1, @col+@_first_column_print+1, marker
1049
+ end
1050
+ # print table header
1051
+ # 2011-09-17 added repaint all check so that external components can triger this
1052
+ # e.g. multi-container when it changes tables.
1053
+ def print_header
1054
+ return unless @table_changed || @repaint_all
1055
+ $log.debug " TABLE: inside printheader 2009-10-07 11:51 DDD "
1056
+
1057
+ r,c = rowcol
1058
+ header_model = @table_header.table_column_model
1059
+ tcm = @table_column_model ## could have been overridden, should we use this at all
1060
+ offset = 0
1061
+ header_model.each_with_index do |tc, colix|
1062
+ next if colix < @_first_column_print # added for scrolling rt and left 2009-02-14 17:49
1063
+ acolumn = tcm.column colix
1064
+ renderer = tc.cell_renderer
1065
+ renderer = @table_header.default_renderer if renderer.nil?
1066
+ renderer.display_length acolumn.width unless acolumn.nil?
1067
+ width = renderer.display_length + 1
1068
+ content = tc.header_value
1069
+ if c+offset+width > @col+@width
1070
+ #$log.debug " TABLE: experimental code to NOT print if chance of exceeding table width"
1071
+ # 2009-02-14 14:24 now printing, but truncating data for last column
1072
+ space_left = (@width-3)-(offset)
1073
+ space_left = 0 if space_left < 0
1074
+ if content.length > space_left
1075
+ clen = space_left
1076
+ renderer.display_length clen
1077
+ else
1078
+ clen = -1
1079
+ renderer.display_length space_left
1080
+ end
1081
+ #$log.debug " TABLE BREAKING SINCE sl: #{space_left},#{crow},#{colix}: #{clen} "
1082
+ # passing self so can prevent renderer from printing outside 2009-10-05 22:56
1083
+ #renderer.repaint @graphic, r, c+(offset), 0, content[0..clen], false, false
1084
+ renderer.repaint self, r, c+(offset), 0, content[0..clen], false, false
1085
+ break
1086
+ end
1087
+ # passing self so can prevent renderer from printing outside 2009-10-05 22:56
1088
+ #renderer.repaint @graphic, r, c+(offset),0, content, false, false
1089
+ renderer.repaint self, r, c+(offset),0, content, false, false
1090
+ offset += width
1091
+ end
1092
+ end
1093
+ # 2009-01-17 13:25
1094
+ def set_focus_on arow
1095
+ @oldrow = @current_index
1096
+ @current_index = arow
1097
+ bounds_check if @oldrow != @current_index
1098
+ end
1099
+ attr_accessor :toprow # top visible
1100
+ def ask_search_backward
1101
+ regex = get_string("Enter regex to search (backward)")
1102
+ ix = @table_model.find_prev regex, @current_index
1103
+ if ix.nil?
1104
+ alert("No matching data for: #{regex}")
1105
+ else
1106
+ set_focus_on(ix)
1107
+ end
1108
+ end
1109
+ def find_prev
1110
+ ix = @table_model.find_prev
1111
+ regex = @table_model.last_regex
1112
+ if ix.nil?
1113
+ alert("No previous matching data for: #{regex}")
1114
+ else
1115
+ set_focus_on(ix)
1116
+ end
1117
+ end
1118
+ def ask_search_forward
1119
+ regex = get_string("Enter regex to search (forward)")
1120
+ #ix = @table_model.find_next regex, @current_index
1121
+ ix = @table_model.find_match regex, @current_index
1122
+ if ix.nil?
1123
+ alert("No matching data for: #{regex}")
1124
+ else
1125
+ set_focus_on(ix)
1126
+ end
1127
+ end
1128
+ # table find_next
1129
+ def find_next
1130
+ ix = @table_model.find_next
1131
+ regex = @table_model.last_regex
1132
+ if ix.nil?
1133
+ alert("No more matching data for: #{regex}")
1134
+ else
1135
+ set_focus_on(ix)
1136
+ end
1137
+ end
1138
+ def scroll_right
1139
+ cc = @table_model.column_count
1140
+ if @_first_column_print < cc-1
1141
+ @_first_column_print += 1
1142
+ @_last_column_print += 1 if @_last_column_print < cc-1
1143
+ @current_column = @_first_column_print
1144
+ set_form_col # FIXME not looking too good till key press
1145
+ @repaint_required = true
1146
+ @table_changed = true # so columns are modified
1147
+ end
1148
+ end
1149
+ def scroll_left
1150
+ if @_first_column_print > 0
1151
+ @_first_column_print -= 1
1152
+ @current_column = @_first_column_print
1153
+ set_form_col
1154
+ @repaint_required = true
1155
+ @table_changed = true
1156
+ end
1157
+ end
1158
+ ##
1159
+ # Makes an estimate of columns sizes, returning a hash, and storing it as @column_widths
1160
+ # based on checking first 20 rows of data.
1161
+ # This does not try to fit all columns into table, but gives best width, so you
1162
+ # can scroll right to see other columns.
1163
+ # @params - columns is columns returned by database
1164
+ # using the command: @columns, *rows = @db.execute2(command)
1165
+ # @param - datatypes is an array returned by following command to DB
1166
+ # @datatypes = @content[0].types
1167
+ def estimate_column_widths columns, datatypes=nil
1168
+ tablewidth = @width-3
1169
+ colwidths = {}
1170
+ unless datatypes
1171
+ datatypes = []
1172
+ row = columns[0]
1173
+ $log.debug " XXX row: #{row} "
1174
+
1175
+ row.each do |c|
1176
+ $log.debug " XXX c: #{c} "
1177
+ case c
1178
+ when Fixnum, Integer
1179
+ datatypes << "int"
1180
+ when Date, Time
1181
+ datatypes << "date"
1182
+ else
1183
+ datatypes << "varchar"
1184
+ end
1185
+ end
1186
+ end
1187
+ min_column_width = (tablewidth/columns.length) -1
1188
+ $log.debug("min: #{min_column_width}, #{tablewidth}")
1189
+ 0.upto(20) do |rowix|
1190
+ break if rowix >= row_count
1191
+ #@content.each_with_index do |row, cix|
1192
+ # break if cix >= 20
1193
+ @table_column_model.each_with_index do |acolumn, ix|
1194
+ col = get_value_at(rowix, ix)
1195
+ colwidths[ix] ||= 0
1196
+ colwidths[ix] = [colwidths[ix], col.to_s.length].max
1197
+ end
1198
+ end
1199
+ total = 0
1200
+ # crashing in 1.9.2 due to hash key no insert in iteration 2010-08-22 20:09
1201
+ #colwidths.each_pair do |k,v|
1202
+ tkeys = colwidths.keys
1203
+ tkeys.each do |k|
1204
+ name = columns[k.to_i]
1205
+ v = colwidths[k]
1206
+ colwidths[name] = v
1207
+ total += v
1208
+ end
1209
+ colwidths["__TOTAL__"] = total
1210
+ column_widths = colwidths
1211
+ @max_data_widths = column_widths.dup
1212
+
1213
+ $log.debug "XXXX datatypes #{datatypes} "
1214
+ columns.each_with_index do | col, i|
1215
+ break if datatypes[i].nil?
1216
+ if datatypes[i].match(/(real|int)/) != nil
1217
+ wid = column_widths[i]
1218
+ # cw = [column_widths[i], [8,min_column_width].min].max
1219
+ $log.debug("XXX #{wid}. #{columns[i].length}")
1220
+ cw = [wid, columns[i].length].max
1221
+ $log.debug("int #{col} #{column_widths[i]}, #{cw}")
1222
+ elsif datatypes[i].match(/(date)/) != nil
1223
+ cw = [column_widths[i], [12,min_column_width].min].max
1224
+ #cw = [12,min_column_width].min
1225
+ $log.debug("date #{col} #{column_widths[i]}, #{cw}")
1226
+ else
1227
+ cw = [column_widths[i], min_column_width].max
1228
+ if column_widths[i] <= col.length and col.length <= min_column_width
1229
+ cw = col.length
1230
+ end
1231
+ $log.debug("else #{col} #{column_widths[i]}, #{col.length} #{cw}")
1232
+ end
1233
+ column_widths[i] = cw
1234
+ total += cw
1235
+ end
1236
+ column_widths["__TOTAL__"] = total
1237
+ $log.debug("Estimated col widths: #{column_widths.inspect}")
1238
+ @column_widths = column_widths
1239
+ return column_widths
1240
+ end
1241
+ ##
1242
+ # convenience method
1243
+ # sets column widths given an array of ints
1244
+ # You may get such an array from estimate_column_widths
1245
+ def set_column_widths cw
1246
+ raise "Cannot call set_column_widths till table set" unless @table_column_model
1247
+ tcm = @table_column_model
1248
+ tcm.each_with_index do |col, ix|
1249
+ col.width cw[ix]
1250
+ end
1251
+ table_structure_changed(nil)
1252
+ end
1253
+ def size_columns_to_fit
1254
+ delta = @width - table_column_model().get_total_column_width()
1255
+ tcw = table_column_model().get_total_column_width()
1256
+
1257
+ $log.debug "size_columns_to_fit D #{delta}, W #{@width}, TCW #{tcw}"
1258
+ accomodate_delta(delta) if delta != 0
1259
+ #set_width_from_preferred_widths
1260
+ end
1261
+ private
1262
+ def accomodate_delta delta
1263
+ tcm = @table_column_model
1264
+ cc = tcm.column_count
1265
+ return if cc == 0
1266
+ average = (delta/cc).ceil
1267
+ total = 0
1268
+ tcm.each do |col|
1269
+ oldcw = col.width + average
1270
+ next if oldcw < col.min_width or oldcw > col.max_width
1271
+ if delta >0
1272
+ break if total > delta
1273
+ else
1274
+ break if total < delta
1275
+ end
1276
+ col.width oldcw
1277
+ total += average
1278
+ end
1279
+ $log.debug "accomodate_delta: #{average}. #{total}"
1280
+ table_structure_changed(nil)
1281
+ end
1282
+ public
1283
+ def init_actions
1284
+ return if @actions_added
1285
+ @actions_added = true
1286
+ am = action_manager()
1287
+ am.add_action( Action.new("&Auto Edit On ") { @editing_policy = :EDITING_AUTO })
1288
+ am.add_action( Action.new("Auto Edit O&ff ") { @editing_policy = nil })
1289
+
1290
+ end
1291
+
1292
+
1293
+ # ADD METHODS HERE
1294
+ end # class Table
1295
+
1296
+ ## TC
1297
+ # All column changes take place in ColumnModel not in data. TC keeps pointer to col in data via
1298
+ # TODO - can't change width beyond min and max if set
1299
+ # resizable - user can't resize but programatically can
1300
+ # model_index
1301
+ # XXX Seems we are not using min_width and max_width.
1302
+ # min should be used for when resizing,, max should not be used. we are using width which is
1303
+ # updated as changed
1304
+ class TableColumn
1305
+ include RubyCurses::EventHandler # 2009-01-15 22:49
1306
+ attr_reader :identifier
1307
+ attr_accessor :min_width, :max_width, :is_resizable
1308
+ attr_accessor :cell_renderer
1309
+ attr_accessor :model_index # index inside TableModel
1310
+ # user may override or set for this column, else headers default will be used
1311
+ attr_accessor :header_renderer
1312
+ dsl_property :header_value
1313
+ dsl_property :width # XXX don;t let user set width later, should be readonly
1314
+ dsl_property :preferred_width # user should use this when requesting a change
1315
+ # some columns may not be editable. e.g in a Finder, file size or time not editable
1316
+ # whereas name is.
1317
+
1318
+ # is this column editable. Set to false to disable a column from editing IF the table
1319
+ # allows editing. Setting to true not required.
1320
+ dsl_accessor :editable # if not set takes tables value 2009-01-16 22:49
1321
+ ## added column_offset on 2009-01-12 19:01
1322
+ attr_accessor :column_offset # where we've place this guy. in case we need to position cursor
1323
+ attr_accessor :cell_editor
1324
+ dsl_accessor :edit_length # corresponds to maxlen, if not set, col width will be useda 2009-02-16 21:55
1325
+
1326
+
1327
+ # width is used as initial and preferred width. It has actual value at any time
1328
+ # width must never be directly set, use preferred width later
1329
+ def initialize model_index, identifier, header_value, width, config={}, &block
1330
+ @width = width
1331
+ @preferred_width = width
1332
+ @min_width = 4
1333
+ @max_width = 1000
1334
+ @model_index = model_index
1335
+ @identifier = identifier
1336
+ @header_value = header_value
1337
+ @config={}
1338
+ instance_eval &block if block_given?
1339
+ @_events = [:PROPERTY_CHANGE]
1340
+ end
1341
+ def fire_property_change(text, oldval, newval)
1342
+ #$log.debug "TC: def fire_property_change(#{text}, #{oldval}, #{newval})"
1343
+ # need to send changeevent FIXME XXX maybe dsl_prop should do this.
1344
+ fire_handler :PROPERTY_CHANGE, self
1345
+ end
1346
+ end # class tc
1347
+
1348
+ ## TCM
1349
+ #
1350
+ class TableColumnModel
1351
+ def column ix
1352
+ nil
1353
+ end
1354
+ def columns
1355
+ nil
1356
+ end
1357
+ def column_count
1358
+ 0
1359
+ end
1360
+ def column_selection_allowed
1361
+ false
1362
+ end
1363
+ def selected_column_count
1364
+ 0
1365
+ end
1366
+ def selected_columns
1367
+ nil
1368
+ end
1369
+ def total_column_width
1370
+ -1
1371
+ end
1372
+ def get_selection_model
1373
+ nil
1374
+ end
1375
+ def set_selection_model lsm
1376
+ end
1377
+ def add_column tc
1378
+ end
1379
+ def remove_column tc
1380
+ end
1381
+ def move_column ix, newix
1382
+ end
1383
+ def column_index identifier
1384
+ nil
1385
+ end
1386
+ # add tcm listener
1387
+ end
1388
+ ## DTCM DCM
1389
+ class DefaultTableColumnModel < TableColumnModel
1390
+ include Enumerable
1391
+ include RubyCurses::EventHandler # widget does 2009-01-15 15:38
1392
+ attr_accessor :column_selection_allowed
1393
+
1394
+ ##
1395
+ # takes a column names array
1396
+ def initialize cols=[]
1397
+ @columns = []
1398
+ @total_column_width= -1
1399
+ ##cols.each_with_index {|c, index| @columns << TableColumn.new(index, c, c, 10) }
1400
+ cols.each_with_index {|c, index| add_column(TableColumn.new(index, c, c, 10)) }
1401
+ @selected_columns = []
1402
+ @_events = [:TABLE_COLUMN_MODEL_EVENT, :PROPERTY_CHANGE]
1403
+ end
1404
+ def column ix
1405
+ raise "Invalid arg #{ix}" if ix < 0 or ix > (@columns.length() -1)
1406
+ @columns[ix]
1407
+ end
1408
+ def columns; @columns; end
1409
+ ##
1410
+ # yields a table column
1411
+ def each
1412
+ @columns.each { |c|
1413
+ yield c
1414
+ }
1415
+ end
1416
+ def column_count
1417
+ @columns.length
1418
+ end
1419
+ def selected_column_count
1420
+ @selected_columns.length
1421
+ end
1422
+ def selected_columns
1423
+ @selected_columns
1424
+ end
1425
+ def clear_selection
1426
+ @selected_columns = []
1427
+ end
1428
+ ##
1429
+ # added 2009-10-07 23:04
1430
+ def get_total_column_width
1431
+ @total_column_width = -1 # XXX
1432
+ if @total_column_width == -1
1433
+ total = 0
1434
+ each { |c| total += c.width ; $log.debug "get_total_column_width: #{c.width}"}
1435
+ @total_column_width = total
1436
+ end
1437
+ return @total_column_width
1438
+ end
1439
+ def set_selection_model lsm
1440
+ @column_selection_model = lsm
1441
+ end
1442
+ def add_column tc
1443
+ @columns << tc
1444
+ tc.bind(:PROPERTY_CHANGE){|e| column_property_changed(e)}
1445
+ tmce = TableColumnModelEvent.new(nil, @columns.length-1, self, :INSERT)
1446
+ fire_handler :TABLE_COLUMN_MODEL_EVENT, tmce
1447
+ end
1448
+ def column_property_changed evt
1449
+ $log.debug "DTCM def column_property_changed #{evt} "
1450
+ # need to send changeevent FIXME XXX
1451
+ fire_handler :PROPERTY_CHANGE, self
1452
+ end
1453
+ def remove_column tc
1454
+ ix = @columns.index tc
1455
+ @columns.delete tc
1456
+ tmce = TableColumnModelEvent.new(ix, nil, self, :DELETE)
1457
+ fire_handler :TABLE_COLUMN_MODEL_EVENT, tmce
1458
+ end
1459
+ def move_column ix, newix
1460
+ # acol = remove_column column(ix)
1461
+ acol = @columns.delete_at ix
1462
+ @columns.insert newix, acol
1463
+ tmce = TableColumnModelEvent.new(ix, newix, self, :MOVE)
1464
+ fire_handler :TABLE_COLUMN_MODEL_EVENT, tmce
1465
+ end
1466
+ ##
1467
+ # return index of column identified with identifier
1468
+ def column_index identifier
1469
+ @columns.each_with_index {|c, i| return i if c.identifier == identifier }
1470
+ return nil
1471
+ end
1472
+ ## TODO - if we get into column selection somewhen
1473
+ def get_selection_model
1474
+ @lsm
1475
+ end
1476
+ def set_selection_model lsm
1477
+ @lsm = lsm
1478
+ end
1479
+ # add tcm listener
1480
+ end
1481
+
1482
+ ## TM
1483
+ class TableModel
1484
+ def column_count
1485
+ end
1486
+ def row_count
1487
+ end
1488
+ def set_value_at row, col, val
1489
+ end
1490
+ def get_value_at row, col
1491
+ end
1492
+ def get_total_column_width
1493
+ end
1494
+ =begin
1495
+ def << obj
1496
+ end
1497
+ def insert row, obj
1498
+ end
1499
+ def delete obj
1500
+ end
1501
+ def delete_at row
1502
+ end
1503
+
1504
+ =end
1505
+ end # class
1506
+
1507
+ ##
1508
+ # DTM
1509
+ class DefaultTableModel < TableModel
1510
+ attr_reader :last_regex
1511
+ include RubyCurses::EventHandler # 2009-01-15 15:38
1512
+ def initialize data, colnames_array
1513
+ @data = data
1514
+ @column_identifiers = colnames_array
1515
+ @_events = [:TABLE_MODEL_EVENT, :PROPERTY_CHANGE]
1516
+ end
1517
+ def column_count
1518
+ # 2010-01-12 19:35 changed count to size since size is supported in 1.8.6 also
1519
+ #@column_identifiers.count
1520
+ @column_identifiers.size
1521
+ end
1522
+ def row_count
1523
+ @data.length
1524
+ end
1525
+ #
1526
+ # please avoid directly hitting this. Suggested to use get_value_at of jtable
1527
+ # since columns could have been switched.
1528
+ def set_value_at row, col, val
1529
+ # $log.debug " def set_value_at #{row}, #{col}, #{val} "
1530
+ # if editing allowed
1531
+ @data[row][col] = val
1532
+ tme = TableModelEvent.new(row, row, col, self, :UPDATE)
1533
+ fire_handler :TABLE_MODEL_EVENT, tme
1534
+ end
1535
+ ##
1536
+ # please avoid directly hitting this. Suggested to use get_value_at of jtable
1537
+ # since columns could have been switched.
1538
+ def get_value_at row, col
1539
+ #$log.debug " def get_value_at #{row}, #{col} "
1540
+
1541
+ raise "IndexError get_value_at #{row}, #{col}" if @data.nil? or row >= @data.size
1542
+ return @data[row][ col]
1543
+ end
1544
+ def << obj
1545
+ @data << obj
1546
+ tme = TableModelEvent.new(@data.length-1,@data.length-1, :ALL_COLUMNS, self, :INSERT)
1547
+ fire_handler :TABLE_MODEL_EVENT, tme
1548
+ # create tablemodelevent and fire_table_changed for all listeners
1549
+ end
1550
+ def insert row, obj
1551
+ @data.insert row, obj
1552
+ tme = TableModelEvent.new(row, row,:ALL_COLUMNS, self, :INSERT)
1553
+ fire_handler :TABLE_MODEL_EVENT, tme
1554
+ # create tablemodelevent and fire_table_changed for all listeners
1555
+ end
1556
+ def delete obj
1557
+ row = @data.index obj
1558
+ return if row.nil?
1559
+ ret = @data.delete obj
1560
+ tme = TableModelEvent.new(row, row,:ALL_COLUMNS, self, :DELETE)
1561
+ fire_handler :TABLE_MODEL_EVENT, tme
1562
+ # create tablemodelevent and fire_table_changed for all listeners
1563
+ return ret
1564
+ end
1565
+ def delete_at row
1566
+ if !$multiplier or $multiplier == 0
1567
+ @delete_buffer = @data.delete_at row
1568
+ else
1569
+ @delete_buffer = @data.slice!(row, $multiplier)
1570
+ end
1571
+ $multiplier = 0
1572
+ #ret = @data.delete_at row
1573
+ # create tablemodelevent and fire_table_changed for all listeners
1574
+ # we don;t pass buffer to event as in listeditable. how to undo later?
1575
+ tme = TableModelEvent.new(row, row+@delete_buffer.length,:ALL_COLUMNS, self, :DELETE)
1576
+ fire_handler :TABLE_MODEL_EVENT, tme
1577
+ return @delete_buffer
1578
+ end
1579
+ # a quick method to undo deletes onto given row. More like paste
1580
+ def undo where
1581
+ return unless @delete_buffer
1582
+ case @delete_buffer[0]
1583
+ when Array
1584
+ @delete_buffer.each do |r|
1585
+ insert where, r
1586
+ end
1587
+ else
1588
+ insert where, @delete_buffer
1589
+ end
1590
+ end
1591
+ ##
1592
+ # added 2009-01-17 21:36
1593
+ # Use with caution, does not call events per row
1594
+ def delete_all
1595
+ len = @data.length-1
1596
+ @data=[]
1597
+ tme = TableModelEvent.new(0, len,:ALL_COLUMNS, self, :DELETE)
1598
+ fire_handler :TABLE_MODEL_EVENT, tme
1599
+ end
1600
+ ##
1601
+ # for those quick cases when you wish to replace all the data
1602
+ # and not have an event per row being generated
1603
+ def data=(data)
1604
+ raise "Data nil or invalid" if data.nil? or data.size == 0
1605
+ delete_all
1606
+ @data = data
1607
+ tme = TableModelEvent.new(0, @data.length-1,:ALL_COLUMNS, self, :INSERT)
1608
+ fire_handler :TABLE_MODEL_EVENT, tme
1609
+ end
1610
+ def ask_search_forward
1611
+ regex = get_string "Enter regex to search for:"
1612
+ ix = get_list_data_model.find_match regex
1613
+ if ix.nil?
1614
+ alert("No matching data for: #{regex}")
1615
+ else
1616
+ set_focus_on(ix)
1617
+ end
1618
+ end
1619
+ # continues previous search
1620
+ ##
1621
+ def find_match regex, ix0=0, ix1=row_count()
1622
+ $log.debug " find_match got #{regex} #{ix0} #{ix1}"
1623
+ @last_regex = regex
1624
+ @search_start_ix = ix0
1625
+ @search_end_ix = ix1
1626
+ @data.each_with_index do |row, ix|
1627
+ next if ix < ix0
1628
+ break if ix > ix1
1629
+ if row.grep(/#{regex}/) != []
1630
+ #if !row.match(regex).nil?
1631
+ @search_found_ix = ix
1632
+ return ix
1633
+ end
1634
+ end
1635
+ return nil
1636
+ end
1637
+ def find_prev regex=@last_regex, start = @search_found_ix
1638
+ raise "No previous search" if @last_regex.nil?
1639
+ $log.debug " find_prev #{@search_found_ix} : #{@current_index}"
1640
+ start -= 1 unless start == 0
1641
+ @last_regex = regex
1642
+ @search_start_ix = start
1643
+ start.downto(0) do |ix|
1644
+ row = @data[ix]
1645
+ if row.grep(/#{regex}/) != []
1646
+ @search_found_ix = ix
1647
+ return ix
1648
+ end
1649
+ end
1650
+ return nil
1651
+ #return find_match @last_regex, start, @search_end_ix
1652
+ end
1653
+ ## dtm findnext
1654
+ def find_next
1655
+ raise "No more search" if @last_regex.nil?
1656
+ start = @search_found_ix && @search_found_ix+1 || 0
1657
+ return find_match @last_regex, start, @search_end_ix
1658
+ end
1659
+ end # class DTC
1660
+
1661
+ ##
1662
+ ##
1663
+ # Class that manages Table's Header
1664
+ # are we not taking events such as column added, removed ?
1665
+ class TableHeader
1666
+ attr_accessor :default_renderer
1667
+ attr_accessor :table_column_model
1668
+ def initialize table_column_model
1669
+ @table_column_model = table_column_model
1670
+ create_default_renderer
1671
+ end
1672
+ def create_default_renderer
1673
+ #@default_renderer = TableCellRenderer.new "", {"display_length" => 10, "justify" => :center}
1674
+ @default_renderer = TableCellRenderer.new "", {"display_length" => 10, "justify" => :center, "color"=>"white", "bgcolor"=>"blue"}
1675
+ end
1676
+
1677
+ # added 2009-10-07 14:03
1678
+ # returns the column being resized
1679
+ # @returns TableColumn
1680
+ # @protected
1681
+ def get_resizing_column
1682
+ end
1683
+
1684
+ end # class TableHeader
1685
+ ##
1686
+ # When an event is fired by TableModel, contents are changed, then this object will be passed
1687
+ # to trigger
1688
+ # type is :INSERT :UPDATE :DELETE :HEADER_ROW
1689
+ # columns: number or :ALL_COLUMNS
1690
+ class TableModelEvent
1691
+ attr_accessor :firstrow, :lastrow, :column, :source, :type
1692
+ def initialize firstrow, lastrow, column, source, type
1693
+ @firstrow = firstrow
1694
+ @lastrow = lastrow
1695
+ @column = column
1696
+ @source = source
1697
+ @type = type
1698
+ end
1699
+ def to_s
1700
+ "#{@type.to_s}, firstrow: #{@firstrow}, lastrow: #{@lastrow}, column: #{@column}, source: #{@source}"
1701
+ end
1702
+ def inspect
1703
+ to_s
1704
+ end
1705
+ end
1706
+ ##
1707
+ # event sent when a column is added, removed or moved
1708
+ # type :INSERT :DELETE :MOVE
1709
+ # in the case of add query first col, for removed query second
1710
+ class TableColumnModelEvent
1711
+ attr_accessor :from_col, :to_col, :source, :type
1712
+ def initialize from_col, to_col, source, type
1713
+ @from_col = from_col
1714
+ @to_col = to_col
1715
+ @source = source
1716
+ @type = type
1717
+ end
1718
+ def to_s
1719
+ "#{@type.to_s}, from_col: #{@from_col}, to_col: #{@to_col}, source: #{@source}"
1720
+ end
1721
+ def inspect
1722
+ to_s
1723
+ end
1724
+ end
1725
+ ## caller can create one and reuse NOTE TODO
1726
+ class TableTraversalEvent
1727
+ attr_accessor :oldrow, :oldcol, :newrow, :newcol, :source
1728
+ def initialize oldrow, oldcol, newrow, newcol, source
1729
+ @oldrow, @oldcol, @newrow, @newcol, @source = oldrow, oldcol, newrow, newcol, source
1730
+ end
1731
+ def set oldrow, oldcol, newrow, newcol, source
1732
+ @oldrow, @oldcol, @newrow, @newcol, @source = oldrow, oldcol, newrow, newcol, source
1733
+ end
1734
+ def to_s
1735
+ "TRAVERSAL oldrow: #{@oldrow}, oldcol: #{@oldcol}, newrow: #{@newrow}, newcol: #{@newcol}, source: #{@source}"
1736
+ end
1737
+ def inspect
1738
+ to_s
1739
+ end
1740
+ end
1741
+ ## caller can create one and reuse NOTE TODO
1742
+ class TableEditingEvent
1743
+ attr_accessor :row, :col, :source, :oldvalue, :newvalue, :type
1744
+ def initialize row, col, source, oldvalue, newvalue, type
1745
+ set row, col, source, oldvalue, newvalue, type
1746
+ end
1747
+ def set row, col, source, oldvalue, newvalue, type
1748
+ @row, @col, @source, @oldvalue, @newvalue, @type = row, col, source, oldvalue, newvalue, type
1749
+ end
1750
+ def to_s
1751
+ "TABLEDITING #{@type} row: #{@row}, col: #{@col}, oldval: #{@oldvalue}, newvalue: #{@newvalue}, source: #{@source}"
1752
+ end
1753
+ def inspect
1754
+ to_s
1755
+ end
1756
+ end
1757
+
1758
+ end # module