Class: RubyCurses::TabularWidget

Inherits:
Widget show all
Includes:
ListScrollable, NewListSelectable
Defined in:
lib/rbcurse/extras/tabularwidget.rb

Overview

A viewable read only, scrollable table. This is supposed to be a minimal, and (hopefully) fast version of Table (@see rtable.rb).

Defined Under Namespace

Classes: Circular, ColumnInfo, TableRowSorter

Constant Summary

Constants included from Io

Io::ERROR_COLOR_PAIR, Io::FOOTER_COLOR_PAIR, Io::LINEONE, Io::MAIN_WINDOW_COLOR_PAIR

select related collapse

Instance Attribute Summary collapse

Attributes included from ListScrollable

#find_offset, #find_offset1, #search_found_ix, #show_caret

Attributes inherited from Widget

#_object_created, #col_offset, #cols_panned, #config, #curpos, #focussed, #form, #id, #parent_component, #row_offset, #rows_panned, #state

Instance Method Summary collapse

Methods included from NewListSelectable

#add_selection_interval, #add_to_selection, #ask_select, #clear_selection, #get_matching_indices, #goto_next_selection, #goto_prev_selection, #insert_index_interval, #invert_row_selection, #invert_selection, #is_row_selected, #list_bindings, #list_init_vars, #paint_selector, #remove_selection_interval, #select_all, #select_values, #selected_rows, #toggle_row_selection, #unselect_values

Methods included from ListScrollable

#_find_next, #_find_prev, #ask_search, #bounds_check, #find_more, #find_next, #find_prev, #focussed_index, #forward_char, #forward_word, #goto_bottom, #goto_last_position, #goto_top, #install_keys, #next_match, #next_row, #previous_row, #sanitize, #scroll_backward, #scroll_forward, #scroll_left, #scroll_right, #selected_item, #set_focus_on, #set_form_row, #set_selection_for_char, #show_caret_func

Methods inherited from Widget

#changed, #click, #destroy, #enter, #event_list, #focus, #get_preferred_size, #getvalue_for_paint, #height, #height=, #hide, #leave, #modified?, #move, #on_leave, #override_graphic, #printstring, #process_key, #remove, #repaint_all, #repaint_required, #set_buffer_modified, #set_buffering, #set_form, #set_form_row, #set_modified, #setformrowcol, #setrowcol, #show, #text_variable, #unbind_key, #width, #width=

Methods included from Io

#askchoice, #askyesno, #askyesnocancel, #clear_error, #clear_this, #get_string, #newaskyesno, #old_print_header, #old_print_top_right, #print_action, #print_error, #print_footer_help, #print_headers, #print_help, #print_help_page, #print_in_middle, #print_key_labels, #print_key_labels_row, #print_screen_labels, #print_status, #print_this, #print_top_right, #rbgetstr, #warn

Methods included from Utils

#_process_key, #bind_key, #clean_string!, #get_color, #keycode_tos, #repeatm, #view, #wrap_text

Methods included from ConfigSetup

#cget, #config_setup, #configure, #variable_set

Methods included from EventHandler

#bind, #fire_handler, #fire_property_change

Constructor Details

#initialize(form = nil, config = {}, &block) ⇒ TabularWidget

Returns a new instance of TabularWidget.



88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
# File 'lib/rbcurse/extras/tabularwidget.rb', line 88

def initialize form = nil, config={}, &block
  @focusable = true
  @editable = false
  @sanitization_required = true
  @estimate_column_widths = true
  @row = 0
  @col = 0
  @cw = {} # column widths keyed on column index - why not array ??
  @pw = [] # preferred column widths 2010-10-20 12:58 
  @calign = {} # columns aligns values, on column index
  @coffsets = {}
  @suppress_borders = false
  @row_offset = @col_offset = 1 
  @chash = {}
  # this should have index of displayed column
  # so user can reorder columns
  #@column_position = [] # TODO
  @separ = @columns = @numbering =  nil
  @y = '|'
  @x = '+'
  @list = []
  @_header_adjustment = 0
  @show_focus = false  # don't highlight row under focus TODO
  @selection_mode = :multiple # default is multiple, anything else given becomes single
  @row_selected_symbol = '*'
  @show_selector = true
  super
  # ideally this should have been 2 to take care of borders, but that would break
  # too much stuff !
  @win = @graphic

  @_events.push :CHANGE # thru vieditable
  @_events << :PRESS # new, in case we want to use this for lists and allow ENTER
  @_events << :ENTER_ROW # new, should be there in listscrollable ??
  @_events << :COLUMN_RESIZE_EVENT 
  install_keys # << almost jnuk now, clean off TODO
  init_vars
  map_keys
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(name, *args) ⇒ Object (private)



1060
1061
1062
1063
1064
1065
1066
1067
1068
# File 'lib/rbcurse/extras/tabularwidget.rb', line 1060

def method_missing(name, *args)
  name = name.to_s
  case name 
  when 'cell_editing_allowed', 'editing_policy'
    # silently ignore to keep compatible with Table
  else
    raise NoMethodError, "Undefined method #{name} for TabularWidget"
  end
end

Instance Attribute Details

#_header_adjustmentObject (readonly)

we need to adjust when using current_index !!! UGH



85
86
87
# File 'lib/rbcurse/extras/tabularwidget.rb', line 85

