function out = uiimport(filename)
%UIIMPORT Starts the GUI for importing data (Import Wizard).
%
% UIIMPORT Starts the Import Wizard in the current directory.  Options to
% load data from a file or the clipboard are presented.
%
% UIIMPORT(FILENAME) Starts the Import Wizard, opening the file specified in
% FILENAME.  The Import Wizard displays a preview of the data in the file.
%
% UIIMPORT('-file') works as above but the file selection dialog is presented
% first.
% 
% UIIMPORT('-pastespecial') works as above but the clipboard contents are
% presented first.
%
% S = UIIMPORT(...) works as above with resulting variables stored as
% fields in the struct S.
%
% For ASCII data, you must verify that the Import Wizard recognized the column
% delimiter.
%
% See also: LOAD, FILEFORMATS, CLIPBOARD

% Copyright 1984-2000 The MathWorks, Inc.
% $Revision: 1.34 $  $Date: 2000/09/15 07:31:32 $

% NOTE: This function uses undocumented java objects whose behavior will
%       change in future releases.  When using this function as an example,
%       use java objects from the java.awt or javax.swing packages to ensure
%       forward compatibility.

if ~usejava('mwt')
    error('Java is not currently enabled.  See JAVA for more information.');
end

if isappdata(0, 'MATLABImportWizardAppData')
    % only allow one Import Wizard at a time - bring current one to foreground
    ad = getappdata(0, 'MATLABImportWizardAppData');
    if isfield(ad, 'FrameHandle')
        try
            ad.FrameHandle.show;
        catch
            % if the show failed, the frame may not be finished building yet
        end
        return;
    end
end

if nargout
    out = [];
end

if nargin == 1 & strcmp(filename,'-file')
    if isunix
        filename = '';
    else
        if isappdata(0,'MATLABImportWizardStartDir')
            prevdir = pwd;
            cd(getappdata(0,'MATLABImportWizardStartDir'));
        end
        [fn, pn] = uigetfile(importTypes, 'Import');
        if isappdata(0,'MATLABImportWizardStartDir')
            cd(prevdir);
        end
    
        if ~all(pn == 0) & ~all(fn == 0)
            filename = fullfile(pn,fn);
        else
            return;
        end
    end
end

try
    % lock this file in memory so persistent variables don't get hosed
    mlock

    if nargin == 1
        ad = setup(filename);
    else
        ad = setup;
    end
    
    if nargout
        ad.AssignInCaller = 0;
    else
        ad.AssignInCaller = 1;
    end
    
    setappdata(0, 'MATLABImportWizardAppData', ad)

    if nargout
        % block until done 
        waitfor(ad.HGHandle)

        if isappdata(0, 'MATLABImportWizardAppData');
            % fetch current app data
            ad = getappdata(0, 'MATLABImportWizardAppData');
            
            % data only gets set when finish is pressed
            if isfield(ad,'data')
                out = ad.data;
            end

            % flush app data
            rmappdata(0, 'MATLABImportWizardAppData');
        else
            % cancel was hit
        end
    end

catch
 
    % show any errors from setup function
    if ~isempty(lasterr) & ~isappdata(0, 'MATLABImportWizardAppData');
        % clear mlock
        munlock
        
        error(lasterr)
    end
    
    if isappdata(0, 'MATLABImportWizardAppData');
        % ctrl c was pressed or a nasty error occured
        doCancel;
    end
end

function ad = setup(filename)
% create wizard frame and shove in first panel

% do imports
import java.awt.*;
import com.mathworks.mwt.*;
import com.mathworks.mwt.dialog.*;
import com.mathworks.mwt.window.*;

% create frame
defaultTitle = sprintf('Import Wizard');
f = MWFrame(defaultTitle);
f.setLayout(BorderLayout(3,3));

