class Canis::DefaultListSelectionModel

Object that takes care of selection of rows. This may be replace with a custom object at time of instantiation of list Note that there are only two selection modes: single and multiple. Multiple refers to multiple intervals. There is also a multiple row selection mode, single interval, which only allows one range to be selected, much like a text object, i.e. any text editor.

I am copying this from listselectable. that was a module so was included and shared variables

but now this is a class, and cannot access state as directly

Public Class Methods

new(component) click to toggle source
# File lib/canis/core/include/listselectionmodel.rb, line 83
def initialize component
  raise "Components passed to DefaultListSelectionModel is nil" unless component
  @obj = component

  @selected_indices = @obj.selected_indices
  # in this case since it is called immediately upon extend, user cannot change this
  # Need a method to let user change after extending
  @selection_mode = @obj.selection_mode
  list_bindings
end

Public Instance Methods

add_row_selection_interval(ix0, ix1) click to toggle source

add the following range to selected items, unless already present should only be used if multiple selection interval

# File lib/canis/core/include/listselectionmodel.rb, line 220
def add_row_selection_interval ix0, ix1
  return if @obj.selection_mode != :multiple
  @anchor_selection_index = ix0
  @lead_selection_index = ix1
  ix0.upto(ix1) {|i| 
                 @selected_indices  << i unless @selected_indices.include? i
                 @obj.fire_row_changed i
  }
  lse = ListSelectionEvent.new(ix0, ix1, @obj, :INSERT)
  @obj.fire_handler :LIST_SELECTION_EVENT, lse
  #$log.debug " DLSM firing LIST_SELECTION EVENT #{lse}"
end
ask_select(prompt="Enter selection pattern: ") click to toggle source

Asks user to enter a string or pattern for selecting rows Selects rows based on pattern, leaving other selections as-is

# File lib/canis/core/include/listselectionmodel.rb, line 300
def ask_select prompt="Enter selection pattern: "
  ret = get_string prompt
  return if ret.nil? || ret ==  ""
  indices = get_matching_indices ret
  #$log.debug "listselectionmodel: ask_select got matches#{@indices} "
  return if indices.nil? || indices.empty?
  indices.each { |e|
    # will not work if single select !! FIXME
    add_row_selection_interval e,e
  }
end
ask_unselect(prompt="Enter selection pattern: ") click to toggle source

Asks user to enter a string or pattern for UNselecting rows UNSelects rows based on pattern, leaving other selections as-is

# File lib/canis/core/include/listselectionmodel.rb, line 326
def ask_unselect prompt="Enter selection pattern: "
  ret = get_string prompt
  return if ret.nil? || ret ==  ""
  indices = get_matching_indices ret
  return if indices.nil? || indices.empty?
  indices.each { |e|
    # will not work if single select !! FIXME
    remove_row_selection_interval e,e
  }
end
clear_selection() click to toggle source

clears selected indices, typically called when multiple select Key binding is application specific

# File lib/canis/core/include/listselectionmodel.rb, line 175
def clear_selection
  return if @selected_indices.nil? || @selected_indices.empty?
  arr = @selected_indices.dup # to un highlight
  @selected_indices.clear
  arr.each {|i| @obj.fire_row_changed(i) }
  @selected_index = nil
  @old_selected_index = nil
  #  User should ignore first two params
  lse = ListSelectionEvent.new(0, arr.size, @obj, :CLEAR)
  @obj.fire_handler :LIST_SELECTION_EVENT, lse
  arr = nil
end
get_matching_indices(pattern) click to toggle source

returns a list of matching indices using a simple regex match on given pattern returns an empty list if no match

# File lib/canis/core/include/listselectionmodel.rb, line 313
def get_matching_indices pattern
  matches = []
  @obj.content.each_with_index { |e,i| 
    # convert to string for tables
    e = e.to_s unless e.is_a? String
    if e  =~ /#{pattern}/
      matches << i
    end
  }
  return matches
end
goto_next_selection() click to toggle source

after selecting, traverse selections forward

# File lib/canis/core/include/listselectionmodel.rb, line 202
def goto_next_selection
  return if selected_rows().length == 0 
  row = selected_rows().sort.find { |i| i > @obj.current_index }
  row ||= @obj.current_index
  #@obj.current_index = row
  @obj.goto_line row
end
goto_prev_selection() click to toggle source

after selecting, traverse selections backward

# File lib/canis/core/include/listselectionmodel.rb, line 211
def goto_prev_selection
  return if selected_rows().length == 0 
  row = selected_rows().sort{|a,b| b <=> a}.find { |i| i < @obj.current_index }
  row ||= @obj.current_index
  #@obj.current_index = row
  @obj.goto_line row
