www.gusucode.com > mbctools 工具箱 matlab 源码程序 > mbctools/+mbcmodelview/+testplan/Actions.m

    classdef Actions < handle
    %mbcmodelview.testplan.Actions test plan actions
    
    %  Copyright 2015-2016 The MathWorks, Inc. and Ford Global Technologies, Inc.
    
    properties (SetAccess=private)
        %MessageService test plan message service
        MessageService
    end
    
    properties(SetAccess=private)
        %EditModel edit model of currently selected stage
        EditModel
        %EditInputs edit inputs of currently selected stage
        EditInputs
        %EditDesign edit design of currently selected stage
        %    The outer stage design is edited if no stage is selected
        EditDesign
        %NewResponse create new response model
        %    Data is selected if no data is set up for test plan
        NewResponse
        %ViewDesign view data design of currently selected stage
        ViewDesign
        %ViewModel view model design of currently selected stage
        ViewModel
        %SummaryStats define summary statistics for outer stage
        SummaryStats
        %FitModels select new data and fit response models
        FitModels
        %EditData edit test plan data
        EditData
        %EditBoundary edit boundary models
        EditBoundary
        %ValidationData select validation data for test plan
        ValidationData
        %MakeTemplate make test plan template
        MakeTemplate
        %ExportPointByPoint export point-by-point models
        %   Create optimizations, tradeoff, data sets
        ExportPointByPoint
        %Export2Simulink export response models to Simulink
        Export2Simulink
        %Export2CAGE export response models to CAGE
        %   CAGE is openned if necessary
        Export2CAGE
    end
    
    properties (Access=private)
        %Listeners storage for listeners
        Listeners
    end
    
    
    methods
        function obj = Actions(MessageService)
        %Actions constructor
        obj.MessageService = MessageService;
        
        % input setup
        obj.EditInputs = mbcgui.actions.StatefulAction(@obj.onEditInputs, ...
            'Edit &Inputs...', 'Edit inputs', []);
        
        % DoE actions
        obj.EditDesign = mbcgui.actions.StatefulAction(@obj.onEditDesign, ...
            'Design &Experiment...', 'Design experiment', xregrespath('doe.bmp'));
        obj.ViewDesign = mbcgui.actions.StatefulAction(@obj.onViewDesign, ...
            'View Design...', 'View design', xregrespath('doe.bmp'));
        
        % model setup actions
        obj.EditModel = mbcgui.actions.StatefulAction(@obj.onEditModel, ...
            'Edit &Model...', 'Edit model', []);
        obj.ViewModel = mbcgui.actions.StatefulAction(@obj.onViewModel, ...
            'View Model...', 'View model', []);
        obj.SummaryStats = mbcgui.actions.StatefulAction(@obj.onSummaryStats, ...
            '&Summary Statistics...', 'Summary statistics', []);
        
        % actions requiring data
        obj.NewResponse = mbcgui.actions.StatefulAction(@obj.onNewResponse, ...
            'New &Response...', 'New response model', []);
        obj.FitModels = mbcgui.actions.StatefulAction(@obj.onFitModels, ...
            '&Fit Models...', 'Fit models', xregrespath('viewPlot.bmp'));
        obj.EditData = mbcgui.actions.StatefulAction(@obj.onEditData, ...
            'Edit &Data...', 'Edit data', xregrespath('data.bmp'));
        obj.EditBoundary = mbcgui.actions.StatefulAction(@obj.onEditBoundary, ...
            'Edit &Boundary...', 'Edit boundary models', xregrespath('bdryEdit.bmp'));
        obj.ValidationData = mbcgui.actions.StatefulAction(@obj.onValidationData, ...
            '&Validation Data...', 'Assign validation data', []);
        
        % export functions
        obj.ExportPointByPoint = mbcgui.actions.StatefulAction(@obj.onExportPointByPoint, ...
            'E&xport Point-by-point Models...', 'Export point-by-point models', []);
        obj.Export2Simulink = mbcgui.actions.StatefulAction(@obj.onExport2Simulink, ...
            'Export to &Simulink...', 'Export to Simulink', xregrespath('simulink_app_16.bmp'));
        obj.Export2CAGE = mbcgui.actions.StatefulAction(@obj.onExport2CAGE, ...
            'Generate &Calibration...', 'Generate calibration', cgrespath('cage.bmp'));
        obj.Export2CAGE.TransparentColor = [255 0 255];
        
        obj.MakeTemplate = mbcgui.actions.StatefulAction(@obj.onMakeTemplate, ...
            'Make &Template', 'Make template', xregrespath('tptemplate.bmp'));
        
        obj.Listeners = event.listener(obj.MessageService,'NodeUpdated',@obj.onNodeUpdated);
        
        end % Actions
        
        function createMenus(obj,hParents,~)
        %createTestplanMenu create test plan and view menu for model browser
        createTestplanMenu(obj,hParents(1))
        createViewMenu(obj,hParents(2))
        end % createMenus
        
        function createTestplanMenu(obj,hParent)
        %createTestplanMenu create test plan menu for model browser
        
        AG = mbcgui.actions.ActionGroup([],'Set up test plan');
        AG.Actions = [obj.EditInputs obj.EditModel obj.EditDesign obj.SummaryStats];
        AG.MenuType = 'separate';
        hMenu = createMenuItem(AG,hParent);
        hMenu(2).Accelerator = 'M';
        % FitModels, Edt data, boundary and Validation data
        AG.Actions =  [obj.FitModels,obj.EditData,obj.EditBoundary,obj.ValidationData];
        createMenuItem(AG,hParent);
        
        AG.Actions =  [obj.MakeTemplate,obj.ExportPointByPoint];
        createMenuItem(AG,hParent);
        end % createTestplanMenu
        
        function createViewMenu(obj,hParent)
        %createViewMenu create test plan view menu for model browser
        
        AG = mbcgui.actions.ActionGroup([],'Set up test plan');
        AG.Actions = [obj.ViewModel obj.ViewDesign];
        createMenuItem(AG,hParent);
        end % createViewMenu
        
        function createToolbar(obj,hParent)
        %createToolbar create test plan toolbar
        
        createToolbutton(obj.EditDesign,hParent);
        AG = mbcgui.actions.ActionGroup([],'Set up test plan');
        AG.Actions = [obj.FitModels,obj.EditData,obj.EditBoundary];
        tb = createToolbutton(AG,hParent);
        tb(1).Separator = 'on';
        
        AG.Actions = [obj.Export2Simulink,obj.Export2CAGE];
        tb = createToolbutton(AG,hParent);
        tb(1).Separator = 'on';
        
        tb = createToolbutton(obj.MakeTemplate,hParent);
        tb.Separator = 'on';
        end % createToolbar
        
        function createWorkflowItems(obj,hWorkflow)
        %createWorkflowItems create workflow items in workflow panel
        
        AG = mbcgui.actions.ActionGroup([],'Workflow');
        % could have New Model as well
        AG.Actions = obj.EditDesign;
        AG.MenuType = 'separate';
        wf = createWorkflowItems(AG,hWorkflow);
        wf.Separator = 'on';
        
        AG.Actions = obj.FitModels;
        wf = createWorkflowItems(AG,hWorkflow);
        wf.Separator = 'on';
        
        AG.Actions = [obj.Export2Simulink,obj.Export2CAGE];
        createWorkflowItems(AG,hWorkflow);
        end % createWorkflowItems
        
        function enable(obj)
        %enable enable actions
        
        ms = obj.MessageService;
        
        T = ms.Testplan;
        
        if ms.NumStages>1
            % two-stage or point-by-point
            Stage= ms.CurrentStage;
            IsPointByPoint = ms.IsPointByPoint;
            if strcmp(ms.SelectionType,'model')
                % a model is selected
                obj.EditInputs.Enabled = false;
                obj.EditModel.Enabled = true;
                obj.SummaryStats.Enabled = true;
                obj.ViewModel.Enabled = true;
                if Stage==1
                    % if we are in the first stage of a 2 stage (local) we can't have
                    % Summary Stats
                    obj.SummaryStats.Enabled = false;
                elseif Stage>1 && IsPointByPoint
                    % disable model menus for operating point models
                    obj.EditModel.Enabled = false;
                    obj.ViewModel.Enabled = false;
                    obj.SummaryStats.Enabled = false;
                end
                
            else
                % a port is selected
                obj.EditModel.Enabled = false;
                obj.SummaryStats.Enabled = false;
                obj.ViewModel.Enabled = false;
                % Input port selected
                obj.EditInputs.Enabled  = strcmp(ms.SelectionType,'inputs');
            end
        else
            % one-stage test plan
            
            % can always edit inputs and model
            obj.EditModel.Enabled = true;
            obj.EditInputs.Enabled = true;
            obj.ViewModel.Enabled = true;
            obj.SummaryStats.Enabled = true;
        end
        
        % require data to use ValidationData, Boundary and View Design
        obj.ValidationData.Enabled = IsMatched(T);
        obj.EditBoundary.Enabled  = IsMatched(T);
        obj.ViewDesign.Enabled = IsMatched(T);
        
        obj.ExportPointByPoint.Enabled = ms.NumStages==2 && nfactors(getModel(designdev(T))) ==2;
        end  % enable
        
    end % public methods
    
    methods (Access=private)
        function onNodeUpdated(obj,~,~)
        %onNodeUpdated MessageService.NodeUpdated event handling
        enable(obj)
        end % onNodeUpdated
        
        function onEditModel(obj,~,~)
        %onEditModel edit model definition
        
        ms = obj.MessageService;
        if editing(ms)
            xregerror('Error','The model cannot be setup while the design editor or the data selection figure is open');
            return
        end
        d = ms.DesignDev;
        m = getModel(d);
        [m,OK]= gui_ModelSetup(m);
        if OK
            ms.DesignDev = setmodel(d,m);
            % update test plan views
            update(ms);
        end
        end % onEditModel
        
        function onEditInputs(obj,~,~)
        %onEditInputs edit test plan inputs
        ms = obj.MessageService;
        ReadOnly= IsMatched(ms.Testplan) || editing(ms);
        if ms.NumStages>1
            % dialog title for two-stage or point-by-point inputs
            Title= sprintf('%s Input Factor Setup',ms.StageName);
        else
            % dialog title for one-stage inputs
            Title= 'Input Factor Setup';
        end
        Inputs = getInputs(ms.Testplan);
        done= false;
        while ~done
            [Inputs{ms.CurrentStage},OK] = gui_InputSetup(Inputs{ms.CurrentStage},'figure',~ReadOnly,Title);
            if OK
                AllInputs = cat(1,Inputs{:});
                if OK && length( unique(getList(AllInputs,'Symbol')) ) ~= length(AllInputs)
                    % check for unique symbols across all stages
                    h= errordlg('Duplicate symbols in two-stage model','Input Error','modal');
                    uiwait(h);
                    done= false;
                else
                    done= true;
                end
            else
                done= true;
            end
        end
        
        if OK
            % update test plan inputs
            setInputs(ms.Testplan,Inputs);
            change(ms);
        end
        end % onEditInputs
        
        function onEditDesign(obj,~,~)
        %onEditDesign edit design
        
        ms = obj.MessageService;
        pTP= ms.Pointer;
        dStage= ms.DesignDev;
        
        if editing(ms,'data')
            xregerror('Error','The design editor cannot be used while the data selection figure is open');
            return
        end
        initialTree = dStage.DesignTree;
        if isscalar(initialTree.designs)
            % create initial design and select it
            initialTree.designs{2} = initialTree.designs{1};
            initialTree.parents(2) = 1;
            initialTree.CurrentIndex = 2;
        elseif ~isfield(initialTree,'CurrentIndex')
            % select last design by default
            initialTree.CurrentIndex = length(initialTree.designs);
        end
        designStage = ms.CurrentStage;
        
        if ms.NumStages>1
            title = sprintf('Design Editor - [%s (%s)]',name(ms.Testplan),ms.StageName);
        else
            title = sprintf('Design Editor - [%s]',name(ms.Testplan));
        end
        
        doeEditor = xregdesgui.Editor.create('Locked',true,...
            'Title',title,...
            'TreeStruct',initialTree,...
            'CurrentStage',designStage);
        % create a design editor
        ms.EditMode = 'DoE';
        % setup close listener
        doeEditor.UserData = event.listener(doeEditor,'Close',@closeDoE);
        registerSubFigure(ms,doeEditor.Figure);
        
            function closeDoE(doeEditor,evt)
            %closeEditor close DoE editor
            
            % ask user if they want to save their changes
            buttonName = questdlg('Do you want to save the changes you made to your design?', ...
                'Keep changes','Yes','No','Cancel','Yes');
            switch buttonName
                case 'Yes'
                    % update DoE in test plan
                    
                    % grab a copy of the design tree
                    dtree=doeEditor.TreeStruct;
                    dAllStages = pTP.designdev;
                    dStage = dAllStages(designStage);
                    OldTree= dStage.DesignTree;
                    OldDes= factorsettings(getdesign(dStage));
                    NewDes= factorsettings(dtree.designs{dtree.chosen});
                    if OldTree.chosen ~= dtree.chosen || size(OldDes,1)~=size(NewDes,1) || any(OldDes(:)~=NewDes(:))
                        % make best design model the default
                        m = model(dtree.designs{dtree.chosen});
                        dtree.designs{1}= model(dtree.designs{1},m);
                        
                    end
                    % update designdev in test plan
                    dStage.DesignTree= dtree;
                    dAllStages(designStage) = dStage;
                    pTP.designdev(dAllStages);
                    % clear edit mode and listeners
                    ms.EditMode = '';
                    doeEditor.UserData = [];
                case 'No'
                    % clear edit mode and listeners
                    ms.EditMode = '';
                    doeEditor.UserData = [];
                case 'Cancel'
                    % cancel close actions
                    evt.CancelClose = true;
            end
            end % closeDoE
        end % onEditDesign
        
        function onNewResponse(obj,~,~) %#ok<INUSD>
        %onNewResponse create new response
        
        NewNode(MBrowser);
        end % onNewResponse
        
        function onViewDesign(obj,~,~)
        %onViewDesign view design
        
        ms = obj.MessageService;
        T = ms.Testplan;
        d = ms.DesignDev;
        dtree= d.DesignTree;
        if dtree.chosen
            if ms.CurrentStage < ms.NumStages
                % local designs
                % get the data
                X= getdata(T,'X',0);
                X=X{ms.CurrentStage};
                
                des= dtree.designs{dtree.chosen};
                m= model(des);
                dtree.designs= dtree.designs(1);
                tn= testnum(X);
                for i= 1:size(X,3)
                    % create one design per operating point
                    des= reinit(des,code(m,X{i}));
                    des= name(des,sprintf('Test %2d',tn(i)));
                    dtree.designs=[dtree.designs,{des}];
                end
                dtree.parents=[0,ones(1,size(X,3))];
            else
                % one-stage or global designs
                X= getdata(T,'X',0);
                if iscell(X)
                    X=X{end};
                end
                des= dtree.designs{dtree.chosen};
                m = model(des);
                des = reinit(des,code(m,double(X)));
                des = name(des,'Selected Data');
                dtree.designs=[dtree.designs(1),{des}];
                dtree.parents= [0,1];
            end
            % root node selected as best
            dtree.chosen = 1;
            % select the first design in the tree
            dtree.CurrentIndex = 2;
            
            designStage = ms.CurrentStage;
            
            if ms.NumStages>1
                title = sprintf('Design Editor - [%s (%s)]',name(T),ms.StageName);
            else
                title = sprintf('Design Editor - [%s]',name(T));
            end
            
            doeEditor = xregdesgui.Editor.create('Locked',true,...
                'Title',title,...
                'TreeStruct',dtree,...
                'CurrentStage',designStage);
            % create a design editor
            ms.EditMode = 'DoE';
            
            doeEditor.UserData = event.listener(doeEditor,'Close',@closeDoE);
            hDOE=doeEditor.Figure;
            registerSubFigure(ms,hDOE);
            ms.EditMode = 'DoE';
            
        end
        
            function closeDoE(~,~)
            %closeDoE close DoE editor
            
            % clear edit mode and listeners
            ms.EditMode = '';
            doeEditor.UserData = [];
            end % closeDoE
        end % onViewDesign
        
        function onViewModel(obj,~,~)
        %onViewModel view default model definition
        ms = obj.MessageService;
        d = ms.DesignDev;
        
        hFig= view(getModel(d));
        if numstages(ms.Testplan)>1
            set(hFig,'Name',['Default ' ms.StageName ' Model']);
        else
            set(hFig,'Name','Default Model');
        end
        registerSubFigure(ms,hFig);
        
        end % onViewModel
        
        function onSummaryStats(obj,~,~)
        %onSummaryStats edit default summary statistics
        
        ms = obj.MessageService;
        d = ms.DesignDev;
        m= getModel(d);
        % setup gui
        [m,OK]= gui_SummaryStats(m);
        if OK
            d= setmodel(d,m);
            ms.DesignDev = d;
        end
        end % onSummaryStats
        
        function onFitModels(obj,~,~)
        %onFitModels fit models for test plan
        ms = obj.MessageService;
        
        if ~editing(ms)
            % can't define new data if data or design editor is open
            T = ms.Testplan;
            if IsMatched(T)
                resp= questdlg('Fitting models to new data will change all the test plan response models. Do you want to continue?',...
                    'Fit Models','Yes','No','No');
                if ~strcmp(resp,'Yes')
                    return
                end
            end
            % close other figures
            OK = ms.closeSubFigures; 
            if ~OK
                return
            end
            
            busy(ms,'Fitting models to data')
            
            D= designdev(T);
            [des,index]= ActualDesign(D);
            if strcmp(name(des),'Actual Design')
                % delete actual design
                T = designdev(T,DeleteDesign(D,index));
                xregpointer(T);
            end
            if numChildren(T)>0
                % store current models in T.Responses
                T.Responses = children(T,@model);
                xregpointer(T);
            end
            % call data wizard
            datawizard(T);
            hData = xregdatagui.Editor.find('dataEditor');
            if ~isempty(hData) && strcmp(hData.Visible,'on')
                ms.EditMode = 'data';
                hList = addlistener(hData,'PostClose',@closeDataEditor);
            end
            idle(ms);
        else
            xregerror('Error', ...
                ['Fit models cannot be selected while the design editor ' ...
                'or the data editor is open']);
        end
        
            function closeDataEditor(~,~)
            ms.EditMode = '';
            % delete the listener
            delete(hList); 
            end  %   closeDataEditor
        
        end % onFitModels
        
        function onValidationData(obj,~,~)
        %onValidationData define validation data for test plan
        ms = obj.MessageService;
        p = ms.Pointer;
        
        if ~editing(ms)
            % can't define validation data if data or design editor is open
            [ssf,ok] = ValDataWizard(p,'Select Data for Validation');
            
            if ok
                % update validation data
                valdata(ms.Testplan,ssf);
                
                % force a complete redraw
                ms.change
            end
        else
            xregerror('Error', ...
                ['Valdation data cannot be selected while the design editor ' ...
                'or the data selection figure is open']);
        end
        end % onValidationDatas
        
        function onExportPointByPoint(obj,~,~)
        %onExportPointByPoint export
        if canExport(obj)
            ms = obj.MessageService;
            if get(cgbrowser,'GUIExists')
                %define multimodel export through dialog
                [CreateItems,ok] = guiMultiModel(ms.Testplan);
            else
                % will export to legacy file for multimodel tradeoff
                CreateItems = [];
                ok = true;
            end
            if ok
                mv_busy('Building point-by-point models...')
                drawnow;
                exportMultiModels(ms.Testplan,CreateItems);
                ms.update;
            end
        end
        end % onExportPointByPoint
        
        function onExport2Simulink(obj,~,~)
        %onExport2Simulink export to Simulink
        
        if canExport(obj)
            
            ms = obj.MessageService;
            
            % Check to see if we have asked to export a validated model
            if ~any(hasBestExportModel(ms.Testplan))
                errordlg('You must validate the model before exporting','Error','modal');
            else
                xreg_ExportTool(ms.Pointer);
            end
        end
        end % onExport2Simulink
        
        function OK = canExport(obj)
        T = obj.MessageService.Testplan;
        msg = '';
        if numChildren(T)==0
            msg = 'Your test plan has no response models. Fit models to data.';
        elseif ~all(hasBestExportModel(T))
            if strcmpi(type(T),'two-stage')
                msg = 'Create two-stage models for each response.';
            else
                msg = 'Select best models for each response.';
            end
            msg = sprintf('Your response models are not ready to export. %s',msg);
        end
        OK = isempty(msg);
        if ~OK
           errordlg( msg,'Export','modal');
        end
        
        
        end
        
        
        function onExport2CAGE(obj,~,~)
        %onExport2CAGE export models to CAGE
        
        if canExport(obj)
            
            ms = obj.MessageService;
            mdls = getBestExportModel(ms.Testplan);
            
            if ~isempty(mdls)
                % open CAGE and export dialog
                cage;
                EXMdialog(ms.Testplan,mdls,get(MBrowser,'Figure'));
            end
        end
        end % onExport2CAGE
        
        
        
        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
        function onEditData(obj,~, ~)
        %onEditData edit test plan data
        
        ms = obj.MessageService;
        
        if ~editing(ms,'DoE')
            T= ms.Testplan;
            busy(ms)
            dataEditorExists = false;
            if editing(ms,'data')
                % bring data editor to front
                hData = findall(0,'Tag','dataEditor');
                figure(hData);
                dataEditorExists = true;
            elseif ~IsMatched(T)
                % select initial data using wizard
                datawizard(T);
                change(ms);
            else
                % open data editor
                OldTP = T;
                pData = DataLinkPtr(T);
                oldTSSF = info(pData);
                % store current models in T.Responses
                T = setResponseModels(T);
                xregpointer(T);
                editData(ms, pData,OldTP,oldTSSF,false);
            end
            hData = mbcgui.Application.find('dataEditor');
            if ~isempty(hData) && strcmp(hData.Visible,'on') && ~dataEditorExists
                % add listener to close data editor
                ms.EditMode = 'data';
                hList = addlistener(hData,'PostClose',@closeFigure);
            end
            idle(ms);
        else
            xregerror('Error','Data cannot be selected while the design editor is open');
        end
        
            function closeFigure(~,~)
            %closeFigure clear EditMode
            
            ms.EditMode = '';
            % delete the listener
            delete(hList);
            end % closeFigure
        end % onEditData
        
        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
        function onMakeTemplate(obj,~,~)
        %onMakeTemplate make test plan template
        ms = obj.MessageService;
        TemplateDialog(ms.Testplan);
        end % onMakeTemplate
        
        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
        function onEditBoundary(obj,~,~)
        %onEditBoundary edit boundary models in boundary editor
        ms = obj.MessageService;
        pTP = ms.Pointer;
        
        busy(ms);
        
        broot = dataobject( boundarytree(ms.Testplan) );
        hBdryEditor = xregbdrygui.Editor.create('Root',broot );
        
        hBdryFigure = hBdryEditor.Figure;
        registerSubFigure( ms, hBdryFigure);
        % set up boundary editor close function
        hBdryEditor.UserData = [event.listener(hBdryEditor,'PostClose' ,@closeBdryEditor)
            event.listener(ms,'NodeUpdated' ,@updateBoundaryEditor)];
        IsOpen = true;
        idle(ms);
        
            function closeBdryEditor(~,~)
            % make sure that the test plan is updated
            
            % prevent the boundary editor from being updated during close
            IsOpen = false;
            if ms.Pointer == pTP
                % update current model browser view if you are still on the same node
                change(ms);
            end
            % delete the listener
            hBdryFigure.UserData = [];
            end
        
            function updateBoundaryEditor(~,~)
            %updateBoundaryEditor update the boundary editor when the test
            %plan is updated
            
            if IsOpen && ms.Pointer == pTP
                % get latest boundary tree
                broot = dataobject( boundarytree(ms.Testplan) );
                hBdryEditor.Root = broot;
            end
            end % updateBoundaryEditor
        
        end % onEditBoundary
        
    end
    
end