Class: RubyCurses::TableWidget
- Inherits:
-
TextPad
- Object
- TextPad
- RubyCurses::TableWidget
- Defined in:
- lib/rbcurse/experimental/widgets/tablewidget.rb
Overview
If we make a pad of the whole thing then the columns will also go out when scrolling So then there’s no point storing columns separately. Might as well keep in content so scrolling works fine, otherwise textpad will have issues scrolling. Making a pad of the content but not column header complicates stuff, do we make a pad of that, or print it like the old thing.
Instance Attribute Summary collapse
-
#table_row_sorter ⇒ Object
attr_reader :columns.
Instance Method Summary collapse
-
#_calculate_column_offsets ⇒ Object
This calculates and stores the offset at which each column starts.
-
#_convert_curpos_to_column ⇒ Fixnum
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).
-
#_init_model(array) ⇒ Object
size each column based on widths of this row of data.
- #_invalidate_width_cache ⇒ Object
-
#add(array) ⇒ Object
(also: #<<)
add a row to the table.
-
#add_column(tc) ⇒ Object
tmce = TableColumnModelEvent.new(ix, newix, self, :MOVE) fire_handler :TABLE_COLUMN_MODEL_EVENT, tmce.
- #calculate_column_width(col, maxrows = 99) ⇒ Object
-
#clear_matches ⇒ Object
return @indices.
-
#column_align(colindex, align) ⇒ Object
convenience method to set alignment of a column.
-
#column_hidden(colindex, hidden) ⇒ Object
convenience method to hide or unhide a column Provided since column offsets need to be recalculated in the case of a width change or visibility change.
-
#column_model ⇒ Object
returns collection of ColumnInfo objects.
-
#column_width(colindex, width) ⇒ Object
convenience method to set width of a column For setting other attributes, use get_column(index).
-
#columns ⇒ Object
returns array of column names as Strings.
-
#columns=(array) ⇒ Object
(also: #headings=)
Set column titles with given array of strings.
-
#content_cols ⇒ Object
calculate pad width based on widths of columns.
- #contract_column ⇒ Object
- #create_default_sorter ⇒ Object
- #delete_at(ix) ⇒ Object
-
#each_column ⇒ Object
yields non-hidden columns (ColumnInfo) and the offset/index This is the order in which columns are to be printed.
-
#ensure_visible(row = @current_index) ⇒ Object
Ensure current row is visible, if not make it first row This overrides textpad due to header_adjustment, otherwise during next_match, the header overrides the found row.
- #expand_column ⇒ Object
-
#expand_column_to_max_width ⇒ Object
find the width of the longest item in the current columns and expand the width to that.
- #expand_column_to_width(w = nil) ⇒ Object
- #fire_action_event ⇒ Object
-
#get_column(index) ⇒ Object
retrieve the column info structure for the given offset.
- #header_row? ⇒ Boolean
-
#initialize(form = nil, config = {}, &block) ⇒ TableWidget
constructor
A new instance of TableWidget.
-
#matching_indices ⇒ Object
yields each column to caller method for true returned, collects index of row into array and returns the array Value yielded can be fixnum or date etc.
- #model_row(index) ⇒ Object
-
#move_column(ix, newix) ⇒ Object
should all this move into table column model or somepn move a column from offset ix to offset newix.
-
#next_column ⇒ Object
jump cursor to next column TODO : if cursor goes out of view, then pad should scroll right or left and down.
-
#next_match(str) ⇒ Object
Find the next row that contains given string Overrides textpad since each line is an array NOTE does not go to next match within row NOTE: FIXME ensure_visible puts prow = current_index so in this case, the header overwrites the matched row.
-
#padrefresh ⇒ Object
refresh pad onto window overrides super.
-
#prev_column ⇒ Object
jump cursor to previous column TODO : if cursor goes out of view, then pad should scroll right or left and down.
- #remove_column(tc) ⇒ Object
- #render_all ⇒ Object
-
#renderer(r) ⇒ Object
def method_missing(name, *args) @tp.send(name, *args) end.
-
#resultset(columns, data) ⇒ Object
set column array and data array in one shot Erases any existing content.
-
#text(lines, fmt = :none) ⇒ Object
insert entire database in one shot WARNING: overwrites columns if put there, should contain columns already as in CSV data.
Constructor Details
#initialize(form = nil, config = {}, &block) ⇒ TableWidget
Returns a new instance of TableWidget.
369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 |
# File 'lib/rbcurse/experimental/widgets/tablewidget.rb', line 369 def initialize form = nil, config={}, &block # hash of column info objects, for some reason a hash and not an array @chash = [] # chash should be an array which is basically the order of rows to be printed # it contains index, which is the offset of the row in the data @content # When printing we should loop through chash and get the index in data # # should be zero here, but then we won't get textpad correct @_header_adjustment = 0 #1 @col_min_width = 3 super bind_key(?w, "next column") { self.next_column } bind_key(?b, "prev column") { self.prev_column } bind_key(?-, "contract column") { self.contract_column } bind_key(?+, "expand column") { self. } bind_key(?=, "expand column to width") { self. } bind_key(?\M-=, "expand column to width") { self. } end |
Instance Attribute Details
#table_row_sorter ⇒ Object
attr_reader :columns
367 368 369 |
# File 'lib/rbcurse/experimental/widgets/tablewidget.rb', line 367 def table_row_sorter @table_row_sorter end |
Instance Method Details
#_calculate_column_offsets ⇒ Object
This calculates and stores the offset at which each column starts. Used when going to next column or doing a find for a string in the table. TODO store this inside the hash so it’s not calculated again in renderer
427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 |
# File 'lib/rbcurse/experimental/widgets/tablewidget.rb', line 427 def _calculate_column_offsets @coffsets = [] total = 0 #@chash.each_pair { |i, c| #@chash.each_with_index { |c, i| #next if c.hidden each_column {|c,i| w = c.width @coffsets[i] = total c.offset = total # if you use prepare_format then use w+2 due to separator symbol total += w + 1 } end |
#_convert_curpos_to_column ⇒ Fixnum
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)
446 447 448 449 450 451 452 453 454 455 456 457 458 |
# File 'lib/rbcurse/experimental/widgets/tablewidget.rb', line 446 def _convert_curpos_to_column #:nodoc: _calculate_column_offsets unless @coffsets x = 0 @coffsets.each_with_index { |i, ix| if @curpos < i break else x += 1 end } x -= 1 # since we start offsets with 0, so first auto becoming 1 return x end |
#_init_model(array) ⇒ Object
size each column based on widths of this row of data. Only changed width if no width for that column
554 555 556 557 558 559 560 561 562 |
# File 'lib/rbcurse/experimental/widgets/tablewidget.rb', line 554 def _init_model array array.each_with_index { |c,i| # if columns added later we could be overwriting the width c = get_column(i) c.width ||= 10 } # maintains index in current pointer and gives next or prev @column_pointer = Circular.new array.size()-1 end |
#_invalidate_width_cache ⇒ Object
637 638 639 |
# File 'lib/rbcurse/experimental/widgets/tablewidget.rb', line 637 def _invalidate_width_cache #:nodoc: @coffsets = nil end |
#add(array) ⇒ Object Also known as: <<
add a row to the table
599 600 601 602 603 604 605 606 607 608 |
# File 'lib/rbcurse/experimental/widgets/tablewidget.rb', line 599 def add array unless @content # columns were not added, this most likely is the title @content ||= [] _init_model array end @content << array fire_dimension_changed self end |
#add_column(tc) ⇒ Object
tmce = TableColumnModelEvent.new(ix, newix, self, :MOVE) fire_handler :TABLE_COLUMN_MODEL_EVENT, tmce
650 651 652 653 |
# File 'lib/rbcurse/experimental/widgets/tablewidget.rb', line 650 def add_column tc raise "to figure out add_column" _invalidate_width_cache end |
#calculate_column_width(col, maxrows = 99) ⇒ Object
658 659 660 661 662 663 664 665 666 667 668 669 670 671 |
# File 'lib/rbcurse/experimental/widgets/tablewidget.rb', line 658 def calculate_column_width col, maxrows=99 ret = 3 ctr = 0 @content.each_with_index { |r, i| #next if i < @toprow # this is also a possibility, it checks visible rows break if ctr > maxrows ctr += 1 #next if r == :separator c = r[col] x = c.to_s.length ret = x if x > ret } ret end |
#clear_matches ⇒ Object
return @indices
767 768 769 770 771 772 773 774 |
# File 'lib/rbcurse/experimental/widgets/tablewidget.rb', line 767 def clear_matches # clear previous match so all data can show again if @indices && @indices.count > 0 fire_dimension_changed init_vars end @indices = nil end |
#column_align(colindex, align) ⇒ Object
convenience method to set alignment of a column
626 627 628 |
# File 'lib/rbcurse/experimental/widgets/tablewidget.rb', line 626 def column_align colindex, align get_column(colindex).align = align end |
#column_hidden(colindex, hidden) ⇒ Object
convenience method to hide or unhide a column Provided since column offsets need to be recalculated in the case of a width change or visibility change
632 633 634 635 |
# File 'lib/rbcurse/experimental/widgets/tablewidget.rb', line 632 def column_hidden colindex, hidden get_column(colindex).hidden = hidden _invalidate_width_cache end |
#column_model ⇒ Object
returns collection of ColumnInfo objects
404 405 406 |
# File 'lib/rbcurse/experimental/widgets/tablewidget.rb', line 404 def column_model @chash end |
#column_width(colindex, width) ⇒ Object
convenience method to set width of a column For setting other attributes, use get_column(index)
619 620 621 622 |
# File 'lib/rbcurse/experimental/widgets/tablewidget.rb', line 619 def column_width colindex, width get_column(colindex).width = width _invalidate_width_cache end |
#columns ⇒ Object
returns array of column names as Strings
548 549 550 |
# File 'lib/rbcurse/experimental/widgets/tablewidget.rb', line 548 def columns @content[0] end |
#columns=(array) ⇒ Object Also known as: headings=
Set column titles with given array of strings. NOTE: This is only required to be called if first row of file or content does not contain titles. In that case, this should be called before setting the data as the array passed is appended into the content array.
531 532 533 534 535 536 537 538 539 540 541 542 543 544 |
# File 'lib/rbcurse/experimental/widgets/tablewidget.rb', line 531 def columns=(array) @_header_adjustment = 1 # I am eschewing using a separate field for columns. This is simpler for textpad. # We always assume first row is columns. #@columns = array # should we just clear column, otherwise there's no way to set the whole thing with new data # but then if we need to change columns what do it do, on moving or hiding a column ? # Maybe we need a separate clear method or remove_all TODO @content ||= [] @content << array # This needs to go elsewhere since this method will not be called if file contains # column titles as first row. _init_model array end |
#content_cols ⇒ Object
calculate pad width based on widths of columns
409 410 411 412 413 414 415 416 417 418 419 420 |
# File 'lib/rbcurse/experimental/widgets/tablewidget.rb', line 409 def content_cols total = 0 #@chash.each_pair { |i, c| #@chash.each_with_index { |c, i| #next if c.hidden each_column {|c,i| w = c.width # if you use prepare_format then use w+2 due to separator symbol total += w + 1 } return total end |
#contract_column ⇒ Object
506 507 508 509 510 511 512 513 |
# File 'lib/rbcurse/experimental/widgets/tablewidget.rb', line 506 def contract_column x = _convert_curpos_to_column w = get_column(x).width return if w <= @col_min_width column_width x, w-1 if w @coffsets = nil fire_dimension_changed end |
#create_default_sorter ⇒ Object
690 691 692 693 |
# File 'lib/rbcurse/experimental/widgets/tablewidget.rb', line 690 def create_default_sorter raise "Data not sent in." unless @content @table_row_sorter = DefaultTableRowSorter.new @content end |
#delete_at(ix) ⇒ Object
609 610 611 612 613 |
# File 'lib/rbcurse/experimental/widgets/tablewidget.rb', line 609 def delete_at ix return unless @content fire_dimension_changed @content.delete_at ix end |
#each_column ⇒ Object
yields non-hidden columns (ColumnInfo) and the offset/index This is the order in which columns are to be printed
789 790 791 792 793 794 |
# File 'lib/rbcurse/experimental/widgets/tablewidget.rb', line 789 def each_column @chash.each_with_index { |c, i| next if c.hidden yield c,i if block_given? } end |
#ensure_visible(row = @current_index) ⇒ Object
Ensure current row is visible, if not make it first row
This overrides textpad due to header_adjustment, otherwise
during next_match, the header overrides the found row.
781 782 783 784 785 |
# File 'lib/rbcurse/experimental/widgets/tablewidget.rb', line 781 def ensure_visible row = @current_index unless is_visible? row @prow = @current_index - @_header_adjustment end end |
#expand_column ⇒ Object
481 482 483 484 485 486 487 |
# File 'lib/rbcurse/experimental/widgets/tablewidget.rb', line 481 def x = _convert_curpos_to_column w = get_column(x).width column_width x, w+1 if w @coffsets = nil fire_dimension_changed end |
#expand_column_to_max_width ⇒ Object
find the width of the longest item in the current columns and expand the width to that.
501 502 503 504 505 |
# File 'lib/rbcurse/experimental/widgets/tablewidget.rb', line 501 def x = _convert_curpos_to_column w = calculate_column_width x w end |
#expand_column_to_width(w = nil) ⇒ Object
488 489 490 491 492 493 494 495 496 497 498 |
# File 'lib/rbcurse/experimental/widgets/tablewidget.rb', line 488 def w=nil x = _convert_curpos_to_column unless w # expand to width of current cell s = @content[@current_index][x] w = s.to_s.length + 1 end column_width x, w @coffsets = nil fire_dimension_changed end |
#fire_action_event ⇒ Object
698 699 700 701 702 703 704 705 706 707 708 709 710 711 |
# File 'lib/rbcurse/experimental/widgets/tablewidget.rb', line 698 def fire_action_event if header_row? if @table_row_sorter x = _convert_curpos_to_column c = @chash[x] # convert to index in data model since sorter only has data_model index = c.index @table_row_sorter.toggle_sort_order index @table_row_sorter.sort fire_dimension_changed end end super end |
#get_column(index) ⇒ Object
retrieve the column info structure for the given offset. The offset pertains to the visible offset not actual offset in data model. These two differ when we move a column.
394 395 396 397 398 399 400 401 |
# File 'lib/rbcurse/experimental/widgets/tablewidget.rb', line 394 def get_column index return @chash[index] if @chash[index] # create a new entry since none present c = ColumnInfo.new c.index = index @chash[index] = c return c end |
#header_row? ⇒ Boolean
694 695 696 |
# File 'lib/rbcurse/experimental/widgets/tablewidget.rb', line 694 def header_row? @prow == 0 end |
#matching_indices ⇒ Object
yields each column to caller method for true returned, collects index of row into array and returns the array Value yielded can be fixnum or date etc
748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 |
# File 'lib/rbcurse/experimental/widgets/tablewidget.rb', line 748 def matching_indices raise "block required for matching_indices" unless block_given? @indices = [] ## content can be string or Chunkline, so we had to write <tt>index</tt> for this. @content.each_with_index do |fields, ix| flag = yield ix, fields if flag @indices << ix end end $log.debug "XXX: INDICES found #{@indices}" if @indices.count > 0 fire_dimension_changed init_vars else @indices = nil end #return @indices end |
#model_row(index) ⇒ Object
563 564 565 566 567 568 569 570 571 572 |
# File 'lib/rbcurse/experimental/widgets/tablewidget.rb', line 563 def model_row index array = @content[index] array.each_with_index { |c,i| # if columns added later we could be overwriting the width ch = get_column(i) ch.width = c.to_s.length + 2 } # maintains index in current pointer and gives next or prev @column_pointer = Circular.new array.size()-1 end |
#move_column(ix, newix) ⇒ Object
should all this move into table column model or somepn move a column from offset ix to offset newix
643 644 645 646 647 648 649 |
# File 'lib/rbcurse/experimental/widgets/tablewidget.rb', line 643 def move_column ix, newix acol = @chash.delete_at ix @chash.insert newix, acol _invalidate_width_cache #tmce = TableColumnModelEvent.new(ix, newix, self, :MOVE) #fire_handler :TABLE_COLUMN_MODEL_EVENT, tmce end |
#next_column ⇒ Object
jump cursor to next column TODO : if cursor goes out of view, then pad should scroll right or left and down
461 462 463 464 465 466 467 468 469 |
# File 'lib/rbcurse/experimental/widgets/tablewidget.rb', line 461 def next_column # TODO take care of multipliers _calculate_column_offsets unless @coffsets c = @column_pointer.next cp = @coffsets[c] #$log.debug " next_column #{c} , #{cp} " @curpos = cp if cp down() if c < @column_pointer.last_index end |
#next_match(str) ⇒ Object
Find the next row that contains given string Overrides textpad since each line is an array NOTE does not go to next match within row NOTE: FIXME ensure_visible puts prow = current_index so in this case, the header
overwrites the matched row.
720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 |
# File 'lib/rbcurse/experimental/widgets/tablewidget.rb', line 720 def next_match str _calculate_column_offsets unless @coffsets first = nil ## content can be string or Chunkline, so we had to write <tt>index</tt> for this. @content.each_with_index do |fields, ix| #col = line.index str #fields.each_with_index do |f, jx| #@chash.each_with_index do |c, jx| #next if c.hidden each_column do |c,jx| f = fields[c.index] # value can be numeric col = f.to_s.index str if col col += @coffsets[jx] first ||= [ ix, col ] if ix > @current_index return [ix, col] end end end end return first end |
#padrefresh ⇒ Object
refresh pad onto window overrides super
675 676 677 678 679 680 681 682 683 684 685 686 687 688 |
# File 'lib/rbcurse/experimental/widgets/tablewidget.rb', line 675 def padrefresh top = @window.top left = @window.left sr = @startrow + top sc = @startcol + left # first do header always in first row retval = FFI::NCurses.prefresh(@pad,0,@pcol, sr , sc , 2 , @cols+ sc ); # now print rest of data # h is header_adjustment h = 1 retval = FFI::NCurses.prefresh(@pad,@prow + h,@pcol, sr + h , sc , @rows + sr , @cols+ sc ); $log.warn "XXX: PADREFRESH #{retval}, #{@prow}, #{@pcol}, #{sr}, #{sc}, #{@rows+sr}, #{@cols+sc}." if retval == -1 # padrefresh can fail if width is greater than NCurses.COLS end |
#prev_column ⇒ Object
jump cursor to previous column TODO : if cursor goes out of view, then pad should scroll right or left and down
472 473 474 475 476 477 478 479 480 |
# File 'lib/rbcurse/experimental/widgets/tablewidget.rb', line 472 def prev_column # TODO take care of multipliers _calculate_column_offsets unless @coffsets c = @column_pointer.previous cp = @coffsets[c] #$log.debug " prev #{c} , #{cp} " @curpos = cp if cp up() if c > @column_pointer.last_index end |
#remove_column(tc) ⇒ Object
654 655 656 657 |
# File 'lib/rbcurse/experimental/widgets/tablewidget.rb', line 654 def remove_column tc raise "to figure out add_column" _invalidate_width_cache end |
#render_all ⇒ Object
795 796 797 798 799 800 801 802 803 804 805 806 |
# File 'lib/rbcurse/experimental/widgets/tablewidget.rb', line 795 def render_all if @indices && @indices.count > 0 @indices.each_with_index do |ix, jx| render @pad, jx, @content[ix] end else @content.each_with_index { |line, ix| #FFI::NCurses.mvwaddstr(@pad,ix, 0, @content[ix]) render @pad, ix, line } end end |
#renderer(r) ⇒ Object
def method_missing(name, *args) @tp.send(name, *args) end
supply a custom renderer that implements render()
521 522 523 |
# File 'lib/rbcurse/experimental/widgets/tablewidget.rb', line 521 def renderer r @renderer = r end |
#resultset(columns, data) ⇒ Object
set column array and data array in one shot Erases any existing content
587 588 589 590 591 592 593 594 595 |
# File 'lib/rbcurse/experimental/widgets/tablewidget.rb', line 587 def resultset columns, data @content = [] _init_model columns @content << columns @_header_adjustment = 1 @content.concat( data) fire_dimension_changed end |
#text(lines, fmt = :none) ⇒ Object
insert entire database in one shot WARNING: overwrites columns if put there, should contain columns already as in CSV data
578 579 580 581 582 |
# File 'lib/rbcurse/experimental/widgets/tablewidget.rb', line 578 def text lines, fmt=:none _init_model lines[0] fire_dimension_changed super end |