Code covered by the BSD License  

Highlights from
TeXed

image thumbnail
from TeXed by Jonathan Lister
TeXed is a fork of Ben Hinkle's TeXEditor (#11946).

texed(varargin)
function varargout = texed(varargin)
%TEXED TeX equation editor
%   TEXED starts an equation editor for LaTeX equations.
%
% Syntax:
%    texStr = texed           % this generates the dialog/figure
%    texStr = texed(varargin) % appears to be for internal use only!
%
% Description:
%    TEXED is a graphical interface for editing and previewing LaTeX 
%    equations for use in MATLAB. Keyboard shortcuts and equation templates
%    are supported. TEXED is a fork of the MATLAB Central File Exchange
%    entry titled TeXEditor (FEX ID# 11946) by Ben Hinkle.  The main
%    difference between the two entries is the ability of this one to
%    return the TeX string that the user had crafted via the GUI, and the
%    unknown zip contents that were in a string in the extractFiles
%    function have been fully exposed.  JD GUI was used to expose the
%    source code of the TeXAction.class file.
%
% Inputs:
%     varargin - no documentation was present in the original entry. For
%     the most part varargin should be considered a place holder for
%     additional extensions to this tool.
%
% Output:
%     texStr = the last TeX string that was constructed prior to closing
%     the editor.
%
% Example:
%    texStr = texed
%    type into the first text box the following:
%     X_k=\frac{1}{N}\sum_{n=0}^{N-1}x_ne^{-i2\pi \frac{k}{N}n}
%    The equation will be rendered in the preview pane.
%    Clicking close will pass the TeX string that you just crafted into the
%    texStr varialbe.
%
% Bugs and suggestions:
%    Please send to jonathan lister (mechanical.engineer78 at gmail.com)
%
% Change log:
%    2013-07-11 initial re-release of texeditor as texed
%    2013-07-14 removed interal zip file and extraction routine
%
figs = allchild(0);
f = findall(figs,'flat','Type','figure','Tag','TexEdFigure'); %<-- so this is a trick to make a gui behave as a singleton?

%determine if texed is to return the TeX string and set flag.
outflg = false;
if nargout ==1
    varargout{1} = ''; 
    outflg = true;
end

if nargin > 0
    callbacks = getappdata(f,'Callbacks');
    feval(callbacks.cmdCB,varargin{:});
    return;
end

if ~isempty(f)
    set(f,'Visible','on');
    figure(f);
    return;
end

if ~usejava('swing')
    error('texed:NeedSwing','Equation editor requires Java Swing.');
end


% ---- this needs to be replaced -----
dirname = mfilename('fullpath');
% make sure Java .class and other helper files are on the path

%TeXAction.class is in zip file, source code is provided at the end of this
%file.

if ~exist(dirname,'dir') || isempty(which('TeXAction')) 
    javaaddpath(dirname);
    addpath(dirname);
end
% -------------------------------------

% make sure icons are on the path
back = get(0,'DefaultFigureColor');
set(f,'Color',back);
[addim,addcmap] = imread('move_down.gif'); % in zip file
addcmap(end,:) = back;
rolladdcmap = addcmap;
roll = back.*[.75 .75 1];
rolladdcmap(end,:) = roll;
[delim,delcmap] = imread('delete.gif'); % in zip file
delcmap(200:end,:) = repmat(back,size(delcmap,1)-199,1);
disdelcmap = delcmap;
disdelcmap(1:100,:) = repmat(back*.7,100,1);
rolldelcmap = delcmap;
rolldelcmap(200:end,:) = repmat(roll,size(delcmap,1)-199,1);

addbuth = []; % for callbacks
deletebuth = []; % for callbacks
f = figure('MenuBar','none','ToolBar','none',...
    'Name','Equation Editor',...
    'Tag','TexEdFigure',...
    'NumberTitle','off',...
    'HandleVisibility','callback',...
    'DeleteFcn',@deletecb,...
    'ResizeFcn',@layoutcb,...
    'Position',[0 0 450 350],...
    'Visible','off');

% read preferences or create defaults if none
if ispref('texed','ActionTable')
    actionTable = getpref('texed','ActionTable');
else
    actionTable = { ...
        % key, cmd
        '/','\frac{}{}';...
        'f','\frac{}{}';...
        's','\sum_{}^{}';...
        'p','\prod_{}^{}';...
        'i','\int_{}^{}';...
        'l','\lim_{ \to }';...
        'q','\sqrt{}';...
        'a','\alpha ';...
        'b','\beta ';...
        'g','\gamma ';...
        'd','\delta ';...
        'o','\overline{}';...
        'u','\underline{}';...
        't','\dot{}';...
        'h','\hat{}'...
        };
end
if ispref('texed','Templates')
    templates = getpref('texed','Templates');
else
    templates = {...
        'X_k=\frac{1}{N}\sum_{n=0}^{N-1}x_ne^{-j2\pi\frac{k}{N}n}',...
        '\alpha x_1^2 + \beta x_2^2',...
        '\sqrt{x+1}',...
        '\lim_{n \to \infty} \frac{1}{1+n}',...
        '\int_0^1 x \,dx',...
        '\sum_{n=0}^{\infty} \frac{1}{n^2}',...
        ['\left[ \begin{array}{cc}' char(10) ' A\ & B \\' ...
        char(10) ' C\ & D' char(10) '\end{array}\right]']...
        };
end

% spacing in pixels
bgap = 6;

left = 107;
bottom = 40;

% template buttons
buttonHeight = 48;
buttonWidth = 80;

% gui buttons
guiBW = 65;
guiBH = 25;

% make Preview pane
ax=axes('Units','pixels',...
    'XLim',[0 1],'YLim',[0 1],...
    'Layer','top',...
    'Parent',f,...
    'XTick',[],'YTick',[],'Box','on');
defaultFontSize = 20;
dt = text(.5,.9,'','Interpreter','latex',...
    'VerticalAlignment','top','HorizontalAlignment','center',...
    'FontSize',defaultFontSize,'Parent',ax);
errt = text(.5,.1,'','Interpreter','none',...
    'VerticalAlignment','bottom','HorizontalAlignment','center',...
    'FontSize',12,'Parent',ax);
setappdata(f,'lastKnownGoodString','');
setappdata(f,'lastEditedString','');

% make Java text pane - undocumented feature alert!
jc = com.mathworks.mwswing.MJTextPane;
try
    jfont = com.mathworks.hg.peer.FontConverter.convertToJavaFont('Courier',14,0,0);
catch %#ok<*CTCH>
    jfont = com.mathworks.hg.util.FontConverter.convertToJavaFont('Courier',14,0,0);
end
set(jc,'Font',jfont);
%[dummy,jch] = javacomponent(jc,[left+bgap .75 1-2*bgap-left .17].*pos,f);
[dummy,jch] = javacomponent(jc,[0 0 1 1],f);
jcc = handle(jc,'CallbackProperties');
set(jcc,'KeyTypedCallback',@typedCB)
set(jcc,'CaretUpdateCallback',@caretCB)
tabAct = TeXAction;
tabAct.putValue(javax.swing.Action.SHORT_DESCRIPTION,'Tab');
% hmm... this still will put a Tab character into the contents...
keymap = jc.getKeymap;
keymap.addActionForKeyStroke(...
    javax.swing.KeyStroke.getKeyStroke('released TAB'),tabAct);
setappdata(f,'Callbacks',jcc); % needed?

%todo: margin in scrollpane
jbp = com.mathworks.mwswing.MJPanel(com.mathworks.page.utils.VertFlowLayout);
jsp = com.mathworks.mwswing.MJScrollPane(jbp,javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS,...
    javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
jsbar = jsp.getVerticalScrollBar;
set(jsp,'Font',jfont);
[dummy,jcompsp] = javacomponent(jsp,[0 0 1 1],f);

list = templates;
addbut = addIconButton('Add Template',addim,addcmap,...
    @addtmplcb,[],rolladdcmap);
[dummy,addbuth] = javacomponent(addbut,[0 0 1 1],f);
deletebut = addIconButton('Delete Template',delim,delcmap,...
    @deltmplcb,disdelcmap,rolldelcmap);
[dummy,deletebuth] = javacomponent(deletebut,[0 0 1 1],f);
setEnabled(deletebut,false);
miniax = axes('Units','pixels',...
    'XLim',[0 1],'YLim',[0 1],...
    'Layer','top','Visible','on',...
    'Parent',f,...
    'XTick',[],'YTick',[],'Box','off','Clipping','on',...
    'XColor',back,'YColor',back);
defaultMiniFontSize = 10;
minit = text(.5,.5,'','Interpreter','latex',...
    'VerticalAlignment','middle','HorizontalAlignment','center',...
    'FontSize',defaultMiniFontSize,'Clipping','on',...
    'HitTest','off','Parent',miniax);
set(miniax,'ButtonDownFcn',@lastbutcb);
set(f,'WindowButtonMotionFcn',@mousemovecb);

scutbut = uicontrol('style','pushbutton',...
    'String','Shortcuts',...
    'Parent',f,...
    'Callback',@shortcutscb);
symsbut = uicontrol('style','pushbutton',...
    'String','Symbols',...
    'Parent',f,...
    'Callback',@symbolscb);
helpbut = uicontrol('style','pushbutton',...
    'String','Help',...
    'Parent',f,...
    'Callback',@helpcb);
closebut = uicontrol('style','pushbutton',...
    'String','Close',...
    'Parent',f,...
    'Callback',@closecb);

movegui(f,'center');
set(f,'visible','on')
tim = timer('timerfcn',@dotimer,'startdelay',1,'executionmode','singleshot');
setappdata(f,'Callbacks',struct('cmdCB',@cmdCB));
doLayout;
drawnow;
pause(.5);
for k1=length(list):-1:1
    addTemplate(jbp,list{k1},[]);
end
jc.requestFocus;
uiwait(f)

    function doLayout
        pos = get(f,'Position');
        origpos = pos;
        if pos(3) < 120
            pos(3) = 120;
        end
        if pos(4) < 150
            pos(4) = 150;
        end
        if ~isequal(pos,origpos)
            set(f,'Position',pos);
        end
        width = pos(3)-2*bgap-left;
        height = pos(4)-bottom-2*bgap;
        ratio = .6;
        set(ax,'Position',[left+bgap bottom+bgap width ratio*height]);
        axtop = bottom+bgap+ratio*height;
        set(jch,'Position',[left+bgap axtop+bgap width (1-ratio)*height-bgap]);
        is = 24;
        scrolltop = pos(4)-buttonHeight-4*bgap-is;
        set(addbuth,'Position',[left/2-bgap-is scrolltop+bgap is is]);
        set(deletebuth,'Position',[left/2+bgap scrolltop+bgap is is]);
        set(miniax,'Position',[left/2-buttonWidth/2 scrolltop+2*bgap+is ...
            buttonWidth buttonHeight]);
        set(jcompsp,'Position',...
            [bgap bottom+bgap left-bgap scrolltop-bottom-bgap]);
        w = guiBW+bgap;
        w0 = left+bgap;
        set(scutbut,'Position',[w0 bgap guiBW guiBH]);
        set(symsbut,'Position',[w0+w bgap guiBW guiBH]);
        set(helpbut,'Position',[w0+2*w bgap guiBW guiBH]);
        set(closebut,'Position',[w0+3*w bgap guiBW guiBH]);
        fitEqnToAxes(dt,defaultFontSize);
    end

    function layoutcb(src,ev) %#ok
        doLayout;
    end

    function cmdCB(name)
        name(name == ' ') = [];
        switch name
            case char(9)
                doAction(true,char(9));
        end
        jc.requestFocus;
    end

    function typedCB(hSrc,evdata) %#ok
        % if anything other than shift, return
        iscmd = false;
        ch = get(evdata,'KeyChar');
        if bitand(get(evdata,'modifiers'),8)
            iscmd = true;
        elseif get(evdata,'modifiers') > 1
            return
        end
        doAction(iscmd,ch);
    end

    function caretCB(hSrc,evdata) %#ok
        dot = evdata.getDot;
        mark = evdata.getMark;
        if dot == mark
            % draw caret
        else
            % highlight region
        end
    end

    function str = doCmd(ch,str)
        selStart = jc.getSelectionStart()+1;
        selEnd = jc.getSelectionEnd()+1;
        if strcmp(ch,'n') || strcmp(ch,char(9))
            if strcmp(ch,char(9))
                
            end
            % skip to next bracket
            inds = find(str=='}' | str=='{' | str==')' | str=='(');
            next = inds(inds >= selEnd);
            if ~isempty(next)
                next = next(1);
                if strncmp(str(next:end),'}{',2)
                    jc.setCaretPosition(next+1);
                elseif strncmp(str(next:end),'}_{',3) || ...
                        strncmp(str(next:end),'}^{',3)
                    jc.setCaretPosition(next+2);
                else
                    jc.setCaretPosition(next);
                end
            else
                jc.setCaretPosition(length(str));
            end
        else
            if isappdata(f,'ActionTable');
                actionTable = getappdata(f,'ActionTable');
            end
            for kk=1:length(actionTable)
                action = actionTable(kk,:);
                if strcmp(ch,action{1})
                    cmdTemplate = action{2};
                    inds = find(cmdTemplate=='{');
                    if isempty(inds)
                        inds=length(cmdTemplate);
                    end
                    cmd = cmdTemplate(1:inds(1));
                    cmdEnd = cmdTemplate(inds(1)+1:end);
                    str = [str(1:selStart-1) cmd str(selStart:selEnd-1) ...
                        cmdEnd str(selEnd:end)];
                    doc = jc.getDocument;
                    doc.insertString(selEnd-1,cmdEnd,[]);
                    doc.insertString(selStart-1,cmd,[]);
                    if (selEnd - selStart > 0) && length(inds)>1
                        jc.setCaretPosition(selEnd+inds(2)-1);
                    else
                        jc.setCaretPosition(selStart+length(cmd)-1);
                    end
                end
            end
        end
        awtinvoke(deletebut,'setEnabled(Z)',false);
    end

    function doAction(iscmd,ch)
        str = get(jc,'Text');
        if iscmd
            str = doCmd(ch,str);
        end
        orig_str = str;
        str(str == 10) = ' ';
        % instead of ripping out tabs instead modify keymap
        tabs = find(str == char(9));
        if ~isempty(tabs)
            jc.setSelectionStart(tabs(1)-1);
            jc.setSelectionEnd(tabs(1));
            jc.replaceSelection('');
        end
        selStart = jc.getSelectionStart()+1;
        selEnd = jc.getSelectionEnd()+1;
        if selStart == selEnd
            % draw single caret
        else
            % highlight selected construct
        end
        %ind = jc.getCaretPosition;
        %str = [str(1:ind) '\vrule{}' str(ind+1:end)];
        str = ['$$ ' str '$$'];
        [dvi,err] = tex(str); %#ok
        if isempty(err)
            set(dt,'String',str);
            fitEqnToAxes(dt,defaultFontSize);
            set(minit,'String',str);
            fitEqnToAxes(minit,defaultMiniFontSize);
            setappdata(f,'lastKnownGoodString',orig_str);
            setappdata(f,'lastEditedString',orig_str);
            stop(tim);
            set(dt,'Color',[0 0 0]);
            set(errt,'String','');
        else
            if tim.running, stop(tim); end
            start(tim);
            
            % todo: error message from tex now only says "Invalid LaTeX string". Wait
            % until something better comes on line.
            %            set(errt,'string',err);
        end
        awtinvoke(deletebut,'setEnabled(Z)',false);
    end

    function fitEqnToAxes(t,defaultFontSize)
        fsize = defaultFontSize;
        set(t,'FontSize',fsize);
        ex = get(t,'Extent');
        if ex(3) > 1
            fsize = fsize/ex(3);
            set(t,'FontSize',fsize);
        end
        ex = get(t,'Extent');
        if ex(4) > 1
            fsize = fsize/ex(4);
            set(t,'FontSize',fsize);
        end
    end

    function button = addIconButton(str,data,cmap,cb,discmap,rollcmap)
        [m,n]=size(data);
        pdata = ones(m+8,n+8,'uint8');
        pdata(:,:) = data(1,1);
        pdata(5:4+m,5:4+n) = data;
        jdata = im2java(pdata,cmap);
        icon = javax.swing.ImageIcon(jdata);
        button = com.mathworks.mwswing.MJButton(icon);
        
        if ~isempty(discmap) % set disabled icon
            ddata = im2java(pdata,discmap);
            icon = javax.swing.ImageIcon(ddata);
            button.setDisabledIcon(icon);
        end
        
        button.setSize(java.awt.Dimension(24,24));
        button.setBorder([]);
        button.setToolTipText(str);
        button.setRolloverEnabled(true);
        
        pdata(1,:) = 0;
        pdata(end,:) = 0;
        pdata(:,1) = 0;
        pdata(:,end) = 0;
        jdata = im2java(pdata,rollcmap);
        icon2 = javax.swing.ImageIcon(jdata);
        button.setRolloverIcon(icon2);
        
        buttoncb = handle(button,'CallbackProperties');
        set(buttoncb,'ActionPerformedCallback',cb);
    end

    function addtmplcb(src,ev) %#ok
        str = getappdata(f,'lastEditedString');
        im = getframe(miniax);
        addTemplate(jbp,str,im);
        awtinvoke(deletebut,'setEnabled(Z)',false);
        awtinvoke(jc,'requestFocus()');
    end

    function deltmplcb(src,ev) %#ok
        str=char(get(jc,'Text'));
        templ = getappdata(f,'Templates');
        found = 0;
        for k=1:length(templ)
            t = templ{k};
            if strcmp(t,str)
                found = k;
            end
        end
        if found > 0
            templ(found) = [];
            awtinvoke(jbp,'remove(I)',found-1);
            awtinvoke(jsbar,'validate()');
            awtinvoke(jsp,'validate()');
            drawnow;
            setappdata(f,'Templates',templ);
        end
        awtinvoke(deletebut,'setEnabled(Z)',false);
    end

    function symbolscb(src,ev) %#ok
        web('http://omega.albany.edu:8008/Symbols.html')
    end

    function helpcb(src,ev) %#ok
        web('http://meta.wikimedia.org/wiki/Help:Formula');
    end

    function closecb(src,ev) %#ok
        if outflg
            varargout{1} = jc.getText();
        end
        sfig = getappdata(f,'ShortcutDialog');
        if ~isempty(sfig) && ishandle(sfig)
            delete(sfig);
        end
        deletecb([],[]);
        delete(f);
    end

    function deletecb(src,ev) %#ok
        if isappdata(f,'ActionTable')
            actionTable = getappdata(f,'ActionTable');
            setpref('texed','ActionTable',actionTable);
        end
        if isappdata(f,'Templates')
            templates = getappdata(f,'Templates');
            setpref('texed','Templates',templates);
        end
        delete(tim);
    end

    function dotimer(src,ev) %#ok
        set(dt,'color',[.6 .6 .6]);
    end

    function im = generateIcon(eqn)
        p_eqn = ['$$' eqn '$$'];
        p_eqn(p_eqn==10) = ' ';
        if isempty(p_eqn), p_eqn = ' '; end
        oldstr = get(minit,'String');
        set(minit,'String',p_eqn);
        fitEqnToAxes(minit,defaultMiniFontSize);
        drawnow;
        im = getframe(miniax);
        set(minit,'String',oldstr);
    end

    function addTemplate(jp,eqn,im)
        if isempty(im)
            im = generateIcon(eqn);
        end
        icon = javax.swing.ImageIcon(im2java(im.cdata));
        button = com.mathworks.mwswing.MJButton(icon);
        button.setBorder([]);
        zeroinset = java.awt.Insets(0,0,0,0);
        button.setMargin(zeroinset);
        data2 = im.cdata;
        data2(1,:,:) = 1;
        data2(end,:,:) = 1;
        data2(:,1,:) = 1;
        data2(:,end,:) = 1;
        icon = javax.swing.ImageIcon(im2java(data2));
        button.setRolloverIcon(icon);
        templates = getappdata(f,'Templates');
        if isempty(templates)
            templates = {};
        end
        %templates = {eqn,templates{:}};
        templates = [{eqn} templates];
        buttoncb = handle(button,'CallbackProperties');
        set(buttoncb,'ActionPerformedCallback',{@templatecb,eqn});
        setappdata(f,'Templates',templates)
        awtinvoke(jp,'add(Ljava.awt.Component;I)',button,0);
        awtinvoke(jsp,'validate()');
        awtinvoke(jsbar,'setValue(I)',0);
        drawnow;
    end

    function templatecb(src,ev,eqn) %#ok
        awtinvoke(jc,'setText',java.lang.String(eqn))
        setappdata(f,'lastKnownGoodString',eqn);
        setMainText(eqn);
        set(dt,'color',[0 0 0]);
        set(errt,'string','');
        awtinvoke(deletebut,'setEnabled(Z)',true);
    end

    function mousemovecb(src,ev) %#ok
        pt = get(f,'CurrentPoint');
        ppos = get(miniax,'Position');
        if pt(1) > ppos(1) && pt(2) > ppos(2) && ...
                pt(1) < ppos(1)+ppos(3) && pt(2) < ppos(2)+ppos(4)
            set(miniax,'Box','on');
            set(miniax,'XColor','black','YColor','black');
        else
            set(miniax,'Box','off');
            set(miniax,'XColor',back,'YColor',back);
        end
    end

    function setMainText(eqn)
        eqn(eqn==10)=' ';
        if isempty(eqn), eqn = ' '; end
        set(dt,'string',['$$' eqn '$$']);
        fitEqnToAxes(dt,defaultFontSize);
    end

    function lastbutcb(src,ev) %#ok
        eqn = getappdata(f,'lastEditedString');
        if isempty(eqn), eqn = ' '; end
        awtinvoke(jc,'setText',java.lang.String(eqn))
        setMainText(eqn);
        set(dt,'color',[0 0 0]);
        set(errt,'string','');
        awtinvoke(deletebut,'setEnabled(Z)',false);
    end

    function shortcutscb(src,ev) %#ok
        sfig = findobj('Type','figure','Tag','TexEdFigureShortcuts');
        if isempty(sfig)
            sfig = createShortcutsDialog;
            setappdata(f,'ShortcutDialog',sfig);
            doShortcutLayout;
        end
        set(sfig,'Visible','on');
        figure(sfig);
    end

    function sfig = createShortcutsDialog
        pos = get(f,'Position');
        h = max(420,pos(4));
        w = 200;
        screen = get(0,'ScreenSize');
        l = min(pos(1)+pos(3)+10,screen(3)-w-10);
        sfig = figure('Position',[l pos(2)+pos(4)-h w h],...
            'ToolBar','none',...
            'MenuBar','none',...
            'NumberTitle','off',...
            'Name','TeX Shortcut Editor',...
            'ResizeFcn',@doShortcutLayoutcb);
        str = '<html><a href="none">What is a TeX shortcut?</a>';
        swhatis = com.mathworks.mwswing.MJButton(str);
        swhatis.setBorder([]);
        c = single(back);
        color = java.awt.Color(c(1),c(2),c(3));
        swhatis.setBackground(color);
        cursor = java.awt.Cursor.getPredefinedCursor(java.awt.Cursor.HAND_CURSOR);
        swhatis.setCursor(cursor);
        [dummy,swhatisj] = javacomponent(swhatis,[0 0 1 1],sfig); %#ok
        buttoncb = handle(swhatis,'CallbackProperties');
        set(buttoncb,'ActionPerformedCallback',@shorthelp);
        
        
        sapplybut = uicontrol('style','pushbutton',...
            'String','Apply',...
            'Callback',@shortapplycb);
        sclosebut = uicontrol('style','pushbutton',...
            'String','Close',...
            'Callback',@shortclosecb);
        snewbut = uicontrol('style','pushbutton',...
            'String','New',...
            'Callback',@shortnewcb);
        sdelbut = uicontrol('style','pushbutton',...
            'String','Delete',...
            'Enable','off',...
            'Callback',@shortdeletecb);
        
        % create Table model and populate it with the default shortcuts
        tm = javax.swing.table.DefaultTableModel;
        tm.setColumnCount(2);
        tm.setColumnIdentifiers({'Key','Text'})
        len = size(actionTable,1);
        tm.setRowCount(len);
        for k=1:len
            tm.setValueAt(java.lang.String(actionTable{k,1}),k-1,0);
            tm.setValueAt(java.lang.String(actionTable{k,2}),k-1,1);
        end
        table = javax.swing.JTable(tm);
        table.setAutoResizeMode(javax.swing.JTable.AUTO_RESIZE_OFF);
        cmod = table.getColumnModel;
        col = cmod.getColumn(0);
        col.setPreferredWidth(30);
        col.setResizable(false);
        
        % add selection listener
        rowSM = table.getSelectionModel;
        selcb = handle(rowSM,'CallbackProperties');
        set(selcb,'valueChangedCallback',@shortselectcb);
        
        
        % set column widths and put the table in a scrollpane
        jsp2 = com.mathworks.mwswing.MJScrollPane(table,javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS,...
            javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
        set(jsp2,'Font',jfont);
        [dummy,jcompsp2] = javacomponent(jsp2,[0 0 1 1],sfig);
        objs.table = table;
        objs.scroll = jsp2;
        objs.model = tm;
        objs.mscroll = jcompsp2;
        objs.sapplybut = sapplybut;
        objs.sclosebut = sclosebut;
        objs.swhatisj = swhatisj;
        objs.snewbut = snewbut;
        objs.sdeletebut = sdelbut;
        objs.selmodel = rowSM;
        setappdata(sfig,'shortcutDialogObjs',objs);
    end

    function doShortcutLayout
        sfig = getappdata(f,'ShortcutDialog');
        objs = getappdata(sfig,'shortcutDialogObjs');
        pos = get(sfig,'Position');
        set(objs.mscroll,'Position',[5 40 pos(3)-10 pos(4)-70-35]);
        
        % try Spreadsheet in com.mathworks!!
        cmod = objs.table.getColumnModel;
        col = cmod.getColumn(1);
        vp = objs.scroll.getViewport;
        tsize = vp.getSize;
        col.setPreferredWidth(tsize.width-30);
        set(objs.sapplybut,'Position',[pos(3)-10-2*guiBW 5 guiBW guiBH]);
        set(objs.sclosebut,'Position',[pos(3)-5-guiBW 5 guiBW guiBH]);
        set(objs.snewbut,'Position',[5 pos(4)-25-35 guiBW guiBH]);
        set(objs.sdeletebut,'Position',[10+guiBW pos(4)-25-35 guiBW guiBH]);
        set(objs.swhatisj,'Position',[5 pos(4)-20-5 125 20]);
    end

    function shorthelp(src,ev) %#ok
        str0 = 'A TeX shortcut inserts text when you hit a key.';
        str1 = ['In the equation editor '...
            'holding the Alt key while hitting a key from ' ...
            'the left column (Key) will insert the text from the '...
            'right column (Text).'];
        str2 = 'Hitting Tab will move the cursor to the next brace {.';
        h = msgbox({str0,str1,str2},'What is a TeX shortcut?','modal');
        %    sfig = getappdata(f,'ShortcutDialog');
        %    pos = get(sfig,'Position');
        %    center = pos(1:2)+pos(3:4)/2;
        %    hpos = get(h,'Position');
        %    set(h,'Position',[center-hpos(3:4)/2 hpos(3:4)])
        uiwait(h);
    end

    function shortnewcb(src,ev) %#ok
        sfig = getappdata(f,'ShortcutDialog');
        objs = getappdata(sfig,'shortcutDialogObjs');
        tm = objs.model;
        tm.addRow({'',''});
    end

    function shortselectcb(src,ev) %#ok
        sfig = getappdata(f,'ShortcutDialog');
        objs = getappdata(sfig,'shortcutDialogObjs');
        if (ev.getValueIsAdjusting), return; end
        if objs.selmodel.isSelectionEmpty
            set(objs.sdeletebut,'Enable','off')
        else
            set(objs.sdeletebut,'Enable','on')
        end
    end

    function shortdeletecb(src,ev) %#ok
        sfig = getappdata(f,'ShortcutDialog');
        objs = getappdata(sfig,'shortcutDialogObjs');
        row = objs.table.getSelectedRow;
        while (row ~= -1)
            objs.model.removeRow(row);
            row = objs.table.getSelectedRow;
        end
    end

    function shortapplycb(src,ev) %#ok
        sfig = getappdata(f,'ShortcutDialog');
        objs = getappdata(sfig,'shortcutDialogObjs');
        tm = objs.model;
        count = tm.getRowCount;
        actions = cell(count,2);
        ok = true(count,1);
        for k=1:count
            key = char(tm.getValueAt(k-1,0));
            if isempty(key)
                warning('texed:EmptyKey','Ignoring empty Key shortcut.');
                ok(k) = false;
            else
                if length(key) > 1
                    warning('texed:MultiCharKey',...
                        ['Keys can only be a single character.'...
                        'Ignoring extra characters.']);
                    key = key(1);
                end
                action = char(tm.getValueAt(k-1,1));
                actions{k,1} = key;
                actions{k,2} = action;
            end
        end
        actions = actions(ok,:);
        setappdata(f,'ActionTable',actions);
        
    end

    function shortclosecb(src,ev) %#ok
        delete(gcbf);
    end

    function doShortcutLayoutcb(src,ev) %#ok
        doShortcutLayout;
    end
end

Contact us