www.gusucode.com > mbcdata 工具箱 matlab 源码程序 > mbcdata/@cgoptim/optimwizard.m

    function [objout, OK] = optimwizard(objin, pPROJ, hParent)
%OPTIMWIZARD Wizard for creating a new optimization object
%
%  [NEWOPT, OK] = OPTIMWIZARD(OPT, pPROJ, [hParent])  where OPT is a
%  cgoptim object, pPROJ is a pointer to a cage project and hParent is an
%  optional handle to a parent figure.
%
%  See also XREGWIZARD.

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

if nargin<3
    hParent = [];
end
[OK, out] = xregwizard(hParent, 'Optimization Wizard', {@i_createCardOne, pPROJ});
if OK
    objout = out.optim;
else
    objout = objin;
end


%------------------------------------------------------------------------
% CARD ONE FUNCTIONS BELOW
%------------------------------------------------------------------------
function [layout, localData] = i_createCardOne( pPROJ, fh, iFace, localData )
% GUI Layout for card one: Select an algorithm

if isa(fh, 'xregcontainer')
    layout = fh;
    layoutUD = get(layout, 'UserData');
else
    % Set the wizard size to be more appropriate
    feval(iFace.setWizardSize, [600 300]);

    builtin = initfrommbc(cgoptimfuncs);
    userfuncs = cgoptimfuncs;

    optimlist = [makeoptim(builtin), makeoptim(userfuncs)];
    optimdata = struct( 'list', {optimlist}, 'index', -1 );
    layoutUD.optimdata = xregGui.RunTimePointer( optimdata );
    layoutUD.optimdata.LinkToObject(fh);

    listtitle = uicontrol('Parent', fh, ...
        'Visible', 'off', ...
        'Style', 'text', ...
        'String', 'Available optimization algorithms:', ...
        'Enable', 'inactive', ...
        'HorizontalAlignment', 'left');
    % Draw the ListView control
    
    listbox = mbcwidgets.List( 'Parent', fh,...
        'Editable', false, ...
        'Visible','off',...
        'Grid',false,...
        'SelectionChangedCallback',{@cbkSelectInput,iFace},...
        'SelectionMode', 'SingleRow');
    
    listbox.Peer.setColumnData({'Name','Free Variables','Objectives','Constraints','Operating Point Sets'});
    listbox.Peer.setColumnWidths([120 85 80 80 115]);

    Data = cell(length(optimlist),5);
    for n = 1:length(optimlist)
        opts = getSetup(optimlist{n});
        Data{n,1}= getName(opts);
        desc = getModeDescriptions(opts);
        Data(n,2:end) = desc;
    end
    listbox.Peer.setData(Data);
    listbox.selectRows(1);
    
    layoutUD.listbox = listbox;
    layoutUD.nextFcn = @i_cardOneNext;
    layoutUD.cancelFcn = @i_cardCancel;

    layout = xreggridbaglayout(fh, ...
        'packstatus', 'off', ...
        'dimension', [2 1], ...
        'rowsizes', [15 -1], ...
        'gapy', 5, ...
        'elements', {listtitle, listbox}, ...
        'border', [7 0 7 10]);
    infostr = 'Select from the list the algorithm that you want the new optimization to use.';
    layout = i_maketitlearea(fh, 'Algorithm Selection', infostr, layout);

    globalUD.Project = pPROJ;
    feval( iFace.setUserData,  globalUD );
end

feval( iFace.setFinishButton, 'off' );
feval( iFace.setNextButton,   'on' );
set( layout, 'UserData', layoutUD );


%------------------------------------------------------------------------
function [nextCardID, localData] = i_cardOneNext( layoutUD, iFace )

optimdata = layoutUD.optimdata;

% Get the selected item from the listview
index = layoutUD.listbox.getSelectedRows;

% set the index of the chosen optimization object in the user data for Card One
optimdata.info.index = index;
feval( iFace.setCardUserdata, layoutUD );

% Set the localData
localData = optimdata;

% Check to see if we need to go to card two
obj = optimdata.info.list{index};
opts = getSetup(obj);

if canAddVariable(opts) || canRemoveVariable(opts) ...
        || canAddObjective(opts) || canRemoveObjective(opts) ...
        || canAddConstraint(opts) || canRemoveConstraint(opts) ...
        || canAddOperatingPointSet(opts) || canRemoveOperatingPointSet(opts)
    nextCardID = @i_createCardTwo;
else
    % we can skip card two
    nextCardID = @i_createCardThree;
end



%------------------------------------------------------------------------
% CARD TWO FUNCTIONS BELOW
%------------------------------------------------------------------------
function layout = i_createCardTwo( fh, iFace, localData )
% GUI Layout for card two: Number of free variables, objectives, constraints
% and OpPoint sets

% Have we been called to create the layout or simply update?
if isa( fh, 'xregcontainer' )
    layout = fh;
    layoutUD = get( layout, 'UserData' );

else
    optseditor = cgoptimgui.optionsEditor('Parent', fh, ...
        'Visible', 'off');
    layout = xreggridbaglayout(fh,...
        'dimension', [3 1],...
        'rowsizes',[-1 110 -1],...
        'rowratios', [1 0 2], ...
        'border', [30 0 0 0],....
        'elements', {[], optseditor});
    infostr = ['Algorithms may be able to use a variable number of items.', ...
        '  Select the number of each item that you want to use in this optimization.'];
    layout = i_maketitlearea(fh, 'Algorithm Options', infostr, layout);

    layoutUD.optseditor = optseditor;
    layoutUD.nextFcn = @i_cardTwoNext;
    layoutUD.cancelFcn = @i_cardCancel;
end

if nargin > 2,
    layoutUD.optimdata = localData;
end

layoutUD = i_cardTwoUpdate( layoutUD, iFace );
set( layout, 'UserData', layoutUD );

%------------------------------------------------------------------------
function layoutUD = i_cardTwoUpdate( layoutUD, iFace )
% Fills card two with information

% Get the chosen optimization object
obj = layoutUD.optimdata.info.list{layoutUD.optimdata.info.index};
layoutUD.optseditor.OptionsObject = getSetup(obj);

% Always have to go to card three
feval( iFace.setFinishButton, 'Off' );
feval( iFace.setNextButton,   'On');

%------------------------------------------------------------------------
function [nextCardID, localData] = i_cardTwoNext( layoutUD, ~ )

obj = layoutUD.optimdata.info.list{layoutUD.optimdata.info.index};
obj = setSetup(obj, layoutUD.optseditor.OptionsObject);
layoutUD.optimdata.info.list{layoutUD.optimdata.info.index} = obj;

% set up the local data
localData = layoutUD.optimdata;

% Card three should always be visited
nextCardID = @i_createCardThree;



