image thumbnail

embeddedmethodsviewer - show functions and methods within matlab editor

by

 

26 Aug 2013 (Updated )

Plugin for the matlab editor, which lists all functions and methods of the currently edited document

embeddedmethodsviewer(argin)
function embeddedmethodsviewer(argin)
%embeddedmethodsviewer()
%    - starts the function
%    - to stop the plugin, simply call the function a second time 
%
%Creates overview of all functions, subfunctions or methods of the currently 
%edited function or class file. For script files the section headlines are
%drawn. For that, a list below the document bar is generated, which refreshes
%automatically while you are typing.
%
%It only works if the position of the document bar is on the right or left
%side of the editor.
%
%The list of functions is sortable and can be used for navigation. It
%should help to keep the overview in large projects or class files.
%Mouseover gives information about in- and output arguments of the
%functions and methods.
%
%Furthermore an instance of the currently edited class file is generated 
%in the base workspace, if the constructor can be called with no arguments.
%Names of instances are: this, obj (change createInstance_, if necessary)
%
%Please report all bugs found.
%
%If you like the plugin, add 'embeddedmethodsviewer' to your 'startup.m' file
%
%Many thanks to Yair Altman for providing findjobj.
%
%In most cases function needs 'findjobj' from matlabcentral.com:
%http://www.mathworks.com/matlabcentral/fileexchange/14317

%history:
%2013/08/26 - first release
%2013/08/30 - resolved problems with r2013b preview, changed way to quit program

persistent running_;

createInstance_ = {'this','obj'};
htmlData_ = cell(0,0);
data_ = cell(0,0);
objLineNum = [];
htmlDataOld_ = cell(0,0);
dataOld_ = cell(0,0);
selectedFunOld_ = -1;
openedFileOld_ = '';
textOld_ = cell(0,0);
fileType_ = 'script';
drawTyp_ = 'cells';
filetext_ = cell(0,0);
fileActiveObj_ = matlab.desktop.editor.Document.getActiveEditor;
header_ = '';
filenameShort_ = '';
% debugMode_ = 1;
matlabVersion_ = verLessThan('matlab','8.2.0');


% import javax.swing.*
% import java.awt.*

if nargin == 0
    argin = [];
end

[jhDocumentContainer, jhPane_, jhBar_, startError] = getDocumentContainer();
if isempty(jhDocumentContainer) || startError ~=0
    if startError == 1
        fprintf(2,'Can''t find the handle of the editor. Make sure the function "findjobj" is in your matlab path.\n\nYou can download it from matlabcentral.com:\n');
        fprintf('<a href = "http://www.mathworks.com/matlabcentral/fileexchange/14317">http://www.mathworks.com/matlabcentral/fileexchange/14317</a>\n');
        return;
%         error('embeddedmethodsviewer:findjobj','Can''t find the handle of the editor. Make sure the function "findjobj" is in your matlab path.\n\nYou can download it from matlabcentral.com: http://www.mathworks.com/matlabcentral/fileexchange/14317') ;
    elseif startError == 2
        fprintf(2,'Editor is not opened. Please open the matlab editor and retry.\n');
%         error('embeddedmehtodsviewer:Editor','Editor is not opened. Please open editor and retry.')
        return;
    end
    return;
%     rethrow(exception)
end

% 
% if matlabVersion_ == 1
%     jhBar_ = jhDocumentContainer.getComponent(0);
%     jhPane_ = jhDocumentContainer.getComponent(1);
% else
%     jhPane_ = jhDocumentContainer.getComponent(0);
%     if ~isempty(running_)
%         jhBar_ = jhPane_.getComponent(0).getComponent(0);
%     else
%         jhBar_ = jhPane_.getComponent(0);
%     end
% end


%% determine if embeddedmethodsviews was already started

if ~isempty(running_) % function runs
    deleteCallback(jhDocumentContainer, jhBar_, jhPane_)
    deleteSplitPane (jhPane_, jhBar_)
    munlock;
    clear running_
    clear
    return;
end
[jhTablePlace,jhTable_] = generateTable();
jhSplit_ = generateSplitPane(jhPane_, jhBar_, jhTablePlace);

running_ = true;
mlock; %lock file to prevent deleting of running_


setCallbacks(jhTable_,jhDocumentContainer,jhBar_,jhPane_)

updateTableFull(jhTable_);

updateSizeBar(jhPane_,jhBar_,jhSplit_);
if matlabVersion_
    if jhPane_.getHeight ~= jhDocumentContainer.getComponent(0).getHeight
        disp('Please make sure that the document bar position is right or left')
    end
else
    if jhPane_.getHeight ~= jhPane_.getComponent(1).getHeight
        disp('Please make sure that the document bar position is right or left')
    end
end
clear jhDocumentContainer jhTablePlace startError;

   

%% helper functions


function setCallbacks(jhTable_,jhDocumentContainer,jhBar_,jhPane_)%,jh_SaveB)
% sets callbacks to refresh table when necassary
    
    set(handle(jhDocumentContainer,'CallbackProperties'),'ComponentAddedCallback',@editorComponentChangedCall);
    set(handle(jhPane_,'CallbackProperties'),'ComponentAddedCallback',@componentAddedfunction);
%     set(handle(jhPane_,'CallbackProperties'),'ComponentMovedCallback',@sizeBarCall);

    
    set(handle(jhTable_.getTableHeader,'CallbackProperties'),'MouseMovedCallback',@mouseMovedHeaderCall);
    set(handle(jhTable_,'CallbackProperties'),'MousePressedCallback',@mousePressedCall);
    set(handle(jhTable_,'CallbackProperties'), 'MouseMovedCallback',   @mouseMovedCall);    % mouse hover tooltips
    
    setRefreshCallbacks(jhPane_)    