def _header_adjustment
  @_header_adjustment
end

#current_indexObject

Returns the value of attribute current_index.



61
62
63
# File 'lib/rbcurse/extras/tabularwidget.rb', line 61

def current_index
  @current_index
end

#numberingObject

boolean, whether lines should be numbered



71
72
73
# File 'lib/rbcurse/extras/tabularwidget.rb', line 71

def numbering
  @numbering
end

#selected_indexObject

should we use only indices ??



82
83
84
# File 'lib/rbcurse/extras/tabularwidget.rb', line 82

def selected_index
  @selected_index
end

#selected_indicesObject (readonly)

index of selected rows, if multiple selection asked for



84
85
86
# File 'lib/rbcurse/extras/tabularwidget.rb', line 84

def selected_indices
  @selected_indices
end

#table_row_sorterObject (readonly)

default or custom sorter



73
74
75
# File 'lib/rbcurse/extras/tabularwidget.rb', line 73

def table_row_sorter
  @table_row_sorter
end

#toprowObject (readonly)

the toprow in the view (offsets are 0)



56
57
58
# File 'lib/rbcurse/extras/tabularwidget.rb', line 56

def toprow
  @toprow
end

#winrowObject (readonly)

the row in the viewport/window



57
58
59
# File 'lib/rbcurse/extras/tabularwidget.rb', line 57

def winrow
  @winrow
end

Instance Method Details

#[](off0) ⇒ Object



220
221
222
# File 'lib/rbcurse/extras/tabularwidget.rb', line 220

def [](off0)
  @list[off0]
end

#[]=(off0, data) ⇒ Object



217
218
219
# File 'lib/rbcurse/extras/tabularwidget.rb', line 217

def []=(off0, data)
  @list[off0] = data
end

#_convert_curpos_to_columnFixnum

Convert current cursor position to a table column calculate column based on curpos since user may not have user w and b keys (:next_column)

Returns:

  • (Fixnum)

    column index base 0



891
892
893
894
895
896
897
898
899
900
901
902
# File 'lib/rbcurse/extras/tabularwidget.rb', line 891

def _convert_curpos_to_column  #:nodoc:
  x = 0
  @coffsets.each_pair { |e,i| 
    if @curpos < i 
      break
    else 
      x += 1
    end
  }
  x -= 1 # since we start offsets with 0, so first auto becoming 1
  return x
end

#_estimate_column_widthsObject

:nodoc:



758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
# File 'lib/rbcurse/extras/tabularwidget.rb', line 758

def _estimate_column_widths  #:nodoc:
  return unless @estimate_column_widths
  @estimate_column_widths = false # XXX testing why its failing in gmail
  @columns.each_with_index { |c, i|  
    if @pw[i]
      @cw[i] = @pw[i]
    else
      @cw[i] = calculate_column_width(i)
    end
  }
  total = 0
  @cw.each_pair { |name, val| total += val }
  @preferred_width = total + (@cw.size() *2)
  @preferred_width += 4 if @numbering # FIXME this 4 is rough
end

#_guess_col_widthsObject

perhaps we can delete this since it does not respect @pw



736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
# File 'lib/rbcurse/extras/tabularwidget.rb', line 736

def _guess_col_widths  #:nodoc:
  return if @second_time
  @second_time = true if @list.size > 0
  @list.each_with_index { |r, i| 
    break if i > 10
    next if r == :separator
    r.each_with_index { |c, j|
      x = c.to_s.length
      if @cw[j].nil?
        @cw[j] = x
      else
        @cw[j] = x if x > @cw[j]
      end
    }
  }
  #sum = @cw.values.inject(0) { |mem, var| mem + var  }
  #$log.debug " SUM is #{sum} "
  total = 0
  @cw.each_pair { |name, val| total += val }
  @preferred_width = total + (@cw.size() *2)
  @preferred_width += 4 if @numbering # FIXME this 4 is rough
end

#_prepare_formatObject

:nodoc:



789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
# File 'lib/rbcurse/extras/tabularwidget.rb', line 789

def _prepare_format  #:nodoc:
  @fmtstr = nil
  fmt = []
  total = 0
  @cw.each_with_index { |c, i| 
    next if get_column(i).hidden == true # added 2010-10-28 19:08 
    w = @cw[i]
    @coffsets[i] = total
    total += w + 2

    case @calign[i]
    when :right
      fmt << "%#{w}s "
    else
      fmt << "%-#{w}s "
    end
  }
  @fmstr = fmt.join(@y)
  if @numbering
    @rows ||= @list.size.to_s.length
    @headerfmtstr = " "*(@rows+1)+@y + @fmstr
    @fmstr = "%#{@rows}d "+ @y + @fmstr
    @coffsets.each_pair { |name, val| @coffsets[name] = val + @rows + 2 }
  end
  #$log.debug " FMT : #{@fmstr} "
  #alert "format:     #{@fmstr} "
end

#add(array) ⇒ Object Also known as: <<, add_row, append

add a row of data

Parameters:

  • an (Array)

    array containing entries for each column



200
201
202
203
204
205
# File 'lib/rbcurse/extras/tabularwidget.rb', line 200

def add array
  @list ||= []
  @list << array
  @repaint_required = true
  @recalc_required = true