%------------------------------------------------------------------------
% CARD THREE FUNCTIONS BELOW
%------------------------------------------------------------------------
function layout = i_createCardThree(fh, iFace, localData)
% GUI Layout for card three: Assign Variables

% Have we been called to create the layout or simply update?
if isa(fh, 'xregcontainer')
    layout = fh;
    layoutUD = get(layout, 'UserData');
else
    % Draw the ListView control
    
    layoutUD.List = mbcwidgets.List('Parent', fh,...
        'Editable', false, ...
        'Visible','off',...
        'Grid',false,...
        'SelectionChangedCallback',{@i_VarListCbk, iFace},...
        'SelectionMode', 'SingleRow');
    
    layoutUD.List.Peer.setColumnData({'Label','CAGE Variable'});
    layoutUD.List.Peer.setColumnWidths([140 100]);
    
    
    % Make a title for this ListView
    t = uicontrol('Parent',fh,...
        'Style','text',...
        'Visible','off',...
        'HorizontalAlignment','left',...
        'String','Optimization inputs:');
    t2 = uicontrol('Parent',fh,...
        'Style','text',...
        'Visible','off',...
        'HorizontalAlignment','left',...
        'String','CAGE variables:');
    layoutUD.selbutton = xregGui.iconuicontrol('parent',fh,...
        'imageFile', xregrespath('leftarrow.bmp'),...
        'transparentColor', [255 255 0],...
        'ToolTip','Select CAGE Variable',...
        'visible','off',...
        'callback',{@i_select,iFace});
    layoutUD.namelist = cgtools.exprList('Parent', fh, ...
        'visible', 'off', ...
        'DisplayTypeColumn', false, ...
        'DisplayHeaderRow', false);

    layout = xreggridbaglayout(fh, ...
        'dimension', [5 3], ...
        'gapx', 10, ...
        'border', [7 0 7 10], ...
        'rowsizes', [15 2 -1 80 -1], ...
        'colsizes', [-1 80 -1], ...
        'colratios', [2 0 1], ...
        'mergeblock', {[3 5], [1 1]}, ...
        'mergeblock', {[3 5], [3 3]}, ...
        'elements', {t, [], layoutUD.List, [],[], ...
        [],[],[], layoutUD.selbutton, [], ...
        t2, [], layoutUD.namelist, [], []});
    infostr = ['Match each required variable in the optimization to a ' ...
        'variable from the Variable Dictionary.'];
    layout = i_maketitlearea(fh, 'Required Variables', infostr, layout);
    layoutUD.cancelFcn = @i_cardCancel;
end

if nargin > 2
    layoutUD.optimdata = localData;
end

layoutUD = i_cardThreeUpdate(layoutUD, iFace);
set(layout, 'UserData', layoutUD);

%------------------------------------------------------------------------
function layoutUD = i_cardThreeUpdate(layoutUD, iFace)
% fills the card with information
optim = layoutUD.optimdata.info.list{layoutUD.optimdata.info.index};
opts = getSetup(optim);

% List of available variables
globalUD = feval(iFace.getUserData);
pDD = globalUD.Project.getdd;
cgvarptrs = pDD.listptrs('variable');
layoutUD.namelist.Items = cgvarptrs;


% List of optimization variable labels to match

% Free variables and dataset required variables
strVal = [getFreeVariables(opts), getOperatingPointSetVarLabels(opts)];
pVal = get(optim, 'oppointvalues');
pVal = [get(optim, 'values'), pVal{:}];
Data= cell(length(strVal),2);
for n = 1:length(strVal)
    Data{n,1}=strVal{n};
    if ~isnull(pVal(n))
        % variable already matched
       Data{n,2}= pVal(n).getname;
    end
end
layoutUD.List.Peer.setData(Data);
layoutUD.List.selectRows(1);

i_VarListCbk([], [], iFace, layoutUD);

layoutUD.nextFcn   = @i_cardThreeNext;
layoutUD.finishFcn = @i_cardSixFinish;

% --------------------------------------------------
function i_VarListCbk(~, ~, iFace, layoutUD)

if nargin<4
    layoutUD = feval(iFace.getCardUserdata);
end

optim = layoutUD.optimdata.info.list{layoutUD.optimdata.info.index};
selected = layoutUD.List.getSelectedRows;

if ~isempty(selected)
    TableData = layoutUD.List.getData;
    selected = TableData{selected,1};
    
    pVar = getItem(optim, selected, {'variable', 'operatingpointsetvariable'});
    set(layoutUD.namelist,  'SelectedItems', pVar);

    if isempty(layoutUD.namelist.Items)
        % disable the select button when there are no variables to select
        set(layoutUD.selbutton,'Enable', 'off');
    else
        set(layoutUD.selbutton,'Enable', 'on');
    end
else
    set(layoutUD.selbutton,'Enable', 'off');
end
i_CardThreeEnableNextFinish( layoutUD, iFace )


%------------------------------------------------------------------------
function i_CardThreeEnableNextFinish( layoutUD, iFace )
% Enable/disable the 'Next' and 'Finish' buttons for card three
optim = layoutUD.optimdata.info.list{layoutUD.optimdata.info.index};
opts = getSetup(optim);

pVal = get(optim, 'oppointvalues');
pVal = [get(optim, 'values'), pVal{:}];
canLeaveCard = ~any(isnull(pVal));
hasNextCard = numObjectives(opts)>0 ...
    || numConstraints(opts)>0 ...
    || numOperatingPointSets(opts)>0;
if canLeaveCard
    feval(iFace.setFinishButton, 'on');
    if hasNextCard
        feval(iFace.setNextButton, 'on');
    else
        feval(iFace.setNextButton, 'off');
    end
else
    feval(iFace.setFinishButton, 'off');
    feval(iFace.setNextButton, 'off');
end


%------------------------------------------------------------------------
function i_select(~, ~, iFace)
layoutUD = feval(iFace.getCardUserdata);

% get handles
TargetItem = layoutUD.List.getSelectedRows;
pSelVal = layoutUD.namelist.SelectedItems;

if isempty(pSelVal)
    return
end
layoutUD.List.Peer.setDataAt(pSelVal.getname,TargetItem-1,1)

optim = layoutUD.optimdata.info.list{layoutUD.optimdata.info.index};

TargetList =  layoutUD.List.getData;
Target = TargetList{TargetItem,1};
optim = setItem(optim, Target, pSelVal, {'variable', 'operatingpointsetvariable'});
layoutUD.optimdata.info.list{layoutUD.optimdata.info.index} = optim;

% Get the current label items selection and increment to the next one
N = layoutUD.List.getRowCount;
newInd = mod(TargetItem,double(N))+1;
layoutUD.List.selectRows(newInd);


i_VarListCbk([], [], iFace, layoutUD);

feval(iFace.setCardUserdata, layoutUD);

