www.gusucode.com > mbcview 工具箱matlab源码程序 > mbcview/cgcalmanager.m

    function varargout = cgcalmanager(Action,varargin)
%CGCALMANAGER GUI to manage importing cal files
%
%  CGCALMANAGER(action,varargin) starts the calibration manager. 

%  Copyright 2000-2015 The MathWorks, Inc. and Ford Global Technologies, Inc.


switch lower(Action)
    case 'gethandle'
        varargout{1} = i_GetHandle;
    case 'precreate'
        varargout{1} = i_CreateFigure(true); % modal dialog
    case 'create'
        i_StartNoAction(varargin{:});
    case 'choosefile'
        i_StartChooseFile(varargin{:});
    case 'loadcal'
        i_StartLoadCalData(varargin{:});
       % ---------------- Test functions -------------
    case 'numnodes'
        fh = i_GetHandle;
        ud = get(fh,'UserData');
        num(1) = length(ud.Hand.BlockList.findAllNodes)-1;
        num(2) = ud.Hand.ParamContents.getRowCount;
        varargout{1} = num;
    case 'testshow'
        fh = i_CreateFigure(false); % not modal, for test purposes
        set(fh,'Visible','on');
        varargout{1}=fh;
    case 'testrun'
        fh = i_CreateFigure(false); % not modal, for test purposes
        c = cgbrowser;
        proj = c.RootNode;
        if nargin>1
            % Select a given item
            i_StartNoAction(proj,'selectitem',varargin{1});
        else
            i_StartNoAction(proj);
        end
        set(fh,'Visible','on');
end
end

% ----------------------------------------------
function h = i_GetHandle
% ----------------------------------------------
h = findall(0,'Tag','CalManager');
if isempty(h)
    h = [];
end
h = mbcgui.hgclassesutil.toHandle(h);
end

% ----------------------------------------------
function fh = i_CreateFigure(modal)
% ----------------------------------------------

% just incase we have a Calibration Manager hanging around somewhere
fh=i_GetHandle;
delete(fh);
c = cgbrowser;

fhWidth = 700; fhHeight = 600;
if modal
    fh= xregdialog('visible','off',...
        'renderer','painters',...
        'Tag','CalManager',...
        'name','Calibration Manager',...
        'pointer','watch');
else
    fh= xregfigure('Visible','off',...
        'Renderer','painters',...
        'Tag','CalManager',...
        'Name','Calibration Manager',...
        'Pointer','watch');
    
end
if c.GUIExists
    % Center on the browser window
    xregcenterfigure(fh, [fhWidth fhHeight], c.Figure);
else
    set(fh, 'Position', [100 100 fhWidth fhHeight]);
end
% Hook into figure position persistence
xregpersistfigpos(fh,'key','CalManager');

% Fields used to hold cal file contents and information
ud.cal = [];
ud.calfile = {};

% Field to track the source of current view: cal file or project item (or
% neither).
ud.displaysource = '';
ud.displayitem = null(xregpointer,0);

% Fields for undo information
ud.Undo.ptr = [];
ud.Undo.obj = [];

% GUI close callback function
ud.closecallback = '';

% create the various panels
[toolbar,ud]=i_CreateToolbar(fh,ud);
[bottom,ud] = i_CreateBottomPanel(fh,ud);
[link,ud] = i_CreateLinkPanel(fh,ud);
[blocklist,ud] = i_CreateBlockListPanel(fh,ud);
[calfile,ud] = i_CreateCalfilePanel(fh,ud);
[display,ud] = i_CreateDisplayPanel(fh,ud);

g = xreggridbaglayout(fh, 'dimension', [1 3], ...
    'colsizes', [-1 70 -1], ...
    'elements', {blocklist, link, calfile});
sp = xregsplitlayout(fh, ...
    'dividerstyle', 'flat', ...
    'dividerwidth', 4, ...
    'orientation', 'ud', ...
    'minwidth', [135 25], ...
    'top', g, ...
    'bottom', display);

% create the main layout
g2 = xreggridbaglayout(fh,'dimension',[3 1], ...
    'rowsizes',[31 -1 25],...
    'gapy',2, ...
    'elements',{toolbar, sp, bottom});
fh.LayoutManager = g2;

% Finish up
set(g2,'packstatus','on','visible','on');
set(fh,'UserData',ud,'Pointer','arrow');
end


%---------------------------
function [toolbarlayout,ud]=i_CreateToolbar(fh,ud)
toolbarlayout = mbcgui.container.layoutpanel(...
    'Parent', fh, ...
    'BorderType', 'beveledin');
tb = xregGui.uitoolbar('Parent',toolbarlayout,...
    'ResourceLocation',cgrespath);
set(toolbarlayout, 'LayoutComponent', tb);
tb.setRedraw(false);
ud.Hand.ClearMenu = xregGui.uipushtool(tb,'ImageFile','new.bmp',...
    'transparentcolor',[0 255 0], ...
    'ClickedCallback',@i_Clear, ...
    'Enable','off', ...
    'TooltipString','Clear Calibration File');
xregGui.uipushtool(tb,'ImageFile','open.bmp',...
    'transparentcolor',[0 255 0], ...
    'ClickedCallback' , @i_LoadFile, ...
    'TooltipString','Open Calibration File');
ud.Hand.PasteMenu = xregGui.uipushtool(tb,'ImageFile','paste.bmp',...
    'transparentcolor',[0 255 0], ...
    'TooltipString','Paste into Table', ...
    'ClickedCallback',{@i_ApplyData, 'pastedata'}, ...
    'Enable','off');
ud.Hand.InitMenu = xregGui.uipushtool(tb,'ImageFile','cgdsfilltable.bmp',...
    'transparentcolor',[0 255 0], ...
    'TooltipString','Set Up from Ascii File', ...
    'ClickedCallback',{@i_ApplyData, 'asciifile'}, ...
    'Enable','off');
ud.Hand.UndoMenu = xregGui.uipushtool(tb,'ImageFile','undo.bmp',...
    'transparentcolor',[0 255 0], ...
    'TooltipString','Undo', ...
    'ClickedCallback',@i_Undo, ...
    'Enable','off');
ud.Hand.RedoMenu = xregGui.uipushtool(tb,'ImageFile','redo.bmp',...
    'transparentcolor',[0 255 0], ...
    'TooltipString','Redo', ...
    'ClickedCallback',@i_Redo, ...
    'Enable','off');
cghelptoolbutton(tb,'CGCALMANAGER','tooltip','Calibration Manager Help');

tb.setRedraw(true); 
end


%--------------------------------
function [panel,ud] = i_CreateBlockListPanel(fh,ud)

panel = mbcgui.container.titlebarpanel(...
    'Parent', fh, ...
    'BarTitle', 'Project Calibration Items', ...
    'FocusAppearance', 'off');

% tree control
tree = mbctreeadapter.CageTree('Parent',panel,...
    'SelectionChangedCallback',@i_TreeCallback,...
    'Editable',false);

