function handle = fileBrowser(startingDir)
% browse data files or a given data file
% fileBrowser(starting_directory);
% fileBrowser(starting_cell);
% fileBrowser(starting_episode);
% handle = fileBrowser;
%

versionNumber = 3.00;
if nargin == 1 && ischar(startingDir) && strcmp(startingDir(1), '$')
    if strcmp(startingDir, '$version')
        handle = versionNumber;
        return
    elseif strcmp(startingDir(1:7), '$write ')
        % write the current columns to the file given
        fid = fopen(startingDir(8:end), 'w');
            fprintf(fid, '[%s]\n', num2str(getpref('fileBrowser', 'columnOrders')));
            columnNames = getpref('fileBrowser','columnNames');
            columnWidths = getpref('fileBrowser','columnWidths');
            columnTags = getpref('fileBrowser','columnTags');
            for i = 1:numel(columnNames)
                fprintf(fid, '"%s"\t%1.0f\t"%s"\n', columnNames{i}, columnWidths(i), columnTags{i});
            end
        fclose(fid);
        return
    else
        % assume that the path of a text file was passed and load it as
        % columns
        % add preknown channels if none present
        if exist(startingDir(2:end), 'file') == 2
            try
                fid = fopen(startingDir(2:end), 'r');
                    setpref('fileBrowser','columnOrders', str2num(fgetl(fid)));                
                    C = textscan(fid, '%q %u16 %q', 'delimiter', char(9));
                fclose(fid);
                setpref('fileBrowser','columnNames', C{1});
                setpref('fileBrowser','columnWidths', C{2});
                setpref('fileBrowser','columnTags', C{3});
                
                startingDir = '';
            catch
                error(['Error reading column file: ' startingDir(2:end)])
            end
        else
            error(['No such file: ' startingDir(2:end)])
        end
    end
end

% create a browser if none exists
	if ~isappdata(0, 'fileBrowser')
        whereAt = mfilename('fullpath');
        whereAt = whereAt(1:find(whereAt == filesep, 1, 'last') - 1);
        javaaddpath([whereAt filesep 'fileBrowser.jar']);
%         javaaddpath('C:\Users\twoPhotonB\Desktop\mPhys\workspace\TableSorter\bin');

        import javax.swing.*;
        import javax.swing.table.*;
        import javax.swing.tree.*;
%         import javax.swing.ImageIcon.*;
        
%         import ca.odell.renderpack.*;        
        
        if ~ispref('locations', 'fileBrowser')
			setpref('locations', 'fileBrowser', [0 30 1200 300 .25]);
        end
        
        installDir = which('fileBrowser');
        installDir = installDir(1:find(installDir == filesep, 1, 'last'));        
		
        % create the figure 
            location = getpref('locations', 'fileBrowser');        
            handle = figure('closerequestfcn', @closeBrowser, 'menu', 'none', 'name', ['Loading fileBrowser v' sprintf('%1.2f', versionNumber)], 'numbertitle', 'off', 'visible', 'on', 'position', location(1:4), 'resizefcn', @resizeMe);
            setappdata(handle, 'ratio', location(5));

        % create the tree view
            desktopNode = javax.swing.tree.DefaultMutableTreeNode(NodeInfo('Desktop', java.lang.Integer(0), ['Desktop' filesep], '1'));
            treeModel = javax.swing.tree.DefaultTreeModel(desktopNode);
            treeHandle = javax.swing.JTree(treeModel);
            treeHandle.addTreeSelectionListener(TreeCallback(treeHandle));

            treeScroller = JScrollPane(treeHandle);
            treeScroller.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
            treeScroller.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);              
            [treeScroller treeScroller] = javacomponent(treeScroller, [0 0 location(3) * location(5) location(4)], handle);
            set(treeHandle, 'TreeWillExpandCallback', @treeExpand);
            set(treeHandle, 'MouseReleasedCallback', @treeMouseUp);
            iconDir = [whereAt filesep 'Icons' filesep];
            iconDir(iconDir == filesep) = '/';
            treeHandle.setCellRenderer(FileTreeRenderer(iconDir));
            
        % create a ui context menu for right clicks on the tree view
            f = uicontextmenu;
                uimenu(f,'label','Reparse Directory', 'callback', @reparseDir, 'separator', 'on');
                fileNames = dir([installDir 'Directory Characterization']);
                beenSeparated = 0;
                for iFiles = {fileNames(~cat(2, fileNames.isdir) & cellfun(@(x) ~isempty(x), strfind({fileNames.name}, '.m'))).name};
                    try
                        funHandle = str2func(iFiles{1}(1:end - 2));
                        if ~beenSeparated
                            uimenu(f, 'Label', funHandle(), 'callback', @characterizeDirectory, 'userData', funHandle, 'separator', 'on');
                            beenSeparated = 1;
                        else
                            uimenu(f, 'Label', funHandle(), 'callback', @characterizeDirectory, 'userData', funHandle);
                        end
                    catch
                        disp(['File ' iFiles{1} ' in Directory Characterization folder is not a valid event detector']);
                    end
                end               
            setappdata(treeHandle, 'uiContextMenu', f);            

        % add preknown channels if none present
        if ~ispref('fileBrowser','columnNames')
            fid = fopen('defaultColumns.txt', 'r');
                setpref('fileBrowser','columnOrders', str2num(fgetl(fid)));                            
                C = textscan(fid, '%q %u16 %q', 'delimiter', char(9));
            fclose(fid);
            setpref('fileBrowser','columnNames', C{1});
            setpref('fileBrowser','columnWidths', C{2});
            setpref('fileBrowser','columnTags', C{3});   
        end
            
        % create the list view for traces
            listHandle = javax.swing.JTable;
            columnOrders = getpref('fileBrowser', 'columnOrders');
            columnNames = getpref('fileBrowser', 'columnNames');
            columnWidths = getpref('fileBrowser', 'columnWidths');
            
            sorter = TableSorter(TableRemovable, listHandle);
            sorter.setColumnCount(numel(columnOrders) + 1);
            listHandle.setModel(sorter);
            listHandle.setAutoCreateColumnsFromModel(0);
            traceScroller = JScrollPane(listHandle);
            traceScroller.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
            traceScroller.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);           
            set(traceScroller, 'Background', [1 1 1]);
            
            % class stolen from Yair Altman with modifications:
            % http://www.mathworks.com/matlabcentral/fileexchange/loadFile.do?objectId=14225&objectType=file
            sorter.setTableHeader(listHandle.getTableHeader());
          
            [traceScroller traceScroller] = javacomponent(traceScroller, [location(3) * location(5) 0 location(3) * (1 - location(5)) location(4)], handle);
            set(listHandle, 'MouseReleasedCallback', @loadEpisode);
            set(listHandle, 'KeyReleasedCallback', @loadEpisode);
            set(listHandle, 'ShowHorizontalLines', 'off');
            set(listHandle, 'ShowVerticalLines', 'off');        
            set(listHandle.getColumnModel, 'ColumnMovedCallback', @moveColumn);
            
            headerHandle = listHandle.getColumnModel;
            column = headerHandle.getColumn(0);
            column.setPreferredWidth(0);
            column.setMinWidth(0);
            column.setMaxWidth(0);
            column.setHeaderValue('');
            for i = 1:numel(columnOrders)
                column = headerHandle.getColumn(i);
                column.setPreferredWidth(columnWidths(columnOrders(i)));
                column.setHeaderValue(columnNames{columnOrders(i)});
            end

        % create a ui context menu for right clicks on the list view
            f = uicontextmenu('tag', 'traceList');
                uimenu(f,'Label','Display Protocol','Callback', @displayProtocol);  
                uimenu(f,'Label','New Scope','Callback', @displayNewScope); 
                uimenu(f,'Label','Image Browser','Callback', @displayImageBrowser);
                uimenu(f,'Label','Copy Rows', 'callback', @copyRows, 'separator', 'on');
                fileNames = dir([installDir 'Episode Characterization']);
                beenSeparated = 0;
                for iFiles = {fileNames(~cat(2, fileNames.isdir) & cellfun(@(x) ~isempty(x), strfind({fileNames.name}, '.m'))).name};
                    try
                        funHandle = str2func(iFiles{1}(1:end - 2));
                        if ~beenSeparated
                            uimenu(f, 'Label', funHandle(), 'callback', @characterizeEpisode, 'userData', funHandle, 'separator', 'on');
                            beenSeparated = 1;
                        else
                            uimenu(f, 'Label', funHandle(), 'callback', @characterizeEpisode, 'userData', funHandle);
                        end
                    catch
                        disp(['File ' iFiles{1} ' in Episode Characterization folder is not a valid event detector']);
                    end
                end                     
            setappdata(listHandle, 'uiContextMenu', f);  
			listHandle.setName('traceList');

        % create a ui context menu for right clicks on the list view column headers
            columnHeadersMenu = uicontextmenu('tag', 'traceList');
                g = uimenu(columnHeadersMenu,'Label','Add Column');  
                    for i = 1:numel(columnNames)
                        if ~ismember(i, columnOrders)
                            uimenu(g,'Label',columnNames{i},'Callback', @addColumn);
                        end
                    end
                    uimenu(g,'Label','New...','Callback', @addColumn,'separator', 'on');
				uimenu(columnHeadersMenu,'Label','Edit Columns...','Callback',@editColumns);
                uimenu(columnHeadersMenu,'Label','Remove Column','Callback', @removeColumn); 
                g = uimenu(columnHeadersMenu,'Label','Plot vs');
                    for i = columnOrders
                    	uimenu(g,'Label',columnNames{i},'Callback', @plotColumnVs);
                    end                
                uimenu(columnHeadersMenu,'Label','Copy Column','Callback', @copyColumn);   
                uimenu(columnHeadersMenu,'Label','Copy all Columns','Callback', @copyAllColumns); 
                uimenu(columnHeadersMenu,'Label','Export Column to Workspace','Callback', @exportColumn);
				
            setappdata(listHandle, 'columnContextMenu', columnHeadersMenu);    
            
        % add preknown channels if none present
        if ~ispref('fileBrowser','columnNamesImage')
            fid = fopen('defaultColumnsImage.txt', 'r');
                setpref('fileBrowser','columnOrdersImage', str2num(fgetl(fid)));                            
                C = textscan(fid, '%q %u16 %q', 'delimiter', char(9));
            fclose(fid);
            setpref('fileBrowser','columnNamesImage', C{1});
            setpref('fileBrowser','columnWidthsImage', C{2});
            setpref('fileBrowser','columnTagsImage', C{3});
        end
		
       % create the list view for traces
            imageListHandle = javax.swing.JTable;
            columnOrders = getpref('fileBrowser', 'columnOrdersImage');
            columnNames = getpref('fileBrowser', 'columnNamesImage');
            columnWidths = getpref('fileBrowser', 'columnWidthsImage');
            
            sorter = TableSorter(TableRemovable, imageListHandle);
            sorter.setColumnCount(numel(columnOrders) + 1);
            imageListHandle.setModel(sorter);
            imageListHandle.setAutoCreateColumnsFromModel(0);
            imageScroller = JScrollPane(imageListHandle);
            imageScroller.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
            imageScroller.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);           
            set(imageScroller, 'Background', [1 1 1]);
            
            % class stolen from Yair Altman with modifications:
            % http://www.mathworks.com/matlabcentral/fileexchange/loadFile.do?objectId=14225&objectType=file
            sorter.setTableHeader(imageListHandle.getTableHeader());
          
            [imageScroller imageScroller] = javacomponent(imageScroller, [location(3) * location(5) 0 location(3) * (1 - location(5)) location(4)], handle);
            set(imageScroller, 'visible', 'off');
            set(imageListHandle, 'MouseReleasedCallback', @loadEpisode);
            set(imageListHandle, 'KeyReleasedCallback', @loadEpisode);
            set(imageListHandle, 'ShowHorizontalLines', 'off');
            set(imageListHandle, 'ShowVerticalLines', 'off');        
            set(imageListHandle.getColumnModel, 'ColumnMovedCallback', @moveColumnImage);
            
            headerHandle = imageListHandle.getColumnModel;
            column = headerHandle.getColumn(0);
            column.setPreferredWidth(0);
            column.setMinWidth(0);
            column.setMaxWidth(0);
            column.setHeaderValue('');
            for i = 1:numel(columnOrders)
                column = headerHandle.getColumn(i);
                column.setPreferredWidth(columnWidths(columnOrders(i)));
                column.setHeaderValue(columnNames{columnOrders(i)});
            end
            
        % create a ui context menu for right clicks on the list view
            f = uicontextmenu('tag', 'imageList');
                uimenu(f,'Label','Image Browser','Callback', @displayImageBrowser);              
            setappdata(imageListHandle, 'uiContextMenu', f);  
			imageListHandle.setName('imageList');
            
        % create a ui context menu for right clicks on the list view column headers
            columnHeadersMenu = uicontextmenu('tag', 'imageList');
                g = uimenu(columnHeadersMenu,'Label','Add Column');  
                    for i = 1:numel(columnNames)
                        if ~ismember(i, columnOrders)
                            uimenu(g,'Label',columnNames{i},'Callback', @addColumn);
                        end
                    end
                    uimenu(g,'Label','New...','Callback', @addColumn,'separator', 'on');
				uimenu(columnHeadersMenu,'Label','Edit Columns...','Callback',@editColumns);
                uimenu(columnHeadersMenu,'Label','Remove Column','Callback', @removeColumn); 
                g = uimenu(columnHeadersMenu,'Label','Plot vs');
                    for i = columnOrders
                    	uimenu(g,'Label',columnNames{i},'Callback', @plotColumnVs);
                    end                
                uimenu(columnHeadersMenu,'Label','Copy Column','Callback', @copyColumn);   
                uimenu(columnHeadersMenu,'Label','Copy all Columns','Callback', @copyAllColumns); 
                uimenu(columnHeadersMenu,'Label','Export Column to Workspace','Callback', @exportColumn);
				
            setappdata(imageListHandle, 'columnContextMenu', columnHeadersMenu);    
            
        % add desktop information            
            if ~addSubDirs(treeModel, desktopNode)
                addSeqNodes(treeModel, desktopNode);
            end
            if desktopNode.getChildCount > 0