%------------------------------------------------------------------------
function [nextCardID, localData] = i_cardThreeNext(layoutUD, ~)
% set up the local data
localData = layoutUD.optimdata;

% Which card is next?
optim = layoutUD.optimdata.info.list{layoutUD.optimdata.info.index};
opts = getSetup(optim);

if numObjectives(opts)>0
    % number of obj funs >= 1 ==> must vist card four
    nextCardID = @i_createCardFour;
elseif numConstraints(opts)>0
    % number of constraint >= 1 ==> must vist card five
    nextCardID = @i_createCardFive;
elseif numOperatingPointSets(opts)>0
    % number of oppoint sets >= 1 ==> must vist card six
    nextCardID = @i_createCardSix;
else
    % We really shouldn't end up here. If we are here it is because the 'Next'
    % button hasn't been disabled. To exit smoothly, we'll just goto card six.
    warning(message('mbc:cgoptim:InvalidState13'));
    nextCardID = @i_createCardSix;
end



%------------------------------------------------------------------------
% CARD FOUR FUNCTIONS BELOW
%------------------------------------------------------------------------
function layout = i_createCardFour(fh, iFace, localData)
% GUI Layout for card four: Assign objectives

% Have we been called to create the layout or simply update?
if isa(fh, 'xregcontainer')
    layout = fh;
    layoutUD = get(layout, 'UserData');

else
    % Draw the ListView control
    
    layoutUD.List = mbcwidgets.List('Parent', fh,...
        'Editable', false, ...
        'Grid',false,...
        'Visible','off',...
        'SelectionChangedCallback',{@i_ObjListCbk, iFace},...
        'SelectionMode', 'SingleRow');
    
    layoutUD.List.Peer.setColumnData({'Optimization Model','CAGE Model', 'Type'});
    layoutUD.List.Peer.setColumnWidths([120 90 110]);
    
    % Make a title for this ListView
    t= uicontrol('Parent',fh,...
        'Style','text',...
        'Visible','off',...
        'HorizontalAlignment','left',...
        'String','Optimization objectives:');
    layoutUD.selbutton= xregGui.iconuicontrol('parent',fh,...
        'imageFile',xregrespath('\leftarrow.bmp'),...
        'transparentColor', [255 255 0],...
        'ToolTip','Select CAGE Model',...
        'visible','off',...
        'callback',{@i_selectObj,iFace});
    t2= uicontrol('Parent',fh,...
        'Style','text',...
        'Visible','off',...
        'HorizontalAlignment','left',...
        'String','CAGE models:');
    layoutUD.namelist = cgtools.exprList('Parent', fh, ...
        'visible', 'off', ...
        'DisplayTypeColumn', false, ...
        'DisplayHeaderRow', false);
    layoutUD.radiobutton= xregGui.rbgroup('parent',fh,...
        'nx', 3, 'ny', 1, ...
        'visible','off',...
        'string',{'Minimize', 'Maximize', 'Helper'},...
        'callback',{@i_radio,iFace});

    rbs = xregGui.labelcontrol('parent', fh, ...
        'Control', layoutUD.radiobutton, ...
        'string', 'Objective type:', ...
        'visible', 'off', ...
        'graydisable', 'off', ...
        'labelsizemode', 'absolute', ...
        'labelsize', 80, ...
        'controlsizemode', 'relative', ...
        'controlsize', 1,...
        'BaselineOffsetMode', 'manual');
    layout = xreggridbaglayout(fh, ...
        'dimension', [7 3], ...
        'gapx', 10, ...
        'border', [7 0 7 10], ...
        'rowsizes', [15 2 -1 80 -1 5 20], ...
        'colsizes', [-1 80 -1], ...
        'colratios', [2 0 1], ...
        'mergeblock', {[3 5], [1 1]}, ...
        'mergeblock', {[3 5], [3 3]}, ...
        'elements', {t, [], layoutUD.List, [], [], [], rbs, ...
        [], [], [], layoutUD.selbutton, [], [], [], ...
        t2, [], layoutUD.namelist});
    infostr = ['Objectives are quantities that the algorithm will attempt to optimize.', ...
        '  Select CAGE models to be used for each objective, and whether it', ...
        ' should be minimized, maximized or used as a helper model for the algorithm.'];
    layout = i_maketitlearea(fh, 'Objectives', infostr, layout);
end

if nargin > 2,
    layoutUD.optimdata = localData;
end

layoutUD = i_cardFourUpdate(layoutUD, iFace);
set(layout, 'UserData', layoutUD);

%------------------------------------------------------------------------
function layoutUD = i_cardFourUpdate(layoutUD, iFace)
% fills the card with information

optim = layoutUD.optimdata.info.list{layoutUD.optimdata.info.index};


% Fill the left-hand list box
OFLabels= get(optim, 'ObjectiveFuncLabels');
OFs = getObjectiveFunc(optim);

Data = cell(length(OFLabels),3);

for i = 1: length(OFLabels)
    Data{i,1} = OFLabels{i};

    if isa(OFs{i}, 'cgpointobjective') || isa(OFs{i}, 'cgsumobjective')
        modptr = getExpression(OFs{i});
        if ~isempty(modptr) && isvalid(modptr)
            Data{i,2} = modptr.getname;
        end
    end

    % Handle case where user has added an objective function. These
    % functions will not be given a type by default.
    Data{i,3} = getObjectiveType(OFs{i});
end
layoutUD.List.Peer.setData(Data);
layoutUD.List.selectRows(1);

% Select the first item
i_ObjListCbk([], [], iFace, layoutUD);

layoutUD.finishFcn = @i_cardSixFinish;
layoutUD.nextFcn = @i_cardFourNext;

% Can always exit from this card. The user can do the wiring in the optim
% node
feval(iFace.setFinishButton, 'on');

nextOK = i_checkPtrsObjs(layoutUD);
if nextOK
    feval(iFace.setNextButton, 'on');
else
    feval(iFace.setNextButton, 'off');
end


% --------------------------------------------------
function i_SetObjectiveRBState(hRB, OF)
if ~isempty(OF)
    minstr = getObjectiveType(OF);
    radiosel = find( strncmp( minstr,{ 'Minimize', 'Maximize', 'Helper' },length(minstr) ) );
    if isempty(radiosel)
        radiosel = 1;
    end

    if ~canChangeType(OF);
        % enable just the chosen radio button
        enableArray = false(1, 3);
        enableArray(radiosel) = true;
    else
        % enable min/max
        enableArray = [true true false];
    end
    set(hRB, ...
        'selected', radiosel, ...
        'enableArray', enableArray);
else
    % No item: disable the radio buttons
    set( layoutUD.radiobutton, 'EnableArray', false( 1, 3 ) );
end


% --------------------------------------------------
function modelptrs = i_FilterCAGEmodels(optim, objtype, pPROJ)