end

#addcol(num) ⇒ Object

2010-01-23 22:41



529
530
531
532
533
534
535
536
537
# File 'lib/rbcurse/extras/tabularwidget.rb', line 529

def addcol num #:nodoc:
  #@repaint_required = true
  @repaint_footer_required = true # 2010-01-23 22:41 
  if @form
    @form.addcol num
  else
    @parent_component.form.addcol num
  end
end

#addrowcol(row, col) ⇒ Object

:nodoc:



538
539
540
541
542
543
544
545
546
# File 'lib/rbcurse/extras/tabularwidget.rb', line 538

def addrowcol row,col #:nodoc:
  #@repaint_required = true
  @repaint_footer_required = true # 2010-01-23 22:41 
  if @form
  @form.addrowcol row, col
  else
    @parent_component.form.addrowcol num
  end
end

#calculate_column_width(col) ⇒ Object

if user has not specified preferred_width for a column then we can calculate the same based on data



775
776
777
778
779
780
781
782
783
784
785
786
787
788
# File 'lib/rbcurse/extras/tabularwidget.rb', line 775

def calculate_column_width col
  ret = @cw[col] || 2
  ctr = 0
  @list.each_with_index { |r, i| 
    #next if i < @toprow # this is also a possibility, it checks visible rows
    break if ctr > 10
    ctr += 1
    next if r == :separator
    c = r[col]
    x = c.to_s.length
    ret = x if x > ret
  }
  ret
end

#check_curposObject

newly added to check curpos when moving up or down



473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
# File 'lib/rbcurse/extras/tabularwidget.rb', line 473

def check_curpos #:nodoc:
  # if the cursor is ahead of data in this row then move it back
  # i don't think this is required
  return
  if @pcol+@curpos > @buffer.length
    addcol((@pcol+@buffer.length-@curpos)+1)
    @curpos = @buffer.length 
    maxlen = (@maxlen || @width-@internal_width)

    # even this row is gt maxlen, i.e., scrolled right
    if @curpos > maxlen
      @pcol = @curpos - maxlen
      @curpos = maxlen-1 
    else
      # this row is within maxlen, make scroll 0
      @pcol=0
    end
    set_form_col 
  end
end

#column_align(colindex, lrc) ⇒ Object

set alignment of given column offset

Parameters:

  • column (Number)

    offset, starting 0

  • :left, (Symbol)

    :right

Raises:

  • (ArgumentError)


240
241
242
243
244
245
246
# File 'lib/rbcurse/extras/tabularwidget.rb', line 240

def column_align colindex, lrc
  raise ArgumentError, "wrong alignment value sent" if ![:right, :left, :center].include? lrc
  @calign[colindex] = lrc
  get_column(colindex).align = lrc
  @repaint_required = true
  #@recalc_required = true
end

#column_hidden(colindex, tf = true) ⇒ Object

Set a column to hidden TODO we are not actually doing that



248
249
250
251
252
253
# File 'lib/rbcurse/extras/tabularwidget.rb', line 248

def column_hidden colindex, tf=true
  #raise ArgumentError, "wrong alignment value sent" if ![:right, :left, :center].include? lrc
  get_column(colindex).hidden = tf
  @repaint_required = true
  @recalc_required = true
end

#column_width(colindex, width) ⇒ Object

TODO more methods like in listbox so interchangeable, delete_at etc

Raises:

  • (ArgumentError)


227
228
229
230
231
232
233
234
235
# File 'lib/rbcurse/extras/tabularwidget.rb', line 227

def column_width colindex, width
  return if width < 0
  raise ArgumentError, "wrong width value sent: #{width} " if width.nil? || !width.is_a?(Fixnum) || width < 0
  #@cw[colindex] = width
  @pw[colindex] = width # XXXXX
  get_column(colindex).width = width
  @repaint_required = true
  @recalc_required = true
end

#columns=(array) ⇒ Object Also known as: headings=

set column names

Parameters:

  • column (Array)

    names or headings



164
165
166
167
168
169
170
171
172
173
# File 'lib/rbcurse/extras/tabularwidget.rb', line 164

def columns=(array)
  @_header_adjustment = 1
  @columns = array
  @columns.each_with_index { |c,i| 
    @cw[i] ||= c.to_s.length
    @calign[i] ||= :left
  }
  # maintains index in current pointer and gives next or prev
  @column_pointer = Circular.new @columns.size()-1
end

#contract_columnObject



259
260
# File 'lib/rbcurse/extras/tabularwidget.rb', line 259

def contract_column
end

#convert_value_to_text(r, count) ⇒ Object

convert data object to a formatted string for print NOTE: useful for overriding and doing custom formatting

Parameters:

  • array (Array)

    of column data, mostly String Can also be :columns or :separator

  • index (Fixnum)

    of row in data



688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
# File 'lib/rbcurse/extras/tabularwidget.rb', line 688

