classdef TSList < toolpack.component.component
  % Toolstrip list.
  %
  % Example:
  %   values = {'One','Two','Three'};
  %
  %   list = toolpack.component.TSList;
  %   list = toolpack.component.TSList(values);
  %
  % See also toolpack.component.TSComboBox
  
  % Author(s): Bora Eryilmaz
  % Revised:
  % Copyright 2012-2013 The MathWorks, Inc.
  
  % ----------------------------------------------------------------------------
  properties (Dependent, Access = public)
    % Component's values (cell array of strings, default = cell(0,1))
    Values
  end
  
  properties (Dependent, Access = public)
    % Current selected value (string, default = '')
    SelectedValue
    % Current selected values (cell array of strings, default = {})
    SelectedValues
  end
  
  properties (Dependent, Access = public, SetObservable, AbortSet)
    % Index of currently selected value (integer, default = 0)
    SelectedIndex
    % Indices of currently selected values (integer array, default = [])
    SelectedIndices
  end
  
  properties (Dependent, Access = public)
    % Selection mode ('single' or 'multiple', default = 'single')
    SelectionMode
  end
  
  properties (Access = private)
    % Integer array
    SelectedIndices_ = [];
    % JList (different than Peer, which is a scroll pane)
    JList_
  end
  
  % ----------------------------------------------------------------------------
  events
    % Event sent upon selected value changes.
    ValueChanged
  end
  
  % ----------------------------------------------------------------------------
  methods
    function this = TSList(values)
      % Creates a toolstrip list.
      this = this@toolpack.component.component;
      cls = 'com.mathworks.toolstrip.components.TSList';
      if nargin == 0
        % TSList()
        this.JList_ = javaObjectEDT(cls);
      else
        % TSList(values)
        this.JList_ = javaObjectEDT(cls, values);
      end
      this.JList_.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION)
      this.Peer = javaObjectEDT('com.mathworks.toolstrip.components.TSScrollPane', ...
        this.JList_);
      
      this.SelectedValue = char(this.JList_.getSelectedValue);
      addListSelectionListener( this, {@LocalValueChanged, this} )
    end
    
    function values = get.Values(this)
      % GET function for Values property.
      model = this.JList_.getModel;
      n = model.getSize;
      values = cell(n,1);
      for k = 1:n
        values{k} = char(model.getElementAt(k-1));
      end
    end
    
    function set.Values(this, value)
      % SET function for Values property.
      value = controllib.internal.util.hString2Char(value);
      if ~iscellstr(value)
        error(message('Controllib:toolpack:InvalidPropertyValue', 'Values'))
      end
      this.JList_.setListData(value(:))
      this.SelectedIndex = 0; % Clear selection
    end
    
    function value = get.SelectedValue(this)
      % GET function for SelectedValue property.
      if ~isempty(this.SelectedIndices_)
        value = this.Values{ min(this.SelectedIndices_) };
      else
        value = '';
      end
    end
    
    function value = get.SelectedValues(this)
      % GET function for SelectedValues property.
      value = this.Values(this.SelectedIndices_);
    end
    
    function set.SelectedValue(this, value)
      % SET function for SelectedValue property.
      value = controllib.internal.util.hString2Char(value);
      if ~ischar(value)
        error(message('Controllib:toolpack:StringArgumentNeeded'))
      elseif ~isempty(value) && ~ismember(value, this.Values)
        error(message('Controllib:toolpack:InvalidPropertyValue', 'SelectedValue'))
      end
      
      if isempty(value)
        this.SelectedIndices = [];
      else
        [~,index] = ismember(value, this.Values);
        this.SelectedIndices = index(:);
      end
    end
    
    function set.SelectedValues(this, value)
      % SET function for SelectedValues property.
      if ~iscellstr(value)
        error(message('Controllib:toolpack:StringArgumentNeeded'))
      elseif ~isempty(value) && ~all(ismember(value, this.Values))
        error(message('Controllib:toolpack:InvalidPropertyValue', 'SelectedValues'))
      end
      
      if isempty(value)
        this.SelectedIndices = [];
      else
        [~,indices] = ismember(value, this.Values);
        this.SelectedIndices = indices(:);
      end
    end
    
    function value = get.SelectionMode(this)
      % GET function for SelectionMode property.
      mode = this.JList_.getSelectionMode;
      if mode == javax.swing.ListSelectionModel.SINGLE_SELECTION
        value = 'single';
      else % javax.swing.ListSelectionModel.MULTIPLE_INTERVAL_SELECTION
        value = 'multiple';
      end
    end
    
    function set.SelectionMode(this, value)
      % SET function for SelectionMode property.
      if strcmp(value, 'single')
        mode = javax.swing.ListSelectionModel.SINGLE_SELECTION;
      elseif strcmp(value, 'multiple')
        mode = javax.swing.ListSelectionModel.MULTIPLE_INTERVAL_SELECTION;
      else
        error(message('Controllib:toolpack:InvalidPropertyValue', 'SelectionMode'))
      end
      this.JList_.setSelectionMode(mode)
    end
    
    function value = get.SelectedIndex(this)
      % GET function for SelectedIndex property.
      if ~isempty(this.SelectedIndices_)
        value = min(this.SelectedIndices_);
      else
        value = 0;
      end
    end
    
    function set.SelectedIndex(this, value)
      % SET function for SelectedIndex property.
      values = this.Values;
      if value < 0 || value > length(values)
        error(message('Controllib:toolpack:InvalidPropertyValue', 'SelectedIndex'))
      elseif value == 0
        this.SelectedIndices = [];
      else
        this.SelectedIndices = value;
      end
    end
    
    function value = get.SelectedIndices(this)
      % GET function for SelectedIndices property.
      value = this.SelectedIndices_;
    end
    
    function set.SelectedIndices(this, value)
      % SET function for SelectedIndices property.
      values = this.Values;
      if isempty(value)
        value = [];
        this.SelectedIndices_ = value;
      elseif any(value < 0) || any(value > length(values))
        error(message('Controllib:toolpack:InvalidPropertyValue', 'SelectedIndices'))
      else
        this.SelectedIndices_ = sort(value(:));
      end
      
      % Break Java --> MCOS -->x Java loop
      indices = double(this.JList_.getSelectedIndices) + 1;
      if ~isequal(value(:), indices(:))
        if isempty(value)
          this.JList_.clearSelection
        else
          this.JList_.setSelectedIndices(value-1);
          this.JList_.ensureIndexIsVisible(max(value)-1)
        end
      end
    end
    
    function value = getVerticalScrollBarPolicy(this)
      % Get vertical scroll bar policy.
      p = this.Peer.getVerticalScrollBarPolicy;
      value = toolpack.component.ScrollPaneConstants.getScrollBarPolicy(p);
    end
    
    function setVerticalScrollBarPolicy(this, value)
      % Set vertical scroll bar policy.
      if ~isa(value, 'toolpack.component.ScrollPaneConstants')
        error(message('Controllib:toolpack:InvalidPropertyValue','VerticalScrollBarPolicy'))
      end
      this.Peer.setVerticalScrollBarPolicy( value.JavaEnum );
    end
    
    function value = getHorizontalScrollBarPolicy(this)
      % Get horizontal scroll bar policy.
      p = this.Peer.getHorizontalScrollBarPolicy;
      value = toolpack.component.ScrollPaneConstants.getScrollBarPolicy(p);
    end
    
    function setHorizontalScrollBarPolicy(this, value)
      % Set horizontal scroll bar policy.
      if ~isa(value, 'toolpack.component.ScrollPaneConstants')
        error(message('Controllib:toolpack:InvalidPropertyValue','HorizontalScrollBarPolicy'))
      end
      this.Peer.setHorizontalScrollBarPolicy( value.JavaEnum );
    end
  end
  
  methods (Access = protected)
    function value = getName_(this)
      % Overloaded to work with the JList_ component instead of the Peer.
      value = char(this.JList_.getName);
    end
    
    function setName_(this, value)
      % Overloaded to work with the JList_ component instead of the Peer.
      this.JList_.setName(value);
    end
    
    function value = getEnabled_(this)
      % Overloaded to work with the JList_ component instead of the Peer.
      value = this.JList_.isEnabled;
    end
    
    function setEnabled_(this, value)
      % Overloaded to work with the JList_ component instead of the Peer.
      this.JList_.setEnabled(value);
    end
  end
  
  methods (Access = private)
    function addListSelectionListener(this, fcn)
      % Do not modify. Use as is to prevent Java memory leaks.
      L = addlistener(this.JList_, 'ValueChanged', fcn);
      this.Listeners = [this.Listeners; L];
    end
  end
end

% ------------------------------------------------------------------------------
function LocalValueChanged(~,hData,obj)
if ~hData.getValueIsAdjusting
  indices = double(obj.JList_.getSelectedIndices) + 1;
  obj.SelectedIndices = indices(:);
  obj.notify('ValueChanged')
end
end