modelptrs = pPROJ.getmodels;
if any(strcmpi(objtype, {'Maximize', 'Minimize'}))
    % Only show models that have a free variable feeding into them
    pFree = get(optim, 'values');
    pInpForAll = pveceval(modelptrs, @getinports);
    KeepIdx = false(size(modelptrs));
    for n = 1:length(modelptrs)
        KeepIdx(n) = anymember(pFree, pInpForAll{n});
    end
    modelptrs = modelptrs(KeepIdx);
end


% --------------------------------------------------
function i_ObjListCbk(~, ~, iFace, layoutUD)

if nargin<4
    layoutUD = feval(iFace.getCardUserdata);
end

optim = layoutUD.optimdata.info.list{layoutUD.optimdata.info.index};
OFs = getObjectiveFunc(optim);
selected = layoutUD.List.getSelectedRows;
if ~isempty(selected)
    ThisOF = OFs{selected};

    % Update radio buttons
    i_SetObjectiveRBState(layoutUD.radiobutton, ThisOF);

    % Refresh the right hand list, as models you can match depend on
    % whether the objective is min/max or helper
    globalUD = feval(iFace.getUserData);
    if isa(ThisOF, 'cgpointobjective') || isa(ThisOF, 'cgsumobjective')
        modelptrs = i_FilterCAGEmodels(optim, getObjectiveType(ThisOF), globalUD.Project);
        selmodel = getExpression(ThisOF);
    else
        modelptrs = mbcpointer(1,0);
        selmodel = mbcpointer;
    end
    set(layoutUD.namelist, 'Items', modelptrs, 'SelectedItems', selmodel);

    if isempty(modelptrs)
        % disable the select button when there are no models or objectives
        set(layoutUD.selbutton,'Enable', 'off');
    else
        set(layoutUD.selbutton,'Enable', 'on');
    end
else
    i_SetObjectiveRBState(layoutUD.radiobutton, []);
    set(layoutUD.namelist, 'Items', []);
    set(layoutUD.selbutton,'Enable', 'off');
end


% --------------------------------------------------
function i_selectObj(~, ~, iFace)
% objective function selection

layoutUD = feval(iFace.getCardUserdata);
optim = layoutUD.optimdata.info.list{layoutUD.optimdata.info.index};

% get handles
target = layoutUD.List.getSelectedRows;
curlst = layoutUD.namelist;

% Model to use
pNewModel = curlst.SelectedItems;
if isempty(pNewModel) && ~isempty(curlst.Items)
    % Try to take first item in the list
    pNewModel = curlst.Items(1);    
end

% Objective to change
ObjLabel = layoutUD.List.getDataAt(target-1,0);

if ~isempty(pNewModel)
    OF = getItem(optim,target,'objective');
    if isa(OF, 'cgpointobjective') || isa(OF, 'cgsumobjective')
        OF = setExpression(OF, pNewModel);
        optim = setObjectiveFunc(optim, ObjLabel, OF);

        layoutUD.optimdata.info.list{layoutUD.optimdata.info.index} = optim;

        % Update the left list
        layoutUD.List.Peer.setDataAt(pNewModel.getname,target-1,1);
    end
end

% Update
i_ObjListCbk(layoutUD.List, [], iFace);


% --------------------------------------------------
function i_radio(radio, ~,iFace)
layoutUD = feval(iFace.getCardUserdata);
optim = layoutUD.optimdata.info.list{layoutUD.optimdata.info.index};

% get handles
selected = layoutUD.List.getSelectedRows;
radiosel = get(radio, 'Selected');
switch radiosel
    case 1
        minstr = 'min';
    case 2
        minstr = 'max';
    case 3
        minstr = 'helper';
end

OF = getItem(optim,selected,'objective');
OF = setObjectiveType(OF, minstr);
OFLabels= get(optim, 'ObjectiveFuncLabels');
optim = setObjectiveFunc(optim, OFLabels{selected}, OF);
layoutUD.optimdata.info.list{layoutUD.optimdata.info.index} = optim;
feval(iFace.setCardUserdata, layoutUD);

layoutUD.List.Peer.setDataAt(getObjectiveType(OF),selected-1,2);



%------------------------------------------------------------------------
function nextOK = i_checkPtrsObjs(layoutUD)
% Check to see if there are any cons or oppts. If not, cannot go any
% further
nextOK = 1;
optim = layoutUD.optimdata.info.list{layoutUD.optimdata.info.index};
hasModelConstraints = i_optimHasModelConstraints(optim);
if ~hasModelConstraints && isempty( get( optim, 'oppoints' ) )
    nextOK = 0;
end


%------------------------------------------------------------------------
function [nextCardID, localData] = i_cardFourNext(layoutUD, ~)

% set up the local data
localData = layoutUD.optimdata;

% Which card is next?
obj = layoutUD.optimdata.info.list{layoutUD.optimdata.info.index};

% Determine whether the constraints are model constraints (and so can be
% edited in the wizard) or not
hasModelConstraints = i_optimHasModelConstraints(obj);

if hasModelConstraints
    % number of model constraints >= 1 ==> must vist card five
    nextCardID = @i_createCardFive;

elseif ~isempty( get( obj, 'oppoints' ) )
    % number of oppoint sets >= 1 ==> must vist card six
    nextCardID = @i_createCardSix;

else
    % We really shouldn't end up here. If we are here it is because the 'Next'
    % button hasn't been disabled. To exit smoothly, we'll just goto card six.
    warning(message('mbc:cgoptim:InvalidState14'));
    nextCardID = @i_createCardSix;
end

%------------------------------------------------------------------------
function hasModelConstraints = i_optimHasModelConstraints(optim)

cons = getConstraint(optim);
isModelCon = mbccellarrayeval(cons, @i_isModelCon, {}, mbclogical);
hasModelConstraints = ~isempty( isModelCon ) && any( isModelCon );


%------------------------------------------------------------------------
% CARD FIVE FUNCTIONS BELOW
%------------------------------------------------------------------------
function layout = i_createCardFive(fh, iFace, localData)
% GUI Layout for card five: assign constraints

% Constraint card
% Have we been called to create the layout or simply update?
if isa(fh, 'xregcontainer')
    layout = fh;
    layoutUD = get(layout, 'UserData');