def convert_value_to_text r, count
  if r == :separator
    return separator
  elsif r == :columns
    return "??" unless @columns # column was requested but not supplied
    # FIXME putting entire header into this, take care of hidden
    r = []
    @columns.each_with_index { |e, i| r << e unless get_column(i).hidden  }
    return @headerfmtstr % r if @numbering
  end
  str = ""

  if @numbering
    #r = r.dup
    #r.insert 0, count+1
    # TODO get the width
    str << "%*d |"%  [2, count + 1]
  end
  # unroll r, get width and align
  # This is to truncate column to requested width
  fmta = []
  r.each_with_index { |e, i| 
    next if get_column(i).hidden == true
    #w = @pw[i] || @cw[i]  # XXX
    #$log.debug "WIDTH XXX  #{i} w= #{w} , #{@pw[i]}, #{@cw[i]} :: #{e} " if $log.debug? 
    w = @cw[i]
    l = e.to_s.length
    fmt = "%-#{w}s "
    if l > w
      fmt = "%.#{w}s "
    else
      # ack we don;t need to recalc this we can pull out of hash FIXME
      case @calign[i]
      when :right
        fmt = "%#{w}s "
      else
        fmt = "%-#{w}s "
      end
    end
    str << fmt % e
    fmta << fmt
  }
  #fmstr = fmta.join(@y)
  #return fmstr % r; # FIXME hidden column still goes int 
  return str
end

#current_valueObject

returns value of current row. NOTE: you may need to adjust it with _header_adjustment - actually you can’t this may give wrong row – depends what you want.



345
346
347
# File 'lib/rbcurse/extras/tabularwidget.rb', line 345

def current_value
  @list[@current_index-@_header_adjustment] # XXX added header_adju 2010-11-01 11:14 
end

#cursor_backwardObject

:nodoc:



547
548
549
550
551
552
553
554
555
556
557
558
559
# File 'lib/rbcurse/extras/tabularwidget.rb', line 547

def cursor_backward  #:nodoc:
  repeatm { 
  if @curpos > 0
    @curpos -= 1
    set_form_col 
    #addcol -1
  elsif @pcol > 0 
    @pcol -= 1   
  end
  }
  #@repaint_required = true
  @repaint_footer_required = true # 2010-01-23 22:41 
end

#cursor_forwardObject

:nodoc:



515
516
517
518
519
520
521
522
523
524
525
526
527
528
# File 'lib/rbcurse/extras/tabularwidget.rb', line 515

def cursor_forward #:nodoc:
  maxlen = @maxlen || @width-@internal_width
  repeatm { 
  if @curpos < @width and @curpos < maxlen-1 # else it will do out of box
    @curpos += 1
    addcol 1
  else
    @pcol += 1 if @pcol <= @buffer.length
  end
  }
  set_form_col 
  #@repaint_required = true
  @repaint_footer_required = true # 2010-01-23 22:41 
end

#delete_at(off0) ⇒ Object



213
214
215
216
# File 'lib/rbcurse/extras/tabularwidget.rb', line 213

def delete_at off0
  ret=@list.delete_at off0
  return ret
end

#disp_menuObject

this is just a test of the simple “most” menu



829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
# File 'lib/rbcurse/extras/tabularwidget.rb', line 829

def disp_menu  #:nodoc:
  $error_message_row ||= 23 # FIXME
  $error_message_col ||= 1 # FIXME
  menu = PromptMenu.new self 
  menu.add( menu.create_mitem( 's', "Goto start ", "Going to start", Proc.new { goto_start} ))
  menu.add(menu.create_mitem( 'r', "scroll right", "I have scrolled ", :scroll_right ))
  menu.add(menu.create_mitem( 'l', "scroll left", "I have scrolled ", :scroll_left ))
  item = menu.create_mitem( 'm', "submenu", "submenu options" )
  menu1 = PromptMenu.new( self, "Submenu Options")
  menu1.add(menu1.create_mitem( 's', "CASE sensitive", "Ignoring Case in search" ))
  menu1.add(menu1.create_mitem( 't', "goto last position", "moved to previous position", Proc.new { goto_last_position} ))
  item.action = menu1
  menu.add(item)
  # how do i know what's available. the application or window should know where to place
  #menu.display @form.window, 23, 1, $datacolor #, menu
  menu.display @form.window, $error_message_row, $error_message_col, $datacolor #, menu
end

#expand_columnObject



257
258
# File 'lib/rbcurse/extras/tabularwidget.rb', line 257

def expand_column
end

#find_first_match(regex) ⇒ Object

returns row of first match of given regex (or nil if not found)



286
287
288
289
290
291
# File 'lib/rbcurse/extras/tabularwidget.rb', line 286

def find_first_match regex #:nodoc:
  @list.each_with_index do |row, ix|
    return ix if !row.match(regex).nil?
  end
  return nil
end

#fire_action_eventObject

on pressing ENTER we send user some info, the calling program would bind :PRESS Added a call to sort, should i still call PRESS or just do a sort in here and not call PRESS ??? – FIXME we can create this once and reuse ++



867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
# File 'lib/rbcurse/extras/tabularwidget.rb', line 867

def fire_action_event
  return unless @list
  return unless @table_row_sorter
  require 'rbcurse/ractionevent'
  # the header event must only be used if columns passed
  if header_row?
    # TODO we need to fire correct even for header row, including
    #alert "you are on header row: #{@columns[x]} curpos: #{@curpos}, x:#{x} "
    #aev = TextActionEvent.new self, :PRESS, @columns[x], x, @curpos
    x = _convert_curpos_to_column
    @table_row_sorter.toggle_sort_order x
    @table_row_sorter.sort
    @repaint_required = true
    aev = TextActionEvent.new self, :PRESS,:header, x, @curpos
  else
    # please check this again current_value due to _header_adjustment XXX test
    aev = TextActionEvent.new self, :PRESS, current_value(), @current_index, @curpos
  end
  fire_handler :PRESS, aev