end
function deleteCallback(jhDocumentContainer,jhBar_,jhPane_)
% delete all callbacks
    set(handle(jhDocumentContainer,'CallbackProperties'),'ComponentAddedCallback',[]);
    set(handle(jhPane_,'CallbackProperties'),'ComponentAddedCallback',[]);    
%     set(handle(jhPane_,'CallbackProperties'),'ComponentMovedCallback',[]);
    jhComp = jhPane_.getComponents;
    if matlabVersion_
        iStart = 1;
    else
        iStart = 2;
    end
    for i_comp = iStart:numel(jhComp)
        jh_he = jhComp(i_comp).getComponent(0).getComponent(0).getComponent(1).getComponent(0).getComponent(0).getComponent(0).getComponent(0).getComponent(1).getComponent(0).getComponent(0);
        callback_handl = handle(jh_he,'CallbackProperties');
        set(callback_handl,'CaretUpdateCallback',[]);
        set(callback_handl,'FocusGainedCallback',[]);
        set(handle(jhPane_.getComponent(i_comp-1),'CallbackProperties'),'ComponentResizedCallback',[]);
        set(handle(jhPane_.getComponent(i_comp-1),'CallbackProperties'),'ComponentMovedCallback',[]);
    end
end

function [jhDocumentContainer, jhPane_, jhBar_, startError] = getDocumentContainer()
    startError = 0;
    try
        desktop = com.mathworks.mde.desk.MLDesktop.getInstance;
        jEditor = desktop.getGroupContainer('Editor').getTopLevelAncestor;
        try
            try 
                %editor window docked
                jh_temp0 = jEditor.getComponent(0).getComponent(1).getComponent(0).getComponent(2).getComponent(4).getComponent(1).getComponent(0).getComponents;
                jh_EditorGroupFrame = [];
                for i1 = 1:numel(jh_temp0)
                    if isequal(char(jh_temp0(i1).getName),'EditorGroupFrame')
                        jh_EditorGroupFrame = jh_temp0(i1);
                        break;
                    end
                end
                if isempty(jh_EditorGroupFrame)
                    error('Editor not found; try undocked');
                end
            catch
                %editor undocked
                try %mac
                    jh_EditorGroupFrame = jEditor.getComponent(0).getComponent(1).getComponent(0).getComponent(1);
                    if ~strcmp(jh_EditorGroupFrame.getName,'EditorGroupFrame')
                        error('Editor not found, try Windows');
                    end
                catch %windows
                    jh_EditorGroupFrame = jEditor.getComponent(0).getComponent(1).getComponent(1).getComponent(1);
                    if ~strcmp(jh_EditorGroupFrame.getName,'EditorGroupFrame')
                        error('Editor not found, try findjobj');
                    end
                end
            end
        catch
            try
                disp('Searching for DocumentContainer')
                jh_EditorGroupFrame = findjobj(jEditor,'property',{'name','EditorGroupFrame'});
            catch exception
                %  error('embeddedmethodsviewer:findjobj','Can''t find the handle of the editor. Make sure the function "findjobj" is in your matlab path.\n\nYou can download it from matlabcentral.com: http://www.mathworks.com/matlabcentral/fileexchange/14317') 
                jh_EditorGroupFrame = [];
                startError = 1;
            end
        end

        try 
            jhDocumentContainer = jh_EditorGroupFrame.getComponent(0).getComponent(0).getComponent(1);
            if ~strcmp(jhDocumentContainer.getName,'DesktopDocumentContainer')
                error('Editor not found try findjobj');
            end
        catch
            try
                jhDocumentContainer = findjobj(jh_EditorGroupFrame.getComponent(0),'class','DTDocumentContainer');
            catch exception
                %  error('embeddedmethodsviewer:findjobj','Can''t find the handle of the editor. Make sure the function "findjobj" is in your matlab path.\n\nYou can download it from matlabcentral.com: http://www.mathworks.com/matlabcentral/fileexchange/14317') 
                jhDocumentContainer = [];
                startError = 1;
            end
        end
    catch exception
        jhDocumentContainer = [];
        startError = 2;
%         warning('embeddedmehtodsviewer:getDocumentContainer','Editor is not opened!')
    end
    if ~isempty(jhDocumentContainer)
        if matlabVersion_ == 1
            jhBar_ = jhDocumentContainer.getComponent(0);
            jhPane_ = jhDocumentContainer.getComponent(1);
        else
            jhPane_ = jhDocumentContainer.getComponent(0);
            if ~isempty(running_)
                jhBar_ = jhPane_.getComponent(0).getComponent(0);
            else
                jhBar_ = jhPane_.getComponent(0);
            end
        end
    else
        jhPane_ = [];
        jhBar_ = [];
    end
end

% function jhSaveB = getSaveButton ()
%     desktop = com.mathworks.mde.desk.MLDesktop.getInstance;
%     jEditor = desktop.getGroupContainer('Editor').getTopLevelAncestor;
%     jhSaveB = findjobj(jEditor,'property',{'name','editor_toolset:save'});
% end

%%
function setRefreshCallbacks(jhPane_)
    
    jhComp = jhPane_.getComponents;
    if matlabVersion_
        iStart = 1;
    else
        iStart = 2;
    end
    for i_comp = iStart:numel(jhComp)
        jh_help = jhComp(i_comp).getComponent(0).getComponent(0).getComponent(1).getComponent(0).getComponent(0).getComponent(0).getComponent(0).getComponent(1).getComponent(0).getComponent(0);
        callback_handles = handle(jh_help,'CallbackProperties');
        set(callback_handles,'CaretUpdateCallback',@caretUpdateCall);
        set(callback_handles,'FocusGainedCallback',@focusGainedCall);
        set(handle(jhPane_.getComponent(i_comp-1),'CallbackProperties'),'ComponentResizedCallback',@sizeBarCall);
        set(handle(jhPane_.getComponent(i_comp-1),'CallbackProperties'),'ComponentMovedCallback',@sizeBarCall);
    end
    