%                 treeExpand(treeHandle, desktopNode);
            end

        % add drives and root
            rootNode = javax.swing.tree.DefaultMutableTreeNode(NodeInfo('My Computer', java.lang.Integer(8), '', '1'));        
            treeModel.insertNodeInto(rootNode, desktopNode, desktopNode.getChildCount());
            fileRoots = java.io.File.listRoots();
            for i = 1:numel(fileRoots)
                tempPath = get(fileRoots(i), 'absolutepath');
                treeModel.insertNodeInto(javax.swing.tree.DefaultMutableTreeNode(NodeInfo(tempPath(1:end - 1), java.lang.Integer(9), tempPath, '0')), rootNode, rootNode.getChildCount());        
            end
            treeHandle.expandPath(javax.swing.tree.TreePath(rootNode.getPath));

		% save the handles in the figure's userData
            set(handle, 'userData', {treeHandle, desktopNode, listHandle, rootNode, imageListHandle, desktopNode, treeScroller, traceScroller, imageScroller});            
            
        % set app data
            setappdata(0, 'fileBrowser', handle);
			
		% move to screen if necessary
            onScreen(handle);
            
        set(handle, 'name', ['FileBrowser v' sprintf('%1.2f', versionNumber)]);
	else
		handle = figure(getappdata(0, 'fileBrowser'));
	end

% if an initial directory is passed then load to it   
    if nargin > 0
        figureHandle = getappdata(0, 'fileBrowser');
        tempData = get(figureHandle, 'userData');
        treeHandle = tempData{1};
        treeModel = treeHandle.getModel;
        listHandle = tempData{3};
        rootNode = tempData{4}; 
        
		startingDir = strtrim({startingDir});
		startingDir = startingDir{1};
        if ispc
            desktopPath = fullfile(getenv('HOMEDRIVE'), getenv('HOMEPATH'), 'Desktop', filesep);        
        else
            desktopPath = fullfile(getenv('HOME'), 'Desktop', filesep);
        end
        if strfind(startingDir, desktopPath)
            startingDir = ['Desktop' startingDir(numel(desktopPath):end)];
            rootNode = tempData{6};
            dirs = find(startingDir == filesep);            
            dirs = dirs(2:end);
        else
            dirs = find(startingDir == filesep);            
        end
        
       try
            % if no slash on the end then add one
            openEpisodes = 0;
            if startingDir(end) ~= filesep
                [cellNameStart cellNameStop] = regexp(startingDir, '\.\d\d(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\d\d', 'ONCE');
                if ~isempty(cellNameStart)
                    dirs(end + 1) = cellNameStart - 1;
                    if cellNameStop == length(startingDir)
                        % this is only cell-specific

                    else
                        openEpisodes = 1;
                        if ~isempty(find(startingDir(cellNameStop:end) == 'E', 1))
                            %this is episode specific
                            dirs(end + 1) = find(startingDir == 'E', 1, 'last') - 2;
                        else
                            % this is only sequence-specific so do it like
                            % a cell-specific
                            dirs(end + 1) = length(startingDir);              
                        end                        
                    end
                elseif exist(startingDir, 'dir') == 7
                    % is directory specific without a slash
                    startingDir = [startingDir filesep];
                    dirs(end + 1) = length(startingDir);
                else
                    % is cell specific without the date
                    dirs(end + 1) = length(startingDir);
                end
            end
            
            node = rootNode;
            alreadyReset = 0;
            currentTreeNode = treeHandle.getLastSelectedPathComponent;
            i = 1;
            while i < length(dirs) + 1
                % expand the current node
                treeHandle.scrollPathToVisible(javax.swing.tree.TreePath(node.getPath));
                
                % determine which node matches our directory
                numKids = node.getChildCount();
                parentNode = node;
                if numKids > 0
                    node = node.getFirstChild();
                    for j = 1:numKids
                        nodeInfo = node.getUserObject;                        
                        if strcmpi(nodeInfo.getPath, startingDir(1:dirs(i)))
                            bestNode = node;
                        end
                        if strcmp(char(nodeInfo.getParsed), '0')
                            try
                                if ~addSubDirs(treeModel, node)
                                    addSeqNodes(treeModel, node);
                                end
                            catch
                                %some folders miss a parsed tag and end up here
                            end
                            nodeInfo.setParsed('1');
                        end
                        if j < numKids
                            node = node.getNextSibling;      
                        end                        
                    end
                    node = bestNode;
                end
                
                nodeInfo = node.getUserObject;                                            
                if ~strcmpi(nodeInfo.getPath, startingDir(1:dirs(i)))
					if alreadyReset
                        error('Already reset');
                    else
                        % node not found so make sure is a directory
                        if ~isempty(dir(startingDir(1:dirs(i))))
                            % add a dir
                            node = javax.swing.tree.DefaultMutableTreeNode(NodeInfo(startingDir(dirs(i-1) + 1:dirs(i) - 1), java.lang.Integer(10), startingDir(1:dirs(i)), '0'));
                            treeModel.insertNodeInto(node, parentNode, parentNode.getChildCount());
                            % and parse it
                            if ~addSubDirs(treeModel, node)
                                addSeqNodes(treeModel, node);
                            end
                            nodeInfo = node.getUserObject;                        
                            nodeInfo.setParsed('1');
                        else
                            % is this a new cell or sequence?
                            if i > 1 && ~isempty(dir(startingDir(1:dirs(i - 1))))
                                % this is a new cell
                                newParent = parentNode.getParent;
                                % remove old dir
                                parentNode.removeFromParent;
                                % recreate old dir
                                node = javax.swing.tree.DefaultMutableTreeNode(NodeInfo(startingDir(dirs(i-2) + 1:dirs(i-1) - 1), java.lang.Integer(10), startingDir(1:dirs(i-1)), '0'));
                                treeModel.insertNodeInto(node, newParent, newParent.getChildCount());
                                % and parse it
                                if ~addSubDirs(treeModel, node)
                                    addSeqNodes(treeModel, node);
                                end
                                nodeInfo = node.getUserObject;                        
                                nodeInfo.setParsed('1');
                                i = i - 1;
                            elseif i > 2 && ~isempty(dir(startingDir(1:dirs(i - 2))))
                                % this is a new sequence
                                newParent = parentNode.getParent;
                                newParent = newParent.getParent;
                                % remove old dir
                                parentNode.getParent.removeFromParent;
                                % recreate old dir
                                node = javax.swing.tree.DefaultMutableTreeNode(NodeInfo(startingDir(dirs(i-3) + 1:dirs(i-2) - 1), java.lang.Integer(10), startingDir(1:dirs(i-2)), '0'));
                                treeModel.insertNodeInto(node, newParent, newParent.getChildCount());
                                % and parse it
                                if ~addSubDirs(treeModel, node)
                                    addSeqNodes(treeModel, node);
                                end
                                nodeInfo = node.getUserObject;                        
                                nodeInfo.setParsed('1');
                                i = i - 2;
                                currentTreeNode = node;
                            else
                                error('Input to fileBrowser must be a valid file name')
                            end
                        end
                        alreadyReset = 1;
					end  
                end
                i = i + 1;
            end
            treeHandle.scrollPathToVisible(javax.swing.tree.TreePath(node.getPath));
            treeHandle.expandPath(javax.swing.tree.TreePath(node.getPath));
            
            % we are at the bottom of the tree so if a sequence is selected
            % show it
            if openEpisodes
				treeHandle.setSelectionPath(javax.swing.tree.TreePath(node.getPath));
				nodeText = char(nodeInfo.getName);
                notCurrentNode = true;
                if ~isempty(currentTreeNode)
                    tempInfo = currentTreeNode.getUserObject;
                    if strcmpi(tempInfo.getPath, nodeInfo.getPath)
                        notCurrentNode = false;
                    end
                end
                if notCurrentNode
                    nodeInfo.setName([nodeText(1:find(nodeText == '(', 1, 'first')) strtrim(num2str(addEpisodes(char(nodeInfo.getPath)))) ')']);
                end
                
                if numel(startingDir) > 7 && strcmp(startingDir(1:8), ['Desktop' filesep])
                    startingDir = [desktopPath startingDir(9:end)];
                end

                foundMatch = false;
                listModel = listHandle.getModel;
                for i = 1:listHandle.getRowCount
                    tempData = listModel.getValueAt(i - 1, 0);
                    if strcmpi(tempData, startingDir)
                        % this episode is already on the list so select it                            
                        foundMatch = true;
                        listHandle.setRowSelectionInterval(i - 1, i - 1);
                        break
                    end
                end

                if ~foundMatch
                    % this is so that the episodes aren't all reparsed when
                    % a new one is added
                    parenStart = find(nodeText == '(', 1, 'first');
                    nodeInfo.setName([nodeText(1:parenStart) strtrim(num2str(str2double(nodeText(parenStart + 1:end - 1)) + 1)) ')']);                    
                    protocol = readTrace(startingDir, 1);
                    if ~isempty(protocol)
                        if strcmp(get(0, 'formatSpacing'), 'loose')
                            % the output of evalc depends on this setting so we have to know it
                            % for filling up the jtable
                            whichSpacing = [9 2];
                        else
                            whichSpacing = [7 1];
                        end
                        newRow = javaArray('java.lang.Object', listHandle.getColumnCount);
                        newRow(1) = java.lang.String(protocol.fileName);
                        columnFunctions = getpref('fileBrowser', 'columnTags');
                        columnIndices = getpref('fileBrowser', 'columnOrders');
                        for j = 1:listHandle.getColumnCount - 1
                            try
                                tempText = evalc(columnFunctions{columnIndices(j)});
                                if numel(tempText) > whichSpacing(1)
                                    tempText = tempText(whichSpacing(1):end - whichSpacing(2));
                                    tempNum = str2double(tempText);
                                    if isnan(tempNum)
                                        newRow(j + 1) = java.lang.String(tempText);
                                    elseif tempNum == round(tempNum)
                                        newRow(j + 1) = java.lang.Integer(tempNum);
                                    else
                                        newRow(j + 1) = java.lang.Float(tempNum);
                                    end
                                else
                                    newRow(j + 1) = java.lang.String('');
                                end
                            catch
                                newRow(j + 1) = java.lang.String('');
                            end
                        end
                        listHandle.getModel.addRow(newRow);                    
                    end
                    if isappdata(0, 'experiment')
                        experimentInfo = getappdata(0, 'currentExperiment');
                        if ~isempty(experimentInfo.matlabCommand)
                            try
                                eval(experimentInfo.matlabCommand);
                            catch
                                warning('Error in post-processing command');
                            end
                        end
                    end
                    listHandle.setRowSelectionInterval(listHandle.getRowCount - 1, listHandle.getRowCount - 1);
                end
                set(figureHandle, 'name', char(nodeInfo.getPath));
                listHandle.scrollRectToVisible(listHandle.getCellRect(listHandle.getSelectedRow, 0, true));
                loadEpisode(listHandle, 0, 1);
            end        
        catch
            error('First Arguement must be a valid directory, cell, sequence, or full path')
        end
    end