end
insert_index_interval(ix0, len) click to toggle source

convenience method to select next len rows

# File lib/canis/core/include/listselectionmodel.rb, line 244
def insert_index_interval ix0, len
  @anchor_selection_index = ix0
  @lead_selection_index = ix0+len
  add_row_selection_interval @anchor_selection_index, @lead_selection_index
end
invert_row_selection(row=@obj.current_index) click to toggle source

toggles selection for given row Typically called by invert_selection

# File lib/canis/core/include/listselectionmodel.rb, line 266
def invert_row_selection row=@obj.current_index
  @repaint_required = true
  if is_selected? row
    remove_row_selection_interval(row, row)
  else
    add_row_selection_interval(row, row) 
  end
end
invert_selection(start_row=0) click to toggle source

toggle selection of entire list Requires application specific key binding

# File lib/canis/core/include/listselectionmodel.rb, line 260
def invert_selection start_row=0 #+@_header_adjustment
  start_row.upto(@obj.list.count()-1){|i| invert_row_selection i }
end
is_row_selected?(crow) click to toggle source

returns true if given row has been selected Now that we use only the array, the multiple check is good enough

# File lib/canis/core/include/listselectionmodel.rb, line 190
def is_row_selected? crow
  case @obj.selection_mode 
  when :multiple
    @selected_indices.include? crow
  else
    @selected_index = @selected_indices[0]
    crow == @selected_index
  end
end
Also aliased as: is_selected?
is_selected?(crow)
Alias for: is_row_selected?
list_bindings() click to toggle source

bindings related to selection

# File lib/canis/core/include/listselectionmodel.rb, line 340
def list_bindings
  # freeing space for paging, now trying out 'v' as selector. 2014-04-14 - 18:57
  @obj.bind_key($row_selector || 'v'.ord, 'toggle selection') { toggle_row_selection }
  
  # the mode may be set to single after the constructor, so this would have taken effect.
  if @obj.selection_mode == :multiple
  # freeing ctrl_space for back paging, now trying out 'V' as selector. 2014-04-14 - 18:57
    @obj.bind_key($range_selector || 'V'.ord, 'range select') { range_select }
    @obj.bind_key(?+, 'ask_select') { ask_select } 
    @obj.bind_key(?-, 'ask_unselect') { ask_unselect } 
    @obj.bind_key(?a, 'select_all') {select_all}
    @obj.bind_key(?*, 'invert_selection') { invert_selection }
    @obj.bind_key(?u, 'clear_selection') { clear_selection }
    @obj.bind_key([?g,?n], 'goto next selection'){ goto_next_selection } # mapping double keys like vim
    @obj.bind_key([?g,?p], 'goto prev selection'){ goto_prev_selection } # mapping double keys like vim
  end
  @_header_adjustment ||= 0 #  incase caller does not use
  #@obj._events << :LIST_SELECTION_EVENT unless @obj._events.include? :LIST_SELECTION_EVENT
end
list_init_vars() click to toggle source
# File lib/canis/core/include/listselectionmodel.rb, line 359
def list_init_vars
  # uncommenting since link with obj will be broken
  #@selected_indices = []
  @selected_index = nil
  @old_selected_index = nil
  #@row_selected_symbol = ''
  ## FIXME we are not doing selectors at present. should we, else remove this
  if @show_selector
    @row_selected_symbol ||= '*'
    @row_unselected_symbol ||= ' '
    @left_margin ||= @row_selected_symbol.length
  end
end
range_select(crow=@obj.current_index) click to toggle source

Range select. Only for multiple mode. Uses the last row clicked on, till the current one. If user clicks inside a selcted range, then deselect from last click till current (remove from earlier) If user clicks outside selected range, then select from last click till current (add to earlier) typically bound to Ctrl-Space (0)

@example

bind_key(0) { range_select }
# File lib/canis/core/include/listselectionmodel.rb, line 146
def range_select crow=@obj.current_index
  #alert "add to selection fired #{@last_clicked}"
  @last_clicked ||= crow
  min = [@last_clicked, crow].min
  max = [@last_clicked, crow].max
  case @obj.selection_mode 
  when :multiple
    if @selected_indices.include? crow
      # delete from last_clicked until this one in any direction
      min.upto(max){ |i| @selected_indices.delete i 
                     @obj.fire_row_changed i
      }
      lse = ListSelectionEvent.new(min, max, @obj, :DELETE)
      @obj.fire_handler :LIST_SELECTION_EVENT, lse
    else
      # add to selection from last_clicked until this one in any direction
      min.upto(max){ |i| @selected_indices << i unless @selected_indices.include?(i) 
                     @obj.fire_row_changed i
      }
      lse = ListSelectionEvent.new(min, max, @obj, :INSERT)
      @obj.fire_handler :LIST_SELECTION_EVENT, lse
    end
  else
  end
  @last_clicked = crow # 2014-04-08 - 01:21 this was missing, i think it is required
  self