end



%% callbackfunction
function caretUpdateCall(varargin)
    updateTable(jhTable_);
%     try
%         updateTable(jhTable_);
%     catch exception
%         if debugMode_ == 0
%             return;
%         elseif debugMode_ == 1
%             warning('error in caretUpdateCall:updateTable');
%             disp(exception.message);
%             fprintf('line: %u\n',exception.stack(1).line) 
%             disp(exception.identifier);
%         else
%             exception.rethrow;
%         end
%     end
% % %     disp('caretUpdateCall')
end

function focusGainedCall(varargin)
    % text regain focus
    updateTableFull(jhTable_);
%     try
%         updateTableFull(jhTable_);
%     catch exception
%         if debugMode_ == 0
%             return;
%         elseif debugMode_ == 1
%             warning('error in focusGainedCall:updateTableFull');
%             disp(exception.message);
%             fprintf('line: %u\n',exception.stack(1).line) 
%             disp(exception.identifier);
%         else
%             exception.rethrow;
%         end
%     end
% % %     disp('focusGainedCall')
end


function componentAddedfunction(varargin)
    % i.e. new text document
% % %     try
% % % %         setRefreshCallbacks(jhDocumentContainer.getComponent(1));
% % %         setRefreshCallbacks(jhPane_);
% % %     catch
% % %         
% % %     end
% % % %     disp('componentAddedfunction')
% % %     updateTable(jhTable_); % changed: 25.08.2013
    setRefreshCallbacks(jhPane_);
    updateTable(jhTable_);
%     try
% %         setRefreshCallbacks(jhDocumentContainer.getComponent(1));
%         setRefreshCallbacks(jhPane_);
%         updateTable(jhTable_);
%     catch exception
%         if debugMode_ == 0
%             return;
%         elseif debugMode_ == 1
%             warning('error in componentAddedfunction:setRefreshCallbacks,updateTable');
%             disp(exception.message);
%             fprintf('line: %u\n',exception.stack(1).line) 
%             disp(exception.identifier);
%         else
%             exception.rethrow;
%         end
%     end
% % %     disp('componentAddedfunction')
    
end

function editorComponentChangedCall(varargin)
    setRefreshCallbacks(jhPane_);
    set(handle(jhPane_,'CallbackProperties'),'ComponentAddedCallback',@componentAddedfunction);
%     try    
%         setRefreshCallbacks(jhPane_);
%         set(handle(jhPane_,'CallbackProperties'),'ComponentAddedCallback',@componentAddedfunction);
% 
%     %     setRefreshCallbacks(jhDocumentContainer.getComponent(1));
%     %     set(handle(jhDocumentContainer.getComponent(1),'CallbackProperties'),'ComponentAddedCallback',@componentAddedfunction);
%     %     disp('editorComponentChangedCall')
%         updateTable(jhTable_);
%     catch exception
%         if debugMode_ == 0
%             return;
%         elseif debugMode_ == 1
%             warning('error in editorComponentChangedCall:setRefeshCallback,updateTable');
%             disp(exception.message);
%             fprintf('line: %u\n',exception.stack(1).line) 
%             disp(exception.identifier);
%         else
%             exception.rethrow;
%         end
%     end
% % % disp('editorComponentChangedCall')
end 

function mousePressedCall(src, event)
    % exit if invalid handle
    if ~ishandle(src)
        return;
    end
    tableObj = event.getComponent;
    modelObj = tableObj.getModel;
    selectedRowIdx    = tableObj.getSelectedRow;
    sortedRowIdx = modelObj.getActualRowAt(selectedRowIdx);
    numline = objLineNum(sortedRowIdx+1);
    fileActiveObj_.goToLine(numline);
    fileActiveObj_.makeActive
    selectedFunOld_ = sortedRowIdx +1;
% % %     disp('mousePressedCall')
%         
%     try
%         tableObj = event.getComponent;
%         modelObj = tableObj.getModel;
%         
%         selectedRowIdx    = tableObj.getSelectedRow;
%         sortedRowIdx = modelObj.getActualRowAt(selectedRowIdx);
%         numline = objLineNum(sortedRowIdx+1);
%         fileActiveObj_.goToLine(numline);
%         fileActiveObj_.makeActive
%         selectedFunOld_ = sortedRowIdx +1;
%    catch exception
%         if debugMode_ == 0
%             return;
%         elseif debugMode_ == 1
%             warning('error in mouseMovedCall');
%             disp(exception.message);
%             fprintf('line: %u\n',exception.stack(1).line) 
%             disp(exception.identifier);
%         else
%             exception.rethrow;
%         end
%     end
% % %     catch %#ok<CTCH>
% % %     end %changed: 25.08.2013
end

function mouseMovedCall(~, event)
    x = event.getX;
    y = event.getY;
    tableObj = event.getComponent;
    modelObj = tableObj.getModel;
    RowIdx = tableObj.rowAtPoint(java.awt.Point(x,y));
    RowIdx = modelObj.getActualRowAt(RowIdx);
    % % %         try
    % Set the tooltip string based on function or cell name

    %                   tooltipStr = objLineNum{RowIdx+1};
    if strcmp(drawTyp_,'cells')
        linetop = objLineNum(RowIdx+1);
        if RowIdx+2 > numel(objLineNum)
            linebottom = numel(filetext_);
        else
            linebottom = objLineNum(RowIdx+2)-1;
        end
        linebottom = min(linebottom,linetop+20);
        tooltipStr = cellNameContent(filetext_,linetop,linebottom);
    else
        tooltipStr = functionNameInOut(filetext_{objLineNum(RowIdx+1)});
    end
    set(tableObj,'ToolTipText',tooltipStr)
