classdef TSComboBox < toolpack.component.component
  % Toolstrip combobox.
  %
  % Example:
  %   items = {'One','Two','Three'};
  %
  %   cmb = toolpack.component.TSComboBox;
  %   cmb = toolpack.component.TSComboBox(items);
  %
  % See also toolpack.component.TSList
  
  % Author(s): Bora Eryilmaz
  % Revised:
  % Copyright 2010-2018 The MathWorks, Inc.
  
  % ----------------------------------------------------------------------------
  properties (Dependent, GetAccess = public, SetAccess = private)
    % Component's items (cell array of strings, default = cell(0,1))
    Items
  end
  
  properties (Dependent, Access = public, SetObservable, AbortSet)
    % Current selected item (string, default = '')
    SelectedItem
  end
  
  properties (Dependent, Access = public)
    % Index of currently selected item (integer, default = 0)
    SelectedIndex
    % Editable state of the component (logical, default = false)
    Editable
  end
  
  properties (Access = private)
    % String
    SelectedItem_ = '';
  end
  
  % ----------------------------------------------------------------------------
  events
    % Event sent upon selection changes.
    ActionPerformed
  end
  
  % ----------------------------------------------------------------------------
  methods
    function this = TSComboBox(items)
      % Creates a toolstrip combobox.
      this = this@toolpack.component.component;
      cls = 'com.mathworks.toolstrip.components.TSComboBox';
      if nargin == 0
        % TSComboBox()
        this.Peer = javaObjectEDT(cls);
      else
        % TSComboBox(items)
        this.Peer = javaObjectEDT(cls, items);
      end
      this.SelectedItem = char(this.Peer.getSelectedItem);
      addActionPerformedListener( this, {@LocalActionPerformed, this} )
    end
    
    function items = get.Items(this)
      % GET function for Items property.
      model = this.Peer.getModel;
      n = model.getSize;
      items = cell(n,1);
      for k = 1:n
        items{k} = char(model.getElementAt(k-1));
      end
    end
    
    function value = get.SelectedItem(this)
      % GET function for SelectedItem property.
      value = this.SelectedItem_;
    end
    
    function set.SelectedItem(this, value)
      % SET function for SelectedItem property.
      value = controllib.internal.util.hString2Char(value);
      if ~ischar(value)
        error(message('Controllib:toolpack:StringArgumentNeeded'))
      end
      this.SelectedItem_ = value;
      % Break Java --> MCOS -->x Java loop
      if ~strcmp(value, char(this.Peer.getSelectedItem))
        this.Peer.setSelectedItem(value);
      end
    end
    
    function value = get.SelectedIndex(this)
      % GET function for SelectedIndex property.
      items = this.Items;
      for k = 1:length(items)
        if strcmp(items{k}, this.SelectedItem)
          value = k;
          return;
        end
      end
      value = 0;
    end
    
    function set.SelectedIndex(this, value)
      % SET function for SelectedIndex property.
      items = this.Items;
      if value == 0
        this.SelectedItem = '';
      elseif value < 0 || value > length(items)
        error(message('Controllib:toolpack:InvalidPropertyValue', 'SelectedIndex'))
      else
        this.SelectedItem = items{value};
      end
    end
    
    function value = get.Editable(this)
      % GET function for Editable property.
      value = this.Peer.isEditable;
    end
    
    function set.Editable(this, value)
      % SET function for Editable property.
      if ~islogical(value)
        error(message('Controllib:toolpack:InvalidPropertyValue', 'Editable'))
      end
      this.Peer.setEditable(value);
    end
    
    function this = addItem(this, item)
      % Adds a new item to the item list.
      item = controllib.internal.util.hString2Char(item);
      if ~ischar(item)
        error(message('Controllib:toolpack:StringArgumentNeeded'))
      end
      this.Peer.addItem(item)
    end
    
    function this = removeItem(this, item)
      % Removes an item from the item list.
      item = controllib.internal.util.hString2Char(item);
      if ~ischar(item)
        error(message('Controllib:toolpack:StringArgumentNeeded'))
      end
      this.Peer.removeItem(item)
    end
    
    function this = insertItemAt(this, item, index)
      % Adds a new item to the item list at a given index.
      item = controllib.internal.util.hString2Char(item);
      if ~ischar(item)
        error(message('Controllib:toolpack:StringArgumentNeeded'))
      end
      this.Peer.insertItemAt(item, index-1)
    end
    
    function this = removeItemAt(this, index)
      % Removes the item at a given index.
      this.Peer.removeItemAt(index-1)
    end
    
    function this = removeAllItems(this)
      % Removes all items from the item list.
      this.Peer.removeAllItems
    end
    
    function this = replaceAllItems(this, items)
      % Replace all items, preserving selection if possible.
      items = string(items);
      selected = this.SelectedItem;
      if ~isequal(items(:), this.Items(:))
        this.removeAllItems();
        for i = items(:)'
          this.addItem(i);
        end
        drawnow; % Flush event queue before selection.
        if any(selected == items)
          this.SelectedItem = selected;
        end
      end
    end
  end
  
  methods (Access = private)
    function addActionPerformedListener(this, fcn)
      % Do not modify. Use as is to prevent Java memory leaks.
      L = addlistener(this.Peer, 'ActionPerformed', fcn);
      this.Listeners = [this.Listeners; L];
    end
  end
end

% ------------------------------------------------------------------------------
function LocalActionPerformed(~,~,obj)
obj.SelectedItem = char(obj.Peer.getSelectedItem);
obj.notify('ActionPerformed')
end