else
    SC = xregGui.SystemColorsDbl;
    
    layoutUD.List = mbcwidgets.List( 'Parent', fh,...
        'Editable', false, ...
        'Grid',false,...
        'Visible','off',...
        'SelectionChangedCallback',{@i_ConListCbk, iFace},...
        'SelectionMode', 'SingleRow');
    
    layoutUD.List.Peer.setColumnData({'Model Constraint','CAGE Model', 'Bound'});
    layoutUD.List.Peer.setColumnWidths([100 100 80]);
    
    % Make a title for this ListView
    t= uicontrol('Parent',fh,...
        'Style','text',...
        'Visible','off',...
        'HorizontalAlignment','left',...
        'String','Optimization constraints:');
    t3 = uicontrol('Parent',fh,...
        'Style','text',...
        'Visible','off',...
        'HorizontalAlignment','left',...
        'String','Constraint:');
    layoutUD.boundtext = uicontrol('Parent',fh,...
        'Style','text',...
        'Visible','off',...
        'HorizontalAlignment','right',...
        'String','');
    layoutUD.boundctrl = mbcgui.widget.Spinner( 'Parent', fh, ...
        'Value', 0, ...
        'Visible', 'Off', ...
        'Max', realmax, ...
        'Callback', { @i_ConstraintBound, iFace } );
    layoutUD.boundtype = uicontrol('Parent',fh,...
        'Visible', 'Off', ...
        'Style', 'Popupmenu', ...
        'String', {'<=', '>='} ,...
        'BackgroundColor', SC.WINDOW_BG, ...
        'Value', 1, ...
        'Callback', { @i_ConstraintBoundType, iFace } );
    layoutUD.selbutton = xregGui.iconuicontrol('parent',fh,...
        'imageFile',xregrespath('leftarrow.bmp'),...
        'transparentColor', [255 255 0],...
        'ToolTip','Select CAGE Model',...
        'visible','off',...
        'callback',{@i_selectCon,iFace});
    t2 = uicontrol('Parent',fh,...
        'Style','text',...
        'Visible','off',...
        'HorizontalAlignment','left',...
        'String','CAGE models:');
    layoutUD.namelist = cgtools.exprList('Parent', fh, ...
        'visible', 'off', ...
        'DisplayTypeColumn', false, ...
        'DisplayHeaderRow', false);

    layoutUD.conlyt = xreggridbaglayout(fh, ...
        'dimension', [4 3], ...
        'rowsizes', [1 3 15 2], ...
        'colsizes', [87 40 80], ...
        'gapx', 7, ...
        'mergeblock', {[1 4], [2 2]}, ...
        'mergeblock', {[2 4], [3 3]}, ...
        'elements', {...
        [],[],layoutUD.boundtext, [],...
        layoutUD.boundtype, [],[],[],...
        [],layoutUD.boundctrl});
  
    layoutUD.constradio= uicontrol('Parent',fh,...
        'Style', 'radio', ...
        'Visible','off',...
        'Value', 1, ...
        'String', '',...
        'Callback',{@i_conradioConstant, iFace});
    layoutUD.boundradio= uicontrol('Parent',fh,...
        'Style', 'radio', ...
        'Visible','off',...
        'Value', 0, ...
        'String', 'Boundary of model',...
        'Callback',{@i_conradioBoundary, iFace}); 
    
    conradlyt = xreggridbaglayout(fh, ...
        'dimension', [4 3], ...
        'rowsizes', [15 21 3 20], ...
        'colsizes', [10 15 -1], ...
        'gapx', 7, ...
        'mergeblock', {[1 1], [1 3]}, ...
        'mergeblock', {[4 4], [2 3]}, ...
        'elements', {t3,                   [], [],                  [], ...
                     [],  layoutUD.constradio, [], layoutUD.boundradio, ...
                     [],      layoutUD.conlyt, [],                  [], ...
                     });
    
    layout = xreggridbaglayout(fh, ...
        'dimension', [7, 3], ...
        'rowsizes', [15 2 -1 80 -1 5 70], ...
        'colsizes', [-1 80 -1], ...
        'colratios', [2 0 1], ...
        'gapx', 10, ...
        'border', [7 0 7 10], ...
        'mergeblock', {[3 5], [1 1]}, ...
        'mergeblock', {[3 5], [3 3]}, ...
        'elements', {t, [], layoutUD.List, [], [], [], conradlyt, ...
        [],[],[], layoutUD.selbutton, [],[],[], ...
        t2, [], layoutUD.namelist});
    infostr = ['Model Constraints define regions that the free variables can vary within.', ...
        ' Select CAGE models to use for each constraint. ', ...
        'Select whether to constrain the model by a fixed value or by ', ...
        'the model''s boundary constraint.'];
    layout = i_maketitlearea(fh, 'Model Constraints', infostr, layout);
    layoutUD.CurrentRow = 1;
    layoutUD.cancelFcn = @i_cardCancel;
end

if nargin > 2,
    layoutUD.optimdata = localData;
end

layoutUD = i_cardFiveUpdate(layoutUD, iFace);
set(layout, 'UserData', layoutUD);


%------------------------------------------------------------------------
function layoutUD = i_cardFiveUpdate( layoutUD, iFace )
% fills the card with information

% Get the optimization object we are setting up
optim = layoutUD.optimdata.info.list{layoutUD.optimdata.info.index};

% Fill left-hand list box and decide which items can be edited here.  The
% wizard only allows editing of model constraints that have a numeric
% bound.  Finding these constraint types is a bit messy, but necessary
conLabels = get( optim, 'ConstraintLabels' );
conItems = getConstraint(optim);

Data = cell(length( conLabels ),3);
IsModCon = false(1,length( conLabels ) );
for n = 1:length( conLabels )
    if i_isModelCon(conItems{n})
        IsModCon(n) = true;
        pConExpr = getConstraintExpression(conItems{n});
        Data{n,1} = conLabels{n};

        conExpr = pConExpr.info;
        pLHS = getlhsexpr(conExpr);
        if isvalid(pLHS)
            Data{n,2} = pLHS.getname;
        end
        if strcmp(getevaluationmode(conExpr), 'constraint')
            Data{n,3} = 'Boundary';
        else
            Data{n,3} = ...
                sprintf('%s %g', getcomparisonoperator(conExpr), getrhsvalue(conExpr));
        end
    end
end
if any(IsModCon)
    layoutUD.List.Peer.setData(Data(IsModCon,:));
    layoutUD.List.selectRows(1);
end

% Get candidate constraint models from the cage browser and put them in the
% right-hand list
globalUD = feval(iFace.getUserData);
modelptrs = globalUD.Project.getmodels;
layoutUD.namelist.Items = modelptrs ;

% Select the current item properly
i_ConListCbk(layoutUD.List, [], iFace, layoutUD);

layoutUD.finishFcn  = @i_cardSixFinish;
layoutUD.nextFcn    = @i_cardFiveNext;

feval(iFace.setFinishButton, 'on');
nextOK = i_checkPtrsCons( layoutUD );
if nextOK
    feval(iFace.setNextButton, 'on');
else
    feval(iFace.setNextButton, 'off');
end


%------------------------------------------------------------------------
function ret = i_isModelCon(obj)
%Check whether we can edit this constraint type
ret = isa(obj, 'cgpointconstraint');
if ret
    pConExpr = getConstraintExpression(obj);
    ConExpr = pConExpr.info;
    ret = isa(ConExpr, 'cgexprconstraint');
    if ret
        ret = strcmp(getvaluemode(ConExpr), 'value');
    end
end


%------------------------------------------------------------------------
function i_UpdateBoundControls(layoutUD, CF)
% Update the bound value and type controls based on the object CF

if isempty( CF )
    % Disable constraint bound value and type controls
    set( layoutUD.boundctrl, 'Enable', 'off' );
    set( layoutUD.boundtype, 'Enable', 'off' );
    set( layoutUD.boundtext, 'String', '' );
    set( layoutUD.boundradio, 'Enable', 'off' );
    set( layoutUD.constradio, 'Enable', 'off' );   
else
    % Get constraint expression
    ConExpr = info(getConstraintExpression(CF));
    pModExpr = getlhsexpr(ConExpr);
    
    % Enable radio buttons. Disable the boundary constraint radio button if
    % the current model does not have any.
    set(layoutUD.constradio, 'Enable', 'on');
    if ~isempty(pModExpr) && isvalid(pModExpr) && concheck(pModExpr.info)
        set(layoutUD.boundradio, 'Enable', 'on');
    else
        set(layoutUD.boundradio, 'Enable', 'off');       
    end
    
    % Assign values to constraint bound value and type controls
    if strcmp(getevaluationmode(ConExpr), 'eval')
        compstr = getcomparisonoperator(ConExpr);
        compmode = find( strcmp( compstr,{ '<=', '>=' } ) );
        set(layoutUD.boundctrl, ...
            'Value', getrhsvalue(ConExpr), ...
            'Enable', 'on');
        set(layoutUD.boundtype, ...
            'Value', compmode, ...
            'Enable', 'on');
        set(layoutUD.boundradio, 'Value', 0);
        set(layoutUD.constradio, 'Value', 1);
    else
        % Boundary constraint. Ensure bound value and type controls are
        % disabled.
        set(layoutUD.boundctrl, 'Enable', 'off');
        set(layoutUD.boundtype, 'Enable', 'off');
        set(layoutUD.boundradio, 'Value', 1);
        set(layoutUD.constradio, 'Value', 0);
    end
    % Set string of model name label
    if isvalid(pModExpr)
        set( layoutUD.boundtext, 'String', pModExpr.getname);
    else
        set( layoutUD.boundtext, 'String', '<no selection>' );
    end
end

%------------------------------------------------------------------------
function i_UpdateModelList(iFace, layoutUD, CF)
% Update the list of possible models that can be used and update the
% selection

% Get all models in project
globalUD = feval(iFace.getUserData);
modelptrs = globalUD.Project.getmodels;

% Get constraint expression
pConExpr = getConstraintExpression(CF);

if strcmp(pConExpr.getevaluationmode, 'constraint')
    % Can only use models with a boundary constraint
    hasBoundary = pveceval(modelptrs, @concheck);
    hasBoundary = [hasBoundary{:}];
    layoutUD.namelist.Items = modelptrs(hasBoundary);
else
    % All project models can be used for bound constraints
    layoutUD.namelist.Items = modelptrs;
end

% Update selection
selmodel = pConExpr.getlhsexpr;
set(layoutUD.namelist, 'SelectedItems', selmodel);

%------------------------------------------------------------------------
function i_ConListCbk(hList, evt, iFace, layoutUD)

if nargin<4
    layoutUD = feval(iFace.getCardUserdata);
end

optim = layoutUD.optimdata.info.list{layoutUD.optimdata.info.index};
if ~isempty(evt)
    selected = evt.data.SelectedRows;
else
    selected = hList.getSelectedRows;
end

if strcmp(get(layoutUD.boundctrl,'Visible'),'on')
    % might need to update the bound control
    i_ConstraintBound( layoutUD.boundctrl, [], iFace )
end
if ~isequal(layoutUD.CurrentRow,selected)
    layoutUD.CurrentRow = selected;
    feval(iFace.setCardUserdata,layoutUD);
end
if ~isempty(selected) 

    ConLabel = hList.getDataAt(selected-1,0);

    CF = getConstraint(optim, ConLabel);

    % Update selection in model list
    i_UpdateModelList(iFace, layoutUD, CF);

    % Disable the select button when there are no models or constraints
    if isempty(layoutUD.namelist.Items)
        set(layoutUD.selbutton,'Enable', 'off');
    else
        set(layoutUD.selbutton,'Enable', 'on');
    end 

    % Update bound controls
    i_UpdateBoundControls(layoutUD, CF);
    
else
    i_UpdateBoundControls(layoutUD, []);
    set(layoutUD.selbutton,'Enable', 'off');
    set(layoutUD.namelist, 'SelectedItems', []);
end

%------------------------------------------------------------------------
function i_ConstraintBound( src, ~, iFace )
layoutUD = feval( iFace.getCardUserdata );
optim = layoutUD.optimdata.info.list{layoutUD.optimdata.info.index};
selected = layoutUD.CurrentRow;
if ~isempty(selected)
    value = get( src, 'Value' );
    ConLabel = layoutUD.List.getDataAt(selected-1,0);
    CF = getConstraint(optim, ConLabel);
    pConExpr = getConstraintExpression(CF);
    pConExpr.info = pConExpr.setrhsvalue(value);
    
    % Update UI
    boundtext = sprintf('%s %g', pConExpr.getcomparisonoperator, value);
    layoutUD.List.Peer.setDataAt(boundtext,selected-1,2);
end
%------------------------------------------------------------------------
function i_ConstraintBoundType( src, ~, iFace )
layoutUD = feval( iFace.getCardUserdata );
optim = layoutUD.optimdata.info.list{layoutUD.optimdata.info.index};
selected = layoutUD.List.getSelectedRows;
value = get( src, 'Value' );
ConLabel = layoutUD.List.getDataAt(selected-1,0);
CF = getConstraint(optim, ConLabel);
pConExpr = getConstraintExpression(CF);
if value==1
    pConExpr.info = pConExpr.setoperator('le');
else
    pConExpr.info = pConExpr.setoperator('ge');
end

% Update UI
boundtext = sprintf('%s %g', pConExpr.getcomparisonoperator, pConExpr.getrhsvalue);
layoutUD.List.Peer.setDataAt(boundtext,selected-1,2);


%------------------------------------------------------------------------
function i_selectCon(~, ~,iFace)
layoutUD = feval(iFace.getCardUserdata);
optim = layoutUD.optimdata.info.list{layoutUD.optimdata.info.index};

% get handles
target = layoutUD.List.getSelectedRows;
curlst = layoutUD.namelist;