ud.Hand.BlockList = tree;

% Table initialisation controls below the tree
SizePanel = mbcgui.container.layoutpanel(...
    'Parent', panel, ...
    'BorderType', 'beveledout');

ud.Hand.EditXSize = mbcgui.widget.Spinner('Parent', SizePanel, ...
    'Min', 0, ...
    'Rule', 'int', ...
    'Callback',@i_EditSize, ...
    'Enable','off');
ud.Hand.ManTextX = xregGui.labelcontrol('parent',SizePanel, ...
    'string','Rows: ',...
    'LabelAlignment','left', ...
    'LabelSizeMode', 'Absolute', ...
    'LabelSize', 50, ...
    'gap',5,...
    'ControlSize',50, ...
    'control', ud.Hand.EditXSize);

ud.Hand.EditYSize = mbcgui.widget.Spinner('Parent', SizePanel, ...
    'Min', 0, ...
    'Rule', 'int', ...
    'Callback',@i_EditSize, ...
    'Enable','off');
ud.Hand.ManTextY = xregGui.labelcontrol('parent',SizePanel, ...
    'string','Columns: ',...
    'LabelAlignment','left', ...
    'LabelSizeMode', 'Absolute', ...
    'LabelSize', 50, ...
    'gap',5,...
    'ControlSize',50, ...
    'control', ud.Hand.EditYSize);

ud.Hand.EditValue = mbcgui.widget.Spinner('Parent', SizePanel, ...
    'Enable','off');
ud.Hand.ValueLabel = xregGui.labelcontrol('parent',SizePanel, ...
    'string', 'Value:',...
    'LabelAlignment','left', ...
    'LabelSizeMode', 'Absolute', ...
    'LabelSize', 35, ...
    'gap',5,...
    'ControlSize',70, ...
    'control', ud.Hand.EditValue);

ud.Hand.SetSizeButton = uicontrol('Parent', SizePanel, ...
    'Style','pushbutton',...
    'String','Apply',...
    'Callback',@i_ApplySize,'Enable','off'); 

PrecPanel = mbcgui.container.layoutpanel(...
    'Parent', panel, ...
    'BorderType', 'beveledout');
ud.Hand.PrecisionLabel = uicontrol('Parent', PrecPanel,...
    'Style','text',...
    'HorizontalAlignment','left',...
    'String','Precision: ');
ud.Hand.SetPropsButton = uicontrol('Parent', PrecPanel, ...
    'Style','pushbutton',...
    'String','Edit Precision...',...
    'Callback',@i_PrecEdit,'Enable','off'); 

grd1 = xreggridbaglayout(SizePanel, ...
    'dimension', [5 4], ...
    'rowsizes', [20 5 2 20 3], ...
    'colsizes', [105 90 -1 65], ...
    'gapx', 10, ...
    'border', [5 5 5 5], ...  
    'mergeblock', {[3 5], [4 4]}, ...
    'mergeblock', {[1 1], [2 4]}, ...
    'elements', {ud.Hand.ManTextX, [], [], ud.Hand.ManTextY, [], ...
        ud.Hand.ValueLabel, [], [], [], [], ...
        [], [], [], [], [], ...
        [], [], ud.Hand.SetSizeButton});
set(SizePanel, 'LayoutComponent', {grd1});
grd2 = xreggridbaglayout(PrecPanel, ...
    'dimension', [2 2], ...
    'gapy', 5, ...
    'gapx', 5, ...
    'border', [5 5 5 3], ...
    'rowsizes', [-1 25], ...
    'colsizes', [-1 85], ...
    'mergeblock',{[1 2], [1 1]}, ...
    'elements', {ud.Hand.PrecisionLabel, [], [], ud.Hand.SetPropsButton});
set(PrecPanel, 'LayoutComponent', {grd2});

grid = xreggridbaglayout(panel, ...
    'dimension',[3,1], ...
    'rowsizes',[-1 62 48], ...
    'elements', {ud.Hand.BlockList, SizePanel, PrecPanel});


set(panel,'ContentHandle',{grid});
ud.Hand.ProjectPanel = panel;  
end


%------------------------------
function [g1,ud] = i_CreateLinkPanel(fh,ud)

ud.Hand.LinkButton = uicontrol('Parent', fh, ...
    'Style','pushbutton',...
    'Callback',@i_Link,...
    'Enable', 'off', ...
    'String','<-----------',...
    'TooltipString','Set Up from Selected Calibration File Item');
ud.Hand.AutoLinkButton = uicontrol('Parent', fh, ...
    'Style','pushbutton',...
    'Callback',@i_AutoLink,...
    'Enable', 'off', ...
    'String',' <-- Auto --',...
    'TooltipString','Set Up All Matching Calibration File Items');
g1 = xreggridlayout(fh, ...
    'dimension',[4 1], ...
    'correctalg','on',...
    'rowsizes',[-1 25 25 -1], ...
    'rowratios', [1 0 0 2], ...
    'gap',10, ...
    'border', [2 0 2 0], ...
    'elements',{[],ud.Hand.LinkButton,ud.Hand.AutoLinkButton});
end


%-------------------------------
function [bottom,ud] = i_CreateBottomPanel(fh,ud)

ud.Hand.Close = uicontrol('Parent', fh,...
    'Style','push',...
    'Callback','close(gcbf)',...
    'String','Close');
MessagePanel = mbcgui.container.layoutpanel( ...
    'Parent', fh, ...
    'BorderType', 'beveledin', ...
    'LayoutBorder', [2 0 2 4]);
ud.Hand.Message = uicontrol('Parent', MessagePanel,...
    'Style','text',...
    'HorizontalAlignment','left',...
    'Enable', 'inactive', ...
    'String','');
set(MessagePanel, 'LayoutComponent', ud.Hand.Message);

bottom= xreggridbaglayout(fh, ...
    'dimension',[1 2],...
    'colsizes',[-1 65], ...
    'gapx', 7, ...
    'elements',{MessagePanel, ud.Hand.Close});
end


%---------------------------------
function [display,ud] = i_CreateDisplayPanel(fh,ud)

display = mbcgui.container.titlebarpanel(...
    'Parent', fh,...
    'BarTitle','Display');

ud.Hand.TableWrapper = mbcwidgets.Table2D('numeric', ...
    'parent', display);
ud.Hand.TableWrapper.Peer.setBorder([]);
set(display,'ContentHandle',ud.Hand.TableWrapper);

ud.Hand.TableTitle = display;
end


%---------------------------------
function [grid,ud] = i_CreateCalfilePanel(fh,ud)

%draw listview control
toppanel = mbcgui.container.titlebarpanel(...
    'Parent', fh, ...
    'BarTitle', 'Calibration File Contents', ...
    'FocusAppearance', 'off');

h = mbcwidgets.List( 'Parent', toppanel,...
    'Editable', false, ...
    'SelectionChangedCallback',@i_ListCallback,...
    'SelectionMode', 'SingleRow');

h.Peer.setColumnData({'Name','Size'});
h.Peer.setColumnWidths([180,60]);
h.Peer.setBorder([])

ud.Hand.ParamContents = h;
set(toppanel,'ContentHandle', h);

bottompanel = mbcgui.container.titlebarpanel(...
    'Parent', fh, ...
    'BarTitle','Calibration File Information');
% Info pane for displaying file information
ud.Hand.CalFileInfo = mbcgui.table.InfoPane('Parent', bottompanel);
set(bottompanel,'ContentHandle', ud.Hand.CalFileInfo);

grid = xreggridbaglayout(fh, ...
    'dimension',[2 1], ...
    'gapy', 2, ...
    'rowsizes',[-1 110],...
    'elements', {toppanel, bottompanel});
ud.Hand.FilePanel = toppanel;
end


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                FINISH               %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function i_Finish(src,evt)
% Pass notification on
fh = i_GetHandle;
set(fh, 'Visible', 'off');
drawnow('expose');
ud = get(fh, 'UserData');
xregcallback(ud.closecallback, fh, []);
end


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% i_FillValuePane                     %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function i_FillValuePane
% Update the information in the table
fh = i_GetHandle;
ud = get(fh,'UserData');
tw = ud.Hand.TableWrapper;
if isempty(ud.displaysource)
    % No valid object selected
    tw.Peer.clearTable;
    set(ud.Hand.TableTitle,'BarTitle','No item selected');
    i_Message('Please select an item');
    set(ud.Hand.ProjectPanel, 'FocusAppearance', 'off');
    set(ud.Hand.FilePanel, 'FocusAppearance', 'off');
else
    if strcmp(ud.displaysource, 'project')
        % Calibratable object
        obj = ud.displayitem;
        mtableview(obj.info,tw);
        set(ud.Hand.TableTitle,'BarTitle',['Project item: ',obj.getname]);
        set(ud.Hand.ProjectPanel, 'FocusAppearance', 'on');
        set(ud.Hand.FilePanel, 'FocusAppearance', 'off');
    else
        obj = ud.displayitem;
        if length(obj) > 1
            obj = obj(1);
        end
        N = obj.name;
        set(ud.Hand.TableTitle,'BarTitle',['Calibration File: ',N]);
        switch obj.numaxes
            case 3
                S = size(obj.data.Z);
                if isfield(obj.data,'X')
                    X = obj.data.X;
                    Y = obj.data.Y;
                else
                    X = 0:S(2)-1;
                    Y = 0:S(1)-1;
                end
                tw.Peer.setData(obj.data.Z, X, Y);
                tw.Peer.setCornerAsBlank;
                tw.ShowColumnHeader = true;
                tw.ShowRowHeader = true;
                tw.ShowHeaderSelection = true;
            case 2
                tw.Peer.setData([obj.data.X(:) obj.data.Y(:)], {'Input','Output'});
                tw.ShowColumnHeader = true;
                tw.ShowRowHeader = false;
                tw.ShowHeaderSelection = false;
            case 1
                tw.Peer.setData(obj.data.X, {obj.name});
                tw.ShowColumnHeader = true;
                tw.ShowRowHeader = false;
                tw.ShowHeaderSelection = false;
            otherwise
                tw.Peer.clearTable;
        end
        set(ud.Hand.ProjectPanel, 'FocusAppearance', 'off');
        set(ud.Hand.FilePanel, 'FocusAppearance', 'on');
    end
    i_Message('');
end
end


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Make Cal file contents window       %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function i_FillCalFilePane
fh = i_GetHandle;
ud = get(fh,'UserData');

list_data = {'Calibration files';...
        'Total number of items'; ...
        'Number of 2D tables'; ...
        'Number of 1D tables'; ...
        'Number of scalar items'};

if isempty(ud.cal)
    % clear listbox and all text fields
    list_str = cell(length(list_data),2);
    list_str(:,1) = list_data;
    list_str(:,2) = {''};
    ud.Hand.CalFileInfo.ListText = list_str;
    set(ud.Hand.ClearMenu, 'Enable', 'off');
    set([ud.Hand.AutoLinkButton; ud.Hand.LinkButton], 'Enable', 'off');
    % clear table
    ud.Hand.ParamContents.Peer.setData([]);
else
    set(fh,'Pointer','watch'); 
    
    % Add items to list and count each type at the same time
    nScalar = 0;
    n1D = 0;
    n2D = 0;
    Data = cell(length(ud.cal),2);
    Icon = cell(length(ud.cal),1);
    for n = 1:length(ud.cal)
        Data{n,1} = ud.cal(n).name;

        switch ud.cal(n).numaxes
            case 3
                Icon{n} = cgrespath('cgfulltable.bmp');

                n2D = n2D + 1;
                sizestr = sprintf('%d x %d', ud.cal(n).numrows, ud.cal(n).numcols);
            case 2
                Icon{n} = cgrespath('cgfullfunction.bmp');
                n1D = n1D + 1;
                sizestr = sprintf('%d', ud.cal(n).numrows);
            case 1
                Icon{n} = cgrespath('cgcontconst.bmp');
                nScalar = nScalar + 1;
                sizestr = '';
        end
        Data{n,2} = sizestr;
    end
    ud.Hand.ParamContents.Peer.setData(Data,Icon);
    
    % Generate information strings
    Nfiles = length(ud.calfile);
    list_str = cell(length(list_data)+Nfiles-1,2);
    list_str(1,1) = list_data(1);
    list_str((end-length(list_data)+2):end,1) = list_data(2:end);
    
    for n = 1:Nfiles
        [unused, file, ext] = fileparts(ud.calfile{n});
        list_str{n,2} = [file ext];
    end
    list_str{Nfiles+1,2} = sprintf('%d', nScalar + n1D + n2D);
    list_str{Nfiles+2,2} = sprintf('%d', n2D);
    list_str{Nfiles+3,2} = sprintf('%d', n1D);
    list_str{Nfiles+4,2} = sprintf('%d', nScalar);
    ud.Hand.CalFileInfo.ListText = list_str;
    
    % Enable the clear menu button
    set(ud.Hand.ClearMenu, 'Enable', 'on');
    set([ud.Hand.AutoLinkButton; ud.Hand.LinkButton], 'Enable', 'on');
    set(fh,'Pointer','arrow');
end
end


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Set up Cal item tree                %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function i_RefreshTree(pPROJ)
fh = i_GetHandle;
ud = get(fh,'UserData');
h = ud.Hand;
PROJ = pPROJ.info;
% Compile block list and disable manual set (there will be no selected item)
h.BlockList.TypeFilter = cgtypes.cgtabletype;
refresh( h.BlockList, pPROJ );

% Explicitly add any cgconstants to the tree.  We only expect to find these in
% featurenodes.
F = filterbytype(PROJ, cgtypes.cgfeaturetype);

