Class: RubyCurses::TabularWidget

Inherits:
Widget show all
Includes:
ListScrollable, NewListSelectable
Defined in:
lib/rbcurse/core/widgets/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

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, #key_label, #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

#_convert_index_to_printable_row, #_convert_index_to_visible_row, #_find_next, #_find_prev, #ask_search, #backward_word, #bounds_check, #find_more, #find_next, #find_prev, #focussed_index, #forward_char, #forward_word, #goto_bottom, #goto_last_position, #goto_top, #highlight_focussed_row, #install_keys, #is_visible?, #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

#action_manager, #changed, #click, #color_pair, #command, #destroy, #enter, #event_list, #focus, #get_preferred_size, #getvalue_for_paint, #height, #height=, #hide, #leave, #modified?, #move, #on_leave, #override_graphic, #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

#__create_footer_window, #clear_this, #get_file, #print_this, #rb_getchar, #rb_gets, #rbgetstr, #warn

Methods included from Utils

#OLDdefine_key, #_process_key, #bind_key, #bind_keys, #clean_string!, #define_key, #define_prefix_command, #display_app_help, #get_attrib, #get_color, #keycode_tos, #last_line, #one_line_window, #parse_formatted_text, #print_key_bindings, #repeatm, #run_command, #shell_out, #shell_output, #suspend, #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.



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
127
128
129
130
# File 'lib/rbcurse/core/widgets/tabularwidget.rb', line 91

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
  bordertitle_init
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

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



1085
1086
1087
1088
1089
1090
1091
1092
1093
# File 'lib/rbcurse/core/widgets/tabularwidget.rb', line 1085

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



87
88
89
# File 'lib/rbcurse/core/widgets/tabularwidget.rb', line 87

def _header_adjustment
  @_header_adjustment
end

#columnsObject

Returns the value of attribute columns.



89
90
91
# File 'lib/rbcurse/core/widgets/tabularwidget.rb', line 89

def columns
  @columns
end

#current_indexObject

dsl_accessor :suppress_borders



63
64
65
# File 'lib/rbcurse/core/widgets/tabularwidget.rb', line 63

def current_index
  @current_index
end

#numberingObject

boolean, whether lines should be numbered



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

def numbering
  @numbering
end

#selected_indexObject

should we use only indices ??



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

def selected_index
  @selected_index
end

#selected_indicesObject (readonly)

index of selected rows, if multiple selection asked for



86
87
88
# File 'lib/rbcurse/core/widgets/tabularwidget.rb', line 86

def selected_indices
  @selected_indices
end

#table_row_sorterObject (readonly)

default or custom sorter



75
76
77
# File 'lib/rbcurse/core/widgets/tabularwidget.rb', line 75

def table_row_sorter
  @table_row_sorter
end

#toprowObject (readonly)

the toprow in the view (offsets are 0)



58
59
60
# File 'lib/rbcurse/core/widgets/tabularwidget.rb', line 58

def toprow
  @toprow
end

Instance Method Details

#[](off0) ⇒ Object



231
232
233
# File 'lib/rbcurse/core/widgets/tabularwidget.rb', line 231

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

#[]=(off0, data) ⇒ Object



227
228
229
230
# File 'lib/rbcurse/core/widgets/tabularwidget.rb', line 227

def []=(off0, data)
  @repaint_required = true
  @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



912
913
914
915
916
917
918
919
920
921
922
923
# File 'lib/rbcurse/core/widgets/tabularwidget.rb', line 912

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:



806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
# File 'lib/rbcurse/core/widgets/tabularwidget.rb', line 806

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



784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
# File 'lib/rbcurse/core/widgets/tabularwidget.rb', line 784

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:



837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
# File 'lib/rbcurse/core/widgets/tabularwidget.rb', line 837

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

NOTE: this is not creating a table sorter

Parameters:

  • an (Array)

    array containing entries for each column



205
206
207
208
209
210
# File 'lib/rbcurse/core/widgets/tabularwidget.rb', line 205

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

#addcol(num) ⇒ Object

2010-01-23 22:41



575
576
577
578
579
580
581
582
583
# File 'lib/rbcurse/core/widgets/tabularwidget.rb', line 575

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:



584
585
586
587
588
589
590
591
592
# File 'lib/rbcurse/core/widgets/tabularwidget.rb', line 584

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



