rbcurse 1.4.1 → 1.5.0.pre1

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