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

    classdef Actions < handle
    %xregdatagui.Actions data editor actions

    %  Copyright 2015-2016 The MathWorks, Inc. and Ford Global Technologies, Inc.
    
    properties (SetAccess=private)
        %ImportFile action to import data from file 
        ImportFile
        %ImportExcel action to import data from Excel
        ImportExcel
        %ImportWorkspace action to import data from MATLAB workspace
        ImportWorkspace
        %RenameData rename data set
        RenameData
        %ExportExcel action to export data to Excel (enables import)
        ExportExcel
        %ExportWorkspace action to export data to MATLAB workspace
        %  dialog to specify name and format
        ExportWorkspace
        %Variables action to add or edit user-defined variables
        Variables
        %Filters action to add or edit filters
        Filters
        %Filters action to add or edit test filters
        TestFilters
        %TestVariables action to add or edit user-defined test variables
        TestVariables
        %TestNotes action to add or edit test notes
        TestNotes
        %DefineTests action to define test groups
        DefineTests        
        %RemoveData action to remove data selected as outliers
        RemoveData
        %RestoreData action to restore data previously removed as outliers
        RestoreData
        %ClearOutliers action to clear all selected outliers
        ClearOutliers
        %MultiSelect action to start outlier selection with a bounding box
        MultiSelect
    end
    
    properties (SetAccess=private)
        %DataOperations action group for data actions based on expressions
        DataOperations
        %OutlierTools action group for outliers actions
        OutlierTools
    end
    
    properties(SetAccess=private)
        %MessageService store for xregdatagui.MessageService
        MessageService
        %Listeners store for listeners
        Listeners
    end
    
    methods
        function obj = Actions(ms)
        %Actions constructor
        %    obj = Actions(MessageService)
        
        obj.MessageService = ms;
        
        % import actions
        obj.ImportFile = mbcgui.actions.StatefulAction(@obj.onImportFile,...
            '&Import File...','Import data from file and merge',xregrespath('import_ts_16.bmp'));
        obj.ImportWorkspace = mbcgui.actions.StatefulAction(@obj.onImportWorkspace,...
            'Import &Workspace...','Import data from workspace and merge',xregrespath('variable_import.bmp'));
        obj.ImportExcel = mbcgui.actions.StatefulAction(@obj.onImportExcel,...
            'Import &Excel...','Import data from Excel',xregrespath('variable_import.bmp'));

        obj.RenameData = mbcgui.actions.StatefulAction(@obj.onRenameData,...
            '&Rename Data...','Rename data set',[]);        
        
        % export actions
        obj.ExportWorkspace = mbcgui.actions.StatefulAction(@obj.onExportWorkspace,...
            'Export &Workspace...','Export data to workspace',xregrespath('Export_16.bmp'));
        obj.ExportExcel = mbcgui.actions.StatefulAction(@obj.onExportExcel,...
            'Export &Excel...','Export data to Excel',xregrespath('Export_16.bmp'));
        
        % test groups
        obj.DefineTests = mbcgui.actions.StatefulAction(@obj.onDefineTests,...
            'Test &Groups...','Define test groups for two-stage or point-by-point modeling',xregrespath('changeGroup.bmp'));
        
        % expression actions
        obj.Variables = mbcgui.actions.StatefulAction(@obj.onVariableEdit,...
            '&Variables...','Edit user-defined variables',xregrespath('editVariable.bmp'));
        obj.Filters = mbcgui.actions.StatefulAction(@obj.onFilterEdit,...
            '&Filters...','Edit filters',xregrespath('editConstraint.bmp'));
        obj.TestFilters = mbcgui.actions.StatefulAction(@obj.onTestFilterEdit,...
            '&Test Filters...','Edit test filters',xregrespath('sweepFilterIcon.bmp'));
        if obj.MessageService.HasExtras
            % test variables are only enabled for extras
            obj.TestVariables = mbcgui.actions.StatefulAction(@obj.onTestVariableEdit,...
                'Test V&ariables...','Edit test variables',xregrespath('sweepVariableIcon.bmp'));
        end
        obj.TestNotes = mbcgui.actions.StatefulAction(@obj.onTestNoteEdit,...
            'Test &Notes...','Edit test notes',xregrespath('sweepNoteIcon.bmp'));
        
        % expression action group
        obj.DataOperations = mbcgui.actions.ActionGroup('',...
            '&Data','Data operations',[]);
        obj.DataOperations.Actions = [obj.Variables,obj.Filters,obj.TestVariables,obj.TestFilters,obj.TestNotes];
        obj.DataOperations.MenuType = 'separate';

        % outlier actions
        obj.RemoveData = mbcgui.actions.StatefulAction(@obj.onRemoveData,...
            '&Remove Data','Remove data',[]);
        obj.RestoreData = mbcgui.actions.StatefulAction(@obj.onRestoreData,...
            'Re&store Data','Restore data',[]);
        obj.ClearOutliers = mbcgui.actions.StatefulAction(@obj.onClearOutliers,...
            '&Clear Outliers','Clear outliers',[]);
        obj.MultiSelect = mbcgui.actions.StatefulAction(@obj.onMultiSelect,...
            '&Select Multiple Outliers','Select Multiple Outliers',[]);
        % outlier action group
        obj.OutlierTools = mbcgui.actions.ActionGroup('',...
            '&Data','Data operations',[]);
        obj.OutlierTools.Actions = [obj.RemoveData,obj.RestoreData,obj.MultiSelect,obj.ClearOutliers];
        obj.OutlierTools.MenuType = 'separate';
        
        % listeners to other objects
        obj.Listeners = [event.proplistener(ms,ms.findprop('IsReadOnly'),'PostSet',@obj.onSetIsReadOnly)
            event.proplistener(ms.OutlierLine,ms.OutlierLine.findprop('OutlierIndices'),...
            'PostSet',@obj.onSelectOutliers)];

        end
        
        function createFileMenu(obj,Parent)
        %createFileMenu create file menu 
        %   createFileMenu(obj,Parent)
        
        % import group
        Group = mbcgui.actions.ActionGroup('',...
            '&Import','Import data',[]);
        Group.Actions = [obj.ImportFile,obj.ImportWorkspace,obj.ImportExcel];
        Group.MenuType = 'separate';        
        createMenuItem(Group,Parent);
        % rename menu
        hRename = createMenuItem(obj.RenameData,Parent);
        hRename.Separator = 'on';

        %export group
        Group = mbcgui.actions.ActionGroup('',...
            '&Export','Export data',[]);
        Group.Actions = [obj.ExportWorkspace,obj.ExportExcel];
        Group.MenuType = 'separate';        
        createMenuItem(Group,Parent);        
        
        end

        function createToolsMenu(obj,Parent)
        %createToolsMenu create tools menu 
        %   createToolsMenu(obj,Parent)
        
        % define test groups
        createMenuItem(obj.DefineTests,Parent);
        % expression action group
        createMenuItem(obj.DataOperations,Parent);
        %outlier action group
        hMenu = createMenuItem(obj.OutlierTools,Parent);
        % CTRL-A remove data, CTRL-Z restore data
        hMenu(1).Accelerator = 'A';
        hMenu(2).Accelerator = 'Z';
        
        end
        
        function createToolbar(obj,Parent)
        %createToolbar create toolbar
        %   createToolbar(obj,Parent)
        
        % import group
        Group = mbcgui.actions.ActionGroup('',...
            '&Import','Import data',[]);
        Group.Actions = [obj.ImportFile,obj.ImportWorkspace];
        Group.MenuType = 'separate';
        % define test groups and expressions
        G2 = mbcgui.actions.ActionGroup('',...
            '&Group','Group data',[]);
        G2.Actions = obj.DefineTests;
        G2.MenuType = 'separate';
        createToolbutton(Group,Parent);
        % define tests and expression operations in same section
        tb = createToolbutton(G2,Parent);
        tb.Separator = 'on';
        createToolbutton(obj.DataOperations,Parent);
        
        end
        
        function enable(obj)
        %enable enable actions
        %  enable(obj)

        ms = obj.MessageService;
        ssf = ms.SweepsetFilter;
        hasData = ~isempty(ms.SweepSet);
        % no data or read-only 
        
        IsEditable = hasData && ~ms.IsReadOnly;
        obj.DataOperations.Enabled = IsEditable;
        obj.DefineTests.Enabled = IsEditable;
        obj.OutlierTools.Enabled = IsEditable;
        obj.MultiSelect.Enabled = hasData;
        obj.RenameData.Enabled = ~ms.IsReadOnly;
        % can't import read-only
        obj.ImportFile.Enabled = ~ms.IsReadOnly;
        obj.ImportExcel.Enabled = ~ms.IsReadOnly;
        obj.ImportWorkspace.Enabled = ~ms.IsReadOnly;
        
        % can export read-only data
        obj.ExportWorkspace.Enabled = hasData;
        obj.ExportExcel.Enabled = hasData;
        
        if hasData && ~ms.IsReadOnly
            % disable test notes, filters and variables if one-stage data
            isOneStage = ms.isOneStage;
            obj.TestFilters.Enabled = ~isOneStage;
            obj.TestVariables.Enabled = ~isOneStage;
            obj.TestNotes.Enabled = ~isOneStage;
            
            % enable outlier actions
            obj.RemoveData.Enabled = ~isempty(ms.OutlierLine.OutlierIndices);
            obj.RestoreData.Enabled = ms.isaSSF && ~isempty( getRemovedRows(ssf) );
            obj.ClearOutliers.Enabled = ~isempty(ms.OutlierLine.OutlierIndices);
        end
        
        end
        
    end
    
    methods (Access=private)
        
        %****** Import Actions *******************************************/
        function onImportFile(obj,~,~)
        %onImportFile import file callback
        
        % Indicate this task might take a little time
        busy(obj.MessageService,'Importing data from a file...');
        [~, ~, ss] = getOriginal(obj.MessageService.SweepsetFilter);
        if ~isempty(ss)
            title = 'Select data file to import and merge';
        else
            title = 'Select data file to import';
        end
        
       [out.sweepset,OK] = xregImportDataFile(title);
        out.filename = get(out.sweepset,'filename');
        if OK && ~isempty(out.sweepset)
            % might need to merge with existing data
            mergeData(obj, out,true);
        end
        % Remove the message and the pointer
        idle(obj.MessageService)
        end
        
        function onImportWorkspace(obj,~,~)
        %onImportWorkspace import from base workspace
        
        % Indicate this task might take a little time
        busy(obj.MessageService,'Importing Data from Workspace...');
        % Find the names of the variables in the base workspace
        varNames = evalin('base','who');
        % Initialise the base structure to ensure a suitable result if there are no
        % variables in the workspace
        base = struct;
        for i = 1:length(varNames)
            % Get copies of the variables in the base workspace
            base.(varNames{i}) = evalin('base',varNames{i});
        end
        % Open the import wizard
        f = getDataEditor;
        [OK, data.sweepset] = xregImportDataStructure(base, 'Workspace', f);
        % Did the user click OK?
        if OK && ~isempty(data.sweepset)
            data.filename = 'Workspace';
            mergeData(obj, data,false)
        end
        % Remove the message and the pointer
        idle(obj.MessageService)
        
        end
        
        function onImportExcel(obj,~,~)
        %onImportExcel import from Excel
        
        busy(obj.MessageService,'Importing Data from Excel...');
        % Get the sweepset to merge with
        [~, ~, ss] = getOriginal(obj.MessageService.SweepsetFilter);
        localData.mergeSweepset = ss;
        % Get the data using the data import from Excel wizard
        f = getDataEditor;
        [OK, out] = xregwizard(f, 'Excel Data Import Wizard', {@xregImportExcelDataWiz 'cardOne'}, localData);
        % Did it all work out OK
        if OK && ~isempty(out.sweepset)
            setSweepsetfilterData(obj, out);
        end
        idle(obj.MessageService)
        end  % importExcel        
        
        function onRenameData(obj,~,~)
        %onRenameData rename data set
        
        % Get the data object - remove TSSF 
        ssf = sweepsetfilter(obj.MessageService.SweepsetFilter);
        % Ask user to change the Data Object Name
        newName = inputdlg('Data Object Name','Change Name', 1, {get(ssf, 'Label')});
        % Did the user cancel
        if ~isempty(newName) && ~isempty(newName{1})
            % Get the orginal data (could be a TSSF)
            ssf = obj.MessageService.DataObject;
            % Change the name
            ssf = set(ssf, 'Label', newName{1});
            % And flush the event queue
            obj.MessageService.flushEventQueue(ssf);
        end
        end
        
        
        %****** Export Actions *******************************************/
        function onExportExcel(obj,~,~)
        %onExportExcel export to Excel callback

        % Indicate this task might take a little time
        busy(obj.MessageService,'Exporting Data to Excel...');
        % Start the excel server
        excel = xregExcel('start');
        % Call the export function
        xregExcel('export', excel, obj.MessageService.Sweepset);
        % Remove the message and the pointer
        idle(obj.MessageService);
        end

        function onExportWorkspace(obj,~,~)
        %onExportWorkspace export data to workspace
        ms = obj.MessageService;
        if ms.isaSSF
            data = obj.MessageService.SweepsetFilter;
        else
            data = obj.MessageService.Sweepset;
        end
        xregdatagui.exportWorkspaceDialog(data,getDataEditor);
        
        end
        
        %****** Test Groups Actions **************************************/
        function onDefineTests(obj,~,~)
        %onDefineTests define test groups dialog
        
        % Indicate this task might take a little time
        ms = obj.MessageService;
        busy(ms,'Define Test Groupings...');
        % Get the current data object
        ssf = ms.SweepsetFilter;
        % Get the current defineTests arguments
        args = struct2cell(get(ssf, 'defineTests'));
        % Get a base picture of the sweepset
        ss = sweepset(setAllows(ssf, {'testfilters' 'Reorder' 'Derived'},'off'));
        % Call the modal dialog
        f = getDataEditor;
        [OK, ~, testDefinition] = xregDefineTests('Create', f, ss, args);
        % Was OK pressed?
        if OK
            % Flush the event queue with the new data
            ssf = modifyTestDefinition(ssf, testDefinition);
            ms.flushEventQueue(ssf);
            enable(obj);
        end
        % Remove the message and the pointer
        idle(ms)
        
        end        
        
        %****** Expression Actions ***************************************/
        function onVariableEdit(obj,~,~)
        %onVariableEdit edit variables
        
        edit(obj,'variables','User-defined Variables');
        end
        
        function onFilterEdit(obj,~,~)
        %onFilterEdit edit filters
        
        edit(obj,'filters','Filters')
        end        
        
        function onTestFilterEdit(obj,~,~)
        %onTestFilterEdit edit test filters
        
        edit(obj,'sweepFilters','Test Filters')
        end
        
        function onTestVariableEdit(obj,~,~)
        %onTestVariableEdit edit test variables
        
        edit(obj,'sweepVariables','Test Variables');
        end
        
        function onTestNoteEdit(obj,~,~)
        %onTestNoteEdit edit test notes
        edit(obj,'sweepNotes','Test Notes')
        end        
        
        %****** Outlier Actions ******************************************/
        function onRemoveData(obj,~,~)
        %onRemoveData remove marked outliers
        
        % Indicate this task might take a little time
        busy(obj.MessageService,'Removing marked data...');
        % Get the current data object
        ssf = obj.MessageService.SweepsetFilter;
        % Modify the filter
        ssf = addGuidFilter(ssf, obj.MessageService.OutlierLine.OutlierGuids);
        % Flush the event queue
        obj.MessageService.flushEventQueue(ssf);
        % enable restore data action
        obj.RestoreData.Enabled = ~isempty( getRemovedRows(ssf) );
        % Remove the message and the pointer
        idle(obj.MessageService);
        
        end        
        
        function onRestoreData(obj,~,~)
        %onRestoreData restore outliers
        
        % Indicate this task might take a little time
        busy(obj.MessageService,'Restoring data...');
        % Get the current data object
        ssf = obj.MessageService.SweepsetFilter;
        % Which guids should be restored
        f = getDataEditor;
        [OK, ssf] = modifyGuidFiltersDlg(ssf, f, obj.MessageService.SweepsetWithBadData);
        % Did the user press OK
        if OK
            % Flush the event queue
            obj.MessageService.flushEventQueue(ssf);
            % enable restore data action
            obj.RestoreData.Enabled = ~isempty( getRemovedRows(ssf) );
        end
        % Remove the message and the pointer
        idle(obj.MessageService)
        end        

        function onMultiSelect(obj,~,~)
        %onMultiSelect multiselect outliers
        
        multiselect(obj.MessageService.OutlierLine);
        end
        
        function onClearOutliers(obj,~,~)
        %onClearOutliers clear outliers
        
        obj.MessageService.OutlierLine.OutlierIndices = [];
        end        
        
        %****** Listener Callbacks ***************************************/
        function onSelectOutliers(obj,~,~)
        %onSelectOutliers listener callback for outlier indices changed
        ms = obj.MessageService;
        obj.RemoveData.Enabled = ~ms.IsReadOnly && ~isempty(ms.OutlierLine.OutlierIndices);
        obj.ClearOutliers.Enabled = ~isempty(ms.OutlierLine.OutlierIndices);
        end
        
        function onSetIsReadOnly(obj,~,~)
        %onSetIsReadOnly listener callback for sset IsReadOnly
        enable(obj)
        end
        
        %****** Helper methods *******************************************/
        function edit(obj,type,title)
        %edit general function to edit expressions with equationEditDlg
        
        % Indicate this task might take a little time
        msg = sprintf('Edit %s...',title);
        busy(obj.MessageService,msg);
        
        % Get the current data object
        ssf = obj.MessageService.SweepsetFilter;
        % Run the equation editor
        f = getDataEditor;
        % always use the dialog with a list
        [OK, ssf] = equationEditDlg(ssf, f, 'type', type, 'list', 'on');
        % Did the user press OK
        if OK
            % Flush the event queue
            obj.MessageService.flushEventQueue(ssf);
        else
            % Remove false events from queue
            obj.MessageService.clearEventQueue;
        end
        % Remove the message and the pointer
        idle(obj.MessageService)
        end
        
        function setSweepsetfilterData(obj, data)
        %setSweepsetfilterData define underlyting data 
        filename = data.filename;
        ss = data.sweepset;
        % Sort the variables alphabetically
        ss = sort(ss);
        % Add the filename to the sweepset
        ss = set(ss, 'FileName', filename);
        % Set the sweepset for the SweepsetFilter (This will trigger an UpdateAll in the
        % SweepsetFilter and hence all relevant events will be triggered)
        ssf = setSweepset(obj.MessageService.SweepsetFilter, ss);
        % Do we need to set any default test groupings?
        testDefinition = get(ssf, 'definetests');
        if isempty(testDefinition) || ~all( ismember( setdiff(testDefinition.variable,'#rec'), get(ssf,'name')) )
            % TO DO - Get these names from the user settings
            names = {'LOGNO' 'logno' 'TESTNUM' 'testnum'};
            [OK,loc]= ismember(get(ss,'name'),names);
            ind = loc(OK);
            if ~isempty(ind)
                % Create the test definition structure - note use of eps rather
                % than zero since we require the change to be greater than or equal
                % to the tolerance
                testDefinition = struct('variable', names{ind(1)}, 'tolerance', eps, 'reorder', false, 'testnumAlias', names{ind(1)});
            else
                testDefinition = struct('variable', '#rec', 'tolerance', 1, 'reorder', false, 'testnumAlias', '');
            end
            % Add it to the
            ssf = modifyTestDefinition(ssf, testDefinition);
        end
        % Now flush the event queue
        obj.MessageService.flushEventQueue(ssf);
        enable(obj);
        end  % setSweepsetfilterData
        
        function mergeData(obj, data,doEditVariables)
        %mergeData merge with existing data
        %    mergeData(obj, data, doEditVariables)
        
        % Get the sweepset to merge with
        [~, ~, ss] = getOriginal(obj.MessageService.SweepsetFilter);
        % sort variables
        data.sweepset = sort(data.sweepset);
        if ~isempty(ss)
            % Create the localData structure to send to the Data Merge Wizard
            localData = struct('mergeSweepset', ss,...
                'newSweepset', data.sweepset,...
                'filename', data.filename);
            
            f = getDataEditor;
            if doEditVariables
                [OK, data] = xregwizard(f, 'Data Merge Wizard', {@xregLoadDataWiz 'editvariables'}, localData);
            else
                % just open a dialog if required
                [data,OK] = xregdatagui.mergeOptions('figure', localData,f);
            end
        elseif doEditVariables
            % no merge requied but allow editing of variable names
            f = getDataEditor;
            [data.sweepset,OK] = xregdatagui.SweepsetList.dialog(data.sweepset,f);
        else 
            % no post editing (import from file with no merge)
            OK = true; 
        end
        if OK 
            % Set the new SweepsetFilter
            setSweepsetfilterData(obj, data);
        end
        end  % mergeData
        
    end
    
end


function f = getDataEditor
%getDataEditor get data editor figure handle
f = findobj(allchild(0),'Tag','dataEditor');
end