www.gusucode.com > mbctools 工具箱 matlab 源码程序 > mbctools/+xregdatagui/MessageService.m
classdef (CaseInsensitiveProperties) MessageService < mbcgui.multiview.AbstractMessageService %xregdatagui.MessageService class % xregdatagui.MessageService properties: % DataObject - Property is of type 'MATLAB array' (read only) % DefaultProperties - Property is of type 'MATLAB array' (read only) % DataObject - Property is of type 'MATLAB array' (read only) % Sweepset - Property is of type 'MATLAB array' (read only) % SweepsetWithBadData - Property is of type 'MATLAB array' (read only) % SweepsetFilter - Property is of type 'MATLAB array' (read only) % TestplanSweepsetFilter - Property is of type 'MATLAB array' (read only) % Design - Property is of type 'MATLAB array' (read only) % Model - Property is of type 'MATLAB array' (read only) % ObjectName - Property is of type 'MATLAB array' (read only) % GoodToBadIndexMap - Property is of type 'MATLAB array' (read only) % isaSS - Property is of type 'bool' (read only) % isaSSF - Property is of type 'bool' (read only) % isaTSSF - Property is of type 'bool' (read only) % isBadDataUpdated - Property is of type 'bool' (read only) % CurrentClusterIndex - Property is of type 'double' (read only) % SelectedTests - Property is of type 'MATLAB array' (read only) % IsReadOnly - Property is of type 'bool' % % xregdatagui.MessageService methods: % addlistener - A short description of the function % clearEventQueue - cancel the events in the event queue % findListeners - find certain listeners from a listener array % flushEventQueue - flushes all pending events in the MessageService queue % getdesign - A short description of the function % isEventPending - Check whether an event is queued for execution % pFlushEventQueue - Flush all pending events in the MessageService queue % queueEvent - a function to add events to the event queue % setCurrentCluster - Set the current cluster index % setDataObject - Set the data object in the data message service % setSelectedTests - Set the selected tests % Copyright 2015-2016 The MathWorks, Inc. and Ford Global Technologies, Inc. properties (AbortSet, SetObservable) %ISREADONLY Property is of type 'bool' IsReadOnly = false; end properties (Access=private) %Listeners store for listeners Listeners = []; end properties (SetAccess=protected, SetObservable) %EVENTQUEUE Property is of type 'MATLAB array' (read only) EventQueue = cell( 1, 0 ); %DEFAULTPROPERTIES Property is of type 'MATLAB array' (read only) DefaultProperties = []; %DATAOBJECT Property is of type 'MATLAB array' (read only) DataObject = []; %SWEEPSET Property is of type 'MATLAB array' (read only) Sweepset = []; %CURRENTCLUSTERINDEX Property is of type 'double' (read only) CurrentClusterIndex = 0; %SELECTEDTESTS Property is of type 'MATLAB array' (read only) SelectedTests = []; %Actions data editor actions Actions %OutlierLine outlier line (with GUIDs) for data editor OutlierLine = []; end properties (SetAccess=protected, SetObservable) %SWEEPSETWITHBADDATA Property is of type 'MATLAB array' (read only) SweepsetWithBadData = []; %SWEEPSETFILTER Property is of type 'MATLAB array' (read only) SweepsetFilter = []; %TESTPLANSWEEPSETFILTER Property is of type 'MATLAB array' (read only) TestplanSweepsetFilter = []; %DESIGN Property is of type 'MATLAB array' (read only) Design = []; %MODEL Property is of type 'MATLAB array' (read only) Model = []; %OBJECTNAME Property is of type 'MATLAB array' (read only) ObjectName = []; %GOODTOBADINDEXMAP Property is of type 'MATLAB array' (read only) GoodToBadIndexMap = []; %ISASS Property is of type 'bool' (read only) isaSS %ISASSF Property is of type 'bool' (read only) isaSSF %ISATSSF Property is of type 'bool' (read only) isaTSSF %ISBADDATAUPDATED Property is of type 'bool' (read only) isBadDataUpdated = false; end properties (Dependent,SetAccess=private) %HasExtras extras are installed HasExtras %isOneStage data is defined as one-stage data isOneStage end events dmsDataTypeChanged ssDataChanged ssRecordsChanged ssNamesChanged ssUnitsChanged ssTestsChanged ssFilenameChanged ssfModifyDataChanged ssfVariablesChanged ssfFiltersChanged ssfTestDefinitionChanged ssfSweepVariablesChanged ssfSweepFiltersChanged ssfSweepOrderChanged ssfSweepNotesChanged ssfNameChanged ssfResamplingChanged ssfBadDataChanged tssfExcludedDataChanged tssfActualDesignChanged tssfClustersCreated tssfClustersChanged SelectedTestsChanged CurrentClusterChanged %Busy notify busy status to app so it can change the figure pointer Busy %Idle notify idle status to app so it can change the figure pointer Idle end % events methods % constructor block function obj = MessageService(varargin) %MessageService constructor for the MessageService object % OBJ = MessageService(VARARGIN) % Initialize DefaultProperties. This was a Factory default value but it is % a little too heavyweight a structure for this, plus we only ever % actually create one of these objects at a time anyway. obj.DefaultProperties = struct('Sweepset', sweepset,... 'SweepsetWithBadData', [],... 'SweepsetFilter', sweepsetfilter,... 'TestplanSweepsetFilter', testplansweepsetfilter,... 'Design', xregdesign,... 'Model', [],... 'ObjectName', '',... 'GoodToBadIndexMap', []); % Need to ensure that the outputs are set obj.pSetDataObject(0); % Listener that ensures the selected tests vector is valid obj.Listeners = [event.listener(obj, 'ssTestsChanged', @iUpdateSelectedTests); event.listener(obj, 'tssfClustersCreated', @iUpdateCurrentCluster) event.listener(obj, 'ssfTestDefinitionChanged', @iUpdateTestDefinition)]; % create outlier line obj.OutlierLine = xregdatagui.OutlierLine; % create actions obj.Actions = xregdatagui.Actions(obj); end % MessageService end % constructor block methods function set.DataObject(obj,value) obj.DataObject = pSetDataObject(obj,value); end function value = get.SweepsetWithBadData(obj) value = i_getSweepsetWithBadData(obj,obj.sweepsetwithbaddata); end function value = get.GoodToBadIndexMap(obj) value = i_getGoodToBadIndexMap(obj,obj.GoodToBadIndexMap); end function ok = get.HasExtras(obj) %#ok<MANU> %get.HasExtras (actually Ford Extras) ext = mbcextensions.Extensions.Model; ok = any( strncmpi(ext.AddOnNames,'Ford',4) ); end function ok = get.isOneStage(obj) if obj.hasData if obj.isaSSF % uses one test per record setting in sweepsetfilter as this % is more reliable in the case of empty data ok = isOneStage(obj.SweepsetFilter); %#ok<CPROP> else ok = isOneStage(obj.Sweepset); %#ok<CPROP> end else ok = false; end end end % set and get functions methods % public methods %---------------------------------------- function ret = hasData(obj) %#ok<MANU> %HASDATA Check whether the MessageService contains viewable data % RET = HASDATA(OBJ) returns true if the MessagerService object contains % a data object that can provide any viewing data. ret = true; end % hasData function busy(ms,msg) %busy send event that MessageService is busy if nargin<2 msg = ''; end data.Message = msg; evt = xregEventData(data); notify(ms,'Busy',evt); end function idle(ms) %idle send event that MessageService is idle notify(ms,'Idle'); end %---------------------------------------- function clearEventQueue(obj) %CLEAREVENTQUEUE cancel the events in the event queue % CLEAREVENTQUEUE(OBJ) obj.EventQueue = cell(1,0); end % clearEventQueue %---------------------------------------- function [lArrayOut] = findListeners(obj, lArrayIn, type, varargin) %FINDLISTENERS find certain listeners from a listener array % LARRAYOUT = FINDLISTENERS(OBJ, LARRAYIN, TYPE, VARARGIN) % Which listeners have been requested switch lower(type) case 'sweepset' % Find all listeners which have and event of the form 'ss' followed by % an uppercase character and the SourceObject as this DMS lArrayOut = lArrayIn.findobj('-depth', 0,... {'-regexp', 'EventName', '^ss[A-Z]'},... '-and', 'Source', {obj},... '-and', varargin{:}); case 'sweepsetfilter' % Find all listeners which have and event of the form 'ssf' followed by % an uppercase character and the SourceObject as this DMS lArrayOut = lArrayIn.findobj('-depth', 0, {'-regexp', 'EventName', '^ssf[A-Z]'}, '-and', 'Source', {obj}); case 'testplansweepsetfilter' % Find all listeners which have and event of the form 'tssf' followed by % an uppercase character and the SourceObject as this DMS lArrayOut = lArrayIn.findobj('-depth', 0, {'-regexp', 'EventName', '^tssf[A-Z]'}, '-and', 'Source', {obj}); otherwise % Return nothing by default lArrayOut = []; end end % findListeners %---------------------------------------- function flushEventQueue(obj, DataObject) %FLUSHEVENTQUEUE flushes all pending events in the MessageService queue % FLUSHEVENTQUEUE(OBJ, DATAOBJECT) if nargin<2 DataObject = obj.DataObject; end % Check that the object type hasn't been changed if isequal(class(obj.DataObject), class(DataObject)) % Is the message service Read-Only if obj.IsReadOnly warning(message('mbc:xregtools:datamessageservice:InvalidState')); obj.clearEventQueue; else obj.pFlushEventQueue(DataObject); end else error(message('mbc:xregtools:datamessageservice:InvalidArgument', class( obj.DataObject ))); end end % flushEventQueue %---------------------------------------- function [out] = getdesign(obj) %GETDESIGN get test plan design % OUT = GETDESIGN(IN) % This method exists to mimic the functionallity in xregdesgui.designpackage % which provides a method for retreiving the current design out = obj.Design; end % getdesign %---------------------------------------- function ret = isEventPending(obj, eventname) %ISEVENTPENDING Check whether an event is queued for execution % RET = ISEVENTPENDING(OBJ, EVENTNAME) where EVENTNAME is either a string % or a cell array of strings returns a boolean vector indicating whether % each event specified is currently queued ready for execution. ret = ismember(eventname, obj.EventQueue); end % isEventPending %---------------------------------------- function pFlushEventQueue(obj, dataObject) %PFLUSHEVENTQUEUE Flush all pending events in the MessageService queue % PFLUSHEVENTQUEUE(OBJ, DATAOBJECT) % Set the current data properties and then flush all events if nargin>1 obj.DataObject = dataObject; end if obj.isOneStage && ~isequal(1:size(dataObject,3),obj.SelectedTests) % make sure all tests are selected for ones-stage data obj.SelectedTests = 1:size(dataObject,3); obj.queueEvent('SelectedTestsChanged'); end % reorder the events in the queue % the desired order for events is: eventOrder = {'dmsDataTypeChanged',... 'tssfExcludedDataChanged',... 'tssfActualDesignChanged',... 'tssfClustersCreated',... 'tssfClustersChanged',... 'ssfModifyDataChanged',... 'ssfVariablesChanged',... 'ssfFiltersChanged',... 'ssfTestDefinitionChanged',... 'ssfSweepVariablesChanged', ... 'ssfSweepFiltersChanged',... 'ssfSweepOrderChanged',... 'ssfSweepNotesChanged',... 'ssfResamplingChanged', ... 'ssfNameChanged',... 'ssFilenameChanged',... 'ssRecordsChanged',... 'ssNamesChanged',... 'ssUnitsChanged',... 'ssTestsChanged',... 'ssfBadDataChanged',... 'ssDataChanged', ... 'SelectedTestsChanged', ... 'CurrentClusterChanged'}; % NOTE - there could be some debate over the positioning of the ssfBadDataChanged % event. Since it relates to changes in something which mimics ssDataChanged it % currently sits just before ssDataChanged. I don't think this will have any long % term repercussions, but I could be proved wrong. JLM 28/07/03 ind = ismember(eventOrder, obj.EventQueue); obj.EventQueue = eventOrder(ind); % Drain the event queue if there are any events in it while ~isempty(obj.EventQueue) % Get the first event eventName = obj.EventQueue{1}; % Remove it from the queue obj.EventQueue(1) = []; % Generate the event data to send with the event eventData = event.EventData; % Send the event notify(obj, eventName, eventData); end enable(obj.Actions); end % pFlushEventQueue %---------------------------------------- function queueEvent(obj, varargin) %QUEUEEVENT a function to add events to the event queue % QUEUEEVENT(OBJ, EVENT) % Setup the valid events array validEvents = true(length(varargin), 1); evtList = events(obj); for i = 1:length(varargin) thisEvent = varargin{i}; % Check that the event is valid for the MessageService if ~any(strcmp(thisEvent,evtList)); warning(message('mbc:datamessageservice:InvalidArgument', thisEvent)); % Remove the offending event validEvents(i) = false; end end % Gte the valid events queuedEvents = varargin(validEvents); % Append those not already in the event queue obj.EventQueue = [obj.EventQueue queuedEvents(~ismember(queuedEvents, obj.EventQueue))]; end % queueEvent %---------------------------------------- function setCurrentCluster(obj, val) %SETCURRENTCLUSTER Set the current cluster index % SETCURRENTCLUSTER(OBJ, VAL) if ~isequal(obj.CurrentClusterIndex,val) obj.CurrentClusterIndex = val; obj.queueEvent('CurrentClusterChanged'); obj.pFlushEventQueue(obj.DataObject); end end % setCurrentCluster %---------------------------------------- function setDataObject(obj, val) %SETDATAOBJECT Set the data object in the data message service % SETDATAOBJECT(OBJ, VAL) % Is it any different to the current data object if builtin('isequaln', val, obj.DataObject) return end % Check if the new object and the old object are of the same type and % queue a type changed event if the classes are different. This will give % view's an opertunity to respond to a changed in type if ~isequal(class(obj.DataObject), class(val)) obj.queueEvent('dmsDataTypeChanged'); end % Queue all events obj.queueEvent('ssDataChanged',... 'ssRecordsChanged',... 'ssNamesChanged',... 'ssUnitsChanged',... 'ssTestsChanged',... 'ssFilenameChanged',... 'ssfModifyDataChanged',... 'ssfVariablesChanged',... 'ssfFiltersChanged',... 'ssfTestDefinitionChanged',... 'ssfSweepVariablesChanged', ... 'ssfSweepFiltersChanged',... 'ssfSweepOrderChanged',... 'ssfSweepNotesChanged',... 'ssfNameChanged',... 'ssfResamplingChanged', ... 'tssfExcludedDataChanged',... 'tssfActualDesignChanged',... 'tssfClustersCreated',... 'tssfClustersChanged'); % Flush the event queue obj.pFlushEventQueue(val); end % setDataObject %---------------------------------------- function setSelectedTests(obj, val) %SETSELECTEDTESTS Set the selected tests % SETSELECTEDTESTS(OBJ, VAL) if ~isequal(obj.SelectedTests,val) obj.SelectedTests = val; obj.queueEvent('SelectedTestsChanged'); obj.pFlushEventQueue(obj.DataObject); end end % setSelectedTests %---------------------------------------- function s = getDataName(obj) s = obj.ObjectName; end %---------------------------------------- function updateViews(obj,SelectedTests) %updateViews force update all views ss = obj.Sweepset; if obj.isOneStage SelectedTests = 1:size(ss,3); else SelectedTests(SelectedTests>size(ss,3)) = []; if isempty(SelectedTests) SelectedTests = min(1,size(ss,3)); end end obj.SelectedTests = SelectedTests; obj.queueEvent('SelectedTestsChanged'); obj.queueEvent('ssDataChanged'); obj.pFlushEventQueue(obj.DataObject); end end % public methods methods (Hidden) % possibly private or hidden %---------------------------------------- function val = pSetDataObject(obj, val) %PSETDATAOBJECT % VAL = PSETDATAOBJECT(OBJ, VAL) % By default all typecase fields are double empty s = obj.DefaultProperties; % What to do with an input? if isa(val, 'sweepset') s.Sweepset = val; s.ObjectName = get(val, 'FileName'); if size(s.ObjectName, 1) > 1 s.ObjectName = s.ObjectName(1,:); end end if isa(val, 'sweepsetfilter') s.Sweepset = sweepset(val); s.SweepsetFilter = val; s.ObjectName = get(val, 'Label'); end if isa(val, 'testplansweepsetfilter') s.TestplanSweepsetFilter = val; end % Copy everything across - Note that we EXPLICITLY set the flag to % indicate that the bad data needs updateing set(obj,'Sweepset', s.Sweepset,... 'SweepsetWithBadData', s.SweepsetWithBadData,... 'SweepsetFilter', s.SweepsetFilter,... 'TestplanSweepsetFilter', s.TestplanSweepsetFilter,... 'Design', s.Design,... 'Model', s.Model,... 'ObjectName', s.ObjectName,... 'GoodToBadIndexMap', s.GoodToBadIndexMap,... 'isBadDataUpdated', false,... 'isaSS', isa(val, 'sweepset'),... 'isaSSF', isa(val, 'sweepsetfilter'),... 'isaTSSF', isa(val, 'testplansweepsetfilter')); end % pSetDataObject %---------------------------------------- function output = pSetSweepsetWithBadData(obj, returnArgument) %PSETSWEEPSETWITHBADDATA dataObject = obj.DataObject; % Proceed differently if the dataObject is a sweepsetfilter or sweepset if isa(dataObject, 'sweepset') ss = dataObject; indexMap = 1:size(ss, 3); elseif isa(dataObject, 'sweepsetfilter') [ss, indexMap] = sweepsetWithBadData(dataObject); else ss = sweepset; indexMap = []; end % Set the fields for next time set(obj,'SweepsetWithBadData', ss,... 'GoodToBadIndexMap', indexMap,... 'isBadDataUpdated', true); % Which argument to return if returnArgument == 1 output = ss; else output = indexMap; end end % pSetSweepsetWithBadData end % possibly private or hidden end % classdef % ------------------------------------------------------------------------------ % Note - get functions can become highly recursive if you try and set the % value inside so make sure they NEVER recurse % ------------------------------------------------------------------------------ function val = i_getGoodToBadIndexMap(obj, val) if ~obj.isBadDataUpdated RETURN_INDEX = 2; val = pSetSweepsetWithBadData(obj, RETURN_INDEX); end end % i_getGoodToBadIndexMap % ------------------------------------------------------------------------------ function val = i_getSweepsetWithBadData(obj, val) if ~obj.isBadDataUpdated RETURN_SWEEPSET = 1; val = pSetSweepsetWithBadData(obj, RETURN_SWEEPSET); end end % i_getSweepsetWithBadData function iUpdateSelectedTests(dms, ~) % Get sweepset ss = dms.Sweepset; tn = testnum(ss); % Find all values that are smaller than the new tests sel = dms.SelectedTests; valuesToKeep = (sel <= length(tn)); % Are any of the values outside the new range if ~all(valuesToKeep) % Only keep valid indices dms.setSelectedTests(sel(valuesToKeep)); end end % iUpdateSelectedTests function iUpdateCurrentCluster(dms, ~) % Quietly reset the current cluster - we don't want to generate more events % while in the ClustersCreated event. dms.CurrentClusterIndex = 0; end % iUpdateCurrentCluster function iUpdateTestDefinition(dms,~) %iUpdateTestDefinition test definition has changed so need to change %selected tests if dms.isOneStage % select all tests if one-stage dms.SelectedTests = 1:size(dms.Sweepset,1); elseif ~isscalar(dms.SelectedTests) % select first test for two-stage dms.SelectedTests = 1; end end