for n = 1:length(F)
    F{n} = getconstants(F{n})';
end
C = unique([F{:}]);

if ~isempty(C)
    add( h.BlockList, C, pPROJ,0 );
end

end


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Set up Cal item size pane           %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function i_FillCalItemPane
fh = i_GetHandle;
ud = get(fh,'UserData');

if ~strcmp(ud.displaysource, 'project')
    % Disable all table property editing devices
    editEn = {'off';'off';'off'};
    applyEn = 'off';
    % Disable precision panel
    precEn = 'off'; precStr = '';
    % Set editors to zeros
    xyMin = {0; 0};
    xyzVals = {0; 0; 0};
else
    obj = ud.displayitem;
    item = obj.info;
    precEn = 'on'; precStr = char(get(item, 'precision'));
    if isa(item, 'cgconstant')
        editEn = {'off';'off';'on'};
        applyEn = 'on';
        xyMin = {1; 1};
        xyzVals = {1; 1; getvalue(item)};
    else
        editEn = {'off';'off';'off'};
        applyEn = 'off';
        xyMin = {0; 0};
        xyzVals = {0; 0; 0};
        
        % Work out whether sizes can be altered
        if ~issizelocked(item)
            if isa(item, 'cglookuptwo')
                editEn{1} = 'on';
                editEn{2} = 'on';
            elseif isa(item, 'cgnormfunction')
                editEn{1} = 'on';
            elseif isa(item, 'cgnormaliser')
                % Need to check whether the parent is a lookupone (no
                % changes allowed in this case
                parents = get(item, 'flist');
                if ~(length(parents)==1 && parents(1).isa('cglookupone'))
                    editEn{1} = 'on';
                end
            end
        end
        
        % Get actual sizes and min values
        % Also get default init value and whether value editor is enabled
        V = get(item, 'values');
        sz = size(V);
        if isa(item, 'cglookuptwo')
            if ~isempty(V)
                xyzVals = {sz(1); sz(2); round(mean(V(:)))};
                xyMin = {2; 2};
                applyEn = 'on';
            end
            editEn{3} = 'on';
            
        elseif isa(item, 'cgnormfunction')
            if ~isempty(V)
                xyzVals = {sz(1); 2; round(mean(V(:)))};
                xyMin = {2; 0};
                applyEn = 'on';
            else
                xyzVals{2} = 2;
            end
            editEn{3} = 'on';
            
        elseif isa(item, 'cgnormaliser')
            if ~isempty(V)
                xyzVals{1} = sz(1);
                xyzVals{2} = 2;
                xyMin = {2; 0};
                applyEn = 'on';
            else
                xyzVals{2} = 2;
            end
        end
    end
end

% Disable Apply button if no editing is allowed or if a zero size is
% currently set
set(ud.Hand.SetSizeButton, 'Enable', applyEn);

% Set size/value editors to appropriate state
set([ud.Hand.EditXSize; ud.Hand.EditYSize], {'Min'}, xyMin);
set([ud.Hand.EditXSize; ud.Hand.EditYSize; ud.Hand.EditValue], {'Value'}, xyzVals);
set([ud.Hand.ManTextX; ud.Hand.ManTextY; ud.Hand.ValueLabel] , {'Enable'}, editEn);

% Set precision panel to appropriate state
set([ud.Hand.PrecisionLabel; ud.Hand.SetPropsButton], 'Enable', precEn);
set(ud.Hand.PrecisionLabel, 'String', ['Precision: ' precStr]);

% Set clipboard/ascii enable state off if no editors are enabled
if all(strcmp(editEn, 'off'))
    set([ud.Hand.PasteMenu, ud.Hand.InitMenu], 'Enable', 'off');
else
    set([ud.Hand.PasteMenu, ud.Hand.InitMenu], 'Enable', 'on');
end
end


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Load calibration info from a file   %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function OK = i_ChooseFile
OK = true;

% Let the user choose what to import
inputObj = cgcalinput;
[inputObj, calinfo] = gui_import( inputObj );
% calinfo is empty if the user aborted etc
if isempty(calinfo)
    OK = false;
else
    i_LoadCalData(inputObj, calinfo);
end
end


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Load calibration data into the tool %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function i_LoadCalData(calobj, calinfo)
fh = i_GetHandle;
set(fh,'Pointer','watch');
ud = get(fh,'UserData');

calfile = get(calobj, 'SourceString');
if isempty(ud.cal)
    ud.cal = calinfo;
    ud.calfile = {calfile};
else
    % Check for name matches and if there are any then keep new info
    L = length(calinfo);
    
    names = lower({ud.cal.name}); 
    NewNames = lower({calinfo.name});
    
    % Replacements
    [unused, iNew, iOld] = intersect(NewNames, names);
    ud.cal(iOld) = calinfo(iNew);
    
    % Additions
    iNew = setdiff(1:L, iNew);
    ud.cal = [ud.cal, calinfo(iNew)];
    
    ud.calfile = [ud.calfile, {calfile}];
end

set(fh,'UserData',ud);
set(fh,'Pointer','arrow');
figure(fh)
end


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Programmatically select a tree node %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function NODE_FOUND = i_SelectTreeNode(pItem)
% Attempt to find the tree node corresponding to the pointer pItem
fh = i_GetHandle;
ud = get(fh,'UserData');
if nargin
    % Look for a node corresponding to the given item
    select(ud.Hand.BlockList,pItem,false)
    NODE_FOUND = isequal(pItem,ud.Hand.BlockList.Selected);
    
else
    % Select the first node on tree
    ch = ud.Hand.BlockList.getChildren(ud.Hand.BlockList.Root);
    NODE_FOUND=~isempty(ch);
    if NODE_FOUND
        select(ud.Hand.BlockList,ch(1),false)
    end
end
    
if NODE_FOUND
    pItem = ud.Hand.BlockList.Selected;
    if pItem.isa('cgcontainer')
       pItem = pItem.getdata; 
    end
    
    ud.displaysource = 'project';
    ud.displayitem = pItem;
    set([ud.Hand.PasteMenu, ud.Hand.InitMenu], 'Enable', 'on');
else
    ud.displaysource = '';
    ud.displayitem = null(xregpointer, 0);
    set([ud.Hand.PasteMenu, ud.Hand.InitMenu], 'Enable', 'off');
end

set(fh, 'UserData', ud);
i_FillCalItemPane;
i_FillValuePane;
end


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Message                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function i_setCloseCallback(cb)
fh = i_GetHandle;
ud = get(fh,'UserData');
ud.closecallback = cb;
set(fh, 'UserData', ud);
end


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Message                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function i_Message(str)
fh = i_GetHandle;
ud = get(fh,'UserData');
if isempty(str)
    % Construct a default string giving the user some info on the selected
    % object
    if strcmp(ud.displaysource, 'project')
        if ud.displayitem.isa('cglookuptwo')
            NR = size(ud.displayitem.get('values'), 1);
            NC = size(ud.displayitem.get('values'), 2);
            str = sprintf('(%d x %d) 2D table', NR, NC);
            if ud.displayitem.issizelocked
                str = [str '.  The size of this item has been locked.'];
            end
        elseif ud.displayitem.isa('cgconstant')
            str = 'Scalar item';
        else
            NR = size(ud.displayitem.get('values'), 1);
            str = sprintf('%d element 1D table', NR);
            if ud.displayitem.issizelocked
                str = [str '.  The size has been locked.'];
            end
        end
        
    elseif strcmp(ud.displaysource, 'calfile')
        switch ud.displayitem.numaxes
            case 3
                str = sprintf('(%d x %d) 2D table', ud.displayitem.numrows, ud.displayitem.numcols);
            case 2
                str = sprintf('%d element 1D table', ud.displayitem.numrows);
            otherwise
                str = 'Scalar item';
        end
    end
    
end
set(ud.Hand.Message,'String',str);
end


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Set up undo store                   %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function i_SetForUndo(ptr)
fh = i_GetHandle;
ud = get(fh,'UserData');
if isempty(ptr)
    % Clear the undo buffer
    ud.Undo.obj = [];
    ud.Undo.ptr = [];
    set([ud.Hand.UndoMenu ud.Hand.RedoMenu],'Enable','off');
else
    % Setup the undo buffer
    ud.Undo.ptr = ptr;
    if length(ptr)==1
        ud.Undo.obj = {info(ptr)};
    else
        ud.Undo.obj = info(ptr);
    end
    set([ud.Hand.UndoMenu ud.Hand.RedoMenu],{'Enable'},{'on'; 'off'});
    
end
set(fh,'UserData',ud);
end


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Undo                                          %
% The Undo store is also used as the redo store %
% There is only one level of undo but more than %
% one object may need undo'ing hence the loop   %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function i_PerformUndo
fh = i_GetHandle;
ud = get(fh,'UserData');
if ~isempty(ud.Undo.ptr) && (length(ud.Undo.ptr) == length(ud.Undo.obj))
    for n = 1:length(ud.Undo.ptr)
        obj = ud.Undo.obj{n};
        ud.Undo.obj{n} = ud.Undo.ptr(n).info; % store redo/undo object
        ud.Undo.ptr(n).info = obj; % Perform the undo/redo
    end
    set(fh,'UserData',ud);
    i_RefreshIcons;
    i_FillValuePane; 
else
    i_SetForUndo([]);
    set([ud.Hand.RedoMenu ud.Hand.UndoMenu],'Enable','off');
end
end


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Only refresh the icons, not the structure %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function i_RefreshIcons
fh = i_GetHandle;
ud = get(fh,'UserData');
h = ud.Hand;

updateAll(h.BlockList);

end


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Transfer data from a load structure %
% to a calibration item               %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function [status, msg] = i_TransferToTable(pItem, Vstruct)
% Vstruct is a structure containing the fields:
%    name
%    description
%    info
%    data
%    numaxes
%    numrows
%    numcols
%
% The data field may contain a combination of X/Y/Z fields.  This structure
% is the same as that used by cgcalinput. (X is the column normaliser
% breakpoints, Y the row ones)
%
% status is a numeric code indicating the outcome of the operation:
%    0 means the operation was successful
%    1 means the data didn't match the type of object in pItem
%    2 means the size of the data caused a problem
%    3 means that the expression object rejected the data for
%          some reason (e.g. because of non-increasing breakpoints)
%
% If the inputs are vectors then the status and msg outputs will be a
% vector and cell array respectively.

Nitems = length(Vstruct);

status = zeros(1, Nitems);
msg = repmat({''}, 1, Nitems);

pItem = pItem(:)';
LUobj = infoarray(pItem);

% vectors to hold undo information for any other objects that are altered
% (normalisers, for example)
pAdditional = null(xregpointer, 0);
objAdditional = {};

    function chk = isInMainList(ptr)
        % Check whether pointer is in main transfer list
        chk = ismember(ptr, pItem);
    end
        
    function obj = i_getObjectForPtr(ptr)
        % Return the object for a pointer.
        idx = findptrs(ptr, pItem);
        if idx==0
            idx = findptrs(ptr, pAdditional);
            if idx==0
                obj = ptr.info;
                pAdditional(end+1) = ptr;
                objAdditional{end+1} = obj; 
            else
                obj = objAdditional{idx};
            end
        else
            obj = LUobj{idx};
        end
        
    end

    function i_setObjectForPtr(ptr, obj)
        % Save the updated object for a pointer
        idx = findptrs(ptr, pItem);
        if idx==0
            idx = findptrs(ptr, pAdditional);
            if idx==0
                pAdditional(end+1) = ptr;
                objAdditional{end+1} = obj; 
            else
                objAdditional{idx} = obj;
            end
        else
            LUobj{idx} = obj;
        end
        
    end


for n = 1:Nitems
    % Check that the data in Vstruct matches the type of object in pItem
    itemAxes = 2;
    if isa(LUobj{n}, 'cglookuptwo')
        itemAxes = 3;
    elseif isa(LUobj{n}, 'cgconstant')
        itemAxes = 1;
    end
    if itemAxes~=Vstruct(n).numaxes
        status(n) = 1;
        msg{n} = 'Incorrect data type for object.';
        continue
    end
    
    % Size checking is rolled together with actually changing the data as
    % they are both dependent on the type of object being used
    if isa(LUobj{n}, 'cgconstant')
        if Vstruct(n).numrows==1 && Vstruct(n).numcols==1
            LUobj{n} = setvalue(LUobj{n}, Vstruct(n).data.X);
        else
            status(n) = 2;
            msg{n} = 'Calibration constants can only be filled with a scalar value.';
        end
    else
        if isa(LUobj{n}, 'cglookuptwo')
            objSize = size(get(LUobj{n}, 'values'));
            if all(size(Vstruct(n).data.Z)>=2)
                ok = i_sizecheck(objSize, size(Vstruct(n).data.Z), issizelocked(LUobj{n}), getname(LUobj{n}));
                if ok
                    try
                        LUobj{n} = set(LUobj{n},'matrix',{Vstruct(n).data.Z Vstruct(n).info});
                        % Check whether normalisers should be set up
                        if length(Vstruct(n).data.X)>=2 
                            pX = get(LUobj{n}, 'x');
                            if ~isInMainList(pX)
                                X = i_getObjectForPtr(pX);
                                ok = i_sizecheck(length(get(X,'values')), length(Vstruct(n).data.X), issizelocked(X), getname(X));
                                if ok
                                    nBP = length(Vstruct(n).data.X);
                                    NewMat = [Vstruct(n).data.X(:) (0:nBP-1)'];
                                    X = set(X, 'matrix',{NewMat Vstruct(n).info},...
                                        'description','');
                                    i_setObjectForPtr(pX, X);
                                end
                            end
                        end
                        if length(Vstruct(n).data.Y)>=2
                            pY = get(LUobj{n}, 'y');
                            if ~isInMainList(pY)
                                Y = i_getObjectForPtr(pY);
                                ok = i_sizecheck(length(get(Y,'values')), length(Vstruct(n).data.Y), issizelocked(Y), getname(Y));
                                if ok
                                    nBP = length(Vstruct(n).data.Y);
                                    NewMat = [Vstruct(n).data.Y(:) (0:nBP-1)'];
                                    Y = set(Y, 'matrix',{NewMat Vstruct(n).info},...
                                        'description','');
                                    i_setObjectForPtr(pY, Y);
                                end
                            end
                        end
                    catch ME
                        [unused, unused, x] = mbcGetLastError(ME,'MessageFormat', 'singleline');
                        status(n) = 3;
                        msg{n} = ['Error copying values: ' x];
                    end
                end
            else
                status(n) = 2;
                msg{n} = 'Table must be at least (2x2) elements.';
            end
            
        elseif isa(LUobj{n}, 'cglookupone')
            objSize = size(get(LUobj{n}, 'values'));
            if length(Vstruct(n).data.X) == length(Vstruct(n).data.Y) ...
                    && length(Vstruct(n).data.X)>=2
                ok = i_sizecheck(objSize(1), length(Vstruct(n).data.X), issizelocked(LUobj{n}), getname(LUobj{n}));
                if ok
                    try
                        LUobj{n} = set(LUobj{n}, 'matrix', {[Vstruct(n).data.X(:) Vstruct(n).data.Y(:)] Vstruct(n).info}); 
                    catch ME
                        [unused, unused, x] = mbcGetLastError(ME,'MessageFormat', 'singleline');
                        status(n) = 3;
                        msg{n} = ['Error copying values: ' x];
                    end

                else
                    status(n) = 2;
                    msg{n} = 'Unable to change size of table.';
                end
            else
                status(n) = 2;
                msg{n} = 'X and Y columns must be the same length and have at least 2 elements.';
            end
            
        elseif isa(LUobj{n}, 'cgnormfunction')
            objSize = size(get(LUobj{n}, 'values'));
            if length(Vstruct(n).data.Y)>=2
                ok = i_sizecheck(objSize(1), length(Vstruct(n).data.Y), issizelocked(LUobj{n}), getname(LUobj{n}));
                if ok
                    try
                        LUobj{n} = set(LUobj{n},'matrix',{Vstruct(n).data.Y(:) Vstruct(n).info});
                        % Check whether normalisers should be set up
                        if length(Vstruct(n).data.X)>=2
                            pX = get(LUobj{n}, 'x');
                            if ~isInMainList(pX)
                                X = i_getObjectForPtr(pX);
                                ok = i_sizecheck(length(get(X,'values')), length(Vstruct(n).data.X), issizelocked(X), getname(X));
                                if ok
                                    nBP = length(Vstruct(n).data.Y);
                                    NewMat = [Vstruct(n).data.X(:) (0:nBP-1)'];
                                    X = set(X, 'matrix',{NewMat Vstruct(n).info},...
                                        'description','');
                                    i_setObjectForPtr(pX, X);
                                end
                            end
                        end
                    catch ME
                        [unused, unused, x] = mbcGetLastError(ME,'MessageFormat', 'singleline');
                        status(n) = 3;
                        msg{n} = ['Error copying values: ' x];
                    end
                end
            else
                status(n) = 2;
                msg{n} = 'Table must be at least 2 elements long.';
            end
            
        elseif isa(LUobj{n}, 'cgnormaliser')
            objSize = size(get(LUobj{n}, 'values'));
            if isempty(Vstruct(n).data.Y)
                Vstruct(n).data.Y = (0:Vstruct(n).numrows-1)';
            end
            if length(Vstruct(n).data.X) == length(Vstruct(n).data.Y) ...
                    && length(Vstruct(n).data.X)>=2
                ok = i_sizecheck(objSize(1), length(Vstruct(n).data.X), issizelocked(LUobj{n}), getname(LUobj{n}));
                if ok
                    try
                        LUobj{n} = set(LUobj{n}, 'matrix', {[Vstruct(n).data.X(:) Vstruct(n).data.Y(:)] Vstruct(n).info});
                    catch ME
                        [unused, unused, x] = mbcGetLastError(ME,'MessageFormat', 'singleline');
                        status(n) = 3;
                        msg{n} = ['Error copying values: ' x];
                    end
                else
                    status(n) = 2;
                    msg{n} = 'Unable to change size of normalizer.';
                end
                
            else
                status(n) = 2;
                msg{n} = 'X and Y columns must be the same length and have at least 2 elements.';
            end
        end
        if ~any(strcmp(Vstruct(n).name, {'asciifile', 'pastedata', 'manualreset'}))
            % Set new description if data is from a calfile
            LUobj{n} = set(LUobj{n}, 'description', Vstruct(n).description);
        end
    end
end

% Place the items that worked into the undo store, then update the pointers
% with the new copies
itemsUpdated = (status==0);
i_SetForUndo([pItem(itemsUpdated), pAdditional]);
passign([pItem(itemsUpdated), pAdditional], [LUobj(itemsUpdated), objAdditional]);
end


function ok = i_sizecheck(oldSize, newSize, islocked, name)
if all(oldSize==newSize) || all(oldSize==0)
    ok = true;
else
    if islocked
        h = errordlg(sprintf('The size of %s has been locked and cannot be altered.', name), ...
        'MBC Toolbox', 'modal');
        waitfor(h);
        ok = false;
    else
        x = questdlg(sprintf('This operation will change the size of %s.  Do you want to continue?', name), ...
            'MBC toolbox', 'Continue', 'Cancel', 'Continue');
        if strcmp(x, 'Continue')
            ok = true;
        else
            ok = false;
        end
    end
end
end


%--------------------------------------
% Callback from clicking item on the tree
%--------------------------------------
function i_TreeCallback(C, evt)
%--------------------------------------
% Retrieve pointer to object from the node's key
pNode = evt.Data.NewNode;
if pNode.isa('cgnode')
    if pNode==pNode.root
        if ~isempty(evt.Data.OldNode)
            select(C,evt.Data.OldNode);
        end
        return
    end
    if pNode.isa('cgcontainer')
        pNode = pNode.getdata;
    end
end

fh = i_GetHandle;
ud = get(fh,'UserData');
if ~strcmp(ud.displaysource, 'project') ...
        || isempty(ud.displaysource) ...
        || ud.displayitem~=pNode
    
    ud.displaysource = 'project';
    ud.displayitem = pNode;
    set(fh, 'UserData', ud);
    
    i_FillCalItemPane;
    i_FillValuePane;
end
end


%--------------------------------------
% Callback from clicking item on the list
%--------------------------------------
function i_ListCallback(src, evt)
%--------------------------------------

% Retrieve index to information from the item's key
idx = src.getSelectedRows;
fh = i_GetHandle;
ud = get(fh,'UserData');
if ~isempty(idx) && (~strcmp(ud.displaysource, 'calfile') ...
        || isempty(ud.displaysource) ...
        || ~strcmp(ud.displayitem.name, ud.cal(idx).name))
    
    ud.displaysource = 'calfile';
    ud.displayitem = ud.cal(idx);
    set(fh, 'UserData', ud);
    
    i_FillCalItemPane;
    i_FillValuePane;
    
    % Disable value import from ascii file and clipboard
    set([ud.Hand.PasteMenu, ud.Hand.InitMenu], 'Enable', 'off');
end
end


%--------------------------------------
% Callback from changing size value
%--------------------------------------
function i_EditSize(src,evt)
%--------------------------------------
% Make sure the min of an edited size is 2
src.Min = 2;
% Enable apply if it was disabled
fh = i_GetHandle;
ud = get(fh, 'UserData');
if get(ud.Hand.EditXSize, 'Value')>0 && get(ud.Hand.EditYSize, 'Value')>0
    set(ud.Hand.SetSizeButton, 'Enable', 'on');
end
end


%--------------------------------------
% Callback from Precision button
%--------------------------------------
function i_PrecEdit(src, evt)
%--------------------------------------
%Handles clicks on tree
fh = i_GetHandle;
ud = get(fh,'UserData');
if strcmp(ud.displaysource, 'project')
    obj = ud.displayitem;
    prec = obj.get('precision');
    [prec, ok] = guiChooserEditor(prec, 'Parent', fh);
    
    if ok
        obj.info = obj.set('Precision', prec);
        i_FillCalItemPane;
        i_FillValuePane;
    end
end
end


%--------------------------------------
% Callback from File loading button
%--------------------------------------
function i_LoadFile(src, evt)
%--------------------------------------
OK = i_ChooseFile;
if OK
    i_FillCalFilePane;
end
end


%--------------------------------------
% Clear Cal File               
%--------------------------------------
function i_Clear(src,evt)
%--------------------------------------
fh = i_GetHandle;
ud = get(fh,'UserData');
ud.cal = [];
ud.calfile = {};
if strcmp(ud.displaysource, 'calfile')
    ud.displaysource = '';
    ud.displayitem = null(xregpointer, 0);
end
set(fh,'UserData',ud);

% Update the cal file info pane
i_FillCalFilePane;
% Update rest of gui
i_FillCalItemPane;
i_FillValuePane;
end


%--------------------------------------
% Undo operation             
%--------------------------------------
function i_Undo(src,evt)
%--------------------------------------
fh = i_GetHandle;
ud = get(fh,'UserData');
set([ud.Hand.UndoMenu ud.Hand.RedoMenu],{'Enable'},{'off'; 'on'});
i_PerformUndo
end


%--------------------------------------
% Redo operation             
%--------------------------------------
function i_Redo(src,evt)
%--------------------------------------
fh = i_GetHandle;
ud = get(fh,'UserData');
set([ud.Hand.UndoMenu ud.Hand.RedoMenu],{'Enable'},{'on'; 'off'});
i_PerformUndo
end


%--------------------------------------
% Apply size/value to table             
%--------------------------------------
function i_ApplySize(src,evt)
%--------------------------------------
fh = i_GetHandle;
ud = get(fh,'UserData');
if strcmp(ud.displaysource, 'project')
    % Set up an appropriate data structure according to the type of object
    % selected and then use subfunction to perform copy
    V = struct('name', 'manualreset', ...
        'description', '', ...
        'info', 'Manually initialised from Calibration Manager', ...
        'data',[], ...
        'numaxes',[], ...
        'numrows',[], ...
        'numcols',[]);
    obj = ud.displayitem.info;
    if isa(obj, 'cglookuptwo')
        V.numrows = ud.Hand.EditXSize.Value;
        V.numcols = ud.Hand.EditYSize.Value;
        V.data.Z = ud.Hand.EditValue.Value*ones(V.numrows, V.numcols);
        V.numaxes = 3;
        % Look to see whether both normalisers are empty - if they are then
        % we'll initialise them too
        pX = get(obj, 'x');
        pY = get(obj, 'y');
        if pX.isempty && pY.isempty
            V.data.X = 0:V.numcols-1;
            V.data.Y = 0:V.numrows-1;
        else
            V.data.X = [];
            V.data.Y = [];
        end
        
    elseif isa(obj, 'cglookupone')
        V.numcols = 1;
        V.numrows = ud.Hand.EditXSize.Value;
        V.numaxes = 2;
        V.data.Y = ud.Hand.EditValue.Value*ones(V.numrows, 1);
        V.data.X = (0:V.numrows-1)';

    elseif isa(obj, 'cgnormfunction')
        V.numrows = ud.Hand.EditXSize.Value;
        V.numcols = 1;
        V.data.Y = ud.Hand.EditValue.Value*ones(V.numrows, 1);
        V.numaxes = 2;
        % Look to see whether the normaliser is empty - if it is then we'll
        % initialise it too
        pX = get(obj, 'x');
        if pX.isempty
            V.data.X = 0:V.numrows-1;
        else
            V.data.X = [];
        end
 
    elseif isa(obj, 'cgnormaliser')
        V.numcols = 1;
        V.numrows = ud.Hand.EditXSize.Value;
        V.numaxes = 2;
        V.data.X = (0:V.numrows-1)';
        V.data.Y = [];
        % Look to see if the normaliser is only used by a single table; in
        % this case we'll kindly initialise it so the output range matches
        % the size of the table
        FL = get(obj, 'Flist');
        if length(FL)==1 && FL.isa('cglookup')
            if FL.isa('cglookuptwo')
                if FL.get('x')==ud.displayitem
                    szInd = 2;
                else
                    szInd = 1;
                end
            else
                szInd = 1;
            end
            L = size(FL.get('values'), szInd);
            if L>=2
                if V.numrows<=L
                    V.data.Y = round(linspace(0, L-1, V.numrows));
                else
                    % Need to pad out ends with repeated breakpoints
                    V.data.Y = [0:(L-1), repmat(L-1, 1, V.numrows-L)];
                end
            end
        end
        
    elseif isa(obj, 'cgconstant')
        V.data.X = ud.Hand.EditValue.Value;
        V.numaxes = 1;
        V.numrows = 1;
        V.numcols = 1;
    end
    
    status = i_TransferToTable(ud.displayitem, V);
    if status==0
        % update GUI
        i_RefreshIcons;
        i_FillValuePane;
    end
    
end
end


%--------------------------------------
% Apply pasted data/ascii file data to table             
%--------------------------------------
function i_ApplyData(src, evt, source)
%--------------------------------------
fh = i_GetHandle;
ud = get(fh,'UserData');
if strcmp(ud.displaysource, 'project')
    if strcmp(source, 'pastedata')
        if mbcutils.Clipboard.isNumeric()
            data = mbcutils.Clipboard.paste();
        else
            data = [];
        end
        info = 'Initialised from clipboard data';
    elseif strcmp(source, 'asciifile');
        [filename, pathname] = uigetfile({'*.txt;*.csv', 'Ascii data file (*.csv, *.txt)'}, ...
            'Select data file', mbcGetPath('cage', 'Data'));
        if filename==0
            return    
        end
        data = cgcalreadtxt(fullfile(pathname,filename));
        info = 'Initialised from ascii file';
    else
        error(message('mbc:cgcalmanager:InvalidArgument'));
    end
    
    if isempty(data)
        h = errordlg('No data was found for importing.', 'MBC Toolbox', 'modal');
        waitfor(h);
        return
    end
    
    % Set up an appropriate data structure according to the type of object
    % selected and then use subfunction to perform copy
    V = struct('name', source, ...
        'description', '', ...
        'info', info, ...
        'data',[], ...
        'numaxes',[], ...
        'numrows',[], ...
        'numcols',[]);
    
    obj = ud.displayitem.info;
    if isa(obj, 'cglookuptwo')
        V.numaxes = 3;
        if isnan(data(1)) && all(size(data)>=2)
            V.data.X = data(1, 2:end);
            V.data.Y = data(2:end, 1);
            V.data.Z = data(2:end, 2:end);
            [V.numrows V.numcols] = size(V.data.Z);
        else
            V.data.X = [];
            V.data.Y = [];
            V.data.Z = data;
            [V.numrows V.numcols] = size(data);
        end
        
    elseif isa(obj, 'cgnormfunction') || isa(obj, 'cgnormaliser')
        V.numaxes = 2;
        V.numcols = 2;
        if size(data, 2)==1
            V.data.X = [];
            V.data.Y = data(:,1);
        else
            V.data.X = data(:,1);
            V.data.Y = data(:,2);
        end
        V.numrows = length(V.data.Y);
    elseif isa(obj, 'cgconstant')
        V.numaxes = 1;
        V.data.X = data;
        [V.numrows V.numcols] = size(data);
        
    end
    
    [status, msg] = i_TransferToTable(ud.displayitem, V);
    if status==0
        % update GUI
        i_RefreshIcons;
        i_FillValuePane;
        i_FillCalItemPane;
    else
        h = errordlg(['Incorrect data for this calibration item.' msg{1}], 'MBC Toolbox', 'modal');
        waitfor(h);
    end
end
end


%--------------------------------------
% Apply calibration data to an item          
%--------------------------------------
function i_Link(src,evt)
%--------------------------------------
fh = i_GetHandle;
ud = get(fh,'UserData');
try
    FileItem = ud.Hand.ParamContents.getSelectedRows;
    ProjectItem = ud.Hand.BlockList.Selected;
catch E
    return
end
if isempty(FileItem) || isempty(ProjectItem)
    return
end

calIdx = FileItem;
if ProjectItem.isa('cgcontainer')
    ProjectItem = ProjectItem.getdata;
end
[status, msg] = i_TransferToTable(ProjectItem, ud.cal(calIdx));
if status==0
    % update GUI
    i_RefreshIcons;
    i_FillValuePane;
    i_FillCalItemPane;
else
    h = errordlg(['Incorrect data for this calibration item. ' msg{1}], 'MBC Toolbox', 'modal');
    waitfor(h);
end
end



%--------------------------------------
% Apply calibration data for as many
% items as can be matched by name
%--------------------------------------
function i_AutoLink(src,evt)
%--------------------------------------
fh = i_GetHandle;
ud = get(fh,'UserData');

% Generate a list of cal item names
nds = ud.Hand.BlockList.findAllNodes;
projnames = get(nds,{'Name'});

% Loop over the Cal file data, locate blocks with matching names and
% collect the matches up.  They will be processed in one go at the end

ptrProjItems = null(xregpointer,0);
idxCalFileItems = [];

calnames = {ud.cal.name};

for n = 1:length(calnames)
    matchedidx = find(strcmpi(calnames{n},projnames));
    if isscalar(matchedidx)
        % Get Project item node by index
        pItem = nds(matchedidx).Pointer;
        if pItem.isa('cgcontainer')
            pItem = pItem.getdata;
        end
        ptrProjItems = [ptrProjItems, pItem];
        idxCalFileItems = [idxCalFileItems, n];
    end
end

if ~isempty(ptrProjItems)
    status = i_TransferToTable(ptrProjItems, ud.cal(idxCalFileItems));
    if any(status==0)
        % update GUI
        i_RefreshIcons;
        i_FillValuePane;
        i_FillCalItemPane;
    end
    if any(status~=0)
        % Warn user that some matches failed
        h = warndlg(['The new data could not be applied to some of the matched items.', ...
                'These items have not been updated.'], 'MBC Toolbox', 'modal');
        waitfor(h);
    end
else
    % Warn user that there were no matches
    h = warndlg('No matches were found.', 'MBC Toolbox', 'modal');
    waitfor(h);
end
end


%--------------------------
function fh = i_Create
fh = i_GetHandle;
if isempty(fh)
    fh = i_CreateFigure(true); % modal dialog
end
end


%--------------------------
function i_PrepareToShow(fh, pPROJ, varargin)
pStartItem = [];
if nargin>2
    % Process prop/value pairs for other inputs
    for n = 1:2:(length(varargin)-1)
        switch lower(varargin{n})
            case 'selectitem'
                pStartItem = varargin{n+1};
            case 'closecallback'
                i_setCloseCallback(varargin{n+1});
        end
    end    
end

% Always update the cal file pane because new data might be loaded
i_FillCalFilePane;

% Update the display of project contents
i_RefreshTree(pPROJ);

found = false;
if ~isempty(pStartItem)
    % Select a given item
    found = i_SelectTreeNode(pStartItem);
end
if ~found
    % Select the first node
    i_SelectTreeNode;
end
end


%--------------------------
function i_StartNoAction(pPROJ, varargin)
fh = i_Create;
i_PrepareToShow(fh, pPROJ, varargin{:});
fh.showDialog();
i_Finish;
end


%--------------------------
function i_StartChooseFile(pPROJ, varargin)
fh = i_Create;

% Load in new cal data before refreshing the gui
OK = i_ChooseFile;

if OK
    i_PrepareToShow(fh, pPROJ, varargin{:});
    fh.showDialog();
    i_Finish;
end
end


%--------------------------
function i_StartLoadCalData(pPROJ, calobj, caldata, varargin)

fh = i_Create;

% Load in new cal data before refreshing the gui
i_LoadCalData(calobj, caldata);

i_PrepareToShow(fh, pPROJ, varargin{:});
fh.showDialog();
i_Finish;

end