end

#get_contentObject

FOR scrollable ###



323
324
325
326
327
# File 'lib/rbcurse/extras/tabularwidget.rb', line 323

def get_content
  @list
  #[:columns, :separator,  *@list]
  #[:columns, *@list]
end

#get_windowObject

:columns, :separator, *@list
:columns, *@list


328
329
330
# File 'lib/rbcurse/extras/tabularwidget.rb', line 328

def get_window #:nodoc:
  @graphic
end

#getstr(prompt, maxlen = 10) ⇒ Object

this is just a test of prompting user for a string + as an alternative to the dialog.



818
819
820
821
822
823
824
825
826
827
# File 'lib/rbcurse/extras/tabularwidget.rb', line 818

def getstr prompt, maxlen=10  #:nodoc:
  tabc = Proc.new {|str| Dir.glob(str +"*") }
  config={}; config[:tab_completion] = tabc
  config[:default] = "default"
  $log.debug " inside getstr before call "
  ret, str = rbgetstr(@form.window, @row+@height-1, @col+1, prompt, maxlen, config)
  $log.debug " rbgetstr returned #{ret} , #{str} "
  return "" if ret != 0
  return str
end

#getvalueObject



339
340
341
# File 'lib/rbcurse/extras/tabularwidget.rb', line 339

def getvalue
  @list
end

#handle_key(ch) ⇒ Object

Tabularwidget



352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
# File 'lib/rbcurse/extras/tabularwidget.rb', line 352

def handle_key ch #:nodoc:
  if header_row?
    ret = header_handle_key ch
    return ret unless ret == :UNHANDLED
  end
  case ch
  when ?\C-d.getbyte(0) #, 32
    scroll_forward
  when ?\C-b.getbyte(0)
    scroll_backward
  when ?\C-[.getbyte(0), ?t.getbyte(0)
    goto_start #start of buffer # cursor_start
  when ?\C-].getbyte(0), ?G.getbyte(0)
    goto_end # end / bottom cursor_end
  when KEY_UP, ?k.getbyte(0)
    #select_prev_row
    ret = up
    get_window.ungetch(KEY_BTAB) if ret == :NO_PREVIOUS_ROW
    check_curpos
    
  when KEY_DOWN, ?j.getbyte(0)
    ret = down
    get_window.ungetch(KEY_TAB) if ret == :NO_NEXT_ROW
    check_curpos
  when KEY_LEFT, ?h.getbyte(0)
    cursor_backward
  when KEY_RIGHT, ?l.getbyte(0)
    cursor_forward
  when KEY_BACKSPACE, KEY_BSPACE, KEY_DELETE
    cursor_backward
  when ?\C-a.getbyte(0) #, ?0.getbyte(0)
    # take care of data that exceeds maxlen by scrolling and placing cursor at start
    @repaint_required = true if @pcol > 0 # tried other things but did not work
    set_form_col 0
    @pcol = 0
  when ?\C-e.getbyte(0), ?$.getbyte(0)
    # take care of data that exceeds maxlen by scrolling and placing cursor at end
    # This use to actually pan the screen to actual end of line, but now somewhere
    # it only goes to end of visible screen, set_form probably does a sanity check
    blen = @buffer.rstrip.length
    set_form_col blen
    # search related 
  when @KEY_ASK_FIND  # FIXME
    ask_search
  when @KEY_FIND_MORE  # FIXME
    find_more
  when 10, 13, KEY_ENTER
    #fire_handler :PRESS, self
    fire_action_event
  when ?0.getbyte(0)..?9.getbyte(0)
    # FIXME the assumption here was that if numbers are being entered then a 0 is a number
    # not a beg-of-line command.
    # However, after introducing universal_argument, we can enters numbers using C-u and then press another
    # C-u to stop. In that case a 0 should act as a command, even though multiplier has been set
    if ch == ?0.getbyte(0) and $multiplier == 0
      # copy of C-a - start of line
      @repaint_required = true if @pcol > 0 # tried other things but did not work
      set_form_col 0
      @pcol = 0
      return 0
    end
    # storing digits entered so we can multiply motion actions
    $multiplier *= 10 ; $multiplier += (ch-48)
    return 0
  #when ?\C-u.getbyte(0)
    ## multiplier. Series is 4 16 64
    #@multiplier = (@multiplier == 0 ? 4 : @multiplier *= 4)
    #return 0
  when ?\M-l.getbyte(0) # just added 2010-03-05 not perfect
    scroll_right # scroll data horizontally 
  when ?\M-h.getbyte(0)
    scroll_left
  when ?\C-c.getbyte(0)
    $multiplier = 0
    return 0
  else
    # check for bindings, these cannot override above keys since placed at end
    begin
      ret = process_key ch, self
    rescue => err
      $error_message.value = err.to_s