%% **************
%% event handlers
%% **************

function resizeMe(varargin)
    handles = get(varargin{1}, 'userData');
    ratio = getappdata(varargin{1}, 'ratio');
    if ~isempty(handles)
        figPos = get(varargin{1}, 'position');
        set(handles{7}, 'position', [0 0 round(figPos(3) * ratio) figPos(4)]);
        set(handles{8}, 'position', [round(figPos(3) * ratio) 0 round(figPos(3) *(1 - ratio)) figPos(4)]);
        set(handles{9}, 'position', [round(figPos(3) * ratio) 0 round(figPos(3) *(1 - ratio)) figPos(4)]);        
    end
    
function treeMouseUp(varargin)
    switch get(varargin{2}, 'Button')
        case 3
            figPos = get(getappdata(0, 'fileBrowser'), 'position');
            handles = get(getappdata(0, 'fileBrowser'), 'userData');            
            set(getappdata(handles{1}, 'uiContextMenu'), 'position', [get(varargin{2}, 'X') figPos(4) - get(varargin{2}, 'Y')], 'visible', 'on');
        case 1
            if strcmp(get(get(varargin{2}, 'Source'), 'name'), 'NodeClicked')
                treeHandle = get(varargin{2}, 'Source');
                set(treeHandle, 'name', '');
                whichNode = treeHandle.getLastSelectedPathComponent;
                nodeInfo = whichNode.getUserObject;
                nodePath = char(nodeInfo.getPath);
                if ~strcmpi(nodePath, '') && ismember(double(nodeInfo.getIcon), [1:7 13:17])
                    set(getappdata(0, 'fileBrowser'), 'name', 'Loading...');
                    drawnow;
                    addEpisodes(nodePath);
                end
                set(getappdata(0, 'fileBrowser'), 'name', nodePath);
                drawnow;
            end
    end
        
function treeExpand(varargin)
    oldName = get(getappdata(0, 'fileBrowser'), 'name');
    set(getappdata(0, 'fileBrowser'), 'name', 'Parsing...');
    drawnow;
    rootNode = get(get(varargin{2}, 'path'), 'LastPathComponent');
    treeModel = get(varargin{2}, 'Source');
    treeModel = treeModel.getModel;
    tempNode = get(rootNode, 'FirstChild');
    for i = 1:get(rootNode, 'childCount')
        nodeObject = tempNode.getUserObject;
        if strcmp(char(nodeObject.getParsed), '0')
            try
                if ~addSubDirs(treeModel, tempNode)
                    addSeqNodes(treeModel, tempNode);
                end
            catch
                % some folders miss a parsed tag and end up here
            end
            nodeObject.setParsed('1');
        end
        if i < get(rootNode, 'childCount')
            tempNode = get(tempNode, 'NextSibling');
        end
    end
    set(getappdata(0, 'fileBrowser'), 'name', oldName);    
   
function moveColumn(varargin)
    columnOrders = getpref('fileBrowser', 'columnOrders');
    columnOrders = columnOrders([1:varargin{2}.getToIndex - 1 varargin{2}.getFromIndex varargin{2}.getToIndex:end]);
    columnOrders(varargin{2}.getFromIndex + (varargin{2}.getToIndex < varargin{2}.getFromIndex)) = [];
    setpref('fileBrowser', 'columnOrders', columnOrders);     

function moveColumnImage(varargin)
    columnOrders = getpref('fileBrowser', 'columnOrdersImage');
    columnOrders = columnOrders([1:varargin{2}.getToIndex - 1 varargin{2}.getFromIndex varargin{2}.getToIndex:end]);
    columnOrders(varargin{2}.getFromIndex + (varargin{2}.getToIndex < varargin{2}.getFromIndex)) = [];
    setpref('fileBrowser', 'columnOrdersImage', columnOrders);    
    
function addColumn(varargin)
    handles = get(getappdata(0, 'fileBrowser'), 'userData');
    parentMenu = get(get(varargin{1}, 'parent'), 'parent');
	if strcmp(get(parentMenu, 'tag'), 'traceList')
		columnNames = getpref('fileBrowser', 'columnNames');
		columnWidths = getpref('fileBrowser', 'columnWidths');
		columnTags = getpref('fileBrowser', 'columnTags');
        columnOrders = getpref('fileBrowser', 'columnOrders');
		handleNum = 3;
	else
		columnNames = getpref('fileBrowser', 'columnNamesImage');
		columnWidths = getpref('fileBrowser', 'columnWidthsImage');
		columnTags = getpref('fileBrowser', 'columnTagsImage');
        columnOrders = getpref('fileBrowser', 'columnOrdersImage');
		handleNum = 5;		
	end
        
    colHeader = get(varargin{1}, 'Label');
    if ~strcmp(colHeader, 'New...')
        whichCol = find(strcmp(columnNames, colHeader), 1, 'first');
        newCol = javax.swing.table.TableColumn(handles{handleNum}.getColumnCount);
        newCol.setHeaderValue(columnNames{whichCol});
        newCol.setPreferredWidth(columnWidths(whichCol));
        handles{handleNum}.getModel.setColumnCount(handles{handleNum}.getColumnCount + 1);
        handles{handleNum}.addColumn(newCol);
        handles{handleNum}.getModel.addColumn(java.lang.String(columnNames{whichCol}));
        handles{handleNum}.getModel.fireTableStructureChanged;
        
        delete(varargin{1});
        if handleNum == 3
            setpref('fileBrowser','columnOrders',[columnOrders whichCol]);
        else
            setpref('fileBrowser','columnOrdersImage',[columnOrders whichCol]);                
        end        
    else
        % input dialog with width, name, tag
        outParams = inputdlg({'Name', 'Width', 'Function'},'Column',1, {'','60',''});
        
        if numel(outParams) > 0
            % add column
            newCol = javax.swing.table.TableColumn(handles{handleNum}.getModel.getColumnCount);
            newCol.setHeaderValue(outParams{1});
            newCol.setPreferredWidth(str2double(outParams{2}));
            handles{handleNum}.getModel.setColumnCount(handles{handleNum}.getColumnCount + 1);            
            handles{handleNum}.addColumn(newCol);            
            handles{handleNum}.getModel.addColumn(java.lang.String(outParams{1}));            
            handles{handleNum}.getModel.fireTableStructureChanged;
            
            % add to prefs
            columnNames{end + 1} = outParams{1};
            columnWidths(end + 1) = str2double(outParams{2});
            columnTags{end + 1} = outParams{3};
            whichCol = length(columnNames);            
            if handleNum == 3
				setpref('fileBrowser','columnNames', columnNames);
				setpref('fileBrowser','columnWidths', columnWidths);
				setpref('fileBrowser','columnTags', columnTags);
                setpref('fileBrowser','columnOrders',[columnOrders numel(columnTags)]);
			else
				setpref('fileBrowser','columnNamesImage', columnNames);
				setpref('fileBrowser','columnWidthsImage', columnWidths);
				setpref('fileBrowser','columnTagsImage', columnTags);			
                setpref('fileBrowser','columnOrdersImage',[columnOrders numel(columnTags)]);                
            end
            colHeader = outParams{1};
        else
            colHeader = [];
        end     
    end
    
    % add to plotVs menu
    if ~isempty(colHeader)
        setpref('fileBrowser', 'columnOrders', [columnOrders whichCol]);
        uimenu(findobj('type', 'uimenu', 'label', 'Plot vs', 'parent', parentMenu), 'Label', colHeader, 'callback', @plotColumnVs);
        oldName = get(getappdata(0, 'fileBrowser'), 'name');
        set(getappdata(0, 'fileBrowser'), 'name', 'Loading Column Data...');    
        drawnow
        whichNode = handles{1}.getLastSelectedPathComponent;
        if ~isempty(whichNode)
            nodeInfo = whichNode.getUserObject;
            nodePath = char(nodeInfo.getPath);
            if ~strcmpi(nodePath, '') && ismember(double(nodeInfo.getIcon), [1:7 13:17])
                set(getappdata(0, 'fileBrowser'), 'name', 'Loading...');
                drawnow;
                addEpisodes(nodePath);
            end    
        end
        set(getappdata(0, 'fileBrowser'), 'name', oldName);
    end
    

function editColumns(varargin)
% edit the available column contents
    if isdeployed
        msgbox('Not available when compiled')
        return
    end
	handles = get(getappdata(0, 'fileBrowser'), 'userData');
	if strcmp(get(get(varargin{1}, 'parent'), 'tag'), 'traceList');
		columnNames = getpref('fileBrowser', 'columnNames');
		columnTags = getpref('fileBrowser', 'columnTags');
        columnOrders = getpref('fileBrowser', 'columnOrders');
		handleNum = 3;
	else
		columnNames = getpref('fileBrowser', 'columnNamesImage');
		columnTags = getpref('fileBrowser', 'columnTagsImage');
        columnOrders = getpref('fileBrowser', 'columnOrdersImage');        
		handleNum = 5;		
	end	
	columnData = [columnNames(columnOrders) columnTags(columnOrders)];
	disp('Type dbcont in the command window when done.');
	openvar('columnData');
	keyboard
	for i = 1:handles{handleNum}.getColumnCount - 1
        handles{handleNum}.getColumnModel.getColumn(i).setHeaderValue(columnData{i, 1});
	end
    if handleNum == 3
		setpref('fileBrowser', 'columnNames', columnData(:,1));
		setpref('fileBrowser', 'columnTags', columnData(:,2));
	else
		setpref('fileBrowser', 'columnNamesImage', columnData(:,1));
		setpref('fileBrowser', 'columnTagsImage', columnData(:,2));		
    end
    whichNode = handles{1}.getLastSelectedPathComponent;
    if ~isempty(whichNode)
        nodeInfo = whichNode.getUserObject;
        nodePath = char(nodeInfo.getPath);
        if ~strcmpi(nodePath, '') && ismember(double(nodeInfo.getIcon), [1:7 13:17])
            set(getappdata(0, 'fileBrowser'), 'name', 'Loading...');
            drawnow;
            addEpisodes(nodePath);
        end    
    end
	
function removeColumn(varargin)
    % ask whether they would like to remove it from the database
    whichMenu = get(varargin{1}, 'parent');
    varargin = getappdata(getappdata(0, 'fileBrowser'), 'varargin');    
    handles = get(getappdata(0, 'fileBrowser'), 'userData');
    whichCol = handles{3}.getColumnModel.getColumnIndexAtX(varargin{2}.getX);
    colHeader = handles{3}.getColumnModel.getColumn(whichCol).getHeaderValue;    
    
    switch questdlg('Do you want to permanently remove the column from the database?', 'Remove Column from Database');
        case 'Yes'
            % remove column
            if strcmp(get(whichMenu, 'tag'), 'traceList')
				columnNames = getpref('fileBrowser', 'columnNames');
				columnTags = getpref('fileBrowser','columnTags');
				columnWidths = getpref('fileBrowser','columnWidths');	
				columnOrders = getpref('fileBrowser','columnOrders');
			else
				columnNames = getpref('fileBrowser', 'columnNamesImage');
				columnTags = getpref('fileBrowser','columnTagsImage');
				columnWidths = getpref('fileBrowser','columnWidthsImage');	
				columnOrders = getpref('fileBrowser','columnOrdersImage');				
            end
            colIndex = find(strcmp(columnNames, colHeader), 1, 'first');
            % stolen entirely from:
            % http://www.exampledepot.com/egs/javax.swing.table/RemCol.html
            col = handles{3}.getColumnModel.getColumn(whichCol);
            columnModelIndex = col.getModelIndex;
            handles{3}.removeColumn(col);    
            colIds = handles{3}.getModel.getTableModel.getColumnIdentifiers;
            data = handles{3}.getModel.getDataVector;
            colIds.removeElementAt(columnModelIndex);
            % Remove the column data
            for r=0:data.size-1
                row = data.get(r);
                row.removeElementAt(columnModelIndex);
            end
            handles{3}.getModel.setDataVector(data, colIds);

            % Correct the model indices in the TableColumn objects
            % by decrementing those indices that follow the deleted column
            enum = handles{3}.getColumnModel().getColumns();
            while enum.hasMoreElements
                c = enum.nextElement();
                if c.getModelIndex() >= columnModelIndex
                    c.setModelIndex(c.getModelIndex()-1);
                end
            end
            handles{3}.getModel.fireTableStructureChanged();
            
            % remove pref
            whichOrder = find(columnOrders == colIndex, 1);
            if strcmp(get(whichMenu, 'tag'), 'traceList')
				setpref('fileBrowser','columnNames',columnNames([1:colIndex - 1 colIndex + 1:end]));
				setpref('fileBrowser','columnTags',columnTags([1:colIndex - 1 colIndex + 1:end]));
				setpref('fileBrowser','columnWidths',columnWidths([1:colIndex - 1 colIndex + 1:end]));
				setpref('fileBrowser','columnOrders',columnOrders([1:whichOrder - 1 whichOrder + 1:end]));				
			else
				setpref('fileBrowser','columnNamesImage',columnNames([1:whichCol - 1 whichCol + 1:end]));
				setpref('fileBrowser','columnTagsImage',columnTags([1:whichCol - 1 whichCol + 1:end]));
				setpref('fileBrowser','columnWidthsImage',columnWidths([1:whichCol - 1 whichCol + 1:end]));
				setpref('fileBrowser','columnOrdersImage',columnOrders([1:whichOrder - 1 whichOrder + 1:end]));								
            end
            
            % remove from plotVs menu
            delete(findobj('type', 'uimenu', 'label', colHeader, 'parent', findobj('type', 'uimenu', 'label', 'Plot vs', 'parent', whichMenu)));
            
        case 'No'
            % stolen entirely from:
            % http://www.exampledepot.com/egs/javax.swing.table/RemCol.html
            col = handles{3}.getColumnModel.getColumn(whichCol);
            columnModelIndex = col.getModelIndex;
            handles{3}.removeColumn(col);    
            colIds = handles{3}.getModel.getTableModel.getColumnIdentifiers;
            data = handles{3}.getModel.getDataVector;
            colIds.removeElementAt(columnModelIndex);
            % Remove the column data
            for r=0:data.size-1
                row = data.get(r);
                row.removeElementAt(columnModelIndex);
            end
            handles{3}.getModel.setDataVector(data, colIds);

            % Correct the model indices in the TableColumn objects
            % by decrementing those indices that follow the deleted column
            enum = handles{3}.getColumnModel().getColumns();
            while enum.hasMoreElements
                c = enum.nextElement();
                if c.getModelIndex() >= columnModelIndex
                    c.setModelIndex(c.getModelIndex()-1);
                end
            end
            handles{3}.getModel.fireTableStructureChanged();

            % add to menus
            addMenu = findobj('label', 'Add Column', 'parent', whichMenu);
            kids = get(addMenu, 'children');
            set(kids(1), 'separator', 'off', 'label', colHeader);
            uimenu(addMenu, 'Label', 'New...', 'separator', 'on', 'callback', @addColumn);
            
            % remove pref
            if strcmp(get(whichMenu, 'tag'), 'traceList')
				columnNames = getpref('fileBrowser', 'columnNames');                
				columnOrders = getpref('fileBrowser','columnOrders');
            else
				columnNames = getpref('fileBrowser', 'columnNamesImage');
				columnOrders = getpref('fileBrowser','columnOrdersImage');				
            end         
            colIndex = find(strcmp(columnNames, colHeader), 1, 'first');
            whichOrder = find(columnOrders == colIndex, 1);
            if strcmp(get(whichMenu, 'tag'), 'traceList')
				setpref('fileBrowser','columnOrders',columnOrders([1:whichOrder - 1 whichOrder + 1:end]));				
            else
				setpref('fileBrowser','columnOrdersImage',columnOrders([1:whichOrder - 1 whichOrder + 1:end]));								
            end
            
            % remove from plotVs menu
            delete(findobj('type', 'uimenu', 'label', colHeader, 'parent', findobj('type', 'uimenu', 'label', 'Plot vs', 'parent', whichMenu)));

        case {'Cancel', ''}
            % do nothing
    end
    
function plotColumnVs(varargin)
    vsColumnName = get(varargin{1}, 'Label');
    handles = get(getappdata(0, 'fileBrowser'), 'userData');
    if strcmp(get(get(get(varargin{1}, 'parent'), 'parent'), 'tag'), 'traceList')
        handleNum = 3;
    else
        handleNum = 5;
    end
    varargin = getappdata(getappdata(0, 'fileBrowser'), 'varargin');    
    thisColumn = handles{handleNum}.getColumnModel.getColumn(handles{handleNum}.getColumnModel.getColumnIndexAtX(varargin{2}.getX)).getModelIndex();  
    thisColumnName = handles{handleNum}.getColumnModel().getColumn(thisColumn).getHeaderValue;
 
    for i = 1:handles{handleNum}.getColumnCount - 1
        if strcmp(handles{handleNum}.getColumnModel.getColumn(i).getHeaderValue, vsColumnName)
            vsColumn = i;
            break
        end
    end    
    
    % determine whether this will be a bar chart or an X-Y scatter
    xData = zeros(handles{handleNum}.getRowCount - 1, 1);
    yData = xData;
    numCategories = 0;
    categories = {};
    xIsTime = 0;
    yIsTime = 0;
    for i = 1:handles{handleNum}.getRowCount
        tempData = handles{handleNum}.getModel.getValueAt(i - 1,vsColumn);
        if length(find(tempData == ':')) > 1
            % this is time data so back convert
            xData(i) = time2sec(tempData);
            xIsTime = 1;
        elseif isnumeric(tempData) %all(ismember(tempData.Text, ['e' '+' 'N' 'a' 'n' ' ' '-' '1' '2' '3' '4' '5' '6' '7' '8' '9' '0' '.']))
            % numeric data
            xData(i) = tempData;
        elseif ismember(tempData(end), ['A' 'V']) && all(ismember(tempData(1:end - 2), ['e' '+' 'N' 'a' 'n' ' ' '-' '1' '2' '3' '4' '5' '6' '7' '8' '9' '0' '.']))
            % numeric with unit suffix
            xData(i) = str2double(tempData(1:end -2));            
        else
            % categorical data
            if any(ismember(tempData, categories))
                xData(i) = find(strcmp(tempData, categories));
            else
                numCategories = numCategories + 1;
                categories{numCategories} = tempData;
                xData(i) = numCategories;
            end
        end
        tempData = handles{handleNum}.getModel.getValueAt(i - 1,thisColumn);
        if length(find(tempData == ':')) > 1
            % this is time data so back convert
            yData(i) = time2sec(tempData);
            yIsTime = 1;
        elseif isnumeric(tempData) %all(ismember(tempData.Text, ['e' '+' ' ' 'N' 'a' 'n' '-' '1' '2' '3' '4' '5' '6' '7' '8' '9' '0' '.']))
            % numeric data
            yData(i) = tempData;
        elseif ismember(tempData(end), ['A' 'V']) && all(ismember(tempData(1:end - 2), ['e' '+' ' ' 'N' 'a' 'n' '-' '1' '2' '3' '4' '5' '6' '7' '8' '9' '0' '.']))
            % numeric with unit suffix
            yData(i) = str2double(tempData(1:end -2));
        else
            error('Ydata cannot be categorical for plotting')
        end        
    end
    
    figure('numbertitle', 'off', 'name', get(getappdata(0, 'fileBrowser'), 'name'));
    if numCategories == 0
        % scatter plot
        plot(xData, yData, 'linestyle', 'none', 'marker', '.', 'color', [0 0 0]);
        if xIsTime
            tempTicks = get(gca, 'xticklabel');
            set(gca, 'xticklabel', sec2time(tempTicks));
        end
        if yIsTime
            tempTicks = get(gca, 'yticklabel');
            set(gca, 'yticklabel', sec2time(tempTicks));
        end        
    else
        % bar like plot
        plot(xData, yData, 'linestyle', 'none', 'marker', '.', 'color', [0 0 0]);
        set(gca, 'xtick', 1:numCategories);
        set(gca, 'xticklabel', categories);
        set(gca, 'xlim', [0.5 numCategories + 0.5]);
        if yIsTime
            tempTicks = get(gca, 'yticklabel');
            set(gca, 'yticklabel', sec2time(tempTicks));
        end           
    end
    xlabel(vsColumnName);
    ylabel(thisColumnName);

function copyColumn(varargin)
    % copy to clipboard as tab-delimited
    handles = get(getappdata(0, 'fileBrowser'), 'userData');
    if strcmp(get(get(varargin{1}, 'parent'), 'tag'), 'traceList')
        handleNum = 3;
    else
        handleNum = 5;
    end    
    
    varargin = getappdata(getappdata(0, 'fileBrowser'), 'varargin');
    thisColumn = handles{handleNum}.getColumnModel.getColumn(handles{handleNum}.getColumnModel.getColumnIndexAtX(varargin{2}.getX)).getModelIndex();  
    
    clipText = '';
    for i = 0:handles{handleNum}.getRowCount - 1
        clipText = [clipText handles{handleNum}.getModel.getValueAt(i,thisColumn) char(13)];
    end
    
    clipboard('copy', clipText);
    
function copyAllColumns(varargin)
    % copy all columns to clipboard as tab-delimited
    handles = get(getappdata(0, 'fileBrowser'), 'userData');    
    if strcmp(get(get(varargin{1}, 'parent'), 'tag'), 'traceList')
        handleNum = 3;
    else
        handleNum = 5;
    end   
    
    clipText = 'Path';
    for j = 1:handles{handleNum}.getColumnCount - 1
        clipText = [clipText char(9) handles{handleNum}.getColumnModel().getColumn(j).getHeaderValue];
    end
    clipText = [clipText char(13)];
    
    for i = 0:handles{handleNum}.getRowCount - 1
        for j = 0:handles{handleNum}.getColumnCount - 1
            clipText = [clipText num2str(handles{handleNum}.getModel.getValueAt(i,j)) char(9)];
        end
        clipText = [clipText(1:end - 1) char(13)];
    end
    
    clipboard('copy', clipText);    

function copyRows(varargin)
    handles = get(getappdata(0, 'fileBrowser'), 'userData');
    if strcmp(get(get(varargin{1}, 'parent'), 'tag'), 'traceList')
        handleNum = 3;
    else
        handleNum = 5;
    end       
    if ~double(handles{handleNum}.getSelectedRowCount)
        return
    end
    whichSelected = handles{handleNum}.getSelectedRows;

    clipText = '';
    for i = whichSelected'
        for j = 1:handles{handleNum}.getColumnCount
            tempText = handles{handleNum}.getModel.getValueAt(i, j - 1);
            if isnumeric(tempText)
                clipText = [clipText num2str(tempText) char(9)];
            else
                clipText = [clipText tempText char(9)];
            end
        end
        clipText = [clipText(1:end - 1) char(13)];
    end
    
    clipboard('copy', clipText);          
    