% % %     disp('mouseMovedCall')
%     try
%         x = event.getX;
%         y = event.getY;
%         tableObj = event.getComponent;
%         modelObj = tableObj.getModel;
%         RowIdx = tableObj.rowAtPoint(java.awt.Point(x,y));
%         RowIdx = modelObj.getActualRowAt(RowIdx);
% % % %         try
%             % Set the tooltip string based on function or cell name
% 
%             %                   tooltipStr = objLineNum{RowIdx+1};
%             if strcmp(drawTyp_,'cells')
%                 linetop = objLineNum(RowIdx+1);
%                 if RowIdx+2 > numel(objLineNum)
%                     linebottom = numel(filetext_);
%                 else
%                     linebottom = objLineNum(RowIdx+2)-1;
%                 end
%                 linebottom = min(linebottom,linetop+20);
%                 tooltipStr = cellNameContent(filetext_,linetop,linebottom);
%             else
%                 tooltipStr = functionNameInOut(filetext_{objLineNum(RowIdx+1)});
%             end
%             set(tableObj,'ToolTipText',tooltipStr)
% % % %         catch er
% % % %             disp(er.message);
% % % %             disp(er.stack(1).line)
% % % % 
% % % %         end %changed: 25.08.2013
%     
%     catch exception
%         if debugMode_ == 0
%             return;
%         elseif debugMode_ == 1
%             warning('error in mouseMovedCall');
%             disp(exception.message);
%             fprintf('line: %u\n',exception.stack(1).line)
%             disp(exception.identifier);
%         else
%             exception.rethrow;
%         end
%     end
% % %     catch %#ok<CTCH>
% % %     end %changed: 25.08.2013
%     return;  % debug breakpoint
end

function mouseMovedHeaderCall(varargin)
    [filename_with_pkg,filenameShort_] = filenameWithPackage(fileActiveObj_.JavaEditor.getLongName);
    isclassfile = exist(filename_with_pkg,'class');
    if isclassfile == 8
        methodslist = getObjMethods(filename_with_pkg);
%         header_ = {[filenameShort_,': methods']};
        jhTable_.getTableHeader.setToolTipText(methodslist);
    else
%         header_ = {[filenameShort_,': ',drawTyp_]};
        jhTable_.getTableHeader.setToolTipText(fileActiveObj_.JavaEditor.getLongName);
    end
% % %     disp('mouseMovedHeaderCall')
%     try
%         [filename_with_pkg,filenameShort_] = filenameWithPackage(fileActiveObj_.JavaEditor.getLongName);
%         isclassfile = exist(filename_with_pkg,'class');
%         if isclassfile == 8
%             methodslist = getObjMethods(filename_with_pkg);
%     %         header_ = {[filenameShort_,': methods']};
%             jhTable_.getTableHeader.setToolTipText(methodslist);
%         else
%     %         header_ = {[filenameShort_,': ',drawTyp_]};
%             jhTable_.getTableHeader.setToolTipText(fileActiveObj_.JavaEditor.getLongName);
%         end
%     catch exception
%         if debugMode_ == 0
%             return;
%         elseif debugMode_ == 1
%             warning('error in mouseMovedHeaderCall');
%             disp(exception.message);
%             fprintf('line: %u\n',exception.stack(1).line) 
%             disp(exception.identifier);
%         else
%             exception.rethrow;
%         end
%     end
end
function sizeBarCall(varargin)
    updateSizeBar(jhPane_, jhBar_, jhSplit_ );
%     disp('sizeBarCall')
end      


%%
function updateSizeBar(jhPane_, jhBar_, jhSplit_)

    if matlabVersion_
        wBar = jhBar_.getSize.getWidth;
        hBar = jhBar_.getSize.getHeight;

        w_grip = jhBar_.getComponent(1).getSize.getWidth;


        if any(w_grip <= 10)
            jhSplit_.setLocation(11,0)
            new_size_w = wBar-11;
            new_size_h = hBar;
            jhSplit_.setSize(new_size_w,new_size_h)
        else
            jhSplit_.setLocation(5,11);
            new_size_w = wBar-5;
            new_size_h = hBar-11;
            jhSplit_.setSize(new_size_w,new_size_h)
        end

        if new_size_h < 150
            
            jhSplit_.getComponent(1).setVisible(false)
            jhSplit_.getComponent(2).setVisible(false)
        else
            jhSplit_.getComponent(1).setVisible(true)
            jhSplit_.getComponent(2).setVisible(true)
        end
    else
        
        boundsPane = jhPane_.getBounds();
        boundsEditor = jhPane_.getComponent(1).getBounds();
        
        wPane = boundsPane.getWidth;
        wEditor = boundsEditor.getWidth;
        hPane = boundsPane.getHeight;
        hEditor = boundsEditor.getHeight;
        if hPane == hEditor %document bar on the right or left side
            wBar = wPane - wEditor;
            hBar = hPane;
            yBar = 0;
            if boundsEditor.getX > 0 %document bar on left side
                xBar = 0;

            else % document bar left 
                xBar = wEditor;
            end
        else % on top or button
            wBar = wPane;
            hBar = hPane - hEditor;
            xBar = 0;
            if boundsEditor.getY > 0 %document bar on the top
                yBar = 0;
            else
                yBar = hEditor;
            end
        end
        jhSplit_.setBounds(xBar,yBar,wBar,hBar);
        if hBar < 150
            jhSplit_.getComponent(1).setVisible(false)
            jhSplit_.getComponent(2).setVisible(false)
        else
            jhSplit_.getComponent(1).setVisible(true)
            jhSplit_.getComponent(2).setVisible(true)
        end



    end

    jhSplit_.validate()

end

%%
function [subFunList,objLineNum ,htmlFunList] = getObjFunctions(txt)
    if numel(txt) == 1
        txt_new = strtrim(txt{1});
        subFunList = [];
        htmlFunList = [];
        objLineNum = [];
        if strncmp(txt_new,'function ',9);
            name = functionName(txt_new);
            if name
                subFunList{1,1} = name;
                htmlFunList{1,1} = ['<html><font color="blue">',name,'</html>'];
                objLineNum = 1;
            end
        end
    else
        %find all lines starting with 'function' signature
        txt_new = strtrim(txt);
        function_pos = strncmp(txt_new,'function ',9);