#          @form.window.print_error_message # changed 2011 dts  
      alert err.to_s
      $log.error " Tabularwidget ERROR #{err} "
      $log.debug(err.backtrace.join("\n"))
      # XXX caller app has no idea error occurred so can't do anything !
    end
    return :UNHANDLED if ret == :UNHANDLED
  end
  $multiplier = 0 # you must reset if you've handled a key. if unhandled, don't reset since parent could use
  set_form_row
  return 0 # added 2010-01-12 22:17 else down arrow was going into next field
end

#header_handle_key(ch) ⇒ Object

allow header to handle keys NOTE: header could become an object in near future We are calling a resize event and passing column index but do we really have a column object that user can access and do something with ?? XXX



451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
# File 'lib/rbcurse/extras/tabularwidget.rb', line 451

def header_handle_key ch   #:nodoc:
  # TODO pressing = should revert to calculated size ?
  col = _convert_curpos_to_column
  #width = @cw[col] 
  width = @pw[col] || @cw[col] 
  case ch
  when ?-.getbyte(0)
    column_width col, width-1
    # if this event has not been used in a sample it could change in near future
    e = ColumnResizeEvent.new self, col,  :DECREASE
    fire_handler :COLUMN_RESIZE_EVENT, e
    # can fire_hander so user can resize another column
    return 0
  when ?\+.getbyte(0)
    column_width col, width+1
    # if this event has not been used in a sample it could change in near future
    e = ColumnResizeEvent.new self, col,  :INCREASE
    return 0
  end
  return :UNHANDLED
end

#header_row?Boolean

returns true if cursor is on header row

Returns:

  • (Boolean)


856
857
858
859
# File 'lib/rbcurse/extras/tabularwidget.rb', line 856

def header_row?
  return false if @columns.nil?
  1 == @row + (@current_index-@toprow)
end

#init_varsObject

:nodoc:



127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
# File 'lib/rbcurse/extras/tabularwidget.rb', line 127

def init_vars #:nodoc:
  @curpos = @pcol = @toprow = @current_index = 0
  @repaint_all=true 
  @repaint_required=true 

  @row_offset = @col_offset = 0 if @suppress_borders == true
  @internal_width = 2
  @internal_width = 0 if @suppress_borders
  # added 2010-02-11 15:11 RFED16 so we don't need a form.
  @win_left = 0
  @win_top = 0
  @current_column = 0
  # currently i scroll right only if  current line is longer than display width, i should use 
  # longest line on screen.
  @longest_line = 0 # the longest line printed on this page, used to determine if scrolling shd work
  list_init_vars

end

#insert(off0, *data) ⇒ Object



223
224
225
# File 'lib/rbcurse/extras/tabularwidget.rb', line 223

def insert off0, *data
  @list.insert off0, *data
end

#load_module(requirename, includename) ⇒ Object

dynamically load a module and execute init method. Hopefully, we can get behavior like this such as vieditable or multibuffers



849
850
851
852
853
# File 'lib/rbcurse/extras/tabularwidget.rb', line 849

def load_module requirename, includename
  require "rbcurse/#{requirename}"
  extend Object.const_get("#{includename}")
  send("#{requirename}_init") #if respond_to? "#{includename}_init"
end

#map_keysObject



145
146
147
148
149
150
151
152
153
154
155
156
157
158
# File 'lib/rbcurse/extras/tabularwidget.rb', line 145

def map_keys
  # remove bindings from here. we call repeatedly
  bind_key([?g,?g]){ goto_start } # mapping double keys like vim
  bind_key([?',?']){ goto_last_position } # vim , goto last row position (not column)
  bind_key(?/, :ask_search) # XXX TESTME
  bind_key(?n, :find_more) # XXX TESTME
  bind_key([?\C-x, ?>], :scroll_right)
  bind_key([?\C-x, ?<], :scroll_left)
  #bind_key(?r) { getstr("Enter a word: ") }
  bind_key(?m, :disp_menu) # enhance this or cut it out - how can app leverage this. TODO
  bind_key(?w, :next_column)
  bind_key(?b, :previous_column)
  list_bindings
end

#move_columnObject



254
255
256
# File 'lib/rbcurse/extras/tabularwidget.rb', line 254

def move_column

end

#next_columnObject

move cursor to next column FIXME need to account for hidden columns and numbering



915
916
917
918
919
920
921
922
923
# File 'lib/rbcurse/extras/tabularwidget.rb', line 915

def next_column
  c = @column_pointer.next
  cp = @coffsets[c] 
  #$log.debug " next_column #{c} , #{cp} "
  @curpos = cp if cp
  next_row() if c < @column_pointer.last_index
  #addcol cp
  set_form_col 
end

#on_enterObject



903
904
905
906
907
# File 'lib/rbcurse/extras/tabularwidget.rb', line 903

def on_enter
  # so cursor positioned on correct row
  set_form_row
  super
end

#on_enter_row(arow) ⇒ Object

called by listscrollable, used by scrollbar ENTER_ROW



909
910
911
912
# File 'lib/rbcurse/extras/tabularwidget.rb', line 909

def on_enter_row arow
  fire_handler :ENTER_ROW, self
  @repaint_required = true
end

#paintObject

NOTE: earlier print_border was called only once in constructor, but when + a window is resized, and destroyed, then this was never called again, so the + border would not be seen in splitpane unless the width coincided exactly with + what is calculated in divider_location.



565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
# File 'lib/rbcurse/extras/tabularwidget.rb', line 565