function exportColumn(varargin)
    % copy to workspace as matrix
    handles = get(getappdata(0, 'fileBrowser'), 'userData');
    varargin = getappdata(getappdata(0, 'fileBrowser'), 'varargin');
    if strcmp(get(get(varargin{1}, 'parent'), 'tag'), 'traceList')
        handleNum = 3;
    else
        handleNum = 5;
    end
    thisColumn = handles{handleNum}.getColumnModel.getColumn(handles{handleNum}.getColumnModel.getColumnIndexAtX(varargin{2}.getX)).getModelIndex();  
    thisColumnName = handles{handleNum}.getColumnModel().getColumn(thisColumn).getHeaderValue;
    
    varName = inputdlg('Enter a name for the workspace variable', 'Export', 1, {thisColumnName});
    if ~isempty(varName)
        xData = zeros(handles{handleNum}.getRowCount, 1);
        for i = 1:handles{handleNum}.getRowCount
            tempData = handles{handleNum}.getModel.getValueAt(i - 1,thisColumn);
            if length(find(tempData == ':')) > 1
                % this is time data so back convert
                xData(i) = time2sec(tempData);
            elseif isnumeric(tempData) %all(ismember(tempData, ['e' '+' 'N' 'a' 'n' ' ' '-' '1' '2' '3' '4' '5' '6' '7' '8' '9' '0' '.']))
                % numeric data
                xData(i) = tempData;
            elseif ismember(tempData(end), ['A' 'V' 'm']) && all(ismember(tempData(1:end - 2), ['e' '+' 'N' 'a' 'n' ' ' '-' '1' '2' '3' '4' '5' '6' '7' '8' '9' '0' '.']))
                % numeric with unit suffix
                xData(i) = str2double(tempData(1:end -2));            
            else
                % categorical data
                if ~iscell(xData)
                    clear xData;
                end
                xData{i} = tempData;
            end
        end
        tempVarName = genvarname(varName, evalin('base', 'who'));
        if strcmp(varName, tempVarName)
        	assignin('base', varName{1}, xData);
        else
            switch questdlg(strcat('''', varName, ''' is not a valid variable name in the base workspace.  Is ''', tempVarName, ''' ok?'), 'Uh oh');
                case 'Yes'
                	assignin('base', tempVarName{1}, xData);
                case 'No'
                    varName = inputdlg('Enter a name for the workspace variable', 'Export', 1, tempVarName);
                    assignin('base', genvarname(varName{1}), xData);
                case 'Cancel'
                    % do nothing
            end
        end
    end

function loadEpisode(varargin)
    handles = get(getappdata(0, 'fileBrowser'), 'userData');
    if strcmp(class(varargin{2}), 'java.awt.event.MouseEvent')
        varargin{1} = get(varargin{2}, 'Source');
        whichButton = get(varargin{2}, 'Button');
    else
        % assume that it is ok to use the file and not the image table
        varargin{1} = handles{3};
        whichButton = 1;
        
        % if this was a keypress then only take certain keys
        if strcmp(class(varargin{2}), 'java.awt.event.KeyEvent') && ~ismember(varargin{2}.getKeyCode, [40 38])
            return
        end
    end
    % determine whether we are over a column
%     whichColumn = varargin{2}.getSource.getColumnModel.getColumn(varargin{2}.getSource.getColumnModel.getColumnIndexAtX(varargin{2}.getX)).getModelIndex();
    if strcmp(class(varargin{1}), 'javax.swing.JTable')
        switch whichButton 
            case 1
                listModel = varargin{1}.getModel;                
                if strcmp(get(varargin{1}, 'name'), 'traceList')
                % add files
                    if isappdata(0, 'scopes')
                        if ~double(varargin{1}.getSelectedRowCount)
                            return
                        end
                        whichSelected = varargin{1}.getSelectedRows;
                        % call a refresh for all current figures     
                        whichScopes = getappdata(0, 'scopes');        
                        whichScopes = whichScopes(ishandle(whichScopes));  

                        % executing the next five commands clears up half of the
                        % memory used by scopes
        %                 evalin('base', 'clear zData');
        %                 set(whichScopes, 'windowButtonDownFcn', [], 'windowButtonMotionFcn', [], 'windowButtonUpFcn', [], 'keyPressFcn', []);
        %                 for i = whichScopes
        %                     setappdata(i, 'updateFunction', []);
        %                 end                
                        % executing the next three commands clears up all of the
                        % memory used by scopes but may take awhile              
        %                 for i = whichScopes
        %                     newScope([0 1], i);
        %                 end       

                        if numel(whichSelected) > 1
                            protocol = readTrace(listModel.getValueAt(whichSelected(1),0));
                            protocol = protocol.protocol;
                            numChannels = numel(protocol.channelNames);
                            for channelIndex = 1:numChannels
                                zData.traceData{channelIndex} = zeros(protocol.sweepWindow * 1000 / protocol.timePerPoint, numel(whichSelected));
                            end
                            for epiIndex = 1:numel(whichSelected)
                                tempData = readTrace(listModel.getValueAt(whichSelected(epiIndex),0));
                                zData.protocol(epiIndex) = tempData.protocol;
                                if tempData.protocol.timePerPoint ~= protocol.timePerPoint
                                    tempData.traceData = resample(tempData.traceData, protocol.timePerPoint, tempData.protocol.timePerPoint);
                                end
                                if size(zData.traceData{1}, 1) == size(tempData.traceData, 1)
                                    for channelIndex = 1:numChannels
                                        zData.traceData{channelIndex}(:, epiIndex) = tempData.traceData(:, channelIndex);
                                    end
                                    zData.protocol(epiIndex).timePerPoint = protocol.timePerPoint;
                                elseif size(zData.traceData{1}, 1) > size(tempData.traceData, 1)
                                    % pad tempData
                                    for channelIndex = 1:numChannels
                                        zData.traceData{channelIndex}(:, epiIndex) = [tempData.traceData(:, channelIndex); nan(size(zData.traceData{channelIndex}, 1) - size(tempData.traceData, 1), 1)];
                                    end
                                    zData.protocol(epiIndex).sweepWindow = protocol.sweepWindow;
                                else
                                    % pad traceData
                                    for channelIndex = 1:numChannels
                                        zData.traceData{channelIndex} = [[zData.traceData{channelIndex}(:, 1:epiIndex - 1); nan(size(tempData.traceData, 1) - size(zData.traceData{channelIndex}, 1), epiIndex - 1)] tempData.traceData(:, channelIndex)];
                                    end
                                    for j = 1:(epiIndex - 1)
                                        zData.protocol(j).sweepWindow = tempData.protocol.sweepWindow;
                                    end
                                end
                            end

                            % concatenate the episodes into the standard list format
                            episodeName = zData.protocol(1).fileName;
                            nameEnd = find(episodeName == 'S', 1, 'last') - 2;
                            episodeName = episodeName(1:nameEnd + 1);

                            % put the data into matrices
                            seqData = zeros(epiIndex, 1);
                            epiData = seqData;
                            for i = 1:epiIndex
                                seqEnd = find(zData.protocol(i).fileName == 'E', 1, 'last') - 2;
                                epiEnd = find(zData.protocol(i).fileName == '.', 1, 'last') - 1;
                                seqData(i) = str2double(zData.protocol(i).fileName(nameEnd + 3:seqEnd));
                                epiData(i) = str2double(zData.protocol(i).fileName(seqEnd + 3:epiEnd));
                            end

                            % sort the data sets
                            whichSeqs = unique(seqData);
                            for i = 1:length(whichSeqs)
                                whichEpis = sort(epiData(seqData == whichSeqs(i)));
                                % concatenate consecutive runs
                                episodeName = strcat(episodeName, 'S', num2str(whichSeqs(i)), '.E', sprintf('%0.0d',whichEpis(1)));
                                lastEpi = whichEpis(1);
                                inRun = 0;
                                for j = 2:length(whichEpis)
                                    if whichEpis(j) - lastEpi == 1
                                        inRun = 1;
                                    else
                                        if inRun
                                            episodeName = strcat(episodeName, '-', sprintf('%0.0d',lastEpi));
                                            inRun = 0;
                                        end
                                        episodeName = strcat(episodeName, ',', sprintf('%0.0d',whichEpis(j)));
                                    end
                                    lastEpi = whichEpis(j);
                                end
                                if inRun
                                    episodeName = strcat(episodeName, '-', sprintf('%0.0d',lastEpi));
                                end
                                episodeName = [episodeName '; '];
                            end
                            episodeName = episodeName(1:end - 2);                    
                        else
                            tempData = readTrace(listModel.getValueAt(whichSelected(1),0));
                            for i = 1:size(tempData.traceData, 2)
                                zData.traceData{i} = tempData.traceData(:,i);
                            end
                            zData.protocol = tempData.protocol;
                            episodeName = listModel.getValueAt(whichSelected(1),0);
                            varargin{1}.scrollRectToVisible(varargin{1}.getCellRect(whichSelected, 0, 1));
                        end

                        set(whichScopes, 'name', episodeName);

                        assignin('base', 'zData', zData);

                        % delete old events
                        for i = whichScopes
                            for j = findobj(i, 'type', 'axes')'
                                if isappdata(j, 'events')
                                    rmappdata(j, 'events');
                                    kids = get(j, 'children');
                                    delete(kids(strcmp(get(kids, 'userData'), 'events')));
                                end
                            end
                        end

                        % call a refresh for all current figures (and any new ones
                        % being created)
                        for i = getappdata(0, 'scopes')
                            newScope(zData.traceData, zData.protocol, i);
                            set(i, 'name', episodeName);
                        end
                    end % isappdata(0, 'scopes')

                % add protocol data if necessary
                    if isappdata(0, 'protocolViewer')
                        set(0, 'currentFigure', getappdata(0, 'fileBrowser'));
                        loadProtocol(listModel.getValueAt(varargin{1}.getSelectedRow, 0));
                    end
                else
                    if isappdata(0, 'imageBrowser')
                        fileNames = {};
                        whichSelected = varargin{1}.getSelectedRows;
                        for i = whichSelected'
                            fileNames{end + 1} = listModel.getValueAt(i,0);
                        end	
                        compressImageStack(fileNames);
                    end
                end
            case 3
                if strcmp(get(handles{9}, 'visible'), 'on')
                    containerPos = get(handles{9}, 'position');
                    set(getappdata(handles{5}, 'uiContextMenu'), 'position', [varargin{2}.getX + handles{1}.getWidth containerPos(4) - varargin{2}.getY], 'visible', 'on');        
                else
                    containerPos = get(handles{8}, 'position');
                    set(getappdata(handles{3}, 'uiContextMenu'), 'position', [varargin{2}.getX + handles{1}.getWidth containerPos(4) - varargin{2}.getY], 'visible', 'on');        
                end
        end
    else % handle column clicks
        if strcmp(get(handles{9}, 'visible'), 'on')
            containerPos = get(handles{9}, 'position');
            set(getappdata(handles{5}, 'columnContextMenu'), 'position', [varargin{2}.getX + handles{1}.getWidth containerPos(4)], 'visible', 'on');        
        else
            containerPos = get(handles{8}, 'position');
            set(getappdata(handles{3}, 'columnContextMenu'), 'position', [varargin{2}.getX + handles{1}.getWidth containerPos(4)], 'visible', 'on');        
        end
        setappdata(getappdata(0, 'fileBrowser'), 'varargin', varargin);
    end
            
    
function closeBrowser(varargin)
	set(gcf, 'units', 'pixels');
	setpref('locations', 'fileBrowser', [get(gcf, 'position') getappdata(gcf, 'ratio')]);
	columnWidths = getpref('fileBrowser', 'columnWidths');
	columnNames = getpref('fileBrowser', 'columnNames');
	columnWidthsImage = getpref('fileBrowser', 'columnWidthsImage');
	columnNamesImage = getpref('fileBrowser', 'columnNamesImage');
	
	handles = get(getappdata(0, 'fileBrowser'), 'userData');
	for i = 1:handles{3}.getColumnCount - 1
        whereColumn = find(strcmp(columnNames, handles{3}.getColumnModel().getColumn(i).getHeaderValue));
        if ~isempty(whereColumn)
            columnOrders(i) = whereColumn;
            columnWidths(columnOrders(i)) = handles{3}.getColumnModel().getColumn(i).getPreferredWidth;
        end
	end
	for i = 1:handles{5}.getColumnCount - 1
        whereColumn = find(strcmp(columnNamesImage, handles{5}.getColumnModel().getColumn(i).getHeaderValue));
        if ~isempty(whereColumn)
            columnOrdersImage(i) = whereColumn;
            columnWidthsImage(columnOrdersImage(i)) = handles{5}.getColumnModel().getColumn(i).getPreferredWidth;
        end
	end
	setpref('fileBrowser', 'columnWidths', columnWidths);
    setpref('fileBrowser', 'columnOrders', columnOrders);
	setpref('fileBrowser', 'columnWidthsImage', columnWidthsImage);
    setpref('fileBrowser', 'columnOrdersImage', columnOrdersImage);
    
    if isappdata(0, 'episodeInfo')
        rmappdata(0, 'episodeInfo');
        rmappdata(0, 'episodeDirectory');
        rmappdata(0, 'episodeHeaders');
        rmappdata(0, 'imageHeaders');
    end
    
    % removes the handle from the appdata construct
    rmappdata(0, 'fileBrowser');
    delete(varargin{1})
    
%% *****************
%% private functions
%% *****************

function parsedSeqs = addSubDirs(treeModel, node)
    parsedSeqs = false;
    nodeInfo = node.getUserObject;
    nodePath = char(nodeInfo.getPath);
    if numel(nodePath) >= 7 && strcmp(nodePath(1:7), 'Desktop')
        if ispc
            fileData = dir(fullfile(getenv('HOMEDRIVE'), getenv('HOMEPATH'), nodePath, filesep));
        else
            fileData = dir(fullfile(getenv('HOME'), nodePath, filesep));
        end
    elseif numel(nodePath) == 2
        % otherwise 'C:' returns the children of the working directory (if
        % it is on C)
        fileData = dir([nodePath filesep]);
        nodePath = [nodePath filesep];
    else
        fileData = dir(nodePath);
    end
    dirCount = 0;
    whichFiles = [];
    if any(strcmp({fileData.name}, 'preParse.mat'))
        if numel(nodePath) >= 7 && strcmp(nodePath(1:7), 'Desktop')
            if ispc
                load(fullfile(getenv('HOMEDRIVE'), getenv('HOMEPATH'), nodePath, filesep, 'preParse.mat')); 
            else
                load(fullfile(getenv('HOME'), nodePath, filesep, 'preParse.mat')); 
            end
        else
            if exist(fullfile(tempdir, 'preParse.mat'), 'file')
                tempData = dir(fullfile(tempdir, 'preParse.mat'));
                currentData = dir([nodePath filesep 'preParse.mat']);
                
                if isempty(tempData) || (tempData.datenum ~= currentData.datenum) || (tempData.bytes ~= currentData.bytes)
                    copyfile([nodePath filesep 'preParse.mat'], fullfile(tempdir, 'preParse.mat'));
                end
            else
                copyfile([nodePath filesep 'preParse.mat'], fullfile(tempdir, 'preParse.mat'));
            end
            load(fullfile(tempdir, 'preParse.mat'));
        end

        if exist('parseData', 'var') && isstruct(parseData) && numel(fieldnames(parseData)) == 6 && all(strcmp(fieldnames(parseData), {'parentNode'; 'text'; 'key'; 'image'; 'episodes'; 'loadWith'}))
            node.getUserObject.setIcon(java.lang.Integer(12));
            parentNode(1) = node;
            for i = 2:numel(parseData)
                treeModel.insertNodeInto(javax.swing.tree.DefaultMutableTreeNode(NodeInfo(parseData(i).text, java.lang.Integer(parseData(i).image), parseData(i).key, '1')), parentNode(parseData(i).parentNode), parentNode(parseData(i).parentNode).getChildCount());                                        
                parentNode(i) =  parentNode(parseData(i).parentNode).getLastChild();
            end   
            setappdata(0, 'episodeInfo', parseData);
            setappdata(0, 'episodeDirectory', directory);
            setappdata(0, 'episodeHeaders', headers);
            setappdata(0, 'imageHeaders', imgHeaders);
            parsedSeqs = true;
        end
    else
        for i = 1:length(fileData)
            if fileData(i).isdir && ~strcmpi(fileData(i).name, 'System Volume Information') && fileData(i).name(1) ~= '.'
                dirCount = dirCount + 1;
                tempData{dirCount} = upper(fileData(i).name);
                whichFiles(dirCount) = i;
                for j = 1:12
                    if ~isempty(strfind(tempData{dirCount}, upper(datestr([2005 j 24 12 34 56], 'mmm')))) || ~isempty(strfind(tempData{dirCount}, datestr([2005 j 24 12 34 56], 'mmm')))
                        tempData{dirCount} = [char(j) tempData{dirCount}];
                        spaces = find(tempData{dirCount} == ' ');
                        if length(spaces) > 1 && spaces(2) - spaces(1) == 2
                            tempData{dirCount} = [tempData{dirCount}(1:spaces(1)) char(1) tempData{dirCount}(spaces(1) + 1:end)]; 
                        end
                    end
                end
            end
        end
        if exist('tempData', 'var')
            [junk indices] = sort(tempData);
            for i = 1:length(indices)
                treeModel.insertNodeInto(javax.swing.tree.DefaultMutableTreeNode(NodeInfo(fileData(whichFiles(indices(i))).name, java.lang.Integer(10), [nodePath fileData(whichFiles(indices(i))).name filesep], '0')), node, node.getChildCount());                        
            end
        end
    end
    
function addSeqNodes(treeModel, node)
    nodeInfo = node.getUserObject;
    nodePath = char(nodeInfo.getPath);
    if numel(nodePath) >= 7 && strcmp(nodePath(1:7), 'Desktop')
        if ispc
            fileList = dir(fullfile(getenv('HOMEDRIVE'), getenv('HOMEPATH'), nodePath));
        else
            fileList = dir(fullfile(getenv('HOME'), nodePath));
        end
    elseif numel(nodePath) == 2
        % otherwise 'C:' returns the children of the working directory (if
        % it is on C)
        fileList = dir([nodePath filesep]);        
    else
        fileList = dir(nodePath);
    end
    
    matList = {fileList(~cellfun('isempty', regexp({fileList.name}, '\.S\d*\.E\d*\.[dm]at'))).name};
    imgList = {fileList(~cellfun('isempty', strfind({fileList.name}, '.img'))).name}; 
    picList = {fileList(~cellfun('isempty', strfind({fileList.name}, '.pic'))).name}; 
	
	% find the unique cell names
    cellNames = cell(numel(matList) + numel(imgList) + numel(picList), 1);
	dots = nan(numel(matList) + numel(imgList) + numel(picList), 3);
	dotCount = 1;
    for i = [matList imgList picList]
        try
            dots(dotCount, :) = find(i{1} == '.', 3, 'first');
            cellNames{dotCount} = i{1}(1:dots(dotCount, 1) - 1);
            dotCount = dotCount + 1;
        catch
            cellNames(dotCount) = '';
        end
    end
    if length(cellNames) == 1 && isempty(cellNames{1})
        return
    end
	[cellNames whichCell whichCell] = unique(cellNames);	
	whichMat = whichCell(1:numel(matList));
	whichMatSeq = nan(numel(matList), 1);
    for i = 1:numel(matList)
		whichMatSeq(i) = str2double(matList{i}(dots(i, 2) + 2:dots(i, 3) - 1));
    end
    try
        whichImageStack = cell(numel(imgList), 1);	
        whichImg = whichCell(numel(matList) + (1:numel(imgList)));
        numMat = numel(matList);
        for i = 1:numel(imgList)
            whichImageStack{i} = imgList{i}(dots(numMat + i, 1) + 1:dots(numMat + i, 2) - 1);
        end
    catch
        whichImg = [];
    end
	whichPic = whichCell(numel(matList) + numel(imgList) + (1:numel(picList)));
	for cellIndex = 1:numel(cellNames)
		% determine what type of files exist for this cell
			whatPresent = 0;
			if any(whichMat == cellIndex)
				whatPresent = whatPresent + 2;
			end
			if any(whichImg == cellIndex)
				whatPresent = whatPresent + 1;
			end
			if any(whichPic == cellIndex)
				whatPresent = whatPresent + 4;
			end		
			
		% generate the cell node		
            if any(whichMat == cellIndex) || any(whichPic == cellIndex) || any(whichImg == cellIndex)
                cellPath = [nodePath cellNames{cellIndex}];
                cellNode = javax.swing.tree.DefaultMutableTreeNode(NodeInfo(cellNames{cellIndex}, java.lang.Integer(whatPresent), cellPath, '1'));
                treeModel.insertNodeInto(cellNode, node, node.getChildCount());
            end
		
		% generate any sequence nodes
			if any(whichMat == cellIndex)
				for seqIndex = unique(whichMatSeq(whichMat == cellIndex))'
                    cellNode.add(javax.swing.tree.DefaultMutableTreeNode(NodeInfo(['S' sprintf('%0.0f', seqIndex) '  (' sprintf('%3.0f', sum(whichMatSeq(whichMat == cellIndex) == seqIndex)) ')'], java.lang.Integer(13), [cellPath matList{find(whichMat == cellIndex, 1)}(dots(find(whichMat == cellIndex, 1), 1):dots(find(whichMat == cellIndex, 1), 2)) 'S' sprintf('%0.0f', seqIndex)], '1')));                        
				end
			end
		
		% generate any pic nodes
			if any(whichPic == cellIndex)
                cellNode.add(javax.swing.tree.DefaultMutableTreeNode(NodeInfo(['  (' sprintf('%3.0f', sum(whichPic == cellIndex)) ')'], java.lang.Integer(14), [cellPath '.pic'], '1')));                                        
			end
		
		% generate any img nodes
			if any(whichImg == cellIndex)
                imgNode = javax.swing.tree.DefaultMutableTreeNode(NodeInfo(['  (' sprintf('%3.0f', sum(whichImg == cellIndex)) ')'], java.lang.Integer(15), [cellPath '.img'], '1'));
                cellNode.add(imgNode);

				for imgIndex = unique(whichImageStack(whichImg == cellIndex))'
                	imgNode.add(javax.swing.tree.DefaultMutableTreeNode(NodeInfo([imgIndex{1} '  (' sprintf('%3.0f', numel(strmatch(imgIndex{1}, whichImageStack(whichImg == cellIndex), 'exact'))) ')'], java.lang.Integer(16), [cellPath '.' imgIndex{1}], '1')));                                                                            
				end
			end
	end % for cellIndex = 1:numel(cellNames)

function numEpisodes = addEpisodes(match)
    handles = get(getappdata(0, 'fileBrowser'), 'userData');
    
    path = match(1:find(match == filesep, 1, 'last'));
    if numel(path) >= 7 && strcmp(path(1:7), 'Desktop')
        if ispc
            path = fullfile(getenv('HOMEDRIVE'), getenv('HOMEPATH'), path);
        else
            path = fullfile(getenv('HOME'), path);
        end
    end
    
    if isappdata(0, 'episodeInfo') && ~isempty(strfind(match, getappdata(0, 'episodeDirectory')))
        episodeData = getappdata(0, 'episodeInfo');
        whichEpisodes = episodeData(strcmp({episodeData.key}, match)).episodes;
        if isempty(whichEpisodes)
            whichEpisodes = {};
            for seqIndex = episodeData(strcmp({episodeData.key}, match)).loadWith
                whichEpisodes = [whichEpisodes episodeData(seqIndex).episodes];
            end
        end
        whichDirectory = regexp(episodeData(strcmp({episodeData.key}, match)).key, ['^.+' filesep], 'match');
        whichDirectory = whichDirectory{1};
        imagesOnly = episodeData(strcmp({episodeData.key}, match)).image > 13;
        if imagesOnly
            imgHeaders = getappdata(0, 'imageHeaders');
            fileNames = {'mg'};
            fileNames(1:numel(whichEpisodes)) = fileNames;
        else
            headers = getappdata(0, 'episodeHeaders');
            fileNames = {'at'};
            fileNames(1:numel(whichEpisodes)) = fileNames;
            headerFields = fields(rmfield(whichEpisodes{1}, {'fileName', 'headerIndex'}));
        end
        isParsed = true;
    else
        isParsed = false;
        fileNames = dir(path);
        fileNames = {fileNames(~[fileNames.isdir]).name};

        imagesOnly = false;
        match = match(find(match == filesep, 1, 'last') + 1:end);	
        % determine which episodes are appropriate
        if strcmp(match(end - 3:end), '.img')
            imagesOnly = true;
            % find all images for a cell
            fileNames = fileNames(~cellfun('isempty', strfind(fileNames, match(1:end - 4))) & ~cellfun('isempty', strfind(fileNames, '.img')));
        elseif strcmp(match(end - 3:end), '.pic')
            imagesOnly = true;
            % find all PIC files for a cell
            fileNames = fileNames(~cellfun('isempty', strfind(fileNames, match(1:end - 4))) & ~cellfun('isempty', strfind(fileNames, '.pic')));
        elseif isempty(find(match == '.', 1))
            % a whole cell is selected so bring up all episodes unless only
            % images are present
            tempFileNames = fileNames(~cellfun('isempty', strfind(fileNames, match)) & ~(cellfun('isempty', strfind(fileNames, '.mat')) & cellfun('isempty', strfind(fileNames, '.dat'))));
            if isempty(tempFileNames)
                imagesOnly = true;
                tempFileNames = fileNames(~cellfun('isempty', strfind(fileNames, match)) & ~cellfun('isempty', strfind(fileNames, '.img')));
                if isempty(tempFileNames)
                    fileNames = fileNames(~cellfun('isempty', strfind(fileNames, match)) & ~cellfun('isempty', strfind(fileNames, '.pic')));
                else
                    fileNames = tempFileNames;
                end
            else
                fileNames = tempFileNames;
            end
        else
            fileNames = fileNames(~cellfun('isempty', strfind(fileNames, [match '.'])));
            if ~sum(~cellfun('isempty', strfind(fileNames, match)) & ~(cellfun('isempty', strfind(fileNames, '.mat')) & cellfun('isempty', strfind(fileNames, '.dat'))))
                imagesOnly = true;
            end
        end
    end
    
	numEpisodes = 0;
    if strcmp(get(0, 'formatSpacing'), 'loose')
        % the output of evalc depends on this setting so we have to know it
        % for filling up the jtable
        whichSpacing = [9 2];
    else
        whichSpacing = [7 1];
    end
	if ~imagesOnly
        tableModel = handles{3}.getModel;
        set(handles{3},'visible','off');
        while tableModel.getRowCount
            tableModel.removeRow(0);
        end
        columnFunctions = getpref('fileBrowser', 'columnTags');
        columnIndices = getpref('fileBrowser', 'columnOrders');
        for i = 1:length(fileNames)
            if strcmp(fileNames{i}(end - 1:end), 'at')
                if isParsed
                    protocol = headers(whichEpisodes{i}.headerIndex);
                    protocol.fileName = [whichDirectory whichEpisodes{i}.fileName];
                    for fieldIndex = headerFields'
                        protocol.(fieldIndex{1}) = whichEpisodes{i}.(fieldIndex{1});
                    end
                else
                    protocol = readTrace([path fileNames{i}], 1);
                end
                if ~isempty(protocol)
                    newRow = javaArray('java.lang.Object', handles{3}.getColumnCount);
                    newRow(1) = java.lang.String(protocol.fileName);
                    for j = 1:handles{3}.getColumnCount - 1
                        try
                            tempText = evalc(columnFunctions{columnIndices(j)});
                            if numel(tempText) > whichSpacing(1)
                                tempText = tempText(whichSpacing(1):end - whichSpacing(2));
                                tempNum = str2double(tempText);
                                if isnan(tempNum)
                                    newRow(j + 1) = java.lang.String(tempText);
                                elseif tempNum == round(tempNum)
                                    newRow(j + 1) = java.lang.Integer(tempNum);
                                else
                                    newRow(j + 1) = java.lang.Float(tempNum);
                                end
                            else
                                newRow(j + 1) = java.lang.String('');
                            end
                        catch
                            newRow(j + 1) = java.lang.String('');
                        end
                    end
                    tableModel.addRow(newRow);                    
                    numEpisodes = numEpisodes + 1;            
                end
            end
        end
        set(handles{3},'visible','on');
        set(handles{8}, 'visible', 'on');
        set(handles{9}, 'visible', 'off');
	else
        tableModel = handles{5}.getModel;
        set(handles{5},'visible','off');
        while tableModel.getRowCount
            tableModel.removeRow(0);
        end
        columnFunctions = getpref('fileBrowser', 'columnTagsImage');
        columnIndices = getpref('fileBrowser', 'columnOrdersImage');
        for i = 1:length(fileNames)
            if isParsed
                info = imgHeaders(whichEpisodes{i}.headerIndex);
                info.fileName = [whichDirectory whichEpisodes{i}.fileName];
            else
                headerData = readImage([path fileNames{i}], 1);
                info = headerData.info;
            end
            if ~isempty(info)
                newRow = javaArray('java.lang.Object', handles{3}.getColumnCount);
                newRow(1) = java.lang.String(info.Filename);
                for j = 1:handles{3}.getColumnCount
                    try
                        tempText = evalc(columnFunctions{columnIndices(j)});
                        if numel(tempText) > whichSpacing(1)
                            tempText = tempText(whichSpacing(1):end - whichSpacing(2));
                            tempNum = str2double(tempText);
                            if isnan(tempNum)
                                newRow(j + 1) = java.lang.String(tempText);
                            elseif tempNum == round(tempNum)
                                newRow(j + 1) = java.lang.Integer(tempNum);
                            else
                                newRow(j + 1) = java.lang.Float(tempNum);
                            end
                        else
                            newRow(j + 1) = java.lang.String('');
                        end
                    catch
                        newRow(j + 1) = java.lang.String('');
                    end
                end
                tableModel.addRow(newRow);                    
                numEpisodes = numEpisodes + 1;            
            end
        end
        set(handles{5},'visible','on');
        set(handles{9}, 'visible', 'on');
        set(handles{8}, 'visible', 'off');
	end
    
function characterizeDirectory(varargin)
    handles = get(getappdata(0, 'fileBrowser'), 'userData');
    whichNode = handles{1}.getLastSelectedPathComponent;
    nodeInfo = whichNode.getUserObject;
    nodePath = char(nodeInfo.getPath);
    feval(get(varargin{1}, 'userData'), nodePath);
    
function reparseDir(varargin)
	handles = get(getappdata(0, 'fileBrowser'), 'userData');
    
    whichNode = handles{1}.getLastSelectedPathComponent;
    nodeInfo = whichNode.getUserObject;
    nodeInfo.setParsed('0');
    if nodeInfo.getIcon == 12
        % if this was from a preParse file then let the use know that it is
        % now live
        nodeInfo.setIcon(java.lang.Integer(10));
    end
    whichNode.removeAllChildren;
    if ~addSubDirs(handles{1}.getModel, whichNode)
        addSeqNodes(handles{1}.getModel, whichNode);
    end
    if strcmp(nodeInfo.getPath, ['Desktop' filesep])
        % add drives and root
        rootNode = invoke(handles{1}.nodes, 'add', handles{1}.SelectedItem, 4);
        set(rootNode, 'key', '', 'image', 1, 'text', 'My Computer', 'Tag', 'parsed', 'sorted', 0);
        driveList = getdrives('-nofloppy');
        for i = 1:length(driveList)
            driveNode = invoke(handles{1}.nodes,'add',rootNode,4);
            set(driveNode, 'key', driveList{i}, 'image', 2, 'text', driveList{i}, 'sorted', 0);
        end
    end
    handles{1}.getModel.reload(whichNode);

function characterizeEpisode(varargin)
    handles = get(getappdata(0, 'fileBrowser'), 'userData');

    if ~double(handles{3}.getSelectedRowCount)
        return
    end
    % find all selected files
    fileNames = {};
    for epiIndex = handles{3}.getSelectedRows'
        fileNames{end + 1} = handles{3}.getModel.getValueAt(epiIndex,0);
    end
    if ~iscell(fileNames) == 1
        fileNames = fileNames{1};
    end        
    feval(get(varargin{1}, 'userData'), fileNames);
    
function displayProtocol(varargin)
    handles = get(getappdata(0, 'fileBrowser'), 'userData');
    listModel = handles{3}.getModel;
    if ~double(handles{3}.getSelectedRowCount)
        return
    end
    loadProtocol(listModel.getValueAt(handles{3}.getSelectedRow,0));
    
function displayNewScope(varargin)    
    handles = get(getappdata(0, 'fileBrowser'), 'userData');
    whatKids = get(0, 'children');
    if isappdata(0, 'scopes')
        whatKids = [whatKids; getappdata(0, 'scopes')];
    end    
    figHandle = fix(rand * 255 + 1);
    while ismember(figHandle, whatKids)
        figHandle = fix(rand * 255 + 1);
    end
    setappdata(0, 'scopes', [getappdata(0, 'scopes'); figHandle]);
	loadEpisode(handles{3}, 0, 1);

function displayImageBrowser(varargin)    
    handles = get(getappdata(0, 'fileBrowser'), 'userData');
    whereImages = handles{3}.getSize;
    if whereImages.getWidth > 0
        listModel = handles{3}.getModel;
        if ~double(handles{3}.getSelectedRowCount)
            return
        end        
        fileName = listModel.getValueAt(handles{3}.getSelectedRow,0);
        imageBrowser(fileName(1:find(fileName == filesep, 1, 'last')));
    else       
        listModel = handles{5}.getModel;
        if ~double(handles{5}.getSelectedRowCount)
            return
        end        
        imageBrowser(listModel.getValueAt(handles{5}.getSelectedRow,0));        
    end