823
824
825
826
827
828
829
830
831
832
833
834
835
836
# File 'lib/rbcurse/core/widgets/tabularwidget.rb', line 823

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



519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
# File 'lib/rbcurse/core/widgets/tabularwidget.rb', line 519

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)


297
298
299
300
301
302
303
# File 'lib/rbcurse/core/widgets/tabularwidget.rb', line 297

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



305
306
307
308
309
310
# File 'lib/rbcurse/core/widgets/tabularwidget.rb', line 305

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)


284
285
286
287
288
289
290
291
292
# File 'lib/rbcurse/core/widgets/tabularwidget.rb', line 284

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 # uncommented 2011-12-1 for expand on +
  @pw[colindex] = width # XXXXX
  get_column(colindex).width = width
  @repaint_required = true
  @recalc_required = true
end

#contract_columnObject



320
321
322
323
324
# File 'lib/rbcurse/core/widgets/tabularwidget.rb', line 320

def contract_column
  x = _convert_curpos_to_column
  w = get_column(x).width || @cw[x]
  column_width x, w-1 if w
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



735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
# File 'lib/rbcurse/core/widgets/tabularwidget.rb', line 735

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 value is longer than width, then truncate it
    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

#create_default_sorterObject



214
215
216
217
# File 'lib/rbcurse/core/widgets/tabularwidget.rb', line 214

def create_default_sorter
  raise "Data not sent in." unless @list
  @table_row_sorter = TableRowSorter.new @list
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.



423
424
425
# File 'lib/rbcurse/core/widgets/tabularwidget.rb', line 423

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

#cursor_backwardObject

:nodoc:



593
594
595
596
597
598
599
600
601
602
603
604
605
# File 'lib/rbcurse/core/widgets/tabularwidget.rb', line 593

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:



561
562
563
564
565
566
567
568
569
570
571
572
573
574
# File 'lib/rbcurse/core/widgets/tabularwidget.rb', line 561

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

#data=(data) ⇒ Object



198
199
200
# File 'lib/rbcurse/core/widgets/tabularwidget.rb', line 198

def data=(data)
  set_content(data, nil)
end

#delete_at(off0) ⇒ Object



222
223
224
225
226
# File 'lib/rbcurse/core/widgets/tabularwidget.rb', line 222

def delete_at off0
  @repaint_required = true
  @delete_buffer=@list.delete_at off0
  return @delete_buffer
end

#delete_line(line = real_index()) ⇒ Object

delete current line or lines Should be using listeditable except for _header_adjustment NOTE: user has to map this to some key such as ‘dd’

tw.bind_key([?\d,?\d]) { tw.delete_line }


244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
# File 'lib/rbcurse/core/widgets/tabularwidget.rb', line 244

def delete_line line=real_index()
  #return -1 unless @editable
  if !$multiplier || $multiplier == 0 
    @delete_buffer = @list.delete_at line
  else
    @delete_buffer = @list.slice!(line, $multiplier)
  end
  @curpos ||= 0 # rlist has no such var
  $multiplier = 0
  #add_to_kill_ring @delete_buffer
  @buffer = @list[@current_index]
  if @buffer.nil?
    up
    setrowcol @row + 1, nil # @form.col
  end
  # warning: delete buffer can now be an array
  #fire_handler :CHANGE, InputDataEvent.new(@curpos,@curpos+@delete_buffer.length, self, :DELETE_LINE, line, @delete_buffer)     #  2008-12-24 18:34 
  set_modified 
  #@widget_scrolled = true
  @repaint_required = true
end

#expand_columnObject



314
315
316
317
318
319
# File 'lib/rbcurse/core/widgets/tabularwidget.rb', line 314

def expand_column
  x = _convert_curpos_to_column
  w = get_column(x).width || @cw[x]
  # sadly it seems to be nil
  column_width x, w+1 if w
end

#find_first_match(regex) ⇒ Object

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



350
351
352
353
354
355
# File 'lib/rbcurse/core/widgets/tabularwidget.rb', line 350

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 ++



888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
# File 'lib/rbcurse/core/widgets/tabularwidget.rb', line 888

def fire_action_event
  return unless @list
  return unless @table_row_sorter
  require 'rbcurse/core/include/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 ###



