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,1150 +0,0 @@
1
- =begin
2
- * Name: TabularWidget
3
- * Description A widget based on Tabular
4
- * Author: rk (arunachalesha)
5
- * file created 2010-09-28 23:37
6
- FIXME:
7
-
8
- TODO
9
- * guess_c : have some config : NEVER, FIRST_TIME, EACH_TIME
10
- if user has specified widths then we don't wanna guess. guess_size 20, ALL.
11
- * move columns
12
- * hide columns - importnat since with sorting we may need to store an identifier which
13
- should not be displayed
14
- x data truncation based on col wid TODO
15
- * TODO: search -- how is it working, but curpos is wrong.
16
- * allow resize of column inside column header
17
- * Now that we allow header to get focus, we should allow it to handle
18
- keys, but its not an object like it was in rtable ! AARGH !
19
- * NOTE: header could become an object in near future, but then why did we break
20
- away from rtable ?
21
- * TODO FIXME : after converting to convert_value_to_text and truncation etc, numbering is broken
22
- * we are checking widths of columsn and we have added a column, so columns widths refer to wrong col
23
- TODO : tabbing with w to take care of hidden columns and numbering. FIXME
24
- TODO: we forgot about selection altogether. we need multiple select !!! as in gmail
25
- subject list.
26
- --------
27
- * License:
28
- Same as Ruby's License (http://www.ruby-lang.org/LICENSE.txt)
29
-
30
- =end
31
- require 'rbcurse'
32
- require 'rbcurse/listscrollable'
33
- require 'rbcurse/extras/tabular'
34
- require 'rbcurse/extras/listselectable'
35
-
36
- #include RubyCurses
37
- module RubyCurses
38
- extend self
39
- # used when firing a column resize, so calling application can perhaps
40
- # resize other columns.
41
- class ColumnResizeEvent < Struct.new(:source, :index, :type); end
42
-
43
- ##
44
- # A viewable read only, scrollable table. This is supposed to be a
45
- # +minimal+, and (hopefully) fast version of Table (@see rtable.rb).
46
- class TabularWidget < Widget
47
-
48
-
49
- include ListScrollable
50
- include NewListSelectable
51
- dsl_accessor :title # set this on top
52
- dsl_accessor :title_attrib # bold, reverse, normal
53
- dsl_accessor :footer_attrib # bold, reverse, normal
54
- dsl_accessor :list # the array of arrays of data to be sent by user XXX RISKY bypasses set_content
55
- dsl_accessor :maxlen # max len to be displayed
56
- attr_reader :toprow # the toprow in the view (offsets are 0)
57
- attr_reader :winrow # the row in the viewport/window
58
- # painting the footer does slow down cursor painting slightly if one is moving cursor fast
59
- dsl_accessor :print_footer
60
- dsl_accessor :suppress_borders
61
- attr_accessor :current_index
62
- dsl_accessor :border_attrib, :border_color # color pair for border
63
- dsl_accessor :header_attrib, :header_fgcolor, :header_bgcolor # 2010-10-15 13:21
64
-
65
- # boolean, whether lines should be cleaned (if containing tabs/newlines etc)
66
- dsl_accessor :sanitization_required
67
- # boolean, whether column widths should be estimated based on data. If you want this,
68
- # set to true each time you do a set_content
69
- dsl_accessor :estimate_column_widths
70
- # boolean, whether lines should be numbered
71
- attr_accessor :numbering
72
- # default or custom sorter
73
- attr_reader :table_row_sorter
74
-
75
- # @group select related
76
- dsl_accessor :selection_mode
77
- dsl_accessor :selected_color, :selected_bgcolor, :selected_attr
78
-
79
- dsl_property :show_selector # boolean
80
- dsl_property :row_selected_symbol
81
- dsl_property :row_unselected_symbol
82
- attr_accessor :selected_index # should we use only indices ??
83
- # index of selected rows, if multiple selection asked for
84
- attr_reader :selected_indices
85
- attr_reader :_header_adjustment # we need to adjust when using current_index !!! UGH
86
- # @endgroup select related
87
-
88
- def initialize form = nil, config={}, &block
89
- @focusable = true
90
- @editable = false
91
- @sanitization_required = true
92
- @estimate_column_widths = true
93
- @row = 0
94
- @col = 0
95
- @cw = {} # column widths keyed on column index - why not array ??
96
- @pw = [] # preferred column widths 2010-10-20 12:58
97
- @calign = {} # columns aligns values, on column index
98
- @coffsets = {}
99
- @suppress_borders = false
100
- @row_offset = @col_offset = 1
101
- @chash = {}
102
- # this should have index of displayed column
103
- # so user can reorder columns
104
- #@column_position = [] # TODO
105
- @separ = @columns = @numbering = nil
106
- @y = '|'
107
- @x = '+'
108
- @list = []
109
- @_header_adjustment = 0
110
- @show_focus = false # don't highlight row under focus TODO
111
- @selection_mode = :multiple # default is multiple, anything else given becomes single
112
- @row_selected_symbol = '*'
113
- @show_selector = true
114
- super
115
- # ideally this should have been 2 to take care of borders, but that would break
116
- # too much stuff !
117
- @win = @graphic
118
-
119
- @_events.push :CHANGE # thru vieditable
120
- @_events << :PRESS # new, in case we want to use this for lists and allow ENTER
121
- @_events << :ENTER_ROW # new, should be there in listscrollable ??
122
- @_events << :COLUMN_RESIZE_EVENT
123
- install_keys # << almost jnuk now, clean off TODO
124
- init_vars
125
- map_keys
126
- end
127
- def init_vars #:nodoc:
128
- @curpos = @pcol = @toprow = @current_index = 0
129
- @repaint_all=true
130
- @repaint_required=true
131
-
132
- @row_offset = @col_offset = 0 if @suppress_borders == true
133
- @internal_width = 2
134
- @internal_width = 0 if @suppress_borders
135
- # added 2010-02-11 15:11 RFED16 so we don't need a form.
136
- @win_left = 0
137
- @win_top = 0
138
- @current_column = 0
139
- # currently i scroll right only if current line is longer than display width, i should use
140
- # longest line on screen.
141
- @longest_line = 0 # the longest line printed on this page, used to determine if scrolling shd work
142
- list_init_vars
143
-
144
- end
145
- def map_keys
146
- # remove bindings from here. we call repeatedly
147
- bind_key([?g,?g]){ goto_start } # mapping double keys like vim
148
- bind_key([?',?']){ goto_last_position } # vim , goto last row position (not column)
149
- bind_key(?/, :ask_search) # XXX TESTME
150
- bind_key(?n, :find_more) # XXX TESTME
151
- bind_key([?\C-x, ?>], :scroll_right)
152
- bind_key([?\C-x, ?<], :scroll_left)
153
- #bind_key(?r) { getstr("Enter a word: ") }
154
- bind_key(?m, :disp_menu) # enhance this or cut it out - how can app leverage this. TODO
155
- bind_key(?w, :next_column)
156
- bind_key(?b, :previous_column)
157
- list_bindings
158
- end
159
-
160
- #
161
- # set column names
162
- # @param [Array] column names or headings
163
- #
164
- def columns=(array)
165
- @_header_adjustment = 1
166
- @columns = array
167
- @columns.each_with_index { |c,i|
168
- @cw[i] ||= c.to_s.length
169
- @calign[i] ||= :left
170
- }
171
- # maintains index in current pointer and gives next or prev
172
- @column_pointer = Circular.new @columns.size()-1
173
- end
174
- alias :headings= :columns=
175
- ##
176
- # send in a list of data
177
- # sorting will only happen if data passed using set_content
178
- # NOTE: why doesn't set_content take in columns
179
- # @param [Array / Tabular] data to be displayed
180
- def set_content list, columns=nil
181
- if list.is_a? RubyCurses::Tabular
182
- @list = list
183
- elsif list.is_a? Array
184
- @list = list
185
- else
186
- raise "set_content expects Array not #{list.class}"
187
- end
188
- if @table_row_sorter
189
- @table_row_sorter.model=@list
190
- else
191
- @table_row_sorter = TableRowSorter.new @list
192
- end
193
- # adding columns setting here 2011-10-16
194
- self.columns = columns if columns
195
- @current_index = @_header_adjustment # but this is set when columns passed
196
- @toprow = 0
197
- @second_time = false # so that reestimation of column_widths
198
- @repaint_required = true
199
- @recalc_required = true
200
- self
201
- end
202
- def data=(data)
203
- set_content(data, nil)
204
- end
205
-
206
- # add a row of data
207
- # NOTE: this is not creating a table sorter
208
- # @param [Array] an array containing entries for each column
209
- def add array
210
- @list ||= []
211
- @list << array
212
- @repaint_required = true
213
- @recalc_required = true
214
- end
215
- alias :<< :add
216
- alias :add_row :add
217
- alias :append :add
218
- def create_default_sorter
219
- raise "Data not sent in." unless @list
220
- @table_row_sorter = TableRowSorter.new @list
221
- end
222
- def remove_all
223
- @list = []
224
- init_vars
225
- end
226
- def delete_at off0
227
- ret=@list.delete_at off0
228
- return ret
229
- end
230
- def []=(off0, data)
231
- @list[off0] = data
232
- end
233
- def [](off0)
234
- @list[off0]
235
- end
236
- def insert off0, *data
237
- @list.insert off0, *data
238
- end
239
- # TODO more methods like in listbox so interchangeable, delete_at etc
240
- def column_width colindex, width
241
- return if width < 0
242
- raise ArgumentError, "wrong width value sent: #{width} " if width.nil? || !width.is_a?(Fixnum) || width < 0
243
- #@cw[colindex] = width
244
- @pw[colindex] = width # XXXXX
245
- get_column(colindex).width = width
246
- @repaint_required = true
247
- @recalc_required = true
248
- end
249
-
250
- # set alignment of given column offset
251
- # @param [Number] column offset, starting 0
252
- # @param [Symbol] :left, :right
253
- def column_align colindex, lrc
254
- raise ArgumentError, "wrong alignment value sent" if ![:right, :left, :center].include? lrc
255
- @calign[colindex] = lrc
256
- get_column(colindex).align = lrc
257
- @repaint_required = true
258
- #@recalc_required = true
259
- end
260
- # Set a column to hidden TODO we are not actually doing that
261
- def column_hidden colindex, tf=true
262
- #raise ArgumentError, "wrong alignment value sent" if ![:right, :left, :center].include? lrc
263
- get_column(colindex).hidden = tf
264
- @repaint_required = true
265
- @recalc_required = true
266
- end
267
- def move_column
268
-
269
- end
270
- def expand_column
271
- end
272
- def contract_column
273
- end
274
- ## display this row number on top
275
- # programmataically indicate a row to be top row
276
- def top_row(*val)
277
- if val.empty?
278
- @toprow
279
- else
280
- @toprow = val[0] || 0
281
- end
282
- @repaint_required = true
283
- end
284
- ## ---- for listscrollable ---- ##
285
- def scrollatrow #:nodoc:
286
- # TODO account for headers
287
- if @suppress_borders
288
- @height - @_header_adjustment
289
- else
290
- @height - (2 + @_header_adjustment)
291
- end
292
- end
293
- def row_count
294
- #@list.length
295
- get_content().length + @_header_adjustment
296
- end
297
- ##
298
- # returns row of first match of given regex (or nil if not found)
299
- def find_first_match regex #:nodoc:
300
- @list.each_with_index do |row, ix|
301
- return ix if !row.match(regex).nil?
302
- end
303
- return nil
304
- end
305
- ## returns the position where cursor was to be positioned by default
306
- # It may no longer work like that.
307
- def rowcol #:nodoc:
308
- return @row+@row_offset, @col+@col_offset
309
- end
310
- ## print a border
311
- ## Note that print_border clears the area too, so should be used sparingly.
312
- def print_borders #:nodoc:
313
- raise "#{self.class} needs width" unless @width
314
- raise "#{self.class} needs height" unless @height
315
-
316
- $log.debug " #{@name} print_borders, #{@graphic.name} "
317
-
318
- bordercolor = @border_color || $datacolor
319
- borderatt = @border_attrib || Ncurses::A_NORMAL
320
- @graphic.print_border @row, @col, @height-1, @width, bordercolor, borderatt
321
- print_title
322
- end
323
- def print_title #:nodoc:
324
- raise "#{self.class} needs width" unless @width
325
- $log.debug " print_title #{@row}, #{@col}, #{@width} "
326
- @graphic.printstring( @row, @col+(@width-@title.length)/2, @title, $datacolor, @title_attrib) unless @title.nil?
327
- end
328
- def print_foot #:nodoc:
329
- @footer_attrib ||= Ncurses::A_DIM
330
- gb = get_color($datacolor, 'green','black')
331
- if @current_index == @toprow
332
- footer = "%15s" % " [ header row ]"
333
- else
334
- footer = "%15s" % " [#{@current_index}/ #{@list.length} ]"
335
- end
336
- pos = @col + 2
337
- right = true
338
- if right
339
- pos = @col + @width - footer.length - 1
340
- end
341
- @graphic.printstring( @row + @height -1 , pos, footer, gb, @footer_attrib)
342
- @repaint_footer_required = false # 2010-01-23 22:55
343
- #@footer_attrib ||= Ncurses::A_REVERSE
344
- #footer = "R: #{@current_index+1}, C: #{@curpos+@pcol}, #{@list.length} lines "
345
- ##$log.debug " print_foot calling printstring with #{@row} + #{@height} -1, #{@col}+2"
346
- #@graphic.printstring( @row + @height -1 , @col+2, footer, $datacolor, @footer_attrib)
347
- #@repaint_footer_required = false # 2010-01-23 22:55
348
- end
349
- ### FOR scrollable ###
350
- def get_content
351
- @list
352
- #[:columns, :separator, *@list]
353
- #[:columns, *@list]
354
- end
355
- def get_window #:nodoc:
356
- @graphic
357
- end
358
-
359
- def repaint # Tabularwidget :nodoc:
360
-
361
- #return unless @repaint_required # 2010-02-12 19:08 TRYING - won't let footer print for col move
362
- paint if @repaint_required
363
- # raise "TV 175 graphic nil " unless @graphic
364
- print_foot if @print_footer && @repaint_footer_required
365
- end
366
- def getvalue
367
- @list
368
- end
369
- # returns value of current row.
370
- # NOTE: you may need to adjust it with _header_adjustment - actually you can't
371
- # this may give wrong row -- depends what you want.
372
- def current_value
373
- @list[@current_index-@_header_adjustment] # XXX added header_adju 2010-11-01 11:14
374
- end
375
- def real_index
376
- @current_index-@_header_adjustment # XXX added header_adju 2010-11-06 19:38
377
- end
378
- # Tabularwidget
379
- def handle_key ch #:nodoc:
380
- if header_row?
381
- ret = header_handle_key ch
382
- return ret unless ret == :UNHANDLED
383
- end
384
- case ch
385
- when ?\C-d.getbyte(0) #, 32
386
- scroll_forward
387
- when ?\C-b.getbyte(0)
388
- scroll_backward
389
- when ?\C-[.getbyte(0), ?t.getbyte(0)
390
- goto_start #start of buffer # cursor_start
391
- when ?\C-].getbyte(0), ?G.getbyte(0)
392
- goto_end # end / bottom cursor_end
393
- when KEY_UP, ?k.getbyte(0)
394
- #select_prev_row
395
- ret = up
396
- get_window.ungetch(KEY_BTAB) if ret == :NO_PREVIOUS_ROW
397
- check_curpos
398
-
399
- when KEY_DOWN, ?j.getbyte(0)
400
- ret = down
401
- #get_window.ungetch(KEY_TAB) if ret == :NO_NEXT_ROW
402
- check_curpos
403
- when KEY_LEFT, ?h.getbyte(0)
404
- cursor_backward
405
- when KEY_RIGHT, ?l.getbyte(0)
406
- cursor_forward
407
- when KEY_BACKSPACE, KEY_BSPACE, KEY_DELETE
408
- cursor_backward
409
- when ?\C-a.getbyte(0) #, ?0.getbyte(0)
410
- # take care of data that exceeds maxlen by scrolling and placing cursor at start
411
- @repaint_required = true if @pcol > 0 # tried other things but did not work
412
- set_form_col 0
413
- @pcol = 0
414
- when ?\C-e.getbyte(0), ?$.getbyte(0)
415
- # take care of data that exceeds maxlen by scrolling and placing cursor at end
416
- # This use to actually pan the screen to actual end of line, but now somewhere
417
- # it only goes to end of visible screen, set_form probably does a sanity check
418
- blen = @buffer.rstrip.length
419
- set_form_col blen
420
- # search related
421
- when @KEY_ASK_FIND # FIXME
422
- ask_search
423
- when @KEY_FIND_MORE # FIXME
424
- find_more
425
- when 10, 13, KEY_ENTER
426
- #fire_handler :PRESS, self
427
- fire_action_event
428
- when ?0.getbyte(0)..?9.getbyte(0)
429
- # FIXME the assumption here was that if numbers are being entered then a 0 is a number
430
- # not a beg-of-line command.
431
- # However, after introducing universal_argument, we can enters numbers using C-u and then press another
432
- # C-u to stop. In that case a 0 should act as a command, even though multiplier has been set
433
- if ch == ?0.getbyte(0) and $multiplier == 0
434
- # copy of C-a - start of line
435
- @repaint_required = true if @pcol > 0 # tried other things but did not work
436
- set_form_col 0
437
- @pcol = 0
438
- return 0
439
- end
440
- # storing digits entered so we can multiply motion actions
441
- $multiplier *= 10 ; $multiplier += (ch-48)
442
- return 0
443
- #when ?\C-u.getbyte(0)
444
- ## multiplier. Series is 4 16 64
445
- #@multiplier = (@multiplier == 0 ? 4 : @multiplier *= 4)
446
- #return 0
447
- when ?\M-l.getbyte(0) # just added 2010-03-05 not perfect
448
- scroll_right # scroll data horizontally
449
- when ?\M-h.getbyte(0)
450
- scroll_left
451
- when ?\C-c.getbyte(0)
452
- $multiplier = 0
453
- return 0
454
- else
455
- # check for bindings, these cannot override above keys since placed at end
456
- begin
457
- ret = process_key ch, self
458
- rescue => err
459
- $error_message.value = err.to_s
460
- # @form.window.print_error_message # changed 2011 dts
461
- alert err.to_s
462
- $log.error " Tabularwidget ERROR #{err} "
463
- $log.debug(err.backtrace.join("\n"))
464
- # XXX caller app has no idea error occurred so can't do anything !
465
- end
466
- return :UNHANDLED if ret == :UNHANDLED
467
- end
468
- $multiplier = 0 # you must reset if you've handled a key. if unhandled, don't reset since parent could use
469
- set_form_row
470
- return 0 # added 2010-01-12 22:17 else down arrow was going into next field
471
- end
472
- #
473
- # allow header to handle keys
474
- # NOTE: header could become an object in near future
475
- # We are calling a resize event and passing column index but do we really
476
- # have a column object that user can access and do something with ?? XXX
477
- #
478
- def header_handle_key ch #:nodoc:
479
- # TODO pressing = should revert to calculated size ?
480
- col = _convert_curpos_to_column
481
- #width = @cw[col]
482
- width = @pw[col] || @cw[col]
483
- case ch
484
- when ?-.getbyte(0)
485
- column_width col, width-1
486
- # if this event has not been used in a sample it could change in near future
487
- e = ColumnResizeEvent.new self, col, :DECREASE
488
- fire_handler :COLUMN_RESIZE_EVENT, e
489
- # can fire_hander so user can resize another column
490
- return 0
491
- when ?\+.getbyte(0)
492
- column_width col, width+1
493
- # if this event has not been used in a sample it could change in near future
494
- e = ColumnResizeEvent.new self, col, :INCREASE
495
- return 0
496
- end
497
- return :UNHANDLED
498
- end
499
- # newly added to check curpos when moving up or down
500
- def check_curpos #:nodoc:
501
- # if the cursor is ahead of data in this row then move it back
502
- # i don't think this is required
503
- return
504
- if @pcol+@curpos > @buffer.length
505
- addcol((@pcol+@buffer.length-@curpos)+1)
506
- @curpos = @buffer.length
507
- maxlen = (@maxlen || @width-@internal_width)
508
-
509
- # even this row is gt maxlen, i.e., scrolled right
510
- if @curpos > maxlen
511
- @pcol = @curpos - maxlen
512
- @curpos = maxlen-1
513
- else
514
- # this row is within maxlen, make scroll 0
515
- @pcol=0
516
- end
517
- set_form_col
518
- end
519
- end
520
- # set cursor on correct column tview
521
- def set_form_col col1=@curpos #:nodoc:
522
- @cols_panned ||= 0
523
- @pad_offset ||= 0 # added 2010-02-11 21:54 since padded widgets get an offset.
524
- @curpos = col1
525
- maxlen = @maxlen || @width-@internal_width
526
- #@curpos = maxlen if @curpos > maxlen
527
- if @curpos > maxlen
528
- @pcol = @curpos - maxlen
529
- @curpos = maxlen - 1
530
- @repaint_required = true # this is required so C-e can pan screen
531
- else
532
- @pcol = 0
533
- end
534
- # the rest only determines cursor placement
535
- win_col = 0 # 2010-02-07 23:19 new cursor stuff
536
- col2 = win_col + @col + @col_offset + @curpos + @cols_panned + @pad_offset
537
- #$log.debug "TV SFC #{@name} setting c to #{col2} #{win_col} #{@col} #{@col_offset} #{@curpos} "
538
- #@form.setrowcol @form.row, col
539
- setrowcol nil, col2
540
- @repaint_footer_required = true
541
- end
542
- def cursor_forward #:nodoc:
543
- maxlen = @maxlen || @width-@internal_width
544
- repeatm {
545
- if @curpos < @width and @curpos < maxlen-1 # else it will do out of box
546
- @curpos += 1
547
- addcol 1
548
- else
549
- @pcol += 1 if @pcol <= @buffer.length
550
- end
551
- }
552
- set_form_col
553
- #@repaint_required = true
554
- @repaint_footer_required = true # 2010-01-23 22:41
555
- end
556
- def addcol num #:nodoc:
557
- #@repaint_required = true
558
- @repaint_footer_required = true # 2010-01-23 22:41
559
- if @form
560
- @form.addcol num
561
- else
562
- @parent_component.form.addcol num
563
- end
564
- end
565
- def addrowcol row,col #:nodoc:
566
- #@repaint_required = true
567
- @repaint_footer_required = true # 2010-01-23 22:41
568
- if @form
569
- @form.addrowcol row, col
570
- else
571
- @parent_component.form.addrowcol num
572
- end
573
- end
574
- def cursor_backward #:nodoc:
575
- repeatm {
576
- if @curpos > 0
577
- @curpos -= 1
578
- set_form_col
579
- #addcol -1
580
- elsif @pcol > 0
581
- @pcol -= 1
582
- end
583
- }
584
- #@repaint_required = true
585
- @repaint_footer_required = true # 2010-01-23 22:41
586
- end
587
-
588
- ## NOTE: earlier print_border was called only once in constructor, but when
589
- ##+ a window is resized, and destroyed, then this was never called again, so the
590
- ##+ border would not be seen in splitpane unless the width coincided exactly with
591
- ##+ what is calculated in divider_location.
592
- def paint #:nodoc:
593
- my_win = nil
594
- if @form
595
- my_win = @form.window
596
- else
597
- my_win = @target_window
598
- end
599
- @graphic = my_win unless @graphic
600
- @win_left = my_win.left
601
- @win_top = my_win.top
602
- tm = get_content
603
- rc = tm.length
604
- _estimate_column_widths if rc > 0 # will set preferred_width 2011-10-4
605
- @left_margin ||= @row_selected_symbol.length
606
- @width ||= @preferred_width
607
-
608
- @height ||= [tm.length+3, 10].min
609
- _prepare_format
610
-
611
- print_borders if (@suppress_borders == false && @repaint_all) # do this once only, unless everything changes
612
- _maxlen = @maxlen || @width-@internal_width
613
- $log.debug " #{@name} Tabularwidget repaint width is #{@width}, height is #{@height} , maxlen #{maxlen}/ #{@maxlen}, #{@graphic.name} roff #{@row_offset} coff #{@col_offset}"
614
- tr = @toprow
615
- acolor = get_color $datacolor
616
- h = scrollatrow()
617
- r,c = rowcol
618
- print_header
619
- r += @_header_adjustment # for column header
620
- @longest_line = @width #maxlen
621
- 0.upto(h - @_header_adjustment) do |hh|
622
- crow = tr+hh
623
- if crow < rc
624
- #focussed = @current_index == crow ? true : false
625
- content = tm[crow]
626
-
627
- columnrow = false
628
- if content == :columns
629
- columnrow = true
630
- end
631
-
632
- value = convert_value_to_text content, crow
633
-
634
- @buffer = value if crow == @current_index
635
- # next call modified string. you may wanna dup the string.
636
- # rlistbox does
637
- sanitize value if @sanitization_required
638
- truncate value
639
- ## set the selector symbol if requested
640
- paint_selector crow, r+hh, c, acolor, @attr
641
-
642
- #@graphic.printstring r+hh, c, "%-*s" % [@width-@internal_width,value], acolor, @attr
643
- #print_data_row( r+hh, c, "%-*s" % [@width-@internal_width,value], acolor, @attr)
644
- print_data_row( r+hh, c+@left_margin, @width-@internal_width-@left_margin, value, acolor, @attr)
645
-
646
- else
647
- # clear rows
648
- @graphic.printstring r+hh, c, " " * (@width-@internal_width-@left_margin), acolor,@attr
649
- end
650
- end
651
- @repaint_required = false
652
- @repaint_footer_required = true
653
- @repaint_all = false
654
-
655
- end
656
-
657
- # print data rows
658
- def print_data_row r, c, len, value, color, attr
659
- @graphic.printstring r, c, "%-*s" % [len,value], color, attr
660
- end
661
- #
662
- # Truncates data to fit into display area.
663
- # Copied from listscrollable since we need to take care of left_margin
664
- # 2011-10-6 This may need to be reflected in listbox and others FIXME
665
- def truncate content #:nodoc:
666
- #maxlen = @maxlen || @width-2
667
- _maxlen = @maxlen || @width-@internal_width
668
- _maxlen = @width-@internal_width if _maxlen > @width-@internal_width
669
- _maxlen -= @left_margin
670
- if !content.nil?
671
- if content.length > _maxlen # only show maxlen
672
- @longest_line = content.length if content.length > @longest_line
673
- #content = content[@pcol..@pcol+_maxlen-1]
674
- content.replace content[@pcol..@pcol+_maxlen-1]
675
- else
676
- # can this be avoided if pcol is 0 XXX
677
- content.replace content[@pcol..-1] if @pcol > 0
678
- end
679
- end
680
- content
681
- end
682
-
683
- # print header row
684
- # allows user to override
685
- def print_header_row r, c, len, value, color, attr
686
- #acolor = $promptcolor
687
- @graphic.printstring r, c+@left_margin, "%-*s" % [len-@left_margin ,value], color, attr
688
- end
689
- def separator
690
- #return @separ if @separ
691
- str = ""
692
- if @numbering
693
- rows = @list.size.to_s.length
694
- str = "-"*(rows+1)+@x
695
- end
696
- @cw.each_pair { |k,v| str << "-" * (v+1) + @x }
697
- @separ = str.chop
698
- end
699
- # prints the column headers
700
- # Uses +convert_value_to_text+ and +print_header_row+
701
- def print_header
702
- r,c = rowcol
703
- value = convert_value_to_text :columns, 0
704
- len = @width - @internal_width
705
- truncate value # else it can later suddenly exceed line
706
- @header_color_pair ||= get_color $promptcolor, @header_fgcolor, @header_bgcolor
707
- @header_attrib ||= @attr
708
- print_header_row r, c, len, value, @header_color_pair, @header_attrib
709
- end
710
- # convert data object to a formatted string for print
711
- # NOTE: useful for overriding and doing custom formatting
712
- # @param [Array] array of column data, mostly +String+
713
- # Can also be :columns or :separator
714
- # @param [Fixnum] index of row in data
715
- def convert_value_to_text r, count
716
- if r == :separator
717
- return separator
718
- elsif r == :columns
719
- return "??" unless @columns # column was requested but not supplied
720
- # FIXME putting entire header into this, take care of hidden
721
- r = []
722
- @columns.each_with_index { |e, i| r << e unless get_column(i).hidden }
723
- return @headerfmtstr % r if @numbering
724
- end
725
- str = ""
726
-
727
- if @numbering
728
- #r = r.dup
729
- #r.insert 0, count+1
730
- # TODO get the width
731
- str << "%*d |"% [2, count + 1]
732
- end
733
- # unroll r, get width and align
734
- # This is to truncate column to requested width
735
- fmta = []
736
- r.each_with_index { |e, i|
737
- next if get_column(i).hidden == true
738
- #w = @pw[i] || @cw[i] # XXX
739
- #$log.debug "WIDTH XXX #{i} w= #{w} , #{@pw[i]}, #{@cw[i]} :: #{e} " if $log.debug?
740
- w = @cw[i]
741
- l = e.to_s.length
742
- fmt = "%-#{w}s "
743
- if l > w
744
- fmt = "%.#{w}s "
745
- else
746
- # ack we don;t need to recalc this we can pull out of hash FIXME
747
- case @calign[i]
748
- when :right
749
- fmt = "%#{w}s "
750
- else
751
- fmt = "%-#{w}s "
752
- end
753
- end
754
- str << fmt % e
755
- fmta << fmt
756
- }
757
- #fmstr = fmta.join(@y)
758
- #return fmstr % r; # FIXME hidden column still goes int
759
- return str
760
- end
761
- # perhaps we can delete this since it does not respect @pw
762
- # @deprecated (see _estimate_column_widths)
763
- def _guess_col_widths #:nodoc:
764
- return if @second_time
765
- @second_time = true if @list.size > 0
766
- @list.each_with_index { |r, i|
767
- break if i > 10
768
- next if r == :separator
769
- r.each_with_index { |c, j|
770
- x = c.to_s.length
771
- if @cw[j].nil?
772
- @cw[j] = x
773
- else
774
- @cw[j] = x if x > @cw[j]
775
- end
776
- }
777
- }
778
- #sum = @cw.values.inject(0) { |mem, var| mem + var }
779
- #$log.debug " SUM is #{sum} "
780
- total = 0
781
- @cw.each_pair { |name, val| total += val }
782
- @preferred_width = total + (@cw.size() *2)
783
- @preferred_width += 4 if @numbering # FIXME this 4 is rough
784
- end
785
- def _estimate_column_widths #:nodoc:
786
- return unless @estimate_column_widths
787
- @estimate_column_widths = false # XXX testing why its failing in gmail
788
- @columns.each_with_index { |c, i|
789
- if @pw[i]
790
- @cw[i] = @pw[i]
791
- else
792
- @cw[i] = calculate_column_width(i)
793
- end
794
- }
795
- total = 0
796
- @cw.each_pair { |name, val| total += val }
797
- @preferred_width = total + (@cw.size() *2)
798
- @preferred_width += 4 if @numbering # FIXME this 4 is rough
799
- end
800
- # if user has not specified preferred_width for a column
801
- # then we can calculate the same based on data
802
- def calculate_column_width col
803
- ret = @cw[col] || 2
804
- ctr = 0
805
- @list.each_with_index { |r, i|
806
- #next if i < @toprow # this is also a possibility, it checks visible rows
807
- break if ctr > 10
808
- ctr += 1
809
- next if r == :separator
810
- c = r[col]
811
- x = c.to_s.length
812
- ret = x if x > ret
813
- }
814
- ret
815
- end
816
- def _prepare_format #:nodoc:
817
- @fmtstr = nil
818
- fmt = []
819
- total = 0
820
- @cw.each_with_index { |c, i|
821
- next if get_column(i).hidden == true # added 2010-10-28 19:08
822
- w = @cw[i]
823
- @coffsets[i] = total
824
- total += w + 2
825
-
826
- case @calign[i]
827
- when :right
828
- fmt << "%#{w}s "
829
- else
830
- fmt << "%-#{w}s "
831
- end
832
- }
833
- @fmstr = fmt.join(@y)
834
- if @numbering
835
- @rows ||= @list.size.to_s.length
836
- @headerfmtstr = " "*(@rows+1)+@y + @fmstr
837
- @fmstr = "%#{@rows}d "+ @y + @fmstr
838
- @coffsets.each_pair { |name, val| @coffsets[name] = val + @rows + 2 }
839
- end
840
- #$log.debug " FMT : #{@fmstr} "
841
- #alert "format: #{@fmstr} "
842
- end
843
- ## this is just a test of prompting user for a string
844
- #+ as an alternative to the dialog.
845
- def getstr prompt, maxlen=10 #:nodoc:
846
- tabc = Proc.new {|str| Dir.glob(str +"*") }
847
- config={}; config[:tab_completion] = tabc
848
- config[:default] = "default"
849
- $log.debug " inside getstr before call "
850
- ret, str = rbgetstr(@form.window, @row+@height-1, @col+1, prompt, maxlen, config)
851
- $log.debug " rbgetstr returned #{ret} , #{str} "
852
- return "" if ret != 0
853
- return str
854
- end
855
- # this is just a test of the simple "most" menu
856
- def disp_menu #:nodoc:
857
- $error_message_row ||= 23 # FIXME
858
- $error_message_col ||= 1 # FIXME
859
- menu = PromptMenu.new self
860
- menu.add( menu.create_mitem( 's', "Goto start ", "Going to start", Proc.new { goto_start} ))
861
- menu.add(menu.create_mitem( 'r', "scroll right", "I have scrolled ", :scroll_right ))
862
- menu.add(menu.create_mitem( 'l', "scroll left", "I have scrolled ", :scroll_left ))
863
- item = menu.create_mitem( 'm', "submenu", "submenu options" )
864
- menu1 = PromptMenu.new( self, "Submenu Options")
865
- menu1.add(menu1.create_mitem( 's', "CASE sensitive", "Ignoring Case in search" ))
866
- menu1.add(menu1.create_mitem( 't', "goto last position", "moved to previous position", Proc.new { goto_last_position} ))
867
- item.action = menu1
868
- menu.add(item)
869
- # how do i know what's available. the application or window should know where to place
870
- #menu.display @form.window, 23, 1, $datacolor #, menu
871
- menu.display @form.window, $error_message_row, $error_message_col, $datacolor #, menu
872
- end
873
- ##
874
- # dynamically load a module and execute init method.
875
- # Hopefully, we can get behavior like this such as vieditable or multibuffers
876
- def load_module requirename, includename
877
- require "rbcurse/#{requirename}"
878
- extend Object.const_get("#{includename}")
879
- send("#{requirename}_init") #if respond_to? "#{includename}_init"
880
- end
881
-
882
- # returns true if cursor is on header row
883
- # NOTE: I have no idea why row was used here. it is not working
884
- def header_row?
885
- return false if @columns.nil?
886
- #1 == @row + (@current_index-@toprow)
887
- @current_index == @toprow
888
- end
889
- # on pressing ENTER we send user some info, the calling program
890
- # would bind :PRESS
891
- # Added a call to sort, should i still call PRESS
892
- # or just do a sort in here and not call PRESS ???
893
- #--
894
- # FIXME we can create this once and reuse
895
- #++
896
- def fire_action_event
897
- return unless @list
898
- return unless @table_row_sorter
899
- require 'rbcurse/ractionevent'
900
- # the header event must only be used if columns passed
901
- if header_row?
902
- # TODO we need to fire correct even for header row, including
903
- #alert "you are on header row: #{@columns[x]} curpos: #{@curpos}, x:#{x} "
904
- #aev = TextActionEvent.new self, :PRESS, @columns[x], x, @curpos
905
- x = _convert_curpos_to_column
906
- @table_row_sorter.toggle_sort_order x
907
- @table_row_sorter.sort
908
- @repaint_required = true
909
- aev = TextActionEvent.new self, :PRESS,:header, x, @curpos
910
- else
911
- # please check this again current_value due to _header_adjustment XXX test
912
- aev = TextActionEvent.new self, :PRESS, current_value(), @current_index, @curpos
913
- end
914
- fire_handler :PRESS, aev
915
- end
916
- # Convert current cursor position to a table column
917
- # calculate column based on curpos since user may not have
918
- # user w and b keys (:next_column)
919
- # @return [Fixnum] column index base 0
920
- def _convert_curpos_to_column #:nodoc:
921
- x = 0
922
- @coffsets.each_pair { |e,i|
923
- if @curpos < i
924
- break
925
- else
926
- x += 1
927
- end
928
- }
929
- x -= 1 # since we start offsets with 0, so first auto becoming 1
930
- return x
931
- end
932
- def on_enter
933
- # so cursor positioned on correct row
934
- set_form_row
935
- super
936
- end
937
- # called by listscrollable, used by scrollbar ENTER_ROW
938
- def on_enter_row arow
939
- fire_handler :ENTER_ROW, self
940
- @repaint_required = true
941
- end
942
- # move cursor to next column
943
- # FIXME need to account for hidden columns and numbering
944
- def next_column
945
- c = @column_pointer.next
946
- cp = @coffsets[c]
947
- #$log.debug " next_column #{c} , #{cp} "
948
- @curpos = cp if cp
949
- next_row() if c < @column_pointer.last_index
950
- #addcol cp
951
- set_form_col
952
- end
953
- def previous_column
954
- c = @column_pointer.previous
955
- cp = @coffsets[c]
956
- #$log.debug " prev_column #{c} , #{cp} "
957
- @curpos = cp if cp
958
- previous_row() if c > @column_pointer.last_index
959
- #addcol cp FIXME
960
- set_form_col
961
- end
962
- private
963
- def get_column index #:nodoc:
964
- return @chash[index] if @chash.has_key? index
965
- @chash[index] = ColumnInfo.new
966
- end
967
-
968
- # Some supporting classes
969
-
970
- # This is our default table row sorter.
971
- # It does a multiple sort and allows for reverse sort also.
972
- # It's a pretty simple sorter and uses sort, not sort_by.
973
- # Improvements welcome.
974
- # Usage: provide model in constructor or using model method
975
- # Call toggle_sort_order(column_index)
976
- # Call sort.
977
- # Currently, this sorts the provided model in-place. Future versions
978
- # may maintain a copy, or use a table that provides a mapping of model to result.
979
- # # TODO check if column_sortable
980
- class TableRowSorter
981
- attr_reader :sort_keys
982
- def initialize model=nil
983
- self.model = model
984
- @columns_sort = []
985
- @sort_keys = nil
986
- end
987
- def model=(model)
988
- @model = model
989
- @sort_keys = nil
990
- end
991
- def sortable colindex, tf
992
- @columns_sort[colindex] = tf
993
- end
994
- def sortable? colindex
995
- return false if @columns_sort[colindex]==false
996
- return true
997
- end
998
- # should to_s be used for this column
999
- def use_to_s colindex
1000
- return true # TODO
1001
- end
1002
- # sorts the model based on sort keys and reverse flags
1003
- # @sort_keys contains indices to sort on
1004
- # @reverse_flags is an array of booleans, true for reverse, nil or false for ascending
1005
- def sort
1006
- return unless @model
1007
- return if @sort_keys.empty?
1008
- $log.debug "TABULAR SORT KEYS #{sort_keys} "
1009
- @model.sort!{|x,y|
1010
- res = 0
1011
- @sort_keys.each { |ee|
1012
- e = ee.abs-1 # since we had offsetted by 1 earlier
1013
- abse = e.abs
1014
- if ee < 0
1015
- res = y[abse] <=> x[abse]
1016
- else
1017
- res = x[e] <=> y[e]
1018
- end
1019
- break if res != 0
1020
- }
1021
- res
1022
- }
1023
- end
1024
- # toggle the sort order if given column offset is primary sort key
1025
- # Otherwise, insert as primary sort key, ascending.
1026
- def toggle_sort_order index
1027
- index += 1 # increase by 1, since 0 won't multiple by -1
1028
- # internally, reverse sort is maintained by multiplying number by -1
1029
- @sort_keys ||= []
1030
- if @sort_keys.first && index == @sort_keys.first.abs
1031
- @sort_keys[0] *= -1
1032
- else
1033
- @sort_keys.delete index # in case its already there
1034
- @sort_keys.delete(index*-1) # in case its already there
1035
- @sort_keys.unshift index
1036
- # don't let it go on increasing
1037
- if @sort_keys.size > 3
1038
- @sort_keys.pop
1039
- end
1040
- end
1041
- end
1042
- def set_sort_keys list
1043
- @sort_keys = list
1044
- end
1045
- end #class
1046
- # what about is_resizable XXX
1047
- class ColumnInfo < Struct.new(:name, :width, :align, :hidden)
1048
- end
1049
-
1050
- # a structure that maintains position and gives
1051
- # next and previous taking max index into account.
1052
- # it also circles. Can be used for traversing next component
1053
- # in a form, or container, or columns in a table.
1054
- class Circular < Struct.new(:max_index, :current_index)
1055
- attr_reader :last_index
1056
- attr_reader :current_index
1057
- def initialize m, c=0
1058
- raise "max index cannot be nil" unless m
1059
- @max_index = m
1060
- @current_index = c
1061
- @last_index = c
1062
- end
1063
- def next
1064
- @last_index = @current_index
1065
- if @current_index + 1 > @max_index
1066
- @current_index = 0
1067
- else
1068
- @current_index += 1
1069
- end
1070
- end
1071
- def previous
1072
- @last_index = @current_index
1073
- if @current_index - 1 < 0
1074
- @current_index = @max_index
1075
- else
1076
- @current_index -= 1
1077
- end
1078
- end
1079
- def is_last?
1080
- @current_index == @max_index
1081
- end
1082
- end
1083
- # for some compatibility with Table
1084
- def set_data data, colnames_array
1085
- set_content data
1086
- columns = colnames_array
1087
- end
1088
- def get_column_name index
1089
- @columns[index]
1090
- end
1091
- alias :column_name :get_column_name
1092
- alias :column :get_column
1093
- def method_missing(name, *args)
1094
- name = name.to_s
1095
- case name
1096
- when 'cell_editing_allowed', 'editing_policy'
1097
- # silently ignore to keep compatible with Table
1098
- else
1099
- raise NoMethodError, "Undefined method #{name} for TabularWidget"
1100
- end
1101
- end
1102
-
1103
- end # class tabluarw
1104
-
1105
- end # modul
1106
- if __FILE__ == $PROGRAM_NAME
1107
-
1108
- require 'rbcurse/app'
1109
- App.new do
1110
- t = TabularWidget.new @form, :row => 2, :col => 2, :height => 20, :width => 30
1111
- t.columns = ["Name ", "Age ", " Email "]
1112
- t.add %w{ rahul 33 r@ruby.org }
1113
- t << %w{ _why 133 j@gnu.org }
1114
- t << ["jane", "1331", "jane@gnu.org" ]
1115
- t.column_align 1, :right
1116
- t.create_default_sorter
1117
-
1118
- s = TabularWidget.new @form, :row => 2, :col =>32 do |b|
1119
- b.columns = %w{ country continent text }
1120
- b << ["india","asia","a warm country" ]
1121
- b << ["japan","asia","a cool country" ]
1122
- b << ["russia","europe","a hot country" ]
1123
- #b.column_width 2, 30
1124
- end
1125
- s.create_default_sorter
1126
- s = TabularWidget.new @form , :row => 12, :col => 32 do |b|
1127
- b.columns = %w{ place continent text }
1128
- b << ["india","asia","a warm country" ]
1129
- b << ["japan","asia","a cool country" ]
1130
- b << ["russia","europe","a hot country" ]
1131
- b << ["sydney","australia","a dry country" ]
1132
- b << ["canberra","australia","a dry country" ]
1133
- b << ["ross island","antarctica","a dry country" ]
1134
- b << ["mount terror","antarctica","a windy country" ]
1135
- b << ["mt erebus","antarctica","a cold place" ]
1136
- b << ["siberia","russia","an icy city" ]
1137
- b << ["new york","USA","a fun place" ]
1138
- b.column_width 0, 12
1139
- b.column_width 1, 12
1140
- b.column_hidden 1, true
1141
- b.numbering = true ## FIXME BROKEN
1142
- end
1143
- s.create_default_sorter
1144
- require 'rbcurse/extras/scrollbar'
1145
- sb = Scrollbar.new @form, :parent => s
1146
- #t.column_align 1, :right
1147
- #puts t.to_s
1148
- #puts
1149
- end
1150
- end