%         function_pos_cell =  strfind(txt_new,'function ');
%         function_pos = NaN(size(function_pos_cell));
%         index_n = cellfun('prodofsize',function_pos_cell)==1 & (cellfun('isclass',function_pos_cell,'double'));
%         function_pos(index_n) = [function_pos_cell{index_n}];
%         function_pos = (function_pos == 1);
%         
        numel_funs = sum(function_pos);
        objLineNum = find(function_pos);
        subFunList = cell(numel_funs,1);
        htmlFunList = cell(numel_funs,1);
        objNum = 0;
        lineEmpty = [];
        for i_lineNum = 1:numel_funs  %check one line at a time
            name = functionName(txt_new{objLineNum(i_lineNum)});
            if name
                objNum = objNum +1;
                subFunList{objNum,1} = name;
                htmlFunList{objNum,1} = ['<html><font color="blue">',name,'</html>'];
            else
               % objLineNum(i_lineNum) = [];
                lineEmpty(end+1) = i_lineNum;
                subFunList(end) = [];
                htmlFunList(end) = [];
            end
        end
        objLineNum(lineEmpty) = [];
        
    end
end
    
%     htmlFunList = cell(size(subFunList));
%     for i_fun = 1:numel(subFunList)
%         htmlFunList{i_fun,1} = ['<html><font color="blue">',subFunList{i_fun,1},'</html>'];
%     end
%     if numel(subFunList) >2
%         [~, sortindex] = sort(lower(subFunList(2:end)));
%         subFunList = subFunList([1;sortindex+1]);
%         objLineNum = objLineNum([1;sortindex+1]);
%         htlmfunList = htlmfunList([1;sortindex+1]);
%     end



%%
function name = functionName(txt) %raer
    % returns name of function, if line containes function, else empty
    txt = txt(10:end);
    name = strtrim(regexprep(txt,'\(.*.*|\%.*','','once'));
    name = regexp(name,'((\w)*\.)?(\w)*$','once','match');
end

%%

function namefull = functionNameInOut(txt) %4w5wrerf
    % returns name of function, input and output
    txt = strtrim(txt);
    txt = txt(10:end);
    namefull = regexp(txt,'^(( )*(.)+( )*=( )*)?(\w)+(\.(\w)+)?(\((.)*\))?','once','match');
%     func_pos = regexp(txt,'^( )*function( )+', 'once','split');
%     namefull = func_pos{1}{2};
 
end
%%
function [ObjList, objLineNum ,htmlcellList] = getObjCells(txt)

    [ObjList, objLineNum] = getCells(txt);
    htmlcellList = getHtmlCells(ObjList);
%     ObjList = {};
%     objLineNum = [];
%     htlmcellList = {};
%     objNum = 0;
%     unnamedcellNum = 0;
%     for i_lineNum = 1:numel(txt)  %check one line at a time
% 
%         name = cellName(txt{i_lineNum});
% 
%         if ~isempty(name) %found one, add to list
%             objNum = objNum +1;
%             ObjList(objNum,1) = {name}; %#ok<AGROW>
%             objLineNum(objNum,1) = i_lineNum; %#ok<AGROW>
%             if eq(name,1)
%                 unnamedcellNum = unnamedcellNum +1;
%                 name = ['cell ',num2str(unnamedcellNum)];
%             end
%             htlmcellList(objNum,1) = {['<html><font color="green">',name,'</html>']}; %#ok<AGROW>
%         end
%     end

end
%%
function [CellList, objLineNum] = getCells(txt)
    
    %find all lines starting with '%%' signature
    if numel(txt) == 1
        txt_new = strtrim(txt{1});
        CellList = {};
        objLineNum = [];
        if strncmpi(txt_new,'%%',2);
            name = cellName(txt_new);
            if name
                CellList{1,1} = name;
                objLineNum = 1;
            end
        end
    else
        txt_new = strtrim(txt);
        objLineNum =  strncmp(txt_new,'%%',2);
        numel_cell = sum(objLineNum);
        objLineNum = find(objLineNum);
        CellList = cell(numel_cell,1);
        objNum = 0;
        for i_lineNum = 1:numel_cell  %check one line at a time
            name = cellName(txt_new{objLineNum(objNum+1)});
            if name
                objNum = objNum +1;
                CellList{objNum,1} = name;
            else
                objLineNum(objNum+1) = [];
                CellList = CellList(1:end-1);
            end
        end
%         objLineNum = objLineNum(1:objNum);
    end
%     CellList = {};
%     objLineNum = [];
%     objNum = 0;
%     for i_lineNum = 1:numel(txt)  %check one line at a time
%         name = cellName(txt{i_lineNum});
%         if name %found one, add to list
%             objNum = objNum +1;
%             CellList{objNum,1} = name; %#ok<AGROW>
%             objLineNum(objNum,1) = i_lineNum; %#ok<AGROW>
%         end
%     end
    
end
%%
function htmlcelllist = getHtmlCells(CellList)
    htmlcelllist = cell(size(CellList));
    unnamedcellNum = 0;
    for i_c = 1:numel(CellList)
        if isequal(CellList{i_c},1)
            unnamedcellNum = unnamedcellNum +1;
            name = ['cell ',num2str(unnamedcellNum)];
        else
            name = CellList{i_c};
        end
        htmlcelllist{i_c} = ['<html><font color="green">',name,'</html>'];
    end
end
%%
function cell_out = cellName(txt)
    cell_pos = regexp(txt,'(^%{2}[^\S]*$)|(?<=^%{2}( )+)\S+','once');
    if cell_pos
        if cell_pos == 1;
            cell_out = 1;
        else
            cell_out = txt(cell_pos:end);
        end
    else
        cell_out = [];
    end


