classdef TSTextField < toolpack.component.component
  % Toolstrip text field.
  %
  % Example:
  %   text = 'My text';
  %   columns = 10;
  %
  %   txt = toolpack.component.TSTextField;
  %   txt = toolpack.component.TSTextField(columns);
  %   txt = toolpack.component.TSTextField(text);
  %   txt = toolpack.component.TSTextField(text, columns);
  %
  % See also toolpack.component.TSTextArea
  
  % Author(s): Bora Eryilmaz
  % Revised:
  % Copyright 2010-2012 The MathWorks, Inc.
  
  % ----------------------------------------------------------------------------
  properties (Dependent, Access = public, SetObservable, AbortSet)
    % Component's text (string, default = '')
    Text
  end
  
  properties (Dependent, Access = public)
    % Component's number of columns (integer, default = 0)
    Columns
    % Component's editable state (logical, default = true)
    Editable
  end
  
  properties (Access = private)
    % String
    Text_ = ''; % AbortSet does not let setting []-->'' in the constructor.
  end
  
  % ----------------------------------------------------------------------------
  events
    % Event sent upon pressing Enter.
    ActionPerformed
    % Event sent when the component loses keyboard focus.
    FocusLost
    % Event sent when the component gains keyboard focus.
    FocusGained
    % Event sent upon pressing Enter or losing focus after a real text change.
    TextEdited
  end
  
  % ----------------------------------------------------------------------------
  methods
    function this = TSTextField(text, columns)
      % Creates a toolstrip text field.
      this = this@toolpack.component.component;
      cls = 'com.mathworks.toolstrip.components.TSTextField';
      
      if nargin == 0
        % TSTextField();
        this.Peer = javaObjectEDT(cls);
      elseif nargin == 1
        text = controllib.internal.util.hString2Char(text);
        if ischar(text)
          % TSTextField(text)
          this.Peer = javaObjectEDT(cls, text);
        else
          % TSTextField(columns)
          columns = text;
          this.Peer = javaObjectEDT(cls, columns);
        end
      else
        % TSTextField(text, columns)
        this.Peer = javaObjectEDT(cls, text, columns);
      end
      this.Text = char(this.Peer.getText);
      addActionPerformedListener( this, {@LocalActionPerformed, this} )
      addFocusGainedListener( this, {@LocalFocusGained, this} )
      addFocusLostListener( this, {@LocalFocusLost, this} )
    end
    
    function value = get.Text(this)
      % GET function for Text property.
      value = this.Text_;
    end
    
    function set.Text(this, value)
      % SET function for Text property.
      value = controllib.internal.util.hString2Char(value);
      if isempty(value)
        value = '';
      elseif ~ischar(value)
        error(message('Controllib:toolpack:StringArgumentNeeded'))
      end
      this.Text_ = value;
      % Break Java --> MCOS -->x Java loop
      if ~strcmp(value, char(this.Peer.getText))
        this.Peer.setText(value);
      end
    end
    
    function value = get.Columns(this)
      % GET function for Columns property.
      value = this.Peer.getColumns;
    end
    
    function set.Columns(this, value)
      % SET function for Columns property.
      if ~isnumeric(value)
        error(message('Controllib:toolpack:InvalidPropertyValue', 'Columns'))
      end
      this.Peer.setColumns(value);
    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
  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
    
    function addFocusLostListener(this, fcn)
      % Do not modify. Use as is to prevent Java memory leaks.
      L = addlistener(this.Peer, 'FocusLost', fcn);
      this.Listeners = [this.Listeners; L];
    end
    
    function addFocusGainedListener(this, fcn)
      % Do not modify. Use as is to prevent Java memory leaks.
      L = addlistener(this.Peer, 'FocusGained', fcn);
      this.Listeners = [this.Listeners; L];
    end
  end
end

% ------------------------------------------------------------------------------
function LocalActionPerformed(~,~,obj)
oldText = obj.Text;
newText = char(obj.Peer.getText);
obj.Text = newText;
obj.notify('ActionPerformed')

data = struct('oldValue', oldText, 'newValue', newText);
obj.notify('TextEdited', toolpack.ComponentEventData(data))
end

function LocalFocusLost(~,~,obj)
oldText = obj.Text;
newText = char(obj.Peer.getText);
obj.Text = newText;
obj.notify('FocusLost')

if ~strcmp(oldText, newText)
  % Focus lost after a real text change
  data = struct('oldValue', oldText, 'newValue', newText);
  obj.notify('TextEdited', toolpack.ComponentEventData(data))
end
end

function LocalFocusGained(~,~,obj)
obj.notify('FocusGained')
end