401
402
403
404
405
# File 'lib/rbcurse/core/widgets/tabularwidget.rb', line 401

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

#get_windowObject

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


406
407
408
# File 'lib/rbcurse/core/widgets/tabularwidget.rb', line 406

def get_window #:nodoc:
  @graphic
end

#getvalueObject



417
418
419
# File 'lib/rbcurse/core/widgets/tabularwidget.rb', line 417

def getvalue
  @list
end

#handle_key(ch) ⇒ Object

Tabularwidget



430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
# File 'lib/rbcurse/core/widgets/tabularwidget.rb', line 430

def handle_key ch #:nodoc:
  if header_row?
    ret = header_handle_key ch
    return ret unless ret == :UNHANDLED
  end
  case ch
  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_ENTER, FFI::NCurses::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-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  
      $log.error " Tabularwidget ERROR #{err} "
      $log.debug(err.backtrace.join("\n"))
      textdialog ["Error in TabularWidget: #{err} ", *err.backtrace], :title => "Exception"
      # 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
  $status_message.value =  "F10 quit, F1 Help, : menu, toprow #{@toprow} current #{@current_index} " if $log.debug?
  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



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

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] 
  #alert "got width #{width}, #{@cw[col]} "
  # NOTE: we are setting pw and chash but paint picks from cw
  # TODO check for multiplier too
  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 NOTE: I have no idea why row was used here. it is not working

Returns:

  • (Boolean)


876
877
878
879
880
# File 'lib/rbcurse/core/widgets/tabularwidget.rb', line 876

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

#init_varsObject

:nodoc:



131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
# File 'lib/rbcurse/core/widgets/tabularwidget.rb', line 131

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.
  @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



234
235
236
237
# File 'lib/rbcurse/core/widgets/tabularwidget.rb', line 234

def insert off0, *data
  @repaint_required = true
  @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 TODO CUT THIS OUT AND FIX IT, there are simpler ways like extend()



868
869
870
871
872
# File 'lib/rbcurse/core/widgets/tabularwidget.rb', line 868

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

#map_keysObject



147
148
149
150
151
152
153
154
# File 'lib/rbcurse/core/widgets/tabularwidget.rb', line 147

def map_keys
  require 'rbcurse/core/include/listbindings'
  bindings()
  bind_key(?w, :next_column)
  bind_key(?b, :previous_column)
  bind_key(?>, :expand_column) # just trying out
  list_bindings # selection bindings
end

#move_columnObject



311
312
313
# File 'lib/rbcurse/core/widgets/tabularwidget.rb', line 311

def move_column

end

#next_columnObject

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



936
937
938
939
940
941
942
943
944
# File 'lib/rbcurse/core/widgets/tabularwidget.rb', line 936

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

#OLDprint_bordersObject

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



363
364
365
366
367
368
369
370
371
372
373
# File 'lib/rbcurse/core/widgets/tabularwidget.rb', line 363

def OLDprint_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

#OLDprint_titleObject

:nodoc:



374
375
376
377
378
# File 'lib/rbcurse/core/widgets/tabularwidget.rb', line 374

def OLDprint_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

#on_enterObject



924
925
926
927
928
# File 'lib/rbcurse/core/widgets/tabularwidget.rb', line 924

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



930
931
932
933
# File 'lib/rbcurse/core/widgets/tabularwidget.rb', line 930

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.



611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
# File 'lib/rbcurse/core/widgets/tabularwidget.rb', line 611

def paint  #:nodoc:
  my_win = nil
  if @form
    my_win = @form.window
  else
    my_win = @target_window
  end
  @graphic = my_win unless @graphic
  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
  tr = @toprow
  acolor = get_color $datacolor
  h = scrollatrow() 
  r,c = rowcol
  print_header
  r += @_header_adjustment # for column header
  @longest_line = @width #maxlen
  $log.debug " #{@name} Tabularwidget repaint width is #{@width}, height is #{@height} , maxlen #{maxlen}/ #{@maxlen}, #{@graphic.name} roff #{@row_offset} coff #{@col_offset}, r #{r} top #{toprow} ci #{current_index} "
  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



945
946
947
948
949
950
951
952
953
# File 'lib/rbcurse/core/widgets/tabularwidget.rb', line 945

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 data rows