end
%%
function cell_content = cellNameContent(txt,line1,line2)
    % content of text between the given lines
    cell_content = ['<html><font color="green">',txt{line1},'</font color>'];
    for i_line = line1+1:line2
        cell_content = [cell_content,'<br />',txt{i_line}]; %#ok<AGROW>
    end
    cell_content = [cell_content,'</html>'];
end


%%
function jhSplit_ = generateSplitPane(jhPane_,jhBar_,jhTablePlace)
    import javax.swing.*
    import java.awt.*
% %     
    if matlabVersion_
% %         jhSplit_ = JSplitPane(JSplitPane.VERTICAL_SPLIT,jhBar_.getComponent(0),jhTablePlace);
        jhSplit_ = com.mathworks.mwswing.MJSplitPane(JSplitPane.VERTICAL_SPLIT,jhBar_.getComponent(0),jhTablePlace);
        jhBar_.add(jhSplit_,0);    
    else
% %         jhSplit_ = JSplitPane(JSplitPane.VERTICAL_SPLIT,jhBar_,jhTablePlace);
        % possible use of matlab implementation:
        jhSplit_ = com.mathworks.mwswing.MJSplitPane(JSplitPane.VERTICAL_SPLIT,jhBar_,jhTablePlace);
        jhPane_.remove(jhBar_);
        jhPane_.add(jhSplit_,0);
    end
    
%     jhBar_.setComponentZOrder(jhSplit_,0)
    jhSplit_.setContinuousLayout(true);
    jhSplit_.setOneTouchExpandable(true);
    jhSplit_.setSize(jhSplit_.getPreferredSize)
% %     
    jhSplit_.resetToPreferredSizes()
% %     jhSplit_.setContinuousLayout(true);
% %     jhSplit_.setLocation(5,11);
    jhSplit_.setAlignmentX(0.0);
    jhSplit_.setAlignmentY(0.0);
    jhSplit_.setDividerLocation(0.5);
    jhSplit_.setResizeWeight(0.5);
    jhSplit_.setPreferredSize(java.awt.Dimension(500,5000));

%     jhSplit_.getComponent(1).setBackground(Color(1 ,1, 1));
    jhSplit_.validate()
    

end

%%
function deleteSplitPane (jhPane_, jhBar_)
    if matlabVersion_
        jhStripOrig = jhBar_.getComponent(0).getComponent(0);
        jhBar_.remove(jhBar_.getComponent(0));
        jhBar_.add(jhStripOrig,0);
    else
        jhBarOrig = jhPane_.getComponent(0).getComponent(0);
        jhPane_.remove(jhPane_.getComponent(0));
        jhPane_.add(jhBarOrig,0);
    end
    jhPane_.validate();
    jhPane_.repaint();

    jhBar_.validate();
    jhBar_.repaint();
    
end
%%
function [jh_panel,jhTable_] = generateTable()
    import javax.swing.*
    import java.awt.*

    headers = {' '};
    data_ = {' '};
    com.mathworks.mwswing.MJUtilities.initJIDE;
    jhTable_ = eval('com.jidesoft.grid.TreeTable(data_, headers);');  % prevent JIDE alert by run-time (not load-time) evaluation

    jhTable_.setRowAutoResizes(true);
    jhTable_.setColumnAutoResizable(true);
    jhTable_.setColumnResizable(true);
    jideTableUtils = eval('com.jidesoft.grid.TableUtils;');  % prevent JIDE alert by run-time (not load-time) evaluation
    jideTableUtils.autoResizeAllColumns(jhTable_);
    jhTable_.setShowGrid(0);
    jhTable_.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
    jhTable_.setPreserveSelectionsAfterSorting(true);
    jlist_methods_place = javax.swing.JScrollPane(jhTable_);
    jlist_methods_place.setVerticalScrollBarPolicy(jlist_methods_place.VERTICAL_SCROLLBAR_AS_NEEDED);
%     jlist_methods_place.setHorizontalScrollBarPolicy(jlist_methods_place.HORIZONTAL_SCROLLBAR_AS_NEEDED);
    jlist_methods_place.setAutoscrolls(true)
%     jlist_methods_place.setPreferredSize(java.awt.Dimension(160,5000));
%     jlist_methods_place.setBackground(Color(1 ,1, 1));
    jhTable_.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
    jhTable_.setAutoResizeMode(jhTable_.AUTO_RESIZE_SUBSEQUENT_COLUMNS);
    jhTable_.setShowSortOrderNumber(false)
    jhTable_.setSortArrowForeground(java.awt.Color(1 ,1, 1))
    cbNameTextField = JTextField;
    cbNameTextField.setEditable(false);  % ensure that the callback names are not modified...
    cbNameCellEditor = DefaultCellEditor(cbNameTextField);
    cbNameCellEditor.setClickCountToStart(intmax);  % i.e, never enter edit mode...
    for colIdx = 1:length(headers)
        jhTable_.getColumnModel.getColumn(colIdx-1).setCellEditor(cbNameCellEditor);
    end
    jh_panel = jlist_methods_place;
end



%%
function updateTable(jhTable_)
    fileActiveObj_ = matlab.desktop.editor.Document.getActiveEditor;
    if ~strcmp(fileActiveObj_.JavaEditor.getLongName,openedFileOld_)
        updateTableFull(jhTable_);
        return;
    end
%     import javax.swing.*
%     import java.awt.*
    
%     try