def paint  #:nodoc:
  my_win = nil
  if @form
    my_win = @form.window
  else
    my_win = @target_window
  end
  @graphic = my_win unless @graphic
  @win_left = my_win.left
  @win_top = my_win.top
  tm = get_content
  rc = tm.length
  _estimate_column_widths if rc > 0  # will set preferred_width 2011-10-4 
  @left_margin ||= @row_selected_symbol.length
  @width ||= @preferred_width

  @height ||= [tm.length+3, 10].min
  _prepare_format

  print_borders if (@suppress_borders == false && @repaint_all) # do this once only, unless everything changes
  _maxlen = @maxlen || @width-@internal_width
  $log.debug " #{@name} Tabularwidget repaint width is #{@width}, height is #{@height} , maxlen #{maxlen}/ #{@maxlen}, #{@graphic.name} roff #{@row_offset} coff #{@col_offset}" 
  tr = @toprow
  acolor = get_color $datacolor
  h = scrollatrow() 
  r,c = rowcol
  print_header
  r += @_header_adjustment # for column header
  @longest_line = @width #maxlen
  0.upto(h - @_header_adjustment) do |hh|
    crow = tr+hh
    if crow < rc
        #focussed = @current_index == crow ? true : false 
        content = tm[crow]

        columnrow = false
        if content == :columns
          columnrow = true
        end

        value = convert_value_to_text content, crow

        @buffer = value if crow == @current_index
        # next call modified string. you may wanna dup the string.
        # rlistbox does
        sanitize value if @sanitization_required
        truncate value
        ## set the selector symbol if requested
        paint_selector crow, r+hh, c, acolor, @attr

        #@graphic.printstring  r+hh, c, "%-*s" % [@width-@internal_width,value], acolor, @attr
        #print_data_row( r+hh, c, "%-*s" % [@width-@internal_width,value], acolor, @attr)
        print_data_row( r+hh, c+@left_margin, @width-@internal_width-@left_margin, value, acolor, @attr)

    else
      # clear rows
      @graphic.printstring r+hh, c, " " * (@width-@internal_width-@left_margin), acolor,@attr
    end
  end
  @repaint_required        = false
  @repaint_footer_required = true
  @repaint_all             = false

end

#previous_columnObject



924
925
926
927
928
929
930
931
932
# File 'lib/rbcurse/extras/tabularwidget.rb', line 924

def previous_column
  c = @column_pointer.previous
  cp = @coffsets[c] 
  #$log.debug " prev_column #{c} , #{cp} "
  @curpos = cp if cp
  previous_row() if c > @column_pointer.last_index
  #addcol cp FIXME
  set_form_col 
end

print a border Note that print_border clears the area too, so should be used sparingly.



299
300
301
302
303
304
305
306
307
308
309
# File 'lib/rbcurse/extras/tabularwidget.rb', line 299

def print_borders #:nodoc:
  raise "#{self.class} needs width" unless @width
  raise "#{self.class} needs height" unless @height

  $log.debug " #{@name} print_borders,  #{@graphic.name} "
  
  bordercolor = @border_color || $datacolor
  borderatt = @border_attrib || Ncurses::A_NORMAL
  @graphic.print_border @row, @col, @height-1, @width, bordercolor, borderatt
  print_title
end

print data rows



631
632
633
# File 'lib/rbcurse/extras/tabularwidget.rb', line 631

def print_data_row r, c, len, value, color, attr
  @graphic.printstring  r, c, "%-*s" % [len,value], color, attr
end

:nodoc:



315
316
317
318
319
320
321
# File 'lib/rbcurse/extras/tabularwidget.rb', line 315

def print_foot #:nodoc:
  @footer_attrib ||= Ncurses::A_REVERSE
  footer = "R: #{@current_index+1}, C: #{@curpos+@pcol}, #{@list.length} lines  "
  #$log.debug " print_foot calling printstring with #{@row} + #{@height} -1, #{@col}+2"
  @graphic.printstring( @row + @height -1 , @col+2, footer, $datacolor, @footer_attrib) 
  @repaint_footer_required = false # 2010-01-23 22:55 
end

prints the column headers Uses convert_value_to_text and print_header_row



674
675
676
677
678
679
680
681
682
# File 'lib/rbcurse/extras/tabularwidget.rb', line 674

def print_header
  r,c = rowcol
  value = convert_value_to_text :columns, 0
  len = @width - @internal_width
  truncate value # else it can later suddenly exceed line
  @header_color_pair ||= get_color $promptcolor, @header_fgcolor, @header_bgcolor
  @header_attrib ||= @attr
  print_header_row r, c, len, value, @header_color_pair, @header_attrib
end

print header row

allows user to override


658
659
660
661
# File 'lib/rbcurse/extras/tabularwidget.rb', line 658

def print_header_row r, c, len, value, color, attr
  #acolor = $promptcolor
  @graphic.printstring  r, c+@left_margin, "%-*s" % [len-@left_margin ,value], color, attr
end

:nodoc:



310
311
312
313
314
# File 'lib/rbcurse/extras/tabularwidget.rb', line 310

def print_title #:nodoc:
  raise "#{self.class} needs width" unless @width
  $log.debug " print_title #{@row}, #{@col}, #{@width}  "
  @graphic.printstring( @row, @col+(@width-@title.length)/2, @title, $datacolor, @title_attrib) unless @title.nil?