% size and show - now so the user thinks we're really fast!
ss = get(0,'ScreenSize');
defXSize = 700;
defYSize = 433;
% handle small screens nicely (layout won't look as good though...)
if ss(3) <  defXSize
    defXSize = ss(3) * .8;
    defYSize = defXSize * .6;
end
% use a wait cursor
ad.FrameHandle = f;
ad.FrameHandle.setCursor(java.awt.Cursor.WAIT_CURSOR)

% put a nice message in
niceMessage = MWLabel(sprintf('    Initializing %s...', defaultTitle));
niceMessage.setFont(Font(fontName, 0, fontSize));
ad.niceMessage = niceMessage;
f.add(niceMessage, BorderLayout.CENTER);

xloc = ss(3) / 2 - defXSize / 2;
yloc = ss(4) / 2 - defYSize / 2;
p = Point(xloc,yloc);
f.setSize(defXSize,defYSize);
f.setLocation(p);

f.setFont(Font(fontName,0,12));

% update app data so any errors get cleaned up gracefully
setappdata(0, 'MATLABImportWizardAppData', ad);

f.show;

% initialize app data
ad.DefaultTitle = defaultTitle;
ad.ShowWarnings = 0;
ad.CallbackPending = '';
ad.Source = 'File';
if isappdata(0,'MATLABImportWizardStartDir')
    ad.StartDir = getappdata(0,'MATLABImportWizardStartDir');
else
    ad.StartDir = pwd;
    setappdata(0,'MATLABImportWizardStartDir',ad.StartDir);
end
ad.PathName = pwd;
ad.FileNameText = '';
ad.FileName = '';
ad.OTextDelimiter = NaN;
ad.OHeaderLines = NaN;
ad.FileType = '';
ad.FileText = '';
ad.FilePreview = '';
if nargin
    ad.inputArgs = filename;
else
    ad.inputArgs = '';
end
ad.PreviousPanel = cell(0);
ad.ODataIndex = NaN;
ad.FinishToolTipDefaultString = sprintf('Import selected variables');
ad.CommandWindowMessage = sprintf('%s created variables in the current workspace.', ad.DefaultTitle);

% update app data so callbacks can fire
setappdata(0, 'MATLABImportWizardAppData', ad);

% setup window closing callback - this takes a while so show the frame first
set(f,'WindowClosingCallback', {@doCancel});
set(f,'KeyPressedCallback', {@doKeyPress})
set(f,'Parent',0);
set(f,'Tag','MATLABImportWizardFrame');

ad.HGHandle = findobj(0,'Tag','MATLABImportWizardFrame');

% create card panel
cp = MWCardPanel;
cp.setOpaque(1);
cp.setStyle(MWCardPanel.NONE);
%                    t, l, b, r
cp.setMargins(Insets(3, 3, 3, 3));
f.add(cp, BorderLayout.CENTER);
ad.cardPanel = cp;
% shove into app data before setting callback
set(cp, 'ItemStateChangedCallback', {@doCardPanelChanged})

% add wizard controls
p = MWPanel(FlowLayout(FlowLayout.CENTER,3,3));

cancelButton = MWButton(sprintf('Cancel'));
cancelButton.setFont(Font(fontName, 0, fontSize));
p.add(cancelButton);
set(cancelButton,'ActionPerformedCallback', {@doCancel});
cancelButton.setEnabled(1);
ad.cancelButton = cancelButton;

backButton   = MWButton(sprintf('< Back'));
backButton.setFont(Font(fontName, 0, fontSize));
p.add(backButton);
set(backButton,'ActionPerformedCallback', {@doBack});
backButton.setEnabled(0);
ad.backButton = backButton;

nextButton   = MWButton(sprintf('Next >'));
nextButton.setFont(Font(fontName, 0, fontSize));
p.add(nextButton);
set(nextButton,'ActionPerformedCallback', {@doNext});
nextButton.setEnabled(0);
ad.nextButton = nextButton;

finishButton = MWButton(sprintf('Finish'));
finishButton.setFont(Font(fontName, 0, fontSize));
p.add(finishButton);
set(finishButton,'ActionPerformedCallback', {@doFinish});
finishButton.setEnabled(0);
ad.finishButton = finishButton;

f.add(p, BorderLayout.SOUTH);

% update app data in case source selector fails to build
setappdata(0, 'MATLABImportWizardAppData', ad);

% build sourceSelector panel
[ad, pss] = sourceSelector(ad);

% update app data so callbacks can fire
setappdata(0, 'MATLABImportWizardAppData', ad);

% add sourceSelector - this fires an event
cp.addPanel('sourceSelector', pss);

% make sure persistent data is cleared
setPreview(ad, 'reset');

% add first panel - modifies app data
if nargin == 1

    if ad.niceMessage.isVisible
        ad.niceMessage.setText(sprintf('    Loading preview...'));
        ad.niceMessage.show
    end

    if strcmp(filename, '-pastespecial')
        ad.dataSourceGroup.setSelectedItem(ad.clipButton);

        ad = doSourceChanged(ad);
    else
        ad.dataSourceGroup.setSelectedItem(ad.fileButton);
        
        % update filename text field and fake text event
        ad.filenameTextfield.setText(filename);

        ad = doTextChanged(ad);
    end

    % goto next panel if it's enabled
    if ad.nextButton.isEnabled
        ad = doNext(ad);
    end
else
    % update text preview
    setFilePreview(ad);

end

% done building the frame, turn the cursor back
ad.FrameHandle.setCursor(java.awt.Cursor.DEFAULT_CURSOR);

% hide the nice message
niceMessage.setVisible(0);

% update frame
f.show;

%%
%% callback functions
%%
function doKeyPress(obj, evd)
evd = get(gcbo,'KeyPressedCallbackData');
switch abs(evd.keyChar)
 case 27, doCancel;    % boot window on escape
 case 10,              % do default action on Enter
  ad = locGetAppData;
  if ad.nextButton.isEnabled
      % need to let doNext think this came from a callback
      doNext(obj, evd);
  elseif ad.finishButton.isEnabled
      if ad.AssignInCaller
          evalin('caller', 'doFinish;');
      else
          % need to let doFinish think this came from a callback
          doFinish(obj, evd);
      end
  end
end

function ad = doCardPanelChanged(obj, evd)
ad = locGetAppData(nargin, obj);

cp = ad.cardPanel;

% get name based on selected index
currentPanel = char(cp.getPanelName(cp.getSelectedIndex));

ad = panelUpdate(ad, currentPanel);

if strcmp(currentPanel, 'sourceSelector')
    ad.filenameTextfield.requestFocus;
elseif strcmp(currentPanel, 'delimitedOptions')
    ad.otherDelimiter.requestFocus;
end

locSetAppData(nargin, ad);

function ad = doSourceChanged(obj, evd)
ad = locGetAppData(nargin, obj);

if strcmp(char(ad.dataSourceGroup.getSelectedItem.getName), 'file')
    ad.Source = 'File';
    % need to pass 3 args to doTextChanged to make it look for 'force' option
    ad = doTextChanged(ad, '', 'force');
else
    % disable buttons
    ad.nextButton.setEnabled(0);
    ad.finishButton.setEnabled(0);

    % fetch clipboard contents and update app data
    ad.Source = 'Clipboard';
    ad.FilePreview = clipboard('paste');
    ad.datastruct = [];
    try
        [ad.datastruct, ad.OTextDelimiter, ad.OHeaderLines] = importdata('-pastespecial');
    catch
        % unable to fetch anything from clipboard
        if ad.ShowWarnings
            warning(lasterr)
        end
    end
    
    if isempty(ad.datastruct)
        ad = setPreview(ad, 'source', ' No recognized data on clipboard');
    else
        if ~isstruct(ad.datastruct)
            s = struct('clipboarddata', 1);
            s = setfield(s, 'clipboarddata', ad.datastruct);
            ad.datastruct = s;
        end
        ad = setPreview(ad, 'source', ad.datastruct);
        ad.nextButton.setEnabled(1);
    end

    updatePreviewLabels(ad)

end

setFilePreview(ad);

locSetAppData(nargin, ad);

function ad = doNext(obj, evd)
ad = locGetAppData(nargin, obj);

% goto next panel based on options

% get handle to card panel
cp = ad.cardPanel; % get java object from app data

% get selected index
si = cp.getSelectedIndex;

% get name based on selected index
nextPanel = char(cp.getPanelName(si));

% store path back to this panel (if name is not in list yet)
if length(ad.PreviousPanel) == 0 | ...
        (length(ad.PreviousPanel) > 0 & ~strcmp(char(ad.PreviousPanel{end}),nextPanel))
    ad.PreviousPanel(end+1) = {nextPanel};
end

% figure out which panel is next based on name and app data
switch(nextPanel)
 case 'sourceSelector'
  % determine file type and goto right panel
  if (isnan(ad.OTextDelimiter))
      nextPanel = 'destinationOptions';
  else
      nextPanel = 'delimitedOptions';
  end
 case 'delimitedOptions'
  nextPanel = 'destinationOptions';
 case 'destinationOptions'
  % this is an error, the next button should have been disabled (boo hoo)
  ad.nextButton.setEnabled(0);
 otherwise
  disp(['TBD add support for this panel: ' nextPanel]);
end

% leave if panel name did not change
if strcmp(nextPanel, char(ad.PreviousPanel))
    return;
end

% if panel was not created, create it and add it to app data
if isempty(cp.getPanel(nextPanel))
    [ad, np] = feval(nextPanel, ad);

    % add the panel, udpate the card panel, update app data
    cp.addPanel(nextPanel,np);
    ad = setfield(ad,nextPanel,np);
end

% enable back
ad.backButton.setEnabled(1);

% set the app data before we trigger the event
locSetAppData(nargin, ad);

% select the panel and let the event handler do the rest
cp.selectPanel(nextPanel);

function ad = doBack(obj, evd)
ad = locGetAppData(nargin, obj);

% goto previous panel in wizard

cp = ad.cardPanel; % get java object from app data
if length(ad.PreviousPanel) > 0
    cp.selectPanel(ad.PreviousPanel{end});
    if length(ad.PreviousPanel) == 1
        ad.PreviousPanel = cell(0);
        ad.backButton.setEnabled(0);
    else
        ad.PreviousPanel = ad.PreviousPanel(1:end-1);
    end
end

% next should be enabled whenever back gets clicked
ad.nextButton.setEnabled(1);

% finish should only be enabled on last panel
ad.finishButton.setEnabled(0);

locSetAppData(nargin, ad);

function ad = doCancel(obj, evd)
% clear lock on this file
munlock

if nargin == 0, obj = gcbo; end

ad = locGetAppData(nargin, obj);
if isempty(ad)
    if strcmp(get(obj,'Type'),'com.mathworks.mwt.MWFrame')
        set(obj,'Visible','off');
        return;
    else
        % not much we can do here
        error('Import Wizard is in an invalid state.  Please restart MATLAB.')
    end
end

% close the window
closeWindow(ad.FrameHandle, ad.HGHandle)

% flush app data
if isappdata(0, 'MATLABImportWizardAppData');
    rmappdata(0, 'MATLABImportWizardAppData');
end

function out = doFinish(obj, evd)

if nargin == 0, obj = gcbo; end

try
    ad = locGetAppData(nargin, obj);

    if ad.finishButton.isEnabled == 0
        if nargout, out = ad; end
        return;
    end

    ad.FrameHandle.setCursor(java.awt.Cursor.WAIT_CURSOR);

    % seed result
    if ~ad.AssignInCaller
        out = [];
    end

    currentPanel = char(ad.cardPanel.getPanelName(ad.cardPanel.getSelectedIndex));
    if ~strcmp(currentPanel, 'destinationOptions')
        % we got here cuz finish was enabled before the last panel was shown
        % fetch data and shove off to workspace or output
        names = fieldnames(ad.datastruct);
        if length(names) > 1
            if ad.AssignInCaller
                [p,name] = fileparts(ad.FileName);
                assignin('caller',legalname(name),ad.datastruct);
            end
        else
            if ad.AssignInCaller
                assignin('caller',names{1},getfield(ad.datastruct,names{1}))
            else
                out = ad.datastruct;
            end
        end
    else
        % act based on radio buton clicked
        str = char(ad.destinationLoadOptionsGroup.getSelectedItem.getName);
        switch str
         case '1'
          % save as data only 
          names = fieldnames(ad.datastruct);
          for i = 1:length(names)
              if ad.destinationVariableList{str2double(str)}.isSelected(i - 1)
                  vname = char(ad.destinationVariableList{str2double(str)}.getName(i-1));
                  if ad.AssignInCaller
                      assignin('caller',vname,getfield(ad.datastruct,names{i}));
                  else
                      out = setfield(out,vname,getfield(ad.datastruct,names{i}));
                  end
              end
          end
         case '2'
          % save by column name
          for i = 1:length(ad.datastruct.colheaders)
              if ad.destinationVariableList{2}.isSelected(i - 1)
                  vname = char(ad.destinationVariableList{2}.getName(i-1));
                  if ad.AssignInCaller
                      assignin('caller',vname,ad.datastruct.data(:,i))
                  else
                      out = setfield(out,vname,ad.datastruct.data(:,i));
                  end
              end
          end
         case '3'
          % save by row name
          for i = 1:length(ad.datastruct.rowheaders)
              if ad.destinationVariableList{3}.isSelected(i - 1)
                  vname = char(ad.destinationVariableList{3}.getName(i-1));
                  if ad.AssignInCaller
                      assignin('caller',vname,ad.datastruct.data(i,:))
                  else
                      out = setfield(out,vname,ad.datastruct.data(i,:));
                  end
              end
          end
         otherwise
          error('Internal error: Unknown radio button clicked on "How do you want to load your data panel"');
        end
    end

    if ad.AssignInCaller
        % tell user we're done
        disp(ad.CommandWindowMessage)
        
        % force workspace browser to refresh if using desktop
        if usejava('desktop'), workspace('-refresh'); end
        
        % flush app data if it's there
        if isappdata(0, 'MATLABImportWizardAppData');
            rmappdata(0, 'MATLABImportWizardAppData');
        end
    else    
        % bubble up result for parent function
        ad.data = out;

        locSetAppData(nargin, ad);
    end
catch
    warning(lasterr);
end

try
    closeWindow(ad.FrameHandle, ad.HGHandle);
end

if nargout, out = ad; end


function ad = doTextChanged(obj, evd, force)
try
    if nargin == 2
        % this call came from AWT - pause for tiny bit so it
        % can paint the character just typed
        pause(0.1);
    end

    ad = locGetAppData(nargin, obj);

    % get current app data and build new filename

    if ~isequal(ad.dataSourceGroup.getSelectedItem,ad.fileButton)
        ad.dataSourceGroup.setSelectedItem(ad.fileButton);

        ad = doSourceChanged(ad);
    end

    tf = ad.filenameTextfield;

    newName = char(tf.getText);

    if nargin ~= 3
        force = 0;
    end

    % return if contents of app data match text field
	if strcmp(ad.FileNameText, newName) & ~force
        return;
    end

    % on the PC it's imposible to have a file called foo. (note the trailing dot '.')
    % if filename changed by trailing . only, don't update
    if ispc & ~force & (strcmp([char(ad.FileNameText) '.'], newName) | strcmp(char(ad.FileNameText), [newName '.']))
        return;
    end

    % disable buttons
    ad.nextButton.setEnabled(0);
    ad.finishButton.setEnabled(0);

    % reset previews if name is empty
    if isempty(newName)
        setFilePreview(ad,'default');
        ad = setPreview(ad, 'source', []);
    end

    % update app data
    ad.FileType = '';
    ad.FileText = '';
    ad.FilePreview = '';

    % reset these to their defaults (could use another scheme to store defaults)
    ad.OTextDelimiter = NaN;
    ad.OHeaderLines = NaN;
    ad.ODataIndex = -1;

    % use locate to decide if filename is legit
    cleanName = locate(newName);

    if isempty(cleanName)
        % take one more crack at the file using reg-exp
        if ~isempty(findstr(newName,'*')) | ~isempty(findstr(newName,'?'))
            % use dir to find the files (let OS do matching)
            dirList = dir(newName);
            if ~isempty(dirList)
                cleanName = fullfile(fileparts(newName), dirList(1).name);
            end
        end
    end
        
    if isempty(cleanName)
        % no file was found, try to set path
        setFilePreview(ad,'default');
        ad = setPreview(ad, 'source', []);

        ad.FileName = '';
        if ~isempty(fileparts(newName))
            ad.PathName = fileparts(newName);
            setappdata(0,'MATLABImportWizardStartDir',ad.PathName);
        end
    elseif isdir(cleanName)
        % this is a dir, set path 
        setFilePreview(ad,'default');
        ad = setPreview(ad, 'source', []);

        ad.FileName = '';
        ad.PathName = cleanName;
        setappdata(0,'MATLABImportWizardStartDir',ad.PathName);
    else
        % update file name and path
        [ad.PathName, ad.FileName, ext] = fileparts(cleanName);
        setappdata(0,'MATLABImportWizardStartDir',ad.PathName);
        if ~isempty(ext)
            ad.FileName = [ad.FileName ext];
        end

        setFilePreview(ad,sprintf('\n\n\n\tLoading preview...'));
        ad = setPreview(ad, 'source', [], sprintf('Loading...'));

        ad.FrameHandle.setCursor(java.awt.Cursor.WAIT_CURSOR);

        drawnow     % let pending callback events get processed
        pause(0.1);

        [fileType, opencmd, loadcmd, descr] = finfo(fullfile(ad.PathName, ad.FileName));
        
        ad.FileType = fileType;
        ad.FilePreview = descr;

        if strcmpi(char(ad.FileType),'unknown')
            % preview string for text from finfo is the file
            % contents.  store only 1st meg for preview, shove
            % rest in FileText
            ad.FileText = ad.FilePreview;
        end

        FileName = fullfile(ad.PathName, ad.FileName);

        ismat = 0;
        ad.datastruct = [];
        if strcmp(fileType,'mat')
            try
                % check if this is a binary mat file
                ad.datastruct = load('-mat',FileName);
                ismat = 1;
                if isempty(fieldnames(ad.datastruct))
                    ad.datastruct = [];
                end
            catch
                % not a binary mat file - try using -ascii, this will
                % nearly allways work cuz importdata should be called
                % use try catch just in case
                try
                    ad.datastruct = load('-ascii',FileName);
                    ad.FilePreview = fileread(FileName);
                catch
                    if ad.ShowWarnings
                        warning(lasterr)
                    end
                    ad.datastruct = [];
                end
            end
        end
        if ~ismat & isempty(ad.datastruct)
            try
                % try importdata and get text delimiter if there
                [ad.datastruct, ad.OTextDelimiter, ad.OHeaderLines] = importdata(FileName);
            catch
                % unrecognized file format
                if ad.ShowWarnings
                    warning(lasterr)
                end
                ad.datastruct = [];
            end
        end

        if ismat & isempty(ad.datastruct)
            % empty mat file
            ad = setPreview(ad, 'source', 'Nothing to load. MAT-file is empty.');

            % update text preview (relies on app data)
            setFilePreview(ad, 'default');
        elseif isempty(ad.datastruct)
            % can't load file
            if isempty(loadcmd)
                msg = sprintf('Don''t know how to import this file.\n\n\tSee HELP FILEFORMATS.\n\n%s\n\nFile contains:\n\n%s', ...
                              strrep(lasterr,'\','/'), ad.FilePreview);
            else
                msg = sprintf('%s\n\nFile contains:\n\n%s', ...
                              strrep(lasterr,'\','/'), ad.FilePreview);
            end
            ad = setPreview(ad, 'source', msg);

            % update text preview (relies on app data)
            setFilePreview(ad, 'default');
        else
            if ~isstruct(ad.datastruct) | length(ad.datastruct) > 1
                [p,name] = fileparts(ad.FileName);
                s = struct(legalname(name), 1);
                s = setfield(s, legalname(name), ad.datastruct);
                ad.datastruct = s;
            end
            try
                ad = setPreview(ad, 'source', ad.datastruct);
            catch
                if (ad.ShowWarnings)
                    warning(lasterr)
                end
            end
            
            % if length if datastruct is > 1 or data is movie, image, or sound, enable finish not next
            if length(ad.datastruct) > 1 | ~isempty(getFileTypeFromExt(char(ad.FileType)))
                ad.finishButton.setEnabled(1);
            else
                ad.nextButton.setEnabled(1);
            end

            % update text preview (relies on app data)
            setFilePreview(ad);
        end

        ad.FrameHandle.setCursor(java.awt.Cursor.DEFAULT_CURSOR);
    end

    updatePreviewLabels(ad);

    ad.FileNameText = newName;

    locSetAppData(nargin, ad);
catch
    % refetch app data it was likely not updated
    ad = getappdata(0, 'MATLABImportWizardAppData');

    % update text preview (relies on app data)
    setFilePreview(ad, strrep(lasterr,'\','/'));
    ad = setPreview(ad, 'source', NaN); % nan forces reset (cute eh?)

    resetCursor
    
    % make card panel visible if it isn't
    if isstruct(ad) & ~isVisible(ad.cardPanel)
        ad.cardPanel.setVisible(1);
    end
end

function ad = doBrowse(obj, evd)
try
    prevdir = cd;
    ad = locGetAppData(nargin, obj);

    %  show file selection dialog
    cd(ad.PathName);
    [fn, pn] = uigetfile(importTypes, 'Import');
    cd(prevdir);
    
    if ~all(pn == 0) & ~all(fn == 0)
        ad.filenameTextfield.setText(fullfile(pn,fn))
        ad = doTextChanged(ad);
    end

    locSetAppData(nargin, ad);
catch
    warning(lasterr)
    cd(prevdir)
    % make card panel visible if it isn't
    if isstruct(ad) & ~isVisible(ad.cardPanel)
        ad.cardPanel.setVisible(1);
    end
end


function ad = doTextHeaderLinesChanged(obj, evd)
try
    ad = locGetAppData(nargin, obj);
    textValue = get(obj,'Text');
    if ~isempty(textValue)
        [val, count, msg] = sscanf(textValue, '%d');
        if isempty(msg)
            ad = panelUpdate(ad, 'delimitedOptions', ad.OTextDelimiter, val);
        end
    end
    locSetAppData(nargin, ad);
catch
    warning(lasterr)
    % make card panel visible if it isn't
    if isstruct(ad) & ~isVisible(ad.cardPanel)
        ad.cardPanel.setVisible(1);
    end
end


function ad = doTextDelimiterChanged(obj, evd)
try
    ad = locGetAppData(nargin, obj);

    % if callback came from text field, make sure other button is selected
    if isequal(get(obj,'Type'), 'com.mathworks.mwt.MWTextField')
        if ~isempty(get(obj,'Text'))
            if ~strcmp(char(ad.textDelimiterGroup.getSelectedItem.getName), '5')
                ad.textDelimiterGroup.setSelectedItem(ad.otherButton);
            end
        end
    end

    % act based on radio buton clicked
    switch char(ad.textDelimiterGroup.getSelectedItem.getName)
     case '1', ad = panelUpdate(ad, 'delimitedOptions',',');
     case '2', ad = panelUpdate(ad, 'delimitedOptions',' ');
     case '3', ad = panelUpdate(ad, 'delimitedOptions',';');
     case '4', ad = panelUpdate(ad, 'delimitedOptions',sprintf('\t'));
     case '5', ad = panelUpdate(ad, 'delimitedOptions',char(ad.otherDelimiter.getText));
     otherwise,   error('Internal error: Unknonwn radio button clicked on "What column separator does your data use" panel')
    end
    locSetAppData(nargin, ad);
catch
    warning(lasterr)
    % make card panel visible if it isn't
    if isstruct(ad) & ~isVisible(ad.cardPanel)
        ad.cardPanel.setVisible(1);
    end
end

function ad = doSelectedVariableStateChanged(obj, evd)
try
    ad = locGetAppData(nargin, obj);

    % a checkbox changed, if none are selected, shut off finish and show warning dlg

    % fetch callback data
    cbdata = get(obj,'ValueChangedCallbackData');

    % get name of selected load option (a number from 1 - 4)
    requestedName  = char(ad.destinationLoadOptionsGroup.getSelectedItem.getName);
    requestedIndex = str2double(requestedName);
    rowIndex  = cbdata.row + 1;

    % fetch value of checkbox that was clicked & update SelectedVariables
    %  isSelected uses zero based indexing
    flags = ad.SelectedVariableIndexes{requestedIndex};
    flags(1, rowIndex) = ad.destinationVariableList{requestedIndex}.isSelected(rowIndex - 1);
    ad.SelectedVariableIndexes{requestedIndex} = flags;

    updateFinishButtonState(ad, requestedIndex);

    locSetAppData(nargin, ad);
catch
    warning(lasterr)
    % make card panel visible if it isn't
    if isstruct(ad) & ~isVisible(ad.cardPanel)
        ad.cardPanel.setVisible(1);
    end
end

function ad = doSelectedSourceVariableChanged(obj, evd)
try
    ad = locGetAppData(nargin, obj);

    % a variable was clicked in the variable list

    variableIndex  = ad.sourceMATPreview.getSelectedIndex + 1;
    names = fieldnames(ad.datastruct);
    ad = setPreview(ad, 'source', getfield(ad.datastruct, names{variableIndex}));

    locSetAppData(nargin, ad);
catch
    warning(lasterr)
    % make card panel visible if it isn't
    if isstruct(ad) & ~isVisible(ad.cardPanel)
        ad.cardPanel.setVisible(1);
    end
end

function ad = doSelectedVariableChanged(obj, evd)
try
    ad = locGetAppData(nargin, obj);

    % a variable was clicked in the variable list
    ad = updateDestinationPreview(ad);

    locSetAppData(nargin, ad);
catch
    warning(lasterr)
    % make card panel visible if it isn't
    if isstruct(ad) & ~isVisible(ad.cardPanel)
        ad.cardPanel.setVisible(1);
    end
end

function ad = doLoadOptionsChanged(obj, evd)
try
    ad = locGetAppData(nargin, obj);

    % a radio button was clicked on the destination panel
    ad = updateDestinationPreview(ad);

    locSetAppData(nargin, ad);
catch
    warning(lasterr)
    % make card panel visible if it isn't
    if isstruct(ad) & ~isVisible(ad.cardPanel)
        ad.cardPanel.setVisible(1);
    end
end

%%
%% callback support functions
%%
function resetCursor
try
    % let this fail quietly
    ad = locGetAppData(2);
    ad.FrameHandle.setCursor(java.awt.Cursor.DEFAULT_CURSOR);
end

function ad = locGetAppData(n, obj)
if nargin ~= 0 & n == 1
    ad = obj;
else
    ad = getappdata(0, 'MATLABImportWizardAppData');
end

function ad = locSetAppData(n, ad)
% only set app data if this call came from a callback
if n == 2
    setappdata(0, 'MATLABImportWizardAppData', ad);
end

function updateFinishButtonState(ad, requestedIndex)

% setup may not be finished
if ~isfield(ad,'SelectedVariableIndexes')
    return;
end

% are any selected?
flags = ad.SelectedVariableIndexes{requestedIndex};
if ~any(flags(1,:))
    % put tool tip over finish button
    ad.finishToolTip.setText('Select one or more variables to enable Finish');
    
    % disable finish
    ad.finishButton.setEnabled(0);
else
    % put tool tip over finish button
    ad.finishToolTip.setText(ad.FinishToolTipDefaultString);

    % enable finish
    ad.finishButton.setEnabled(1);
end

function closeWindow(frame, h)
% clear lock on this file
munlock

if ~isempty(frame)
    frame.dispose;
end
if ishandle(h)
    delete(h)
end

function ad = panelUpdate(ad, varargin)
% do post creation stuff

panelName = varargin{1};
panelName = char(panelName);

switch panelName
 case 'sourceSelector' % do nothing
 case 'delimitedOptions',
  if nargin == 4
      headerLines = varargin{3};
  else
      headerLines = ad.OHeaderLines;
      if ~strcmp(char(ad.headerLines.getText), char(ad.OHeaderLines))
          ad.headerLines.setText(num2str(ad.OHeaderLines));
      end
  end
  
  if nargin == 3
      % the user may have clicked the same delimiter twice,
      % avoid double updates
      dlm = char(varargin{2});
  else
      dlm = char(ad.OTextDelimiter);
  end

  % make sure file preview matches file preview on 1st panel
  if ~strcmp(char(ad.delimitedFilePreview.getText), char(ad.sourceFilePreview.getText))
      ad.delimitedFilePreview.setText(char(ad.sourceFilePreview.getText));
      ad.delimitedFilePreview.getView.setHScrollAmount(0);
  end

  % update datastruct if delimiter or headerlines changed
  if  ~strcmp(char(ad.OTextDelimiter), dlm) | ~isequal(char(ad.OHeaderLines), char(headerLines))
      ad.FrameHandle.setCursor(java.awt.Cursor.WAIT_CURSOR);

      drawnow     % let pending callback events get processed
      pause(0.1);

      % disable next until something gets loaded
      ad.nextButton.setEnabled(0);

      % try to load the data
      ad.datastruct = [];
      try
          % do appropriate filename stuff
          if strcmp(char(ad.Source),'Clipboard')
              % do clipboard stuff
              FileName = 'clipboarddata';
              [ad.datastruct, dlm, headerLines] = importdata('-pastespecial', dlm, headerLines);
          else
              % parse string to get datastruct and delim
              FileName = fullfile(ad.PathName, ad.FileName);
              [ad.datastruct, dlm, headerLines] = importdata(FileName, dlm, headerLines);
          end
      catch
          if ad.ShowWarnings
              warning(lasterr)
          end
      end
      
      if ~isempty(ad.datastruct) & ~isstruct(ad.datastruct)
          [p,name] = fileparts(FileName);
          s = struct(legalname(name), 1);
          s = setfield(s, legalname(name), ad.datastruct);
          ad.datastruct = s;
      end
      
      % importdata returns nan for files without delimter
      if isnan(dlm) | isempty(dlm)
          dlm = '';
      end

      ad.OTextDelimiter = dlm;
      ad.OHeaderLines = headerLines;

      ad.FrameHandle.setCursor(java.awt.Cursor.DEFAULT_CURSOR);

      drawnow     % let pending callback events get processed

  end

  % update column separator
  obj = ad.textDelimiterGroup;
  if isequal(obj.getSelectedItem, ad.otherButton) & strcmp(char(ad.otherDelimiter.getText),dlm)
      % don't modify the radio button
  else
      switch dlm
       case ',',
        if ~isequal(obj.getSelectedItem, ad.commaButton),     obj.setSelectedItem(ad.commaButton),     end
       case ' ',
        if ~isequal(obj.getSelectedItem, ad.spaceButton),     obj.setSelectedItem(ad.spaceButton),     end
       case ';', 
        if ~isequal(obj.getSelectedItem, ad.semiColonButton), obj.setSelectedItem(ad.semiColonButton), end
       case sprintf('\t'),
        if ~isequal(obj.getSelectedItem, ad.tabButton),       obj.setSelectedItem(ad.tabButton),       end
       otherwise,
        if ~isequal(obj.getSelectedItem, ad.otherButton),     obj.setSelectedItem(ad.otherButton),     end
        if ~strcmp(char(ad.otherDelimiter.getText),dlm), ad.otherDelimiter.setText(dlm), end
      end
  end

  if isempty(ad.datastruct)
      % datastruct is empty, show error message
      dlmError = sprintf('Can''t find data using that delimiter.\nPlease specify a different one or\nchange the number of text header lines.');

      ad = setPreview(ad, 'delimited', sprintf('%s\n\n%s',dlmError, strrep(lasterr,'\','/')));
  else
      % datastruct is not empty, delimiter is OK
      ad = setPreview(ad, 'delimited', ad.datastruct);

      % OK to enable next
      ad.nextButton.setEnabled(1);
  end
  
 case 'destinationOptions',
  
  % ensure that the datastruct is length 1 (should be handled above)
  if length(ad.datastruct) > 1
      if ad.ShowWarnings
          warning('Internal error handling data length > 1');
      end
      ad=doBack(ad);
      ad.nextButton.setEnabled(0);
      ad.finishButton.setEnabled(1);
      return;
  end
          
  % handle buttons
  ad.finishButton.setEnabled(0);
  ad.nextButton.setEnabled(0);

  % reset variable lists
  for i = 1:3
      ad.destinationVariableList{i}.removeAllItems;
  end

  % set destination options selections to default and call update
  ad.destinationLoadOptionsGroup.setSelectedItem(ad.numbersOnlyButton);
  ad = updateDestinationPreview(ad);
  
  % setup storage for selected variables and initial state
  ad.SelectedVariableIndexes{1} = ones(1,length(fieldnames(ad.datastruct)));
  ad.ODataIndex = NaN;
  
  % update buttons for load options
  ad.numbersByColName.setEnabled(0);
  ad.numbersByRowName.setEnabled(0);
  if isfield(ad.datastruct, 'data')
      if isfield(ad.datastruct, 'colheaders') & ~isempty(ad.datastruct.colheaders)
          ad.numbersByColName.setEnabled(1);
          ad.SelectedVariableIndexes{2} = ones(1,length(ad.datastruct.colheaders));
      end
      if isfield(ad.datastruct, 'rowheaders') & ~isempty(ad.datastruct.rowheaders)
          ad.numbersByRowName.setEnabled(1);
          ad.SelectedVariableIndexes{3} = ones(1,length(ad.datastruct.rowheaders));
      end
  end

  % finish should be OK now
  ad.finishButton.setEnabled(1);
otherwise % do nothing
end

function ad = updateDestinationPreview(ad)

%
% check if update is necessary
%
% decide what view to show based on radio button selected
%
% update the requested view
%
%   fill variable list (if empty)
%
%   show preview of selected variable
%

% only do this if radio button was clicked or we are initializing
% initializing whenever first destinationVariableList is empty

requestedName  = char(ad.destinationLoadOptionsGroup.getSelectedItem.getName);
variableCount  = ad.destinationVariableList{str2double(requestedName)}.getItemCount;
currentIndex   = ad.destinationListCardPanel.getSelectedIndex;
currentName    = char(ad.destinationListCardPanel.getPanelName(currentIndex));
variableIndex  = ad.destinationVariableList{str2double(requestedName)}.getSelectedIndex + 1;

if (variableCount == 0 | ...                              % initalizing
    ~strcmp(requestedName, currentName) | ...             % radio button clicked
    (variableIndex > 0 & variableIndex ~= ad.ODataIndex)) % new var clicked

    % make sure right panel is in front
    if ~strcmp(requestedName, currentName)
        ad.destinationListCardPanel.selectPanel(requestedName);
    end

    % fill variable list if empty
    if variableCount == 0
        ad = fillVariableList(ad, requestedName);
    end

    % do variableSelection if panel changed or variable changed
    if ~strcmp(requestedName, currentName) | variableIndex ~= ad.ODataIndex
        % variableIndex is -1 whenever variablelist started out empty
        if variableIndex < 0;
            setappdata(0, 'MATLABImportWizardAppData', ad);
            ad.destinationVariableList{str2double(requestedName)}.setSelectedIndex(0);
            variableIndex = 1;
        end

        ad.ODataIndex = variableIndex;
        
        ad = fillPreviewTable(ad, requestedName, variableIndex);
    end
end

% make sure finish button is current
updateFinishButtonState(ad, str2double(requestedName));

function ad = fillVariableList(ad, requestedName)
% datastruct defaults to length 1 for text files
% mat, sound, and im files could produce more

requestedName = char(requestedName);

if isempty(ad.datastruct)
    warning('Internal error: Empty datastruct.  Click back and try again.');
    return;
end

requestedName = str2double(requestedName);
switch requestedName
 case 1
  % numbers as they appear in file
  varNames = fieldnames(ad.datastruct);
  len = length(varNames);
  if len > 32
      quietWarning(sprintf('\nOnly importing first 32 variables.  Use IMPORTDATA to fetch all variables.'));
      len = 32;
  end
  for i = 1:len
      tempVars{i}  = getfield(ad.datastruct, varNames{i});
  end
 case 2
  % vectors using col name
  varNames = ad.datastruct.colheaders;
  len = length(varNames);
  if len > 32
      quietWarning(sprintf('\nOnly importing first 32 variables.  Use IMPORTDATA to fetch all variables.'));
      len = 32;
  end
  for i = 1:len
      tempVars{i} = ad.datastruct.data(:,i);
  end
 case 3
  % vectors using row name
  varNames = ad.datastruct.rowheaders;
  len = length(varNames);
  if len > 32
      quietWarning(sprintf('\nOnly importing first 32 variables.  Use IMPORTDATA to fetch all variables.'));
      len = 32;
  end
  for i = 1:len
      tempVars{i} = ad.datastruct.data(i,:);
  end
 otherwise
  error('Internal error: Unknown name passed to fillVariableList')
end

if isempty(varNames)
    errordlg(sprintf('Internal error fetching variables from file "%s".  Please contact The MathWorks with a description of how to reproduce this problem.', ad.FileName));
    doCancel;
    error(' ');
end

for i = 1:len
    % it's OK for MAT files to have empty variables
    if strcmp(char(ad.FileType),'mat') | ~isempty(tempVars{i})
        tempVar  = tempVars{i};
        s = whos('tempVar');
        varSize  = s.size;
        varBytes = s.bytes;
        varClass = s.class;
        varDims  = ndims(tempVar);
        
        % get image for cell 1
        try
            img = javaMethod('getIcon', 'com.mathworks.ide.workspace.VariableTreeView', ...
                              legalname(varNames{i}), varClass);
            if isempty(img)
                error('Internal error: getIcon failed');
            end
        catch
            img = legalname(varNames{i});
        end

        % shove info into variable list
        ad.destinationVariableList{requestedName}.addItem(...
            img, varSize, varBytes, varClass, varDims);
    end
end

if ad.destinationVariableList{requestedName}.getItemCount == 0
    % something went awry.  the list should _always_ get populated
    % just to keep things from getting worse, put a little litter
    % in the variable list
    [p, varName]  = fileparts(ad.FileName);
    varSize  = [0,0];
    varBytes = 0;
    varClass = 'double';
    varDims  = 2;

    img = javaMethod('getIcon', 'com.mathworks.ide.workspace.VariableTreeView', ...
                      legalname(varName), varClass);
    ad.destinationVariableList{requestedName}.addItem(...
            img, varSize, varBytes, varClass, varDims);
end
    

ad.destinationVariableList{requestedName}.setSelectedIndex(0);

function ad = fillPreviewTable(ad, requestedName, variableIndex)
% do preview
switch char(requestedName)
 case '1',
  % show data only
  varNames = fieldnames(ad.datastruct);
  ad = setPreview(ad, 'destination', getfield(ad.datastruct, varNames{variableIndex}));
 case '2',
  % show data for current variable index - slice off Nth column
  ad = setPreview(ad, 'destination', ad.datastruct.data(:,variableIndex));
 case '3',
  % show data for current variable index - slice off Nth row
  ad = setPreview(ad, 'destination', ad.datastruct.data(variableIndex,:));
 otherwise,
  error('Internal error: Unknown name passed to fillPreviewTable');
end

function ad = setPreview(ad, panel, data, tabLabel)
persistent lastdata
persistent inHere

panel = char(panel);

% allow callers to force a reset of the preview, good for when callback
% throws an error and the catch block needs to flush partial preview
if nargin > 2 & ~isstruct(data) & strcmp(class(data),'double') & isnan(data)
    force = 1;
    data = [];
else
    force = 0;
end

% a nifty pseudo 'synchronized' hook
if ~isempty(inHere) & ~force
    % use dbstack to show where the 2nd call is coming from
    % dbstack
    return
end

% a hook to allow clearing persistent data
if nargin == 2
    lastdata = [];
    ad.sourceSheetPreviewLabel{1}.setText('');
    return;
end

if isempty(lastdata) & nargin == 3
    % this is the first call to this function, setup last data
    lastdata = setfield(lastdata, panel, data);
    if isempty(data) & ~force
        return;
    end
elseif isfield(lastdata,panel) & isequal(getfield(lastdata,panel), data) & ...
        nargin == 3 & ~force
    return
end

% special case for destination panel
if strcmp(panel, 'destination')
    setPreviewDataSub(ad, panel, data, 1);

    % make card panel visible if it isn't
    if ~isVisible(ad.cardPanel)
        ad.cardPanel.setVisible(1);
    end

    return
end

% pseudo synchronous
inHere = 1;

if ~isstruct(data) & ~isempty(data) & ~ischar(data)
    try,  disp(data(1:10)), end
    error('Internal error: setPreview doesn''t recognize inputs.');
end

% decide which title to use
if nargin == 3
    tabLabel = sprintf('[no data]');
else
    tabLabel=char(tabLabel);
end

i = 1;
j = 0;

if isempty(data) | ischar(data)
    tab = getfield(ad,[panel 'PreviewTabPanel']);
    tidx = getfield(ad,[panel 'TabIndexes']);

    if (tab.getPanelCount ~= 1 | ~strcmp(char(tab.getPanelNameID(tidx{i})), tabLabel))
        ad.cardPanel.setVisible(0);
        ad = removeAllPreviewPanels(ad,panel);
        ad = buildPreviewPanel(ad, panel, i, tabLabel);
    end

    % update app data in case setpreview chokes
    setappdata(0, 'MATLABImportWizardAppData', ad);
    
    if ischar(data)
        setPreviewTextSub(ad, panel, data, i);
    else
        setPreviewDataSub(ad, panel, data, i)
    end
else
    ad.cardPanel.setVisible(0);
    ad = removeAllPreviewPanels(ad,panel);

    tab = getfield(ad,[panel 'PreviewTabPanel']);

    switch getFileTypeFromExt(char(ad.FileType))
     case 'movie'
        % if this is an avi, show a panel for preview
        j = j + 1;
        ad = buildPreviewPanel(ad, panel, j, sprintf('Movie Preview'), 'movie');
    
     case 'image'
        % if this is an image, show a panel for preview
        j = j + 1;
        ad = buildPreviewPanel(ad, panel, j, sprintf('Image Preview'), 'image');

     case 'sound'
        % if this is a sound, show a panel for preview
        j = j + 1;
        ad = buildPreviewPanel(ad, panel, j, sprintf('Sound Preview'), 'sound');
    end

    names = fieldnames(data);
    len = length(names);
    if len > 32
        quietWarning([10 'Only importing first 32 variables.  Use IMPORTDATA to fetch all variables.']);
        len = 32;
    end
    
    for i = 1:len
        ad = buildPreviewPanel(ad, panel, i + j, names{i});

        % update app data in case setpreview chokes
        setappdata(0, 'MATLABImportWizardAppData', ad);
        
        try
            setPreviewDataSub(ad, panel, getfield(data, names{i}), i + j)
        catch
            setPreviewTextSub(ad, panel, lasterr, i + j)
        end
    end

end

% add dummy panel then remove to force an update
ad = buildPreviewPanel(ad, panel, i + j + 1, tabLabel);
ad = removePreviewPanel(ad, panel, i + j + 1);

% get name based on selected index and set focus
currentPanel = char(ad.cardPanel.getPanelName(ad.cardPanel.getSelectedIndex));
if strcmp(currentPanel, 'sourceSelector')
    ad.filenameTextfield.requestFocus;
elseif strcmp(currentPanel, 'delimitedOptions')
    ad.otherDelimiter.requestFocus;
end

% make card panel visible if it isn't
if ~isVisible(ad.cardPanel)
    ad.cardPanel.setVisible(1);
end

% make sure tab0 is visible
if tab.getSelectedIndex ~= 0
    tab.selectPanel(0);
end

% store this to prevent multiple updates
if isempty(lastdata)
    lastdata.JUNK__ = 1;
end

lastdata = setfield(lastdata, panel, data);

if isfield(lastdata, 'JUNK__')
    lastdata = rmfield(lastdata, 'JUNK__');
end

inHere = [];

function setPreviewDataSub(ad, panel, data, i)
% hide card panel to prevent flashing
ad.cardPanel.setVisible(0);

% truncate non strings
try
    className = class(data);
catch
    className = 'unknown';
    if ad.ShowWarnings
        warning(lasterr)
    end
end

% truncate to 10x10x1
l1 = getfield(ad,[panel 'SheetPreviewLabel']);

if ndims(data) > 2
    [m,n] = size(data(:,:,1));
else
    [m,n] = size(data(:,:));
end

if ~issparse(data) & ~strcmp(className,'char') & (m > 10 | n > 10 | ndims(data) > 2)
    if ndims(data) > 2
        l1{i}.setText(sprintf('Preview truncated to 10x10 - 1st dimension'));
    else
        l1{i}.setText(sprintf('Preview truncated to 10x10'));
    end
    m = min(m,10);
    n = min(n,10);
    data = data(1:m,1:n,1);
else
    l1{i}.setText('');
end

cp = getfield(ad,[panel 'PreviewCardPanel']);
sp = getfield(ad,[panel 'SheetPreview']);

% set up the data
if (~issparse(data) & ...
    (ischar(data) | (iscell(data) & all(cellfun('isclass',data,'char'))) | isnumeric(data) | ...
    (iscell(data) & all( cellfun('isclass',data,'char') |  cellfun('isclass',data,'double') |  ...
                         cellfun('isclass',data,'int8') | cellfun('isclass',data,'uint8') | ...
                         cellfun('isclass',data,'int16') | cellfun('isclass',data,'uint16') | ...
                         cellfun('isclass',data,'int32') | cellfun('isclass',data,'uint32') )) ) )

    if ischar(data) | (iscell(data) & all(cellfun('isclass',data,'char')))
        if ischar(data)
            % nicely handle multi row char arrays
            data = cellstr(data);
        end
        sp{i}.setStringData(data);
    else
        cellData   = cell(size(data));
        isCharData = zeros(size(data));
        for ii = 1:size(data,1)
            for jj = 1:size(data,2)
                if iscell(data) & ischar(data{ii,jj})
                    cellData{ii,jj} = data{ii,jj};
                    isCharData(ii,jj) = 1;
                else
                    if iscell(data(ii,jj))
                        value = data{ii,jj};
                        m = size(value);
                        if length(m) > 2 | any(m > 1)
                            szstr = sprintf('%dx', m);
                            szstr = szstr(1:end-1);
                            str = [szstr ' ' class(value)];
                        else
                            str = sdisp(double(value));
                        end
                    else
                        str = sdisp(double(data(ii,jj)));
                    end
                    cellData{ii,jj} = str;
                end
            end
        end
        % set mixed data looks at isCharData to decide which cells flush left vs right
        if any(isCharData)
            sp{i}.setMixedData(cellData, isCharData);
        else
            sp{i}.setNumericData(cellData);
        end
    end
    sp{i}.setFirstColumn(0);
    sp{i}.setFirstRow(0);

    if ~strcmp(char(cp{i}.getPanelName(cp{i}.getSelectedIndex)),'SheetPreview')
        cp{i}.selectPanel('SheetPreview');
    end

else
    switch className
     case 'sparse'
      str = 'Sparse preview not implemented.';
     
     case 'struct'
      names = fieldnames(data);
      str = sprintf('Struct with fields:\n\t%s', names{:});
      
     case 'cell'
      str = sprintf('Cell array with contents:\n');

      for ii = 1:size(data,1)
          l = sprintf('\t');
          for jj = 1:size(data,2)
              d = data{ii,jj};
              if ischar(d)
                  s = d;
              elseif isnumeric(d)
                  try
                      if ~strcmp(class(d),'double')
                          d = double(d);
                      end
                      s = sprintf('%d', d);
                  catch
                      s = class(d);
                  end
              else
                  s = class(d);
              end
              
              l = sprintf('%s\t%s',l,s);
          end
          str = sprintf('%s\n%s', str, l);
      end
     
     otherwise
      str = [className ' object'];
    
    end

    setPreviewTextSub(ad,panel,str,i);

end

function setPreviewTextSub(ad, panel, data, i)
cp = getfield(ad,[panel 'PreviewCardPanel']);
tp = getfield(ad,[panel 'TextPreview']);

cp = cp{i};
tp = tp{i};

if ~strcmp(char(cp.getPanelName(cp.getSelectedIndex)),'TextPreview')
    cp.selectPanel('TextPreview');
end

if ~strcmp(char(tp.getText),data)
    ad.cardPanel.setVisible(0);
    tp.setText(sprintf(data));
end

% always scroll to top
tp.getView.setHScrollAmount(0);

function setFilePreview(ad, str)
% get handle to text preview and set text to input arg

defaultString = sprintf('\n\n\n\tEnter name of file on MATLAB''s PATH\n\tor click browse.');
if nargin == 1 
    if isempty(ad.FilePreview)
        str = defaultString;
    else 
        str = ad.FilePreview;
    end
elseif nargin == 2
    if strcmp('default',str)
        str = defaultString;
    end
end

if ~ischar(str)
    str = evalc('disp(str)');
end

if length(str) > 1024 * 1024
    str = str(1:1024 * 1024);
end

if ~strcmp(char(ad.sourceFilePreview.getText), str)
    ad.sourceFilePreview.setText(str);
    ad.filenameTextfield.requestFocus;
    ad.sourceFilePreview.getView.setHScrollAmount(0);
end

%
% utility functions
%
function out = legalname(in)

% leading char must be alpha (constraint for structs)
if ~isalpha(in(1))
    in = ['A' in];
end
out = in;
if length(in) < 2
    return;
end
% subsequent chars must be alphanumeric or _
for i = 2:length(out)
    if ~isalpha(in(i)) & ~strcmp(in(i), '_') & ~isdigit(in(i))
        out(i) = '_';
    end
end

function out = isalpha(in)
out = (all(abs(in) >= abs('a')) & all(abs(in) <= abs('z'))) | ...
      (all(abs(in) >= abs('A')) & all(abs(in) <= abs('Z')));

function out = isdigit(in)
out = (all(abs(in) >= abs('0')) & all(abs(in) <= abs('9')));

function out = isdir(name)
% is given name a dir name
if isempty(name)
    out = logical(0);
else
    out = logical(exist(name,'dir') == 7);
end

function out = isqualified(filename)
%ISQUALIFIED Determine if filename has full path specified.
% check if the filename is fully qualified
%  if filename begins with / or \ or 2nd char is :, filename
%  it is fully qualified
out = logical(0);
if ~isempty(filename) & length(filename) > 0
    if ispc & length(filename) > 1 & filename(2) == ':'
        out = logical(1);
    elseif filename(1) == '/' | filename(1) == '\' 
        out = logical(1);
    end
end

function filename = locate(filename)
%LOCATE Find fully qualified path to specified file or dir.

% make sure file or dir exists
if isempty(filename) | exist(filename,'file') == 0
    filename = '';
    return;
end

% file or dir exists, create full file name if it's not qualified
if isqualified(filename)
    % given a full path, the user likely does not want an extension 
    % shoved onto the name for them.  make sure the exact name exists.
    fid = fopen(filename);
    if fid < 0
        filename = '';
        return;
    end
    fclose(fid);
else
    
    % find the full path to the file
    %% because of a "bug" in which, make sure the file (g63337)
    %% has an extention on it (e.g. add a '.' to the end if the file
    %% contains none
    origFilename = filename;
    filename = which(origFilename);
    if isempty(filename) & isempty(find(origFilename == '.'))
        % the filename has no extention - try to find it with a .
        filename = which([origFilename '.']);
    end
end

%%%
%%% panel functions
%%%
function [ad, pp] = sourceSelector(ad)

import java.awt.*;
import com.mathworks.mwt.*;

pp = MWPanel(BorderLayout(3,3));

% parent panel: pp ----------------------
% |top----------------------------------|
% || middle                            || NORTH
% ||-----------------------------------||
% |-------------------------------------|
% |ps-----------------------------------|
% ||             preview               || CENTER
% |-------------------------------------|
%

top = MWPanel(BorderLayout(0,0));

if strcmp(char(ad.inputArgs), '-pastespecial')
    message = MWLabel(sprintf(' Insert contents of clipboard into MATLAB''s workspace as one or more variables.'));
else
    message = MWLabel(sprintf(' Create variables in MATLAB''s workspace using contents of'));
end
message.setFont(Font(fontName, 0, fontSize));
top.add(message, BorderLayout.NORTH);


middle = MWPanel(BorderLayout(3,3));
%                        t, l, b, r
middle.setInsets(Insets(10, 5, 5, 5));

dataSource = MWExclusiveGroup;
ad.dataSourceGroup = dataSource;

% need to glom these three objects into one panel
% () File name: [        ] Browse
filenamePanel = MWPanel(BorderLayout(3,3));

fb = MWCheckbox(sprintf('File:'), 0, dataSource);
fb.setName('file')
fb.setAppearance(MWCheckbox.RADIO_BUTTON);
fb.setFont(Font(fontName, 0, fontSize));
ad.fileButton = fb;
filenamePanel.add(fb, BorderLayout.WEST);
set(fb,'ItemStateChangedCallback',{@doSourceChanged})
dataSource.setSelectedItem(fb);

tf = MWTextField(30);
tf.setFont(Font(fontName, 0, fontSize));
ad.filenameTextfield = tf;
set(tf, 'TextValueChangedCallback', {@doTextChanged});

filenamePanel.add(tf, BorderLayout.CENTER);

bb = MWButton(sprintf('Browse...'));
bb.setFont(Font(fontName, 0, fontSize));
set(bb, 'ActionPerformedCallback', {@doBrowse});
ad.browseButton = bb;

filenamePanel.add(bb, BorderLayout.EAST);

if ~strcmp(char(ad.inputArgs), '-pastespecial')
    middle.add(filenamePanel, BorderLayout.NORTH);
end

clipButton = MWCheckbox(sprintf('Clipboard.'), 0, dataSource);
clipButton.setName('clip')
clipButton.setAppearance(MWCheckbox.RADIO_BUTTON);
clipButton.setFont(Font(fontName, 0, fontSize));
ad.clipButton = clipButton;
middle.add(clipButton, BorderLayout.SOUTH);

set(clipButton,'ItemStateChangedCallback',{@doSourceChanged})

top.add(middle, BorderLayout.SOUTH);

pp.add(top, BorderLayout.NORTH);

[ad, ps] = sourceDataPreview(ad);

pp.add(ps, BorderLayout.CENTER);

function [ad, pp] = delimitedOptions(ad)

import java.awt.*;
import com.mathworks.mwt.*;

pp = MWPanel(BorderLayout(0,0));

% parent panel: pp ----------------------
% |top----------------------------------|
% || middle                            || NORTH
% ||-----------------------------------||
% |-------------------------------------|
% |ps-----------------------------------|
% ||             preview               || CENTER
% |-------------------------------------|
%

top = MWPanel(BorderLayout(0,0));

l1 = MWLabel(sprintf(' What column separator does your data use?'));
l1.setFont(Font(fontName, 0, fontSize));
%l1.setFont(Font(fontName, Font.BOLD, 14));

top.add(l1, BorderLayout.NORTH);

middle = MWPanel(BorderLayout(3,3));
%                        t, l, b, r
middle.setInsets(Insets(10, 5, 5, 5));

middleGB = MWGroupbox(sprintf('Column separator'), MWGroupbox.ETCHED);
middleGB.setFont(Font(fontName, 0, fontSize));
middleGB.setLayout(GridLayout(1,6,3,3));
%                          t, l, b, r
middleGB.setMargins(Insets(0, 3, 0, 3));

textDelimiter = MWExclusiveGroup;
ad.textDelimiterGroup = textDelimiter;

commaButton = MWCheckbox(sprintf('Comma'), 0, textDelimiter);
commaButton.setFont(Font(fontName, 0, fontSize));
commaButton.setName('1')
commaButton.setAppearance(MWCheckbox.RADIO_BUTTON);
middleGB.add(commaButton);
ad.commaButton = commaButton;
set(commaButton,'ItemStateChangedCallback',{@doTextDelimiterChanged})

spaceButton = MWCheckbox(sprintf('Space'), 0, textDelimiter);
spaceButton.setFont(Font(fontName, 0, fontSize));
spaceButton.setName('2')
spaceButton.setAppearance(MWCheckbox.RADIO_BUTTON);
middleGB.add(spaceButton);
ad.spaceButton = spaceButton;
set(spaceButton,'ItemStateChangedCallback',{@doTextDelimiterChanged})

semiColonButton = MWCheckbox(sprintf('Semicolon'), 0, textDelimiter);
semiColonButton.setFont(Font(fontName, 0, fontSize));
semiColonButton.setName('3')
semiColonButton.setAppearance(MWCheckbox.RADIO_BUTTON);
middleGB.add(semiColonButton);
ad.semiColonButton = semiColonButton;
set(semiColonButton,'ItemStateChangedCallback',{@doTextDelimiterChanged})

tabButton = MWCheckbox(sprintf('Tab'), 0, textDelimiter);
tabButton.setFont(Font(fontName, 0, fontSize));
tabButton.setName('4')
tabButton.setAppearance(MWCheckbox.RADIO_BUTTON);
middleGB.add(tabButton);
ad.tabButton = tabButton;
set(tabButton,'ItemStateChangedCallback',{@doTextDelimiterChanged})

p = MWPanel(BorderLayout);
otherButton = MWCheckbox(sprintf('Other'), 0, textDelimiter);
otherButton.setFont(Font(fontName, 0, fontSize));
otherButton.setName('5')
otherButton.setAppearance(MWCheckbox.RADIO_BUTTON);
p.add(otherButton, BorderLayout.WEST);
ad.otherButton = otherButton;
set(otherButton,'ItemStateChangedCallback',{@doTextDelimiterChanged})

otherDelimiter = MWTextField(3);
otherDelimiter.setFont(Font(fontName, 0, fontSize));
middleGB.add(otherDelimiter);
ad.otherDelimiter = otherDelimiter;
p.add(otherDelimiter, BorderLayout.EAST);
set(otherDelimiter,'TextValueChangedCallback',{@doTextDelimiterChanged})
middleGB.add(p);
                                                
% default to comma
textDelimiter.setSelectedItem(commaButton);

% shove groupbox in NORTH so it stretches full width
middle.add(middleGB, BorderLayout.CENTER);

pq = MWPanel(FlowLayout(FlowLayout.CENTER,3,3));
pq.setInsets(middleGB.getInsets);
l2 = MWLabel(sprintf('Text header lines:'));
l2.setFont(Font(fontName, 0, fontSize));
pq.add(l2);
headerLines = MWTextField(3);
headerLines.setFont(Font(fontName, 0, fontSize));
pq.add(headerLines);
headerLines.setText('0');
ad.headerLines = headerLines;
set(headerLines, 'TextValueChangedCallback',{@doTextHeaderLinesChanged});
middle.add(pq, BorderLayout.EAST);

top.add(middle, BorderLayout.SOUTH);

pp.add(top, BorderLayout.NORTH);

[ad, ps]  = delimitedDataPreview(ad);

pp.add(ps, BorderLayout.CENTER);


function [ad, pp] = destinationOptions(ad)

import java.awt.*;
import com.mathworks.mwt.*;

panel = 'destination';

pp = MWPanel(BorderLayout(0,0));

% parent panel: pp ----------------------
% |top----------------------------------|
% || middle                            || NORTH
% ||-----------------------------------||
% |-------------------------------------|
% |bot----------------------------------|
% ||    varList     |     preview      || CENTER
% |-------------------------------------|
%
top = MWPanel(BorderLayout(0,0));

l1 = MWLabel(sprintf(' Select variables to import using checkboxes.'));
l1.setFont(Font(fontName, 0, fontSize));

top.add(l1, BorderLayout.NORTH);

middle = MWPanel(GridLayout(0,1));
%                        t, l, b, r
middle.setInsets(Insets(10, 5, 5, 5));

ex = MWExclusiveGroup;
ad.destinationLoadOptionsGroup = ex;

% card panel with various variable combinations
vl = MWCardPanel;
vl.setMargins(Insets(0,0,0,0));
vl.setStyle(MWCardPanel.NONE);
ad.destinationListCardPanel = vl;

numbersOnlyButton = MWCheckbox(sprintf('Create variables matching preview.'),ex,1);
numbersOnlyButton.setName('1');
numbersOnlyButton.setFont(Font(fontName, 0, fontSize));
middle.add(numbersOnlyButton);
ad.numbersOnlyButton = numbersOnlyButton;
set(numbersOnlyButton,'ItemStateChangedCallback',{@doLoadOptionsChanged})

variableList = com.mathworks.page.dataread.ScrollingList;
variableList.setFont(Font(fontName, 0, fontSize));
opts = variableList.getColumnOptions;
opts.setResizable(1);
variableList.setMinAutoExpandColumnWidth(30);
vl.addPanel('1', variableList);
ad.destinationVariableList{1} = variableList;
set(variableList,'ItemStateChangedCallback',{@doSelectedVariableChanged})
set(variableList,'ValueChangedCallback',{@doSelectedVariableStateChanged})

numbersByColName =  MWCheckbox(sprintf('Create vectors from each column using column names.'),ex,0);
numbersByColName.setFont(Font(fontName, 0, fontSize));
numbersByColName.setName('2');
numbersByColName.setEnabled(0);
middle.add(numbersByColName);
ad.numbersByColName = numbersByColName;
set(numbersByColName,'ItemStateChangedCallback',{@doLoadOptionsChanged})

variableList = com.mathworks.page.dataread.ScrollingList;
opts = variableList.getColumnOptions;
opts.setResizable(1);
variableList.setMinAutoExpandColumnWidth(30);
variableList.setFont(Font(fontName, 0, fontSize));
vl.addPanel('2', variableList);
ad.destinationVariableList{2} = variableList;
set(variableList,'ItemStateChangedCallback',{@doSelectedVariableChanged})
set(variableList,'ValueChangedCallback',{@doSelectedVariableStateChanged})

numbersByRowName =  MWCheckbox(sprintf('Create vectors from each row using row names.'),ex,0);
numbersByRowName.setFont(Font(fontName, 0, fontSize));
numbersByRowName.setName('3');
numbersByRowName.setEnabled(0);
middle.add(numbersByRowName);
ad.numbersByRowName = numbersByRowName;
set(numbersByRowName,'ItemStateChangedCallback',{@doLoadOptionsChanged})

top.add(middle, BorderLayout.CENTER);
pp.add(top, BorderLayout.NORTH);

bot = MWPanel(BorderLayout(3,3));

l2 = MWLabel('');
l2.setFont(Font(fontName, 0, fontSize));
ad.destinationPreviewLabel = l2;
bot.add(l2, BorderLayout.NORTH);

updatePreviewLabels(ad);

variableList = com.mathworks.page.dataread.ScrollingList;
variableList.setFont(Font(fontName, 0, fontSize));
opts = variableList.getColumnOptions;
opts.setResizable(1);
variableList.setMinAutoExpandColumnWidth(30);
vl.addPanel('3', variableList);
ad.destinationVariableList{3} = variableList;
set(variableList,'ItemStateChangedCallback',{@doSelectedVariableChanged})
set(variableList,'ValueChangedCallback',{@doSelectedVariableStateChanged})

% card panel with sheet and text previewers (no tab panel for this one)
ad = buildPreviewPanel(ad, panel);
cp = ad.destinationPreviewCardPanel{1};

mws = MWSplitter(vl, cp, MWSplitter.VERTICAL_SPLITTER);
bot.add(mws, BorderLayout.CENTER)

pp.add(bot, BorderLayout.CENTER);

% put tooltip on finish button
ad.finishToolTip = com.mathworks.mwt.MWToolTip(ad.finishButton, ...
                                               ad.FinishToolTipDefaultString, ...
                                               0, -50, 0, 0);

function [ad, bot] = sourceDataPreview(ad)
[ad, bot] = buildDataPreview(ad, 'source');

function [ad, bot] = delimitedDataPreview(ad)
[ad, bot] = buildDataPreview(ad, 'delimited');

function [ad, bot] = buildDataPreview(ad, panel)

import java.awt.*;
import com.mathworks.mwt.*;

% bottom panel - data preview
bot = MWPanel(BorderLayout(3,3));
bot.setInsets(Insets(3,3,3,3));

l1 = MWLabel('');
l1.setFont(Font(fontName, 0, fontSize));
ad = setfield(ad, [panel 'PreviewLabel'], l1);
bot.add(l1, BorderLayout.NORTH);

updatePreviewLabels(ad);

% text preview of file
fp = MWTextArea;
fp.setFont(Font(fontName, 0, fontSize));
fp.setEditable(0);
fp.setFont(Font(get(0,'fixedwidthfontname'), 0, fontSize));
ad = setfield(ad, [panel 'FilePreview'], fp);

% card panel with sheet & text previews
ad = buildPreviewPanel(ad, panel, 1, sprintf('[no data]'));
tp = getfield(ad, [panel 'PreviewTabPanel']);

mws = MWSplitter(fp, tp, MWSplitter.VERTICAL_SPLITTER);
bot.add(mws, BorderLayout.CENTER)

function updatePreviewLabels(ad)
if isequal(ad.Source, 'File')
    if ~isempty(ad.FileName) & ~isempty(ad.PathName)
        nam = strrep(fullfile(ad.PathName, ad.FileName),'\','/');
        str = sprintf('Preview of %s',nam);
        ad.FrameHandle.setTitle(sprintf('%s: %s', ad.DefaultTitle, nam));
    else
	nam='';
        str = 'Data preview';
        ad.FrameHandle.setTitle(ad.DefaultTitle);
    end
else % clipboard
    nam = 'clipboard';
    str = 'Clipboard preview';
end
panels = {'source','delimited','destination'};
for i=1:length(panels)
    panel = panels{i};
    if isfield(ad, [panel 'PreviewLabel'])
        l2 = getfield(ad, [panel 'PreviewLabel']);
        if strcmp(panel,'destination')
            l2.setText(sprintf('Variables in %s', nam));
        else
            l2.setText(sprintf(str));
        end	
    end
end

function ad = buildPreviewPanel(ad, panel, i, name, fileType)

import java.awt.*;
import com.mathworks.mwt.*;

panel = char(panel);

if nargin == 5
    % this is a call to build a panel with a nifty preview button
    showPreviewButton = 1;
else
    showPreviewButton = 0;
end

if nargin >= 4
    if isfield(ad,[panel 'PreviewTabPanel'])
        tab = getfield(ad,[panel 'PreviewTabPanel']);
    else
        tab = MWTabPanel(MWTabPanel.TOP);
        tab.setStyle(tab.DOCUMENT_OVERLAP);
        tab.setScrollable(1);
        tab.setFont(Font(fontName, 0, fontSize));
        ad = setfield(ad,[panel 'PreviewTabPanel'],tab);
    end
else
    i = 1;
end

% create card panel
cardPanel = MWCardPanel;
cardPanel.setMargins(Insets(0,0,0,0));
cardPanel.setStyle(MWCardPanel.NONE);

% add to app data
if isfield(ad,[panel 'PreviewCardPanel'])
    pcp = getfield(ad,[panel 'PreviewCardPanel']);
end

pcp{i} = cardPanel;
ad = setfield(ad,[panel 'PreviewCardPanel'],pcp);

% create sheet preview
spPanel = MWPanel(BorderLayout(5,5));
l1 = MWLabel('Preview', MWLabel.CENTER);
l1.setFont(Font(fontName, 0, fontSize));
spPanel.add(l1, BorderLayout.NORTH);
if isfield(ad,[panel 'SheetPreviewLabel'])
    labels = getfield(ad,[panel 'SheetPreviewLabel']);
end
labels{i} = l1;
ad = setfield(ad,[panel 'SheetPreviewLabel'], labels);
sheetPreview = com.mathworks.page.dataread.DataTable;
sheetPreview.setFont(Font(fontName, 0, fontSize));
style = sheetPreview.getTableStyle;
style.setEditable(0);
opts = sheetPreview.getSelectionOptions;
opts.setMode(0);
opts = sheetPreview.getColumnOptions;
opts.setResizable(1);
sheetPreview.setMinAutoExpandColumnWidth(30);
spPanel.add(sheetPreview, BorderLayout.CENTER);
% add to card panel
cardPanel.addPanel('SheetPreview', spPanel);

% add to app data
if isfield(ad,[panel 'SheetPreview']);
    psp = getfield(ad,[panel 'SheetPreview']);
end
psp{i} = sheetPreview;
ad = setfield(ad,[panel 'SheetPreview'],psp);

% create text preview
textPreview = MWTextArea;
textPreview.setFont(Font(fontName, 0, fontSize));
textPreview.setEditable(0);
textPreview.setFont(Font(get(0,'fixedwidthfontname'), 0, fontSize));
% add to card panel
cardPanel.addPanel('TextPreview', textPreview);

% add to app data
if isfield(ad,[panel 'TextPreview'])
    ptp = getfield(ad,[panel 'TextPreview']);
end
ptp{i} = textPreview;
ad = setfield(ad,[panel 'TextPreview'],ptp);

if showPreviewButton
    % defaults
    switch char(fileType)
     case 'image'
      s  = sprintf('Show Image');
      cb = sprintf('imageview(''%s'');', fullfile(ad.PathName, ad.FileName));
     case 'sound'
      s  = sprintf('Play Sound');
      cb = sprintf('soundview(''%s'');', fullfile(ad.PathName, ad.FileName));
     case 'movie'
      s  = sprintf('Play Movie');
      cb = sprintf('movieview(''%s'');', fullfile(ad.PathName, ad.FileName));
     otherwise
      error('Internal error: Unknown type passed to buildPreviewPanel')
    end
                    
    otherPreview = MWPanel;
    b = MWButton(s);
    b.setFont(Font(fontName, 0, fontSize));
    ad.otherPreviewButton = b;
    set(b,'ActionPerformedCallback',sprintf('try, %s, end', cb));
    otherPreview.add(b,BorderLayout.CENTER);
    cardPanel.addPanel('OtherPreview', otherPreview);
else
    cardPanel.selectPanel('SheetPreview');
end

if nargin >= 4
    idx = tab.addPanel(name, cardPanel);
    if isfield(ad,[panel 'TabIndexes'])
        tidx = getfield(ad,[panel 'TabIndexes']);
    end
    tidx{i} = idx;
    ad = setfield(ad,[panel 'TabIndexes'],tidx);
end

function ad = removeAllPreviewPanels(ad,panel)
if ~isfield(ad,[panel 'TabIndexes'])
    error('Internal error: TabIndexes not found')
end
tidx = getfield(ad,[panel 'TabIndexes']);

tab = getfield(ad,[panel 'PreviewTabPanel']);
pcp = getfield(ad,[panel 'PreviewCardPanel']);
psp = getfield(ad,[panel 'SheetPreview']);
ptp = getfield(ad,[panel 'TextPreview']);

% whack the panels
for i = 1:length(tidx)
    tab.removePanelID(tidx{i});
end

% whack the cell arrays
newIdx = cell(0);
newPcp = cell(0);
newPsp = cell(0);
newPtp = cell(0);

ad = setfield(ad,[panel 'TabIndexes'],newIdx);
ad = setfield(ad,[panel 'PreviewCardPanel'],newPcp);
ad = setfield(ad,[panel 'SheetPreview'],    newPsp);
ad = setfield(ad,[panel 'TextPreview'],     newPtp);


function ad = removePreviewPanel(ad, panel, i)
if ~isfield(ad,[panel 'TabIndexes'])
    error('Internal error: TabIndexes not found')
end
tab = getfield(ad,[panel 'PreviewTabPanel']);

idx = getfield(ad,[panel 'TabIndexes']);
pcp = getfield(ad,[panel 'PreviewCardPanel']);
psp = getfield(ad,[panel 'SheetPreview']);
ptp = getfield(ad,[panel 'TextPreview']);

% whack the panel
tab.removePanelID(idx{i});

% build empty cell arrays
newIdx = cell(0);
newPcp = cell(0);
newPsp = cell(0);
newPtp = cell(0);

% update the cell arrays (could vectorize)
k = 1;
for j = 1:length(pcp)
    if i ~= j
        newIdx{k} = idx{j};
        newPcp{k} = pcp{j};
        newPsp{k} = psp{j};
        newPtp{k} = ptp{j};
        k = k + 1;
    end
end
ad = setfield(ad,[panel 'TabIndexes'],      newIdx);
ad = setfield(ad,[panel 'PreviewCardPanel'],newPcp);
ad = setfield(ad,[panel 'SheetPreview'],    newPsp);
ad = setfield(ad,[panel 'TextPreview'],     newPtp);

function out = sdisp(in, f)
% disp a number into a string.  use ML format styles.
if ~isnumeric(in) & ~isempty(in)
    error('Internal error: SDISP requires numeric input');
end

if prod(size(in)) > 1
    error('Internal error: SDISP only accepts single digit input');
end

formats = {
    '%ld',   % 12 integers    
    '%0.2f', %  5 bankers  
    '%0.4f', %  7 real short 
    '%0.14f',%  4 real long 
    '%0.4e', %  6 real short e 
    '%0.15e',%  3 real long e 
    '%0.5g', %  6 real short g 
    '%0.15g',%  3 real long g  
    '%x',    %  4 real hex     
    '%c'     % '+'
          };

formatstrs = {
    'int',
    'bank',
    'short',
    'long',
    'shortE',
    'longE',
    'shortG',
    'longG',
    'hex',
    '+'
             };

% Determine format
if nargin == 1
    f = get(0,'format');
end

if isempty(in) | ((strcmp(f,'short') | strcmp(f,'long')) & all(floor(in) == in))
    kf = 1;
else
    kf = min(find(strcmp(f,formatstrs)));
end

if isempty(in)
    out = '';
elseif strcmp(f,'+')
    if in == 0
        out = ' ';
    elseif in < 0
        out = '-';
    else
        out = '+';
    end
elseif ~isreal(in)
    s = '-++';
    cfmt = [formats{kf} ' %c ' formats{kf} 'i'];

    i = imag(in);
    out = sprintf(cfmt, real(in), s(sign(i) + 2), abs(i));
else
    out = sprintf(formats{kf}, in);
end

function types = importTypes
types = {
        '*.gif;*.cur;*.hdf;*.ico;*.jpg;*.jpeg;*.mat;*.avi;*.png;*.au;*.snd;*.wav;*.csv;*.xls;*.wk1;*.tif;*.tiff;*.txt;*.dat;*.dlm;*.tab;*.bmp;*.pcx',sprintf('Recognized data files')
        '*.gif',sprintf('CompuServe Graphics Interchange (*.gif)')
        '*.cur',sprintf('Cursor Format (*.cur)')
        '*.hdf',sprintf('8- or 24-bit raster image (*.hdf)')
        '*.ico',sprintf('Icon Format (*.ico)')
        '*.jpg;*.jpeg',sprintf('JPEG Compliant (*.jpg, *.jpeg)')
        '*.mat',sprintf('MAT (*.mat)')
        '*.avi',sprintf('Movie (*.avi)')
        '*.png',sprintf('Portable Network Graphics (*.png)')
        '*.au;*.snd;*.wav',sprintf('Sound (*.au, *.snd, *.wav)')
        '*.csv;*.xls;*.wk1',sprintf('Spreadsheet (*.csv, *.xls, *.wk1)')
        '*.tif;*.tiff',sprintf('Tagged Image File Format (*.tif, *.tiff)')
        '*.txt;*.dat;*.dlm;*.tab',sprintf('Text (*.txt, *.dat, *.dlm, *.tab)')
        '*.bmp',sprintf('Windows or OS/2 Bitmap (*.bmp)')
        '*.pcx',sprintf('Zsoft Paintbrush (*.pcx)')
        '*.*',sprintf('All Files (*.*)')
        };
  
function name = fontName
persistent localname;
if isempty(localname)
	lang = get(0,'language');
	if strncmpi(lang,'ja',2)
		localname = get(0,'defaultuicontrolfontname');
	else
		localname = 'Helvetica';
	end
end

name = localname;

function sz = fontSize
sz = 12;


function quietWarning(msg)
warnstate = warning('on');
warning(msg);
warning(warnstate)


function result = getFileTypeFromExt(ext)
if strcmp(ext, 'avi')
    result = 'movie';
% finfo returns 'im' for files which are known image types (regardles of file ext)
elseif strcmp(ext, 'im')
    result = 'image';
elseif (strcmp(ext, 'wav') | ...
        strcmp(ext, 'au') | ...
        strcmp(ext, 'snd'))
    result = 'sound';
else
    result = '';
end