end
remove_row_selection_interval(ix0, ix1) click to toggle source

remove selected indices between given indices inclusive

# File lib/canis/core/include/listselectionmodel.rb, line 234
def remove_row_selection_interval ix0, ix1
  @anchor_selection_index = ix0
  @lead_selection_index = ix1
  arr = @selected_indices.dup # to un highlight
  @selected_indices.delete_if {|x| x >= ix0 and x <= ix1 }
  arr.each {|i| @obj.fire_row_changed(i) }
  lse = ListSelectionEvent.new(ix0, ix1, @obj, :DELETE)
  @obj.fire_handler :LIST_SELECTION_EVENT, lse
end
select_all(start_row=0) click to toggle source

select all rows, you may specify starting row. if header row, then 1 else should be 0. Actually we should have a way to determine this, and the default should be zero.

# File lib/canis/core/include/listselectionmodel.rb, line 252
def select_all start_row=0 #+@_header_adjustment
  # don't select header row - need to make sure this works for all cases. we may
  # need a variable instead of hardoded value
  add_row_selection_interval start_row, @obj.list.count()-1
end
select_values(values) click to toggle source

selects all rows with the values given, leaving existing selections intact. Typically used after accepting search criteria, and getting a list of values to select (such as file names). Will not work with tables (array or array) TODO is this even needed, scrap

# File lib/canis/core/include/listselectionmodel.rb, line 278
def select_values values
  return unless values
  values.each do |val|
    row = @list.index val
    add_row_selection_interval row, row unless row.nil?
  end
end
selected_rows() click to toggle source

return the indices selected

# File lib/canis/core/include/listselectionmodel.rb, line 373
def selected_rows
  @selected_indices
end
selected_value() click to toggle source

returns first selection, meant for convenience of single select listboxes earlier called selected_item

# File lib/canis/core/include/listselectionmodel.rb, line 382
def selected_value
  return nil if @selected_indices.empty?
  @obj[@selected_indices.first]
  #selected_values.first
end
selected_values() click to toggle source

return the values selected

# File lib/canis/core/include/listselectionmodel.rb, line 377
def selected_values
  @obj.values_at(*@selected_indices)
end
toggle_row_selection(crow=@obj.current_index) click to toggle source

change selection of current row on pressing space bar (or keybinding) If mode is multiple, then this row is added to previous selections @example

bind_key(32) { toggle_row_selection }
# File lib/canis/core/include/listselectionmodel.rb, line 100
def toggle_row_selection crow=@obj.current_index
  @last_clicked = crow
  @repaint_required = true
  case @obj.selection_mode 
  when :multiple
    if @selected_indices.include? crow
      @selected_indices.delete crow
      lse = ListSelectionEvent.new(crow, crow, @obj, :DELETE)
      @obj.fire_handler :LIST_SELECTION_EVENT, lse
    else
      @selected_indices << crow
      lse = ListSelectionEvent.new(crow, crow, @obj, :INSERT)
      @obj.fire_handler :LIST_SELECTION_EVENT, lse
    end
  else
    # single - now change to use array only
    @selected_index = @selected_indices[0]
    if @selected_index == crow 
      @old_selected_index = @selected_index # 2011-10-15 so we can unhighlight
      @selected_index = nil
      @selected_indices.clear
      lse = ListSelectionEvent.new(crow, crow, @obj, :DELETE)
      @obj.fire_handler :LIST_SELECTION_EVENT, lse
    else
      @selected_indices[0] = crow
      @obj.fire_row_changed(@old_selected_index) if @old_selected_index
      @old_selected_index = crow # 2011-10-15 so we can unhighlight
      lse = ListSelectionEvent.new(crow, crow, @obj, :INSERT)
      @obj.fire_handler :LIST_SELECTION_EVENT, lse
    end
  end
  @obj.fire_row_changed crow
  #alert "toggling #{@selected_indices.join(',')}"
end
unselect_values(values) click to toggle source

TODO is this even needed, scrap unselects all rows with the values given, leaving all other rows intact You can map “-” to ask_select and call this from there.

bind_key(?+, :ask_select) # --> calls select_values
bind_key(?-, :ask_unselect)
# File lib/canis/core/include/listselectionmodel.rb, line 290
def unselect_values values
  return unless values
  values.each do |val|
    row = @list.index val
    remove_row_selection_interval row, row unless row.nil?
  end
end