end

#real_indexObject



348
349
350
# File 'lib/rbcurse/extras/tabularwidget.rb', line 348

def real_index
  @current_index-@_header_adjustment # XXX added header_adju 2010-11-06 19:38 
end

#remove_allObject



209
210
211
212
# File 'lib/rbcurse/extras/tabularwidget.rb', line 209

def remove_all
  @list = []
  init_vars
end

#repaintObject

Tabularwidget :nodoc:



332
333
334
335
336
337
338
# File 'lib/rbcurse/extras/tabularwidget.rb', line 332

def repaint # Tabularwidget :nodoc:

  #return unless @repaint_required # 2010-02-12 19:08  TRYING - won't let footer print for col move
  paint if @repaint_required
  #  raise "TV 175 graphic nil " unless @graphic
  print_foot if @print_footer && @repaint_footer_required
end

#row_countObject



280
281
282
283
# File 'lib/rbcurse/extras/tabularwidget.rb', line 280

def row_count
  #@list.length
  get_content().length + @_header_adjustment
end

#rowcolObject

returns the position where cursor was to be positioned by default It may no longer work like that.



294
295
296
# File 'lib/rbcurse/extras/tabularwidget.rb', line 294

def rowcol #:nodoc:
  return @row+@row_offset, @col+@col_offset
end

#scrollatrowObject

—- for listscrollable —- ##



272
273
274
275
276
277
278
279
# File 'lib/rbcurse/extras/tabularwidget.rb', line 272

def scrollatrow #:nodoc:
  # TODO account for headers
  if @suppress_borders
    @height - @_header_adjustment 
  else
    @height - (2 + @_header_adjustment) 
  end
end

#separatorObject



662
663
664
665
666
667
668
669
670
671
# File 'lib/rbcurse/extras/tabularwidget.rb', line 662

def separator
  #return @separ if @separ
  str = ""
  if @numbering
    rows = @list.size.to_s.length
    str = "-"*(rows+1)+@x
  end
  @cw.each_pair { |k,v| str << "-" * (v+1) + @x }
  @separ = str.chop
end

#set_content(list) ⇒ Object

send in a list of data

Parameters:

  • data (Array / Tabular)

    to be displayed



179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
# File 'lib/rbcurse/extras/tabularwidget.rb', line 179

def set_content list
  if list.is_a? RubyCurses::Tabular
    @list = list
  elsif list.is_a? Array
    @list = list
  else
    raise "set_content expects Array not #{list.class}"
  end
  if @table_row_sorter
    @table_row_sorter.model=@list
  else
    @table_row_sorter = TableRowSorter.new @list
  end
  @current_index = @_header_adjustment
  @toprow = 0
  @second_time = false # so that reestimation of column_widths
  @repaint_required = true
  @recalc_required = true
end

#set_form_col(col1 = @curpos) ⇒ Object

set cursor on correct column tview



494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
# File 'lib/rbcurse/extras/tabularwidget.rb', line 494

def set_form_col col1=@curpos #:nodoc:
  @cols_panned ||= 0
  @pad_offset ||= 0 # added 2010-02-11 21:54 since padded widgets get an offset.
  @curpos = col1
  maxlen = @maxlen || @width-@internal_width
  #@curpos = maxlen if @curpos > maxlen
  if @curpos > maxlen
    @pcol = @curpos - maxlen
    @curpos = maxlen - 1
    @repaint_required = true # this is required so C-e can pan screen
  else
    @pcol = 0
  end
  # the rest only determines cursor placement
  win_col = 0 # 2010-02-07 23:19 new cursor stuff
  col2 = win_col + @col + @col_offset + @curpos + @cols_panned + @pad_offset
  #$log.debug "TV SFC #{@name} setting c to #{col2} #{win_col} #{@col} #{@col_offset} #{@curpos} "
  #@form.setrowcol @form.row, col
  setrowcol nil, col2
  @repaint_footer_required = true
end

#top_row(*val) ⇒ Object

display this row number on top programmataically indicate a row to be top row



263
264
265
266
267
268
269
270
# File 'lib/rbcurse/extras/tabularwidget.rb', line 263

def top_row(*val) 
  if val.empty?
    @toprow
  else
    @toprow = val[0] || 0
  end
  @repaint_required = true
end

#truncate(content) ⇒ Object

Truncates data to fit into display area.

Copied from listscrollable since we need to take care of left_margin
2011-10-6 This may need to be reflected in listbox and others FIXME


638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
# File 'lib/rbcurse/extras/tabularwidget.rb', line 638

def truncate content  #:nodoc:
  #maxlen = @maxlen || @width-2
  _maxlen = @maxlen || @width-@internal_width
  _maxlen = @width-@internal_width if _maxlen > @width-@internal_width
  _maxlen -= @left_margin
  if !content.nil? 
    if content.length > _maxlen # only show maxlen
      @longest_line = content.length if content.length > @longest_line
      #content = content[@pcol..@pcol+_maxlen-1] 
      content.replace content[@pcol..@pcol+_maxlen-1] 
    else
      # can this be avoided if pcol is 0 XXX
      content.replace content[@pcol..-1] if @pcol > 0
    end
  end
  content
end