675
676
677
# File 'lib/rbcurse/core/widgets/tabularwidget.rb', line 675

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

:nodoc:



379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
# File 'lib/rbcurse/core/widgets/tabularwidget.rb', line 379

def print_foot #:nodoc:
  @footer_attrib ||= Ncurses::A_DIM
  gb = get_color($datacolor, 'green','black')
  if @current_index == @toprow
    footer = "%15s" % " [ header row ]"
  else
    footer = "%15s" % " [#{@current_index}/ #{@list.length} ]"
  end
  pos = @col + 2
  right = true
  if right
    pos = @col + @width - footer.length - 1
  end
  @graphic.printstring( @row + @height -1 , pos, footer, gb, @footer_attrib) 
  @repaint_footer_required = false # 2010-01-23 22:55 
  #@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



721
722
723
724
725
726
727
728
729
# File 'lib/rbcurse/core/widgets/tabularwidget.rb', line 721

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


705
706
707
708
# File 'lib/rbcurse/core/widgets/tabularwidget.rb', line 705

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

#real_indexObject



426
427
428
# File 'lib/rbcurse/core/widgets/tabularwidget.rb', line 426

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

#remove_allObject



218
219
220
221
# File 'lib/rbcurse/core/widgets/tabularwidget.rb', line 218

def remove_all
  @list = []
  init_vars
end

#repaintObject

Tabularwidget :nodoc:



410
411
412
413
414
415
416
# File 'lib/rbcurse/core/widgets/tabularwidget.rb', line 410

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



344
345
346
347
# File 'lib/rbcurse/core/widgets/tabularwidget.rb', line 344

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.



358
359
360
# File 'lib/rbcurse/core/widgets/tabularwidget.rb', line 358

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

#scrollatrowObject

—- for listscrollable —- ##



336
337
338
339
340
341
342
343
# File 'lib/rbcurse/core/widgets/tabularwidget.rb', line 336

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

#separatorObject



709
710
711
712
713
714
715
716
717
718
# File 'lib/rbcurse/core/widgets/tabularwidget.rb', line 709

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, columns = nil) ⇒ Object

send in a list of data sorting will only happen if data passed using set_content NOTE: why doesn’t set_content take in columns

Parameters:

  • data (Array / Tabular)

    to be displayed



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

def set_content list, columns=nil
  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
  # adding columns setting here 2011-10-16 
  self.columns = columns if columns
  @current_index = @_header_adjustment # but this is set when columns passed
  @toprow = 0
  @second_time = false # so that reestimation of column_widths
  @repaint_required = true
  @recalc_required = true # is this used, if not remove TODO
  self
end

#set_form_col(col1 = @curpos) ⇒ Object

set cursor on correct column tview



540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
# File 'lib/rbcurse/core/widgets/tabularwidget.rb', line 540

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



327
328
329
330
331
332
333
334
# File 'lib/rbcurse/core/widgets/tabularwidget.rb', line 327

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


682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
# File 'lib/rbcurse/core/widgets/tabularwidget.rb', line 682

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? 
    cl = content.length
    if cl > _maxlen # only show maxlen
      @longest_line = cl if cl > @longest_line
      ## taking care of when scrolling is needed but longest_line is misreported
      # So we scroll always and need to check 2013-03-06 - 00:09 
      #content.replace content[@pcol..@pcol+_maxlen-1] 
      content.replace(content[@pcol..@pcol+maxlen-1] || " ")
    else
      #content.replace content[@pcol..-1] if @pcol > 0
      content.replace(content[@pcol..-1]||" ") if @pcol > 0 
    end
  end
  content
end

#undo_deleteObject

undo deleted row/rows, this is a simple undo, unlike undo_managers more complete undo. I am not calling this undo, so there’s no conflict with undomanager if used. NOTE: user has to map this to some key such as ‘u’

tw.bind_key(?\U) { tw.undo }


272
273
274
275
276
277
278
279
280
281
# File 'lib/rbcurse/core/widgets/tabularwidget.rb', line 272

def undo_delete
  return unless @delete_buffer
  if @delete_buffer[0].is_a? Array
    # multiple rows deleted
    insert real_index(), *@delete_buffer
  else
    # one row deleted
    insert real_index(), @delete_buffer
  end
end