%     fileActiveObj_ = matlab.desktop.editor.getActive;
    filetext_ = regexp(char(fileActiveObj_.JavaEditor.getText),'\n','split')';
    
    selected_row = fileActiveObj_.JavaEditor.getLineNumber + 1;
    
    numel_text = numel(filetext_);
    numel_text_old = numel(textOld_);
    numel_abs = abs(numel_text-numel_text_old);
    
    tablerefresh = false;
    tablerefresh_items = [];

    % try to predict, which lines are changed
    if numel_text > numel_text_old
        cell_input = cell(numel_abs,1);
        textOld_ = [textOld_(1:selected_row-numel_abs); cell_input ;textOld_(selected_row+1-numel_abs:end)];
        objline_shift = (objLineNum > selected_row-numel_abs);
        objLineNum = objLineNum + objline_shift*(numel_abs);
    elseif numel_text < numel_text_old
        textOld_ = [textOld_(1:selected_row);textOld_(selected_row+1+numel_abs:end)];
        objline_shift1 = (objLineNum <= selected_row+numel_abs);
        objline_shift2 = (objLineNum > selected_row);
        objLineNum = objLineNum - objline_shift2*numel_abs;
        objLineNum(objline_shift1 & objline_shift2) = [];
        data_(objline_shift1 & objline_shift2) = [];
        htmlData_(objline_shift1 & objline_shift2) = [];
        if any(objline_shift1 & objline_shift2)
            tablerefresh = true;
        end
    end
    
    num_diff = find(~strcmp(filetext_,textOld_));
    if num_diff
%         disp(['changed line: ',num2str(num_diff)]);
        textOld_ = filetext_;
        
        % delete changed lines from Objline-List and data_-list
        if objLineNum
            objlines = any(bsxfun(@eq,objLineNum,num_diff'),2);
            data_(objlines) = [];
            objLineNum(objlines) = [];
            htmlData_(objlines) = [];
        end
        % find new function
        [data_new,ObjlineNum_new,htmldata_new] = getObjFunctions(filetext_(num_diff));
        if strcmp(drawTyp_,'cells') && ~isempty(data_new)
            updateTableFull(jhTable_,filetext_);
            return;
        end
        
        if strcmp(fileType_,'function') && strcmp(drawTyp_,'subfunctions')
            if (numel(data_) + numel(data_new)) > 1
                % include new function
                if ObjlineNum_new
                    ObjlineNum_new = num_diff(ObjlineNum_new);
                    [objLineNum, sort_ind] = sort([objLineNum; ObjlineNum_new]);
                    data_ = [data_; data_new];
                    htmlData_ = [htmlData_; htmldata_new];
                    data_ = data_(sort_ind);
                    htmlData_ = htmlData_(sort_ind);
                end
            else
                % only one function
                updateTableFull(jhTable_,filetext_);
                return;
            end
        else
            % find
            [data_new,ObjlineNum_new,htmldata_new] = getObjCells(filetext_(num_diff));
            % include new cell in right order
            if ObjlineNum_new
                    ObjlineNum_new = num_diff(ObjlineNum_new);
                    [objLineNum, sort_ind] = sort([objLineNum; ObjlineNum_new]);
                    data_ = [data_; data_new];
                    htmlData_ = [htmlData_; htmldata_new];
                    data_ = data_(sort_ind);
                    htmlData_ = htmlData_(sort_ind);
            end
            % find changed cells with no title
            
            if ~isequal(cellfun('isclass', data_,'double'),cellfun('isclass', dataOld_,'double')) || any(cellfun('isclass', data_new,'double'))
                htmlData_ = getHtmlCells(data_);
            end
        end
        if numel(htmlData_) == numel(htmlDataOld_)
%             tablerefresh_items = cellfun(@(x,y) isequal(x,y), htmlData_, htmlDataOld_);
            tablerefresh_items = strcmp(htmlData_, htmlDataOld_);
            tablerefresh = ~all(tablerefresh_items);
        else
            tablerefresh = true;
        end
    end    
    % refresh table content
    if tablerefresh
        htmlDataOld_ = htmlData_;
        dataOld_ = data_; % necessary for cellelements
        if ~isempty(tablerefresh_items)
            table_refresh_items_index = find(~tablerefresh_items');
            modelObj  = jhTable_.getModel;
            for i_r = table_refresh_items_index
                sortedRowIdx = modelObj.getSortedRowAt(i_r-1);
                jhTable_.setValueAt(htmlData_{i_r},sortedRowIdx,0)
            end
        else
            oldmodel = jhTable_.getModel;
            issorted = oldmodel.isColumnSorted(0);
            isascending = oldmodel.isColumnAscending(0);
            %newtable
            refreshTable(jhTable_,htmlData_,header_);
            if issorted
                jhTable_.sortColumn(0,1,isascending);
            end
        end
%         jhTable_.validate;
    end
        
    % find line/ function or cell
    row_temp = find(objLineNum <= selected_row); 
    [~ ,selected_fun_index] = max(objLineNum(row_temp));
    selected_fun = row_temp(selected_fun_index);
    
    % refresh marked function / cell
    if ~isequal(selected_fun,selectedFunOld_) || tablerefresh
        selectedFunOld_ = updateTableMarked(jhTable_,selected_fun);
    end

%     catch er
%         warning(er.message)
%         disp(er.stack(1).line)        
%         updateTableFull(jhTable_)
%         return
%         
%     end
%     
    
end

%%    
function selectedFunOld_ = updateTableMarked(jhTable_,selected_fun)
    selectedFunOld_ = selected_fun;
    if isempty(selected_fun)
        jhTable_.clearSelectionPermanently;
    else
        modelObj  = jhTable_.getModel;
        sortedRowIdx = modelObj.getSortedRowAt(selected_fun-1);
        jhTable_.setRowSelectionInterval(sortedRowIdx,sortedRowIdx)
        %         jhTable_.validate;
        jhTable_.scrollRowToVisible(sortedRowIdx)
        jhTable_.repaint()
%         jhTable_.getParent.getParent.validate()


    end

end
%% update table content/ changed file
function updateTableFull(jhTable_,txt)
%     import javax.swing.*
%     import java.awt.*
%     disp('full refresh!!!!!!!!!!!')
    
    fileType_ = 'script';
    drawTyp_ = 'cells';
    
%     try
    fileActiveObj_ = matlab.desktop.editor.Document.getActiveEditor;
    if nargin == 1;
        txt = regexp(char(fileActiveObj_.JavaEditor.getText),'\n','split')';
    end
    filetext_ = txt;
    [filename_with_pkg,filenameShort_] = filenameWithPackage(fileActiveObj_.JavaEditor.getLongName);
    selected_row = fileActiveObj_.JavaEditor.getLineNumber + 1;
    
    
    textOld_ = filetext_;
    % funs and cell finding
    [data_,objLineNum,htmlData_] = getObjFunctions(filetext_);
    if ~isempty(data_)
        fileType_ = 'function';
        drawTyp_ = 'subfunctions';
    end

    if numel(data_) < 2
        if numel(data_) == 0
            fileType_ = 'script';
        end
        [data_,objLineNum,htmlData_] = getObjCells(filetext_);
        drawTyp_ = 'cells';
        
    end
    tablerefresh = ~isequal(htmlData_,htmlDataOld_);
%     tablerefresh = true;
    % find line/ function or cell
    row_temp = find(objLineNum <= selected_row); 
    [~ ,selected_fun_index] = max(objLineNum(row_temp));
    selected_fun = row_temp(selected_fun_index);
    if tablerefresh
        dataOld_ = data_; % necessary for cell title
        htmlDataOld_ = htmlData_;
        isclassfile = exist(filename_with_pkg,'class');
        if isclassfile == 8
%             methodslist = getObjMethods(filenameShort_);
            header_ = {[filenameShort_,': methods']};
            createThisInBaseWorkspace(filename_with_pkg);          
%             jhTable_.getTableHeader.setToolTipText(methodslist);
        else
            header_ = {[filenameShort_,': ',drawTyp_]};
%             jhTable_.getTableHeader.setToolTipText(fileActiveObj_.Filename);            
        end
        refreshTable(jhTable_,htmlData_,header_);
        
        if strcmp(drawTyp_,'subfunctions')
            jhTable_.sortColumn(0,1,1);
        end
    end
    
    if ~isequal(selected_fun,selectedFunOld_) || tablerefresh
        selectedFunOld_ = updateTableMarked(jhTable_,selected_fun);
    end
    jhTable_.setSelectionBackground(java.awt.Color(0.79 ,0.79, 0.79))
%     jhTable_.setSelectionForeground(jhTable_.getMarginBackground)
%     catch er
%         warning(er.message)
%         disp(er.stack(1).line)        
%         updateTableFull(jhTable_)
%     end
    
end

%%
function objMethods = getObjMethods(file)
    
    
    try
        s = warning('off','MATLAB:class:cannotUpdateClass:Changed');
        [~,m] = methods(file,'-full');
        
        warning(s);
        if ~isempty(m)
            
            % seperate methods and classnames
%             for i_m1 = 1:size(m,1)
%                 m{i_m1,4} = regexprep(m{i_m1,4},'\.\w+','');
%             end

            % delete ownmethods 
            methods_self = strncmp(file,m(:,4),numel(file));
            m(methods_self,:) = [];
            objMethods = '';
            % sorting: method
            [~, s] = sort(((m(:,3))));
            m = m(s,:);
            % sorting: superclassname
            [~, s] = sort(((m(:,4))));
            m = m(s,:);
            
            % create html table
            for i_m1 = 1:size(m,1)
                objMethods = [objMethods,'<tr>'];
                for i_m2 = 2:size(m,2)
                    objMethods = [objMethods,'<td>',m{i_m1,i_m2},'</td>'];
                end
                objMethods = [objMethods,'</tr>'];
            end
            
            objMethods = ['<html><table border="0">',objMethods,'</table></html>'];
        else
            objMethods = [];
        end
    catch %#ok<CTCH>
        objMethods = [];
    end
    
end

function refreshTable(jhTable_,htmlData_,header_)
    tableModel = javax.swing.table.DefaultTableModel(htmlData_,header_);
    jhTable_.setModel(tableModel)
    
    % Disable editing
    cbNameTextField = javax.swing.JTextField;
    cbNameTextField.setEditable(false);  % ensure that the method names are not modified...
    cbNameCellEditor = javax.swing.DefaultCellEditor(cbNameTextField);
    cbNameCellEditor.setClickCountToStart(intmax);  % i.e, never enter edit mode...
    jhTable_.getColumnModel.getColumn(0).setCellEditor(cbNameCellEditor);
    jhTable_.setPreserveSelectionsAfterSorting(true);
end

function createThisInBaseWorkspace(filename)
    if ~isempty(createInstance_)
        s = warning('off','MATLAB:class:cannotUpdateClass:Changed');
        try 
            dbstat = dbstatus; % check for dbstatus. Don't eval constructor, when breakpoint in file is set.
            if isempty(dbstat) || ~any(arrayfun(@(x) strcmp(x.file,fileActiveObj_.JavaEditor.getLongName), dbstat))
                a = eval(filename);
                for i_i = 1:numel(createInstance_)
                    assignin('base',createInstance_{i_i},a);
                end

            end
        end
        warning(s);
    end
end

function [filename_with_pkg, filenameShort_] = filenameWithPackage(filename_in)
    filenameSplit = regexp(char(filename_in),filesep,'split');
    filenameShort_ = filenameSplit{end};
    filename_with_pkg = filenameSplit{end}(1:end-2);  % without extension (last two characters)
    for ii = length(filenameSplit)-1:-1:1
        if filenameSplit{ii}(1)=='+'
           filename_with_pkg = [filenameSplit{ii}(2:end) '.' filename_with_pkg];
        else
            break
        end
    end
end
end

Contact us