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

    classdef MessageService < mbcmodelview.MessageService
    %MessageService Model cross-section MessageService for GraphView class
    %   MessageService that can be used with the GraphView class to update
    %   a cross-section plot for a model
    
    %  Copyright 2014-2016 The MathWorks, Inc. and Ford Global Technologies, Inc.
    
    
    properties (AbortSet)
        %ShowDataPoints Boolean indicating if data points should be plotted
        % on the cross section view
        ShowDataPoints=true;
        %ShowConstraints Boolean indicating if constraint limits be plotted
        % on cross section view
        ShowConstraints=true;
        %ZoomConstraints Boolean indicating if X-axis should be zoomed in
        % on the boundary limits
        ZoomConstraints=false;
        %ShowErrorLines Boolean indicating if error lines should be plotted
        ShowErrorLines = true;
        %ConfidenceIntervalLevel Confidence interval as a percentage
        ConfidenceIntervalLevel = 95;
        %ShowCommonYAxis show common Y axis for all plots
        ShowCommonYAxis = true;
        %OperatingPointValues Values for operating points
        OperatingPointValues = [];
        %OperatingPointNames Operating point names
        OperatingPointNames = {};
        %SelectionType block diagram selection type ('inputs','model','response')
        SelectionType='';
        %CurrentStage currently selected stage (1,2,[])
        CurrentStage
        %EditMode name of editor being used ('data','DoE','')
        EditMode = '';
    end
    
    properties (SetAccess=private)
        %CurrentTest The currently selected test point
        CurrentTest = 1;
        %MaxTestNumber Number of tests in current node
        MaxTestNumber = 0;
    end
    
    properties (Dependent,SetAccess=private)
        %IsPointByPoint Flag indicating if the current model is point-by-point
        IsPointByPoint = false;
        %ModelFitted array indicating which response has fitted models
        ModelFitted
        %NumStages number of stages
        NumStages
        %StageName name for stage
        StageName
    end
    
    properties (Dependent)
        %DesignDev designdev for current stage
        DesignDev
        %Testplan current test plan object
        Testplan
    end
    
    properties (Access=private)
        IsInitializing = false;
    end
    
    properties(Dependent,SetAccess=private)
        %Title standard title is the name of the response
        Title
    end
    
    events (NotifyAccess=private)
        OptionChanged
        TestChanged
    end
    
    
    methods
        function obj=MessageService()
        %MessageService Constructor for MessageService
        
        obj.Actions = mbcmodelview.testplan.Actions(obj);
        end
        
        function set.ShowErrorLines(obj, value)
        %set.ShowErrorLines Set method for ShowErrorLines property
        % Will fire the OptionChanged event
        obj.ShowErrorLines = value;
        notifyOptionChanged(obj,'ShowErrorLines');
        end
        
        function set.ConfidenceIntervalLevel(obj, value)
        %set.ConfidenceIntervalLevel Set method for ConfidenceIntervalLevel property
        % Will fire the OptionChanged event
        obj.ConfidenceIntervalLevel = value;
        notifyOptionChanged(obj,'ConfidenceIntervalLevel');
        end
        
        function set.ShowDataPoints(obj, value)
        %set.ShowDataPoints Set method for ShowDataPoints property
        % Will fire the OptionChanged event
        obj.ShowDataPoints = value;
        data = xregEventData(struct('Option', 'ShowDataPoints'));
        notify(obj,'OptionChanged', data);
        end
        
        function set.ShowConstraints(obj, value)
        %set.ShowConstraints Set method for ShowConstraints property
        % Will fire the OptionChanged event
        obj.ShowConstraints = value;
        notifyOptionChanged(obj,'ShowConstraints');
        end
        
        function set.ZoomConstraints(obj, value)
        %set.ZoomConstraints Set method for ZoomConstraints property
        % Will fire the OptionChanged event
        obj.ZoomConstraints = value;
        notifyOptionChanged(obj,'ZoomConstraints');
        end
        
        function set.ShowCommonYAxis(obj, value)
        %set.ShowCommonYAxis Set method for ShowCommonYAxis property
        % Will fire the OptionChanged event
        obj.ShowCommonYAxis = value;
        notifyOptionChanged(obj,'ShowCommonYAxis');
        end
        
        function d = get.DesignDev(obj)
        
        d = designdev(obj.Testplan);
        d= d(obj.CurrentStage);
        end
        
        function set.DesignDev(obj,ds)
        
        d = designdev(obj.Testplan);
        d(obj.CurrentStage)=ds;
        designdev(obj.Testplan,d);
        
        end
        
        function T = get.Testplan(obj)
        
        T = info(obj.Pointer);
        
        end
        
        function t = get.Title(obj)
        
        t = name(obj.Testplan);
        
        end
        
        function set.Testplan(obj,T)
        if obj.Pointer==address(T)
            xregpointer(T);
        else
            error('Invalid test plan');
        end
        end
        
        function n = get.NumStages(obj)
        
        n = numstages(obj.Testplan);
        end
        
        
        function setNewTestPlan(obj, newPointer)
        %setNewTestPlan update message service to point to a new test plan node
        % Will fire the NodeChanged event
        obj.Pointer = newPointer;
        obj.EditMode = '';
        if obj.IsPointByPoint && newPointer.IsMatched
            testData = getdata(newPointer.info,'Y');
            obj.MaxTestNumber = size(testData, 3);
            if obj.CurrentTest>obj.MaxTestNumber
                obj.CurrentTest=obj.MaxTestNumber;
            end
        end
        obj.CurrentStage = obj.NumStages;
        updateOperatingPointValues(obj);
        fireNodeChanged(obj)
        end
        
        function updateCurrentTest(obj, testNumber)
        %updateCurrentTest Set the CurrentTest property
        % Will fire the NodeChanged and NodeUpdated events
        if testNumber<=obj.MaxTestNumber && testNumber>=1
            obj.CurrentTest=testNumber;
            updateOperatingPointValues(obj)
        end
        fireNodeChanged(obj)
        update(obj)
        end
        
        function change(obj, newPointer)
        %change change or reset test plan
        %   change(obj, newPointer)
        %   change(obj)
        %   change is the equivalent of a setNewTestPlan and update
        
        if nargin<2
            % use current test plan
            newPointer = obj.Pointer;
        end
        if ~isnull(newPointer)
            setNewTestPlan(obj, newPointer)
            update(obj)
        end
        end
        
        function update(obj)
        %update update message services
        fireNodeUpdated(obj)
        end
        
        function OK = editing(obj,Mode)
        if nargin<2
            OK = ~isempty(obj.EditMode);
        else
            OK = strcmpi(obj.EditMode,Mode);
        end
        end
        
        function deserialize(obj,s)
        %deserialize deserialize cross-section options to MessageService
        
        % don't fire events while deserializing
        obj.IsInitializing = true;
        
        % restore CurrentTest
        updateCurrentTest(obj, s.CurrentTest);
        
        % have to update MessageService copies of Options
        obj.ConfidenceIntervalLevel = s.ConfidenceIntervalLevel;
        obj.ShowDataPoints = s.ShowDataPoints;
        obj.ShowConstraints = s.ShowConstraints;
        obj.ZoomConstraints = s.ZoomConstraints;
        obj.ShowErrorLines = s.ShowErrorLines;
        obj.ShowCommonYAxis = s.ShowCommonYAxis;
        
        obj.IsInitializing = false;
        fireNodeChanged(obj)
        end
        
        function pbp = get.IsPointByPoint(obj)
        %get.IsPointByPoint returns boolean indicating if current node
        % is a point-by-point model
        pointer = obj.Pointer;
        pbp = ~isnull(pointer) && (pointer.numstages == 2);
        if pbp
            models = children(obj.Testplan,@model);
            isPBP = cellfun(@(m)isa(m, 'localmulti'), models);
            pbp = pbp && ((~isempty(models) && all(isPBP)) || strcmpi( type(obj.Testplan),'point-by-point'));
        end
        end
        
        function OK = get.ModelFitted(obj)
        
        if ~isempty(obj.Pointer) && obj.Pointer.numChildren>0
            if obj.IsPointByPoint
                [~,OK] = obj.Pointer.children(@(mdev) LocalModel(mdev,obj.CurrentTest));
            else
                OK = obj.Pointer.children(@hasBest);
            end
            OK = [OK{:}];
        else
            OK = false(1,0);
        end
        end
        
        function s = get.StageName(obj)
        
        if obj.NumStages==1
            s = '';
        else
            if obj.CurrentStage == 1
                s = 'Local';
            elseif obj.IsPointByPoint
                s = 'Operating Point';
            else
                s = 'Global';
            end
        end
        
        end
        
        function editData(obj, pSSF,OldTP,oldTSSF,DO_DELETE,fProcessData)
        %editData Push a data object to the data editor
        %    editData(obj, pSSF,OldTP,oldTSSF,DO_DELETE,fProcessData)
        
        T = obj.Testplan;
        if nargin < 2
            pSSF = DataLinkPtr(T);
        end
        if nargin < 3
            OldTP = T;
        end
        if nargin < 4
            oldTSSF = info(DataLinkPtr(T));
        end
        if nargin < 5
            dataPointers = dataptrs( info(project(T)) );
            DO_DELETE = ~any(T.DataLink==dataPointers);
        end
        if nargin<6
            fProcessData = @obj.applyDataChanges;
        end
        
        % callback to close data editor
        fCloseEditor = mbcutils.callback(@obj.closeDataEditor, OldTP,oldTSSF,DO_DELETE,fProcessData);
        % always edit and test plan
        hData = xregdatagui.Editor.open(pSSF,true,true,fCloseEditor);
        
        if ~isempty(hData)
            % Register as a subfigure
            registerSubFigure(obj,hData.Figure);
        end
        end
        
    end
    
    methods (Access=protected)
        function notifyOptionChanged(obj,option)
        %notifyOptionChanged Fires a OptionChanged event with the event
        % data being the name of the option that was changed
        if ~obj.IsInitializing
            data = xregEventData(struct('Option', option));
            notify(obj,'OptionChanged', data);
        end
        end
        
        function fireNodeChanged(obj)
        if ~obj.IsInitializing
            notify(obj,'NodeChanged');
        end
        end
        function fireNodeUpdated(obj)
        if ~obj.IsInitializing
            notify(obj,'NodeUpdated');
        end
        end
        
        function updateOperatingPointValues(obj)
        %updateOperatingPointValues Will update the operating point
        % names and values for the current node (and test if a
        % point-by-point model is selected)
        if obj.Pointer.IsMatched && obj.IsPointByPoint
            currNode = obj.Pointer.info;
            X = getdata(currNode,'fit');
            numLocal = size(X{1},2);
            numGlobal = size(X{2},2);
            
            allInputs = factors(currNode);
            obj.OperatingPointNames = allInputs(numLocal+1:numLocal+numGlobal);
            obj.OperatingPointValues = X{2}{obj.CurrentTest};
        else
            obj.OperatingPointValues = [];
            obj.OperatingPointNames = {};
        end
        end
        
        function closeDataEditor(obj,hData, evt, originalT,oldTSSF,DO_DELETE,fProcessData)
        %closeDataEditor close data editor and process data
        
        % Make sure that testplan is uptodate
        T = obj.Testplan;
        % Get the pointer being edited
        pSSF = hData.UserData.ObjectBeingEdited;
        % Is the pointer location to copy back to still valid? - Clean up if not.
        % After this section we can assume that we have a valid pointer. Don't know
        % how this situation could arise but we'll keep this just in case!
        if ~isvalid(pSSF)
            xregerror('Data Error', 'Data heap corruption - try recreating this testplan');
            % Update the view
            update(obj)
            return
        end
        newData = hData.NewData;
        
        % Need to ensure that one stage testplans have one stage data - maybe
        % in the long run 1 stage testplans will model the sweep mean of the
        % response in which case this special test doesn't need to exist.
        [newData,OK] = setupGroups(T,newData);
        if ~OK
            % ensure that users setup groups correctly
            evt.CancelClose = true;
            if numstages(T)==1
                errordlg('You must use one-stage data for one-stage models','Data','modal');
            else
                errordlg('You must use define test groups for two-stage or point-by-point models. Define test groups in the data editor.','Data','modal');
            end
            return
        end
            
        % Apply the cluster settings to this copy - someone is going to want to
        % know about the design inside.
        newData = applyClusterSettings(newData);
        % Before we un-cache the data lets ask what has happened to it
        % Get some strings to display in the dialog boxes that appear
        [changes,questMsg] = pAssessDataChanges(T, newData);
        
        if changes.INPUT_SIGNAL_REMOVED || any(changes.RESPONSE_SIGNAL_REMOVED)
            % Split behaviour on INPUT_SIGNAL_REMOVED - can't really continue if this
            % is the case with the new data - so choice is to revert to old data or
            % cancel
            dlgopts = struct('Default', 'Cancel', 'Interpreter', 'tex');
            out = questdlg(questMsg, 'Data Selection', 'OK', 'Cancel', dlgopts);
            if strcmp(out, 'OK')
                % Indicate that changes are not to be accepted
                out = 'No';
            end
        elseif ~isempty(questMsg)
            % Only ask the user if there is something to ask about!
            dlgopts = struct('Default', 'Yes', 'Interpreter', 'tex');
            out = questdlg(questMsg, 'Data Selection', 'Yes', 'No', 'Cancel', dlgopts);
        elseif isempty(newData)
            % don't update new data
            out = 'No';
        else
            % Default - This means no discernable change has occurred - Probably
            % ought to go for No but if we only refit different models
            out = 'Yes';
        end
        
        % Getting here indicates that the user clicked either yes or no, but not
        % cancel
        switch out
            case 'Yes'
                % Write the new data correctly into the project such that pSSF
                % now contains the new data
                try
                    fProcessData(pSSF,newData,changes)
                catch ME
                    Restore(T, originalT, oldTSSF,DO_DELETE);
                    xregerror('Data Error',sprintf('Error updating testplan with new data: %s',ME.message));
                end
            case 'No'
                Restore(T, originalT, oldTSSF,DO_DELETE);
            otherwise
                evt.CancelClose = true;
                return
        end
        
        obj.EditMode = '';
        % Update the view
        % update view if pointer hasn't been changed
        if obj.Pointer==address(T)
            change(obj)
        end
        end
        
        function applyDataChanges(obj, pSSF, newData, changes)
        %applyChanges default method to apply data changes
        
        modifyData(obj.Testplan, pSSF, newData, changes);
        end
    end
end