www.gusucode.com > mbcguitools 工具箱 matlab 源码程序 > mbcguitools/+mbcgui/+actions/ActionGroup.m

    classdef ActionGroup < mbcgui.actions.StatefulAction
    %mbcgui.actions.ActionGroup class
    %   mbcgui.actions.ActionGroup extends mbcgui.actions.StatefulAction.
    %
    %    mbcgui.actions.ActionGroup properties:
    %       Command - Property is of type 'MATLAB callback'
    %       Label - Property is of type 'string'
    %       Description - Property is of type 'string'
    %       IconFile - Property is of type 'string'
    %       Visible - Property is of type 'bool'
    %       Enabled - Property is of type 'bool'
    %       Actions - Property is of type 'handle vector'
    %       MenuType - Property is of type 'string'
    %
    %    mbcgui.actions.ActionGroup methods:
    %       attachToMenu - Take over a menu item for the action
    %       createToolbutton - Create a toolbar button for the action
    %       numRequiredMenus - Get the number of menus that this action requires
    %       setMenuProperties - Set menu item properties to match the action
    %       shouldSeparate - Return true if action should be separated in menus/toolbars
    
    %  Copyright 2005-2014 The MathWorks, Inc. and Ford Global Technologies, Inc.
    
    properties (AbortSet,SetObservable)
        %ACTIONS Property is of type 'handle vector'
        Actions = mbcgui.actions.StatefulAction.empty(0,1);
        %MENUTYPE Property is of type 'string'
        MenuType = 'auto';
    end
    
    methods  % constructor block
        function obj = ActionGroup(varargin)
        %ACTIONGROUP Create a new ActionGroup object
        %
        %  OBJ = ACTIONGROUP(COMMAND, LABEL, DESCRIPTION, ICONFILE) creates a new
        %  ActionGroup object for the specified COMMAND.  If any arguments are omitted
        %  the action will be created with them unset.
        %
        %  ActionGroups contain a set of associated actions.  When added to menus,
        %  ActionGroups will either created a separated set of menus or a submenu,
        %  depending on the value of the MenuType property.  If a command is
        %  defined for an ActionGroup, it will be executed when the submenu parent
        %  is opened.  The command will not be executable from a toolbar or if the
        %  ActionGroup does not create a submenu group.
        
        obj@mbcgui.actions.StatefulAction(varargin{ : }); % converted super class constructor call
        
        end  % ActionGroup
        
    end  % constructor block
    
    methods
        function set.MenuType(obj,value)
        % DataType = 'string'
        validateattributes(value,{'char'}, {'row'},'','MenuType')
        obj.MenuType = i_enforcemenutype(obj,value);
        end
        
        function set.Actions(obj,value)
        if any(value(:)==obj)
            error('Recursive assignment for ActionGroup Actions')
        end
        obj.Actions = value(:);
        end
        
    end   % set and get functions
    
    methods  % public methods
        %----------------------------------------
        function attachToMenu(obj, hMenu)
        %ATTACHTOMENU Take over a menu item for the action
        %
        %  ATTACHTOMENU(OBJ, HMENU) sets the properties of HMENU to reflect the
        %  action OBJ.
        
        if length(hMenu)~=obj.numRequiredMenus
            error(message('mbc:mbcmultiview:ActionGroup:InvalidArgument', obj.numRequiredMenus));
        end
        
        if obj.pShouldMakeSubMenus
            hThisMenu = hMenu(1);
            if length(hMenu)>1
                childMenus = hMenu(2:end);
                set(childMenus, 'Parent', hThisMenu);
            else
                childMenus = [];
            end
            
            set(hThisMenu, 'Callback', @obj.onExecute);
            obj.setMenuProperties(hThisMenu);
            if strcmpi(obj.MenuType, 'separatesubmenu')
                set(hThisMenu, 'Separator', 'on');
            end
            
            % Attach a listener to keep menu state matching the action
            StateList = event.listener(obj, 'StateChanged', @(h,evt) obj.onResetMenu(hThisMenu));
            set(hThisMenu, 'UserData', StateList);
        else
            childMenus = hMenu;
            if strcmpi(obj.MenuType, 'separate') && ~isempty(childMenus)
                % Need to set a separator if there is a preceding menu.
                hFirstMenu = childMenus(1);
                hPrecedingMenu = iGetMenuBefore(hFirstMenu);
                if ~isempty(hPrecedingMenu)
                    set(hFirstMenu, 'Separator', 'on');
                end
            end
        end
        
        % Iterate over subactions
        A = obj.Actions;
        nUsed = 0;
        for n=1:length(A)
            nMenus = A(n).numRequiredMenus;
            A(n).attachToMenu(childMenus((nUsed+1):(nUsed+nMenus)));
            
            if length(childMenus)<nUsed && (A(n).shouldSeparate ...
                    || n>1 && A(n-1).shouldSeparate )
                set(childMenus((nUsed+1)), 'Separator', 'on');
            end
            
            nUsed = nUsed+nMenus;
        end
        end  % attachToMenu
        
        function attachToWorkfow(obj,wf)
        A = obj.Actions;
        nUsed = 0;
        for n=1:length(A)
            nMenus = A(n).numRequiredMenus;
            A(n).attachToWorkfow(wf((nUsed+1):(nUsed+nMenus)));
            
            if length(wf)<nUsed && (A(n).shouldSeparate ...
                    || n>1 && A(n-1).shouldSeparate )
                set(wf((nUsed+1)), 'Separator', 'on');
            end
            
            nUsed = nUsed+nMenus;
        end        
        end
        
        %----------------------------------------
        function hButton = createToolbutton(obj, hParent)
        %CREATETOOLBUTTON Create a toolbar button for the action
        %
        %  HBUTTON = CREATETOOLBUTTON(OBJ, HPARENT) creates toolbar buttons for each
        %  action that is contained in the ActionGroup.
        
        % Iterate over subactions
        A = obj.Actions;
        hButton = [];
        for n = 1:length(A)
            newbtns = A(n).createToolbutton(hParent);
            if A(n).shouldSeparate ...
                    || n>1 && A(n-1).shouldSeparate
                set(newbtns(1), 'Separator', 'on');
            end
            hButton = [hButton, newbtns];
        end
        
        end  % createToolbutton
        
        %----------------------------------------
        function N = numRequiredMenus(obj)
        %NUMREQUIREDMENUS Get the number of menus that this action requires
        %
        %  N = NUMREQUIREDMENUS(OBJ) returns an integer that is the number of menus
        %  that an action will make when createMenuItem is called.
        
        % Iterate over all contained actions and count the menus required for each
        N = 0;
        A = obj.Actions;
        for n = 1:length(A)
            N = N + A(n).numRequiredMenus;
        end
        
        % Add one if a menu is needed for self
        if obj.pShouldMakeSubMenus
            N = N+1;
        end
        
        end  % numRequiredMenus
        
        
        %----------------------------------------
        function setMenuProperties(obj, hMenu)
        %SETMENUPROPERTIES Set menu item properties to match the action
        %
        %  SETMENUPROPERTIES(OBJ, HMENU) is called when the menu item's properties
        %  need to be set up to match the action's state.
        
        hP = get(hMenu, 'Parent');
        if ~isempty(hP)
            hCh = get(hP, 'Children');
            hCh = findobj( hCh, 'flat', 'Type', 'uimenu' );
            hCh(hCh==hMenu) = [];
            OtherLabels = get(hCh, {'Label'});
            lbl = obj.pUniqueMnemonic(obj.Label, OtherLabels);
        else
            lbl = obj.Label;
        end
        
        set(hMenu, ...
            'Enable', mbconoff(~isempty(obj.Actions) && obj.Enabled), ...
            'Visible', mbconoff(obj.Visible), ...
            'Checked', 'off', ...
            'Label', lbl);
        
        end  % setMenuProperties
        
        %----------------------------------------
        function ret = shouldSeparate(obj)
        %SHOULDSEPARATE Return true if action should be separated in menus/toolbars
        %
        %  RET = SHOULDSEPARATE(OBJ) returns true if the action should have
        %  separators placed before and after it.
        
        ret = ~obj.pShouldMakeSubMenus;
        
        end  % shouldSeparate
        
    end  % public methods
    
    methods (Access=protected) % protected methods
        %----------------------------------------
        function ret = pShouldMakeSubMenus(obj)
        %PSHOULDMAKESUBMENUS Return true if submenus should be made
        %
        %  RET = PSHOULDMAKESUBMENUS(OBJ) returns true of this group should
        %  consist of a menu that contains other sub-menus, and false if the
        %  contained Actions should be added as a separated group.
        
        ret = strcmp(obj.MenuType, 'submenu') ...
            || strcmp(obj.MenuType, 'separatesubmenu') ...
            || (strcmp(obj.MenuType, 'auto') && length(obj.Actions)>3);
        
        end  % pShouldMakeSubMenus
        
        %----------------------------------------
        function onExceute(obj,~,~)
        obj.execute;
        end  % i_execute
        
        %----------------------------------------
        function onResetMenu(obj, hMenu)
        obj.setMenuProperties(hMenu);
        end  % i_resetmenu
        
        function onSendState(obj,~,~)
        set(obj.Actions,'Enabled',obj.Enabled)
        onSendState@mbcgui.actions.StatefulAction(obj);
        
        end
    end % protected methods
    
    
end  % classdef

function val = i_enforcemenutype(obj, val) %#ok<INUSL>
% Check for valid settings of property
if ~any(strcmpi(val, {'auto', 'submenu', 'separate', 'separatesubmenu', 'none'}))
    error(message('mbc:mbcmultiview:ActionGroup:InvalidPropertyValue'));
else
    val = lower(val);
end
end  % i_enforcemenutype

function hPreceding = iGetMenuBefore(hSrc)
hPreceding = [];
hP = get(hSrc, 'Parent');
if isgraphics(hP, 'uimenu') || isgraphics(hP, 'uicontextmenu')
    hAll = get(hP, 'Children');
    hPreceding = findobj(hAll, 'Position', get(hSrc, 'Position')-1);
end
end  % iGetMenuBefore