% Model to use
pNewModel = curlst.SelectedItems;
if isempty(pNewModel) && ~isempty(curlst.Items)
    % Try to take first item in the list
    pNewModel = curlst.Items(1);    
end

% Objective to change
ConLabel = layoutUD.List.getDataAt(target-1,0);
    
if ~isempty(pNewModel)
    CF = getConstraint(optim, ConLabel);
    pConExpr = getConstraintExpression(CF);
    pConExpr.info = pConExpr.setlhsexpr(pNewModel);
    
    % Update the left list
    layoutUD.List.Peer.setDataAt(pNewModel.getname,target-1,1);

end

% Update
i_ConListCbk(layoutUD.List, [], iFace);


%------------------------------------------------------------------------
function nextOK = i_checkPtrsCons(layoutUD)
optim = layoutUD.optimdata.info.list{layoutUD.optimdata.info.index};

% Check to see if there are any oppts. If not, cannot go any
% further
nextOK = 1;
if isempty( get( optim, 'oppoints' ) )
    nextOK = 0;
end

%--------------------------------------------------------------------------
function i_conradioConstant(~, ~, iFace)

% Get the user data
layoutUD = feval(iFace.getCardUserdata);

% Set the other button to off
set(layoutUD.boundradio, 'Value', 0);

% Get the selected constraint
layoutUD = feval( iFace.getCardUserdata );
optim = layoutUD.optimdata.info.list{layoutUD.optimdata.info.index};
selected = layoutUD.List.getSelectedRows;

% Get constraint expression
ConLabel = layoutUD.List.getDataAt(selected-1,0);
CF = getConstraint(optim, ConLabel);
pConExpr = getConstraintExpression(CF);
pConExpr.info = pConExpr.setevaluationmode('eval');

% Update bound and operator currently in constraint
value = pConExpr.getrhsvalue;
op = pConExpr.getcomparisonoperator;
boundtext = sprintf('%s %g', op, value);
layoutUD.List.Peer.setDataAt(boundtext,selected-1,2);

% Update the bound constraint layout
i_UpdateBoundControls(layoutUD, CF);

% Update the list of possible models
i_UpdateModelList(iFace, layoutUD, CF);

%------------------------------------------------------------------------
function i_conradioBoundary(~, ~, iFace)

% Get the selected constraint
layoutUD = feval( iFace.getCardUserdata );
optim = layoutUD.optimdata.info.list{layoutUD.optimdata.info.index};
selected = layoutUD.List.getSelectedRows;

% Get constraint expression
ConLabel = layoutUD.List.getDataAt(selected-1,0);
CF = getConstraint(optim, ConLabel);
pConExpr = getConstraintExpression(CF);
pConExpr.info = pConExpr.setevaluationmode('constraint');

% Update UI
layoutUD.List.Peer.setDataAt('Boundary',selected-1,2);

% Update the bound constraint layout
i_UpdateBoundControls(layoutUD, CF);

% Update the list of possible models
i_UpdateModelList(iFace, layoutUD, CF);

%------------------------------------------------------------------------
function [nextCardID, localData] = i_cardFiveNext(layoutUD, ~)

% set up the local data
localData = layoutUD.optimdata;

% Which card is next?
obj = layoutUD.optimdata.info.list{layoutUD.optimdata.info.index};

if ~isempty( get( obj, 'oppoints' ) )
    % number of oppoint sets >= 1 ==> must vist card six
    nextCardID = @i_createCardSix;
else
    % We really shouldn't end up here. If we are here it is because the 'Next'
    % button hasn't been disabled. To exit smoothly, we'll just goto card six.
    warning(message('mbc:cgoppoint:InvalidState12'));
    nextCardID = @i_createCardSix;
end

%------------------------------------------------------------------------
% CARD SIX FUNCTIONS BELOW
%------------------------------------------------------------------------
function layout = i_createCardSix(fh, iFace, localData)
% GUI Layout for card six: assign data sets

% Have we been called to create the layout or simply update?
if isa(fh, 'xregcontainer')
    layout = fh;
    layoutUD = get(layout, 'UserData');
else
    
    layoutUD.List = mbcwidgets.List( 'Parent', fh,...
        'Editable', false, ...
        'Grid',false,...
        'Visible','off',...
        'SelectionChangedCallback',{@i_ListCbk, iFace},...
        'SelectionMode', 'SingleRow');
    
    layoutUD.List.Peer.setColumnData({'Operating Point Set','CAGE Data Set'});
    layoutUD.List.Peer.setColumnWidths([110 120]);    
    
    % Make a title for this ListView we will find this and get it's user data on listview callbacks
    t= uicontrol('Parent',fh,...
        'Style','text',...
        'Visible','off',...
        'HorizontalAlignment','left',...
        'String','Optimization operating point sets:');
    layoutUD.selbutton= xregGui.iconuicontrol('parent',fh,...
        'imageFile',[xregrespath,'\leftarrow.bmp'],...
        'transparentColor', [255 255 0],...
        'ToolTip','Select CAGE Data Set',...
        'visible','off',...
        'callback',{@i_selectOpp,iFace});
    t2= uicontrol('Parent',fh,...
        'Style','text',...
        'Visible','off',...
        'HorizontalAlignment','left',...
        'String','CAGE data sets:');
    layoutUD.namelist = cgtools.nodeList('Parent', fh, ...
        'visible', 'off', ...
        'DisplayTypeColumn', false, ...
        'DisplayHeaderRow', false);

    layout = xreggridbaglayout(fh, ...
        'dimension', [5 3], ...
        'gapx', 10, ...
        'border', [7 0 7 10], ...
        'rowsizes', [15 2 -1 80 -1], ...
        'colsizes', [-1 80 -1], ...
        'colratios', [2 0 1], ...
        'mergeblock', {[3 5], [1 1]}, ...
        'mergeblock', {[3 5], [3 3]}, ...
        'elements', {t, [], layoutUD.List, [],[], ...
        [],[],[], layoutUD.selbutton, [], ...
        t2, [], layoutUD.namelist, [], []});
    infostr = ['Select the data sets that the algorithm will use.  The data', ...
        ' sets contains data that is accessible by the optimization function', ...
        ' when it is run.'];
    layout = i_maketitlearea(fh, 'Operating Point Sets', infostr, layout);
    layoutUD.cancelFcn = @i_cardCancel;
end

if nargin > 2,
    layoutUD.optimdata = localData;
end

layoutUD = i_cardSixUpdate(layoutUD, iFace);
set(layout, 'UserData', layoutUD);

%------------------------------------------------------------------------
function layoutUD = i_cardSixUpdate(layoutUD, iFace)
optim = layoutUD.optimdata.info.list{layoutUD.optimdata.info.index};

% fills the card with information

% fill the left-hand list box
oppointLabels = get(optim, 'oppointLabels');
oppointPtrs = getOppointPtr(optim);
Data = cell(length(oppointLabels),2);
for i = 1:length(oppointLabels)
    Data{i,1} = oppointLabels{i};
    if isvalid(oppointPtrs(i))
        Data{i,2} = oppointPtrs(i).getname;
    end
end
if ~isempty(Data)
    layoutUD.List.Peer.setData(Data);
    layoutUD.List.selectRows(1);
end

% Map between names and nodes for all datasets in the project
globalUD = feval(iFace.getUserData);
proj = globalUD.Project;

dsnodes = filterbytype(proj.info, cgtypes.cgdatasettype);
layoutUD.DSptrs = mbcpointer(size(dsnodes)); 
layoutUD.oppointnames = cell(size(dsnodes));
for n = 1:numel(dsnodes)
    layoutUD.DSptrs(n) = address(dsnodes{n});
    layoutUD.oppointnames{n} = name(dsnodes{n});
end

% Filters of allowed datasets for each optim entry are cached
layoutUD.IsFilterDone = false(size(oppointLabels));
layoutUD.KeepFilter = false(length(layoutUD.DSptrs), length(oppointLabels));

% Select the correct item
layoutUD = i_ListCbk([], [], iFace, layoutUD);

layoutUD.finishFcn = @i_cardSixFinish;
% enable the finish button, disable the next button
feval(iFace.setNextButton, 'off');
feval(iFace.setFinishButton, 'on');


% --------------------------------------------------
function layoutUD = i_ListCbk(~, ~, iFace, layoutUD)
if nargin<4
    layoutUD = feval(iFace.getCardUserdata);
end

optim = layoutUD.optimdata.info.list{layoutUD.optimdata.info.index};
selected = layoutUD.List.getSelectedRows;
if ~isempty(selected)
    % Update the list of allowed data sets
    pAllReqVal = get(optim, 'oppointvalues');
    
    if ~layoutUD.IsFilterDone(selected)
        layoutUD.KeepFilter(:, selected) = ...
            i_FilterAllowedDS(layoutUD.DSptrs, pAllReqVal{selected});
        layoutUD.IsFilterDone(selected) = true;
    end
    
    layoutUD.namelist.Items = layoutUD.DSptrs(layoutUD.KeepFilter(:, selected));

    OpPointLabel = layoutUD.List.getDataAt(selected-1,0);

    pSelOp = getOppointPtr(optim, OpPointLabel);
    if isvalid(pSelOp)
         layoutUD.namelist.SelectedItems = ...
             layoutUD.DSptrs(strcmp(pSelOp.getname, layoutUD.oppointnames));
    else
        layoutUD.namelist.SelectedItems = [];
    end


    % Check whether to enable the select button
    if isempty(layoutUD.namelist.Items)
        % disable the select button when there are no datasets
        set(layoutUD.selbutton,'Enable', 'off');
    else
        set(layoutUD.selbutton,'Enable', 'on');
    end
else
    set(layoutUD.selbutton,'Enable', 'off');
    layoutUD.namelist.Items = [];
end

if nargin<4
    feval(iFace.setCardUserdata, layoutUD);
end


% --------------------------------------------------
function i_selectOpp(~, ~,iFace)
% oppoint selection
layoutUD = feval(iFace.getCardUserdata);
optim = layoutUD.optimdata.info.list{layoutUD.optimdata.info.index};

% get handles
target = layoutUD.List.getSelectedRows;
curlst = layoutUD.namelist;

% Model to use
pNewDSNode = curlst.SelectedItems;
if isempty(pNewDSNode) && ~isempty(curlst.Items)
    % Try to take first item in the list
    pNewDSNode = curlst.Items(1);    
end

% Oppoint to change
OpLabel = layoutUD.List.getDataAt(target-1,0);
    
if ~isempty(pNewDSNode)
    pOp = pNewDSNode.getdata;
    optim = setOppointPtr(optim, OpLabel, pOp);
    
    layoutUD.optimdata.info.list{layoutUD.optimdata.info.index} = optim;

    % Update the left list
    layoutUD.List.Peer.setDataAt(pOp.getname,target-1,1);
end

% Move the left list selection down one
N = layoutUD.List.getRowCount;
newInd = mod(target,double(N))+1;
layoutUD.List.selectRows(newInd);

% Update
i_ListCbk(layoutUD.List, [], iFace);


%-------------------------------------------------------------------
function Keep = i_FilterAllowedDS(pNodes, reqdptrs)
nodes = infoarray(pNodes);
Keep = false(size(nodes));
for i = 1:numel(nodes)
    pOp = getdata(nodes{i});
    ptrs = get(pOp.info, 'ptrlist');
    Keep(i) = all(ismember(reqdptrs, ptrs));
end


%------------------------------------------------------------------------
function i_cardSixFinish(layoutUD, iFace)

optimindex = layoutUD.optimdata.info.index;
optimlist = layoutUD.optimdata.info.list;

otherindices = [ 1:optimindex-1, optimindex+1:length( optimlist ) ];

% Destroy all optim objects that are not used
for n = otherindices
    destroyobject( optimlist{n});
end

% return the new optimization object
outputUD.optim = layoutUD.optimdata.info.list{layoutUD.optimdata.info.index};

% At this point, any linear constraint will not have its inputs set up.
% Set the inputs for all the linear constraints
pFree = getfreevalues(outputUD.optim);
cons = getConstraint(outputUD.optim);
for i = 1:length(cons)
    if isa(cons{i}, 'cgpointconstraint')
        pConExpr = getConstraintExpression(cons{i});
        if isa(pConExpr.info, 'cgconconstraint') 
            conobj = getconobject(pConExpr.info);
            if isa(conobj, 'conlinear')
                pConExpr.info = setinputs(pConExpr.info, pFree);
            end
        end
    end
end
feval(iFace.setOutputData, outputUD);

%------------------------------------------------------------------------
function lyt = i_maketitlearea(fh, sTitle, sInfo, hCenter)
% Wrap a layout handle with a pretty titled area containing more
% information
hInfo = mbcgui.container.InfoPane( 'Parent', fh,...
    'Visible', 'off',...
    'Title', sTitle,...
    'InfoString', sInfo,...
    'Center', hCenter );
lyt = xreglayerlayout(fh, 'elements', {hInfo});

%------------------------------------------------------------------------
function i_cardCancel(layoutUD, ~)
% Need to destroy the optim objects to make sure all pointers are released
alloptims = layoutUD.optimdata.info.list;
for n = 1:length(alloptims)
    destroyobject(alloptims{n});
end


function cbkSelectInput(listbox,~,iFace)

Row = getSelectedRows(listbox);
if isempty(Row)
    feval(iFace.setNextButton, 0 );
else
    feval(iFace.setNextButton, 1 );
end