⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 uiinspect.m

📁 uiinspect Inspect an object handle (Java/COM/HG) and display its methods/props/callbacks in a unifie
💻 M
📖 第 1 页 / 共 4 页
字号:
        propsTable = get(src,'userdata');
        ud = get(propsTable, 'userdata');
        obj = ud.obj;
        inspectorTable = ud.inspectorTable;
        [propData, propHeaders] = getPropsData(obj, ud.cbMetaData.isSelected, ud.cbInspected.isSelected, inspectorTable);
        propsTableModel = javax.swing.table.DefaultTableModel(propData,propHeaders);
        try
            ud.obj = handle(obj,'CallbackProperties');
        catch
            try
                ud.obj = handle(obj);
            catch
                % never mind...
            end
        end
        ud.inspectorTable = inspectorTable;
        set(propsTableModel, 'TableChangedCallback',@tbPropChanged, 'UserData',ud);
        propsTable.setModel(propsTableModel)
        try
            % Try to auto-resize the columns
            propsTable.setRowAutoResizes(true);
            jideTableUtils = eval('com.jidesoft.grid.TableUtils;');  % prevent JIDE alert by run-time (not load-time) evaluation
            jideTableUtils.autoResizeAllColumns(propsTable);
        catch
            % JIDE is probably unavailable - never mind...
        end

        % Update the header label
        if ud.cbInspected.isSelected
            set(ud.othersLabel,'Text',' All properties', 'ToolTipText','All properties (including those shown above)');
        else
            set(ud.othersLabel,'Text',' Other properties', 'ToolTipText','Properties not inspectable by the inspect table above');
        end

        % Disable editing all columns except the property Value
        import javax.swing.*
        propTextField = JTextField;
        propTextField.setEditable(false);  % ensure that the prop names & meta-data are not modified...
        propCellEditor = DefaultCellEditor(propTextField);
        propCellEditor.setClickCountToStart(intmax);  % i.e, never enter edit mode...
        for colIdx = 0 : propsTable.getColumnModel.getColumnCount-1
            thisColumn = propsTable.getColumnModel.getColumn(colIdx);
            if ~strcmp(thisColumn.getHeaderValue,'Value')
                thisColumn.setCellEditor(propCellEditor);
            end
        end
    catch
        % Never mind...
        disp(lasterr);  rethrow(lasterror)
    end
%end  % updatePropsTable

%% Update component callback upon callbacksTable data change
function tbCallbacksChanged(src, evd)
    try
        % exit if invalid handle or already in Callback
        if ~ishandle(src) || ~isempty(getappdata(src,'inCallback')) % || length(dbstack)>1  %exit also if not called from user action
            return;
        end
        setappdata(src,'inCallback',1);  % used to prevent endless recursion

        % Update the object's callback with the modified value
        modifiedColIdx = evd.getColumn;
        modifiedRowIdx = evd.getFirstRow;
        if modifiedColIdx==1 && modifiedRowIdx>=0  %sanity check - should always be true
            table = evd.getSource;
            object = get(src,'userdata');
            cbName = strtrim(table.getValueAt(modifiedRowIdx,0));
            try
                cbValue = strtrim(char(table.getValueAt(modifiedRowIdx,1)));
                if ~isempty(cbValue) && ismember(cbValue(1),'{[@''')
                    cbValue = eval(cbValue);
                end
                if (~ischar(cbValue) && ~isa(cbValue, 'function_handle') && (iscom(object(1)) || iscell(cbValue)))
                    revertCbTableModification(table, modifiedRowIdx, modifiedColIdx, cbName, object, '');
                else
                    for objIdx = 1 : length(object)
                        if ~iscom(object(objIdx))
                            set(object(objIdx), cbName, cbValue);
                        else
                            cbs = object(objIdx).eventlisteners;
                            if ~isempty(cbs)
                                cbs = cbs(strcmpi(cbs(:,1),cbName),:);
                                object(objIdx).unregisterevent(cbs);
                            end
                            if ~isempty(cbValue)
                                object(objIdx).registerevent({cbName, cbValue});
                            end
                        end
                    end
                end
            catch
                revertCbTableModification(table, modifiedRowIdx, modifiedColIdx, cbName, object, lasterr)
            end
        end
    catch
        % never mind...
    end
    setappdata(src,'inCallback',[]);  % used to prevent endless recursion
%end  % tbCallbacksChanged

%% Revert Callback table modification
function revertCbTableModification(table, modifiedRowIdx, modifiedColIdx, cbName, object, errMsg)  %#ok
    try
        % Display a notification MsgBox
        msg = 'Callbacks must be a ''string'', or a @function handle';
        if ~iscom(object(1)),  msg = [msg ' or a {@func,args...} construct'];  end
        if ~isempty(errMsg),  msg = {errMsg, '', msg};  end
        msgbox(msg, ['Error setting ' cbName ' callback'], 'warn');

        % Revert to the current value
        curValue = '';
        try
            if ~iscom(object(1))
                curValue = charizeData(get(object(1),cbName));
            else
                cbs = object(1).eventlisteners;
                if ~isempty(cbs)
                    cbs = cbs(strcmpi(cbs(:,1),cbName),:);
                    curValue = charizeData(cbs(1,2));
                end
            end
        catch
            % never mind... - clear the current value
        end
        table.setValueAt(curValue, modifiedRowIdx, modifiedColIdx);
    catch
        % never mind...
    end
%end  % revertCbTableModification

%% Update component property upon properties table data change
function tbPropChanged(src, evd)
    % exit if invalid handle
    if ~ishandle(src)  % || length(dbstack)>1  %exit also if not called from user action
        return;
    end

    % Update the object's property with the modified value
    modifiedColIdx = evd.getColumn;
    modifiedRowIdx = evd.getFirstRow;
    if modifiedRowIdx>=0  %sanity check - should always be true
        table = evd.getSource;
        ud = get(src,'userdata');
        object = ud.obj;
        inspectorTable = ud.inspectorTable;
        propName = strtrim(table.getValueAt(modifiedRowIdx,0));
        propName = strrep(propName,'<html><font color="#C0C0C0"><i>','');
        propName = strrep(propName,'<html><font color="red"><i>','');
        try
            propValue = strtrim(table.getValueAt(modifiedRowIdx,modifiedColIdx));
            if ~isempty(propValue) && ismember(propValue(1),'{[@''')
                propValue = eval(propValue);
            end
            for objIdx = 1 : length(object)
                set(object(objIdx), propName, propValue);
            end
        catch
            msg = {lasterr, '', ...
                   'Values are interpreted as strings except if enclosed by square brackets [] or curly braces {}', ...
                   '', 'Even simple boolean/numeric values need to be enclosed within [] brackets', ...
                   'For example: [0] or: [pi]'};
            msgbox(msg,['Error setting ' propName ' property'],'error');
            try
                % Revert to the current value (temporarily disable this callback to prevent recursion)
                curValue = charizeData(get(object(1),propName));
                set(table, 'TableChangedCallback',[]);
                table.setValueAt(curValue, modifiedRowIdx, modifiedColIdx);
                set(table, 'TableChangedCallback',@tbPropChanged);
            catch
                % never mind...
            end
        end
        %pause(0.2); awtinvoke(inspectorTable,'repaint(J)',2000);  % not good enough...
        start(timer('TimerFcn',{@repaintInspector,inspectorTable},'StartDelay',2));
    end
%end  % tbPropChanged

%% Repaint inspectorTable following a property modification
function repaintInspector(timerObj, timerData, inspectorTable)  %#ok partially unused
    inspectorTable.repaint;
%end % repaintInspector

%% Get an HTML representation of the object's properties
function dataFieldsStr = getPropsHtml(obj, dataFields)
    try
        % Get a text representation of the fieldnames & values
        undefinedStr = '';
        dataFieldsStr = '';  % just in case the following croaks...
        if isempty(dataFields)
            return;
        end
        dataFieldsStr = evalc('disp(dataFields)');
        if dataFieldsStr(end)==char(10),  dataFieldsStr=dataFieldsStr(1:end-1);  end

        % Strip out callbacks
        dataFieldsStr = regexprep(dataFieldsStr,'^\s*\w*Callback(Data)?:[^\n]*$','','lineanchors');
        dataFieldsStr = regexprep(dataFieldsStr,'\n\n','\n');

        % HTMLize tooltip data
        % First, set the fields' font based on its read-write status
        try
            % ensure this is a Matlab handle, not a java object
            obj = handle(obj, 'CallbackProperties');
        catch
            % HG handles don't allow CallbackProperties...
            obj = handle(obj);
        end
        fieldNames = fieldnames(dataFields);
        for fieldIdx = 1 : length(fieldNames)
            thisFieldName = fieldNames{fieldIdx};
            accessFlags = get(findprop(obj,thisFieldName),'AccessFlags');
            if isfield(accessFlags,'PublicSet') && strcmp(accessFlags.PublicSet,'on')
                % Bolden read/write fields
                thisFieldFormat = ['<b>' thisFieldName '<b>:$2'];
            elseif ~isfield(accessFlags,'PublicSet')
                % Undefined - probably a Matlab-defined field of com.mathworks.hg.peer.FigureFrameProxy...
                thisFieldFormat = ['<font color="blue">' thisFieldName '</font>:$2'];
                undefinedStr = ', <font color="blue">undefined</font>';
            else % PublicSet=='off'
                % Gray-out & italicize any read-only fields
                thisFieldFormat = ['<font color="#C0C0C0"><i>' thisFieldName '</i></font>:<font color="#C0C0C0"><i>$2<i></font>'];
            end
            dataFieldsStr = regexprep(dataFieldsStr, ['([\s\n])' thisFieldName ':([^\n]*)'], ['$1' thisFieldFormat]);
        end
    catch
        % never mind... - probably an ambiguous property name
        disp(lasterr);  rethrow(lasterror)
    end

    try
        % Method 1: simple <br> list
        %dataFieldsStr = strrep(dataFieldsStr,char(10),'&nbsp;<br>&nbsp;&nbsp;');

        % Method 2: 2x2-column <table>
        dataFieldsStr = regexprep(dataFieldsStr, '^\s*([^:]+:)([^\n]*)\n^\s*([^:]+:)([^\n]*)$', '<tr><td>&nbsp;$1</td><td>&nbsp;$2</td><td>&nbsp;&nbsp;&nbsp;&nbsp;$3</td><td>&nbsp;$4&nbsp;</td></tr>', 'lineanchors');
        dataFieldsStr = regexprep(dataFieldsStr, '^[^<]\s*([^:]+:)([^\n]*)$', '<tr><td>&nbsp;$1</td><td>&nbsp;$2</td><td>&nbsp;</td><td>&nbsp;</td></tr>', 'lineanchors');
        dataFieldsStr = ['(<b>modifiable</b>' undefinedStr ' &amp; <font color="#C0C0C0"><i>read-only</i></font> fields)<p>&nbsp;&nbsp;<table cellpadding="0" cellspacing="0">' dataFieldsStr '</table>'];
    catch
        % never mind - bail out (Maybe matlab 6 that does not support regexprep?)
        disp(lasterr);  rethrow(lasterror)
    end
%end  % getPropsHtml

%% Update tooltip string with an object's properties data
function dataFields = updateObjTooltip(obj, uiObject)
    try
        if ischar(obj)
            toolTipStr = obj;
        else
            toolTipStr = builtin('class',obj);
        end
        dataFields = struct;  % empty struct
        dataFieldsStr = '';
        hgStr = '';

        % Add HG annotation if relevant
        if ishghandle(obj)
            hgStr = ' HG Handle';
        end

        % Note: don't bulk-get because (1) not all properties are returned & (2) some properties cause a Java exception
        % Note2: the classhandle approach does not enable access to user-defined schema.props
        ch = classhandle(handle(obj));
        dataFields = [];
        [sortedNames, sortedIdx] = sort(get(ch.Properties,'Name'));
        for idx = 1 : length(sortedIdx)
            sp = ch.Properties(sortedIdx(idx));
            % TODO: some fields (see EOL comment below) generate a Java Exception from: com.mathworks.mlwidgets.inspector.PropertyRootNode$PropertyListener$1$1.run
            if strcmp(sp.AccessFlags.PublicGet,'on') % && ~any(strcmp(sp.Name,{'FixedColors','ListboxTop','Extent'}))
                try
                    dataFields.(sp.Name) = get(obj, sp.Name);
                catch
                    dataFields.(sp.Name) = '<font color="red">Error!</font>';
                end
            else
                dataFields.(sp.Name) = '(no public getter method)';
            end
        end
        dataFieldsStr = getPropsHtml(obj, dataFields);
    catch
        % Probably a non-HG java object
        try
            % Note: the bulk-get approach enables access to user-defined schema-props, but not to some original classhandle Properties...
            dataFields = get(obj);
            dataFieldsStr = getPropsHtml(obj, dataFields);
        catch
            % Probably a missing property getter implementation
            try
                % Inform the user - bail out on error
                err = lasterror;
                if ~ischar(obj)
                    dataFieldsStr = ['<p>' strrep(err.message, char(10), '<br>')];
                else
                    dataFieldsStr = '<p>Cannot inspect fields of class names - only of objects';
                end
            catch
                % forget it...
            end
        end
    end

    % Set the object tooltip
    if ~isempty(dataFieldsStr)
        toolTipStr = ['<html>&nbsp;<b><u><font color="red">' char(toolTipStr) '</font></u></b>' hgStr ':&nbsp;' dataFieldsStr '</html>'];
    end
    uiObject.setToolTipText(toolTipStr);
%end  % updateObjTooltip



%%%%%%%%%%%%%%%%%%%%%%%%%% TODO %%%%%%%%%%%%%%%%%%%%%%%%%
% - Enh: Cleanup internal functions, remove duplicates etc.
% - Enh: link objects to another uiinspect window for these objects
% - Enh: display object children (& link to them)
% - Enh: find a way to merge the other-properties table into the inspector table
% - Fix: some fields generate a Java Exception from: com.mathworks.mlwidgets.inspector.PropertyRootNode$PropertyListener$1$1.run

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -