www.gusucode.com > robotsimulink 工具箱 matlab源码程序 > robotsimulink/robotslros/+robotics/+slros/+internal/+dlg/ArraySizeManager.m
classdef ArraySizeManager < handle %This class is for internal use only. It may be removed in the future. % ArraySizeManager opens a DDG dialog that lets the user inspect % and modify the maximum sizes of variable-length arrays, for all ROS % messages used in a Simulink model. Once the user accepts the % changes, the information is written back to the model and the model % is dirtied, *but it is not saved*. % % Sample use: % mgr = robotics.slros.internal.dlg.ArraySizeManager(gcs); % mgr.openDialog % % See also: bus.VarlenArraySizeStore % Copyright 2014 The MathWorks, Inc. properties(SetAccess=private) Dialog ModelName NumMsgTypesInModel = 0 NumVarLenMsgTypesInModel = 0 end properties(Access=private) VarlenSizeStore MsgVarLenInfo Position = [200 200] % x,y position in pixels SelectedMsgTypeIndex MsgTypeList TruncateAction end methods function obj = ArraySizeManager(modelname) modelname = bdroot(modelname); obj.VarlenSizeStore = robotics.slros.internal.bus.VarlenArraySizeStore(modelname); obj.ModelName = modelname; % Below, we get the maximum length info from % Util.getAllMessageInfoMapForModel, which consults the % current bus, but use VarlenArraySizeStore to distinguish % bewteen customized vs. default values. This can cause a % problem if the bus definitions in the workspace are % out-of-sync for any reason (e.g., if the user has modified % the bus definitions using BUSEDITOR). % % The cleanest solution is to c;ear the buses in the workspace % upon entry; they will be recreated in the call to % Util.getAllMessageInfoMapForModel with the stored % information. (This clearing only needs to be done for the % current model but it is safe to clear buses for all models, % and also simpler). robotics.slros.internal.bus.Util.clearSLBusesInBaseWorkspace(); % Get transitive closure for all messages in model allMsgsMap = robotics.slros.internal.bus.Util.getAllMessageInfoMapForModel(modelname); % Now run over all the messages allMsgsTypesInModel = keys(allMsgsMap); obj.NumMsgTypesInModel = numel(allMsgsTypesInModel); obj.MsgVarLenInfo = containers.Map; for i=1:numel(allMsgsTypesInModel) msgType = allMsgsTypesInModel{i}; msgMapInfo = allMsgsMap(msgType); msginfo = robotics.slros.internal.bus.VarLenArrayInfo.extractFromMsgMapInfo(msgMapInfo); if numel(msginfo.ArrayProps) > 0 % This message has variable-length arrays msgtypeInfo = obj.VarlenSizeStore.getMsgTypeInfo(msgType); if ~isempty(msgtypeInfo) % preexisting custom lengths for model isUserSpecified = true; else % use default values msgtypeInfo = msginfo; isUserSpecified = false; end obj.MsgVarLenInfo(msgType) = ... struct('MsgTypeInfo', msgtypeInfo, 'UserSpecified', isUserSpecified, 'IsDirty', false); end obj.TruncateAction.CurrentState = obj.VarlenSizeStore.getTruncateAction(); obj.TruncateAction.IsDirty = false; end obj.MsgTypeList = sort(keys(obj.MsgVarLenInfo)); obj.NumVarLenMsgTypesInModel = numel(obj.MsgTypeList); obj.SelectedMsgTypeIndex = 1; obj.setPositionWrtModelWindow(); % openDialog() will put up error dialog if there are no % messages in the model end function setPositionWrtModelWindow(obj) % There is no way to set the size of the DDG Window (using MCOS) % without specifying the location as well. So set the location % relative to the model window pos = get_param(obj.ModelName, 'Location'); % [x y width height] (in pixels) % position the dialog 1/10 of the way from top-left corner obj.Position = round([pos(1)+(pos(3)/10) pos(2)+(pos(4)/10)]); end function set.Position(obj, val) % the X,Y position for a block can be obtained using get(gcbh,'Position') validateattributes(val, {'numeric'}, {'size', [1 2], 'real', 'positive', 'integer'}); obj.Position = val; end function openDialog(obj) if obj.NumMsgTypesInModel <= 0 || obj.NumVarLenMsgTypesInModel <= 0 if obj.NumMsgTypesInModel <= 0 msgStr = message('robotics:robotslros:arraysizemgr:NoROSMessages', obj.ModelName).getString; else msgStr = message('robotics:robotslros:arraysizemgr:NoVarLenROSMessages', obj.ModelName).getString; end dlgTitle = message('robotics:robotslros:arraysizemgr:DialogTitle').getString; dlgProvider = DAStudio.DialogProvider; % obj.Dialog = dlgProvider.errordlg(msgStr, dlgTitle, true); % non-blocking obj.Dialog = dlgProvider.msgbox(msgStr, dlgTitle, true); % non-blocking else obj.SelectedMsgTypeIndex = 1; obj.Dialog = DAStudio.Dialog(obj); obj.Dialog.refresh; end end function tableChangedCallback(obj, dlg, row, col, newValue) % Invoked on any changes to the the table msgdata = obj.MsgVarLenInfo( obj.MsgTypeList{obj.SelectedMsgTypeIndex} ); msginfo = msgdata.MsgTypeInfo; oldValue = msginfo.getMaxLength(row+1); newnum = max(round(str2double(newValue)), 0); % row and col are zero-based if isnan(newnum) || ~(newnum > 0) || ~isreal(newnum) strValue = num2str(oldValue); % reset back to old value else % even if new value is valid, may need to modify it % (e.g., due to rounding) msginfo.setMaxLength(row+1, newnum); strValue = num2str(newnum); msgdata.MsgTypeInfo = msginfo; msgdata.IsDirty = true; obj.MsgVarLenInfo( obj.MsgTypeList{obj.SelectedMsgTypeIndex} ) = msgdata; end dlg.setTableItemValue('rostable', row, col, strValue); dlg.refresh; end function msgTypeChangedCallback(obj, dlg, tag, value) %#ok<INUSL> % Invoked when user selects another message type from listbox % value is the index of the user selection (zero-index). try if isnumeric(value) && isscalar(value) obj.SelectedMsgTypeIndex = value+1; msgtype = obj.MsgTypeList{obj.SelectedMsgTypeIndex}; msgdata = obj.MsgVarLenInfo(msgtype); if msgdata.UserSpecified dlg.setWidgetValue('modifydefaults', 0); else dlg.setWidgetValue('modifydefaults', 1); end end catch ME disp(ME.getReport); end dlg.refresh; end function useDefaultsCheckboxCallback(obj, dlg, tag, value) %#ok<INUSL> % Invoked when user changes the "use defaults" dropdown % <value> is the index of the selection % 0 = use default, 1 = specify custom try msgtype = obj.MsgTypeList{obj.SelectedMsgTypeIndex}; msgdata = obj.MsgVarLenInfo(msgtype); wasUserSpecified = msgdata.UserSpecified; msgdata.UserSpecified = (value == 0); if wasUserSpecified && ~msgdata.UserSpecified % transitioning from user-specified to default obj.VarlenSizeStore.applyDefaultMaxLengths(msgdata.MsgTypeInfo); msgdata.IsDirty = true; end obj.MsgVarLenInfo(msgtype) = msgdata; catch ME disp(ME.getReport); end dlg.refresh; end function truncateActionDropdownCallback(obj, dlg, tag, value) %#ok<INUSL> % Invoked when user changes the truncate action dropdown. % <value> is the index of the selection % 0 = Truncate w/ warning, 1 = Truncate silently try if value == 0 newState = ... robotics.slros.internal.bus.VarLenArrayTruncationAction.EmitWarning; else newState = ... robotics.slros.internal.bus.VarLenArrayTruncationAction.DoNothing; end if obj.TruncateAction.CurrentState ~= newState obj.TruncateAction.CurrentState = newState; obj.TruncateAction.IsDirty = true; end catch ME disp(ME.getReport); end dlg.refresh; end function dlgClose(obj, closeaction) % closeaction is 'ok' if user clicked OK % 'cancel' if user clicked cancel or closed window if ~isvalid(obj.VarlenSizeStore) % if the user closed the model, then obj.VarlenSizeStore % would have deleted itself % warn the user & exit warning(message('robotics:robotslros:arraysizemgr:ModelAlreadyClosed', obj.ModelName)); return; end if ~strcmpi(closeaction, 'ok') % Nothing to do if user clicked cancel or closed window return; end try modelDirty = false; msgTypes = keys(obj.MsgVarLenInfo); for i=1:numel(msgTypes) msgdata = obj.MsgVarLenInfo(msgTypes{i}); if msgdata.IsDirty modelDirty = true; if msgdata.UserSpecified obj.VarlenSizeStore.setMsgTypeInfo(msgTypes{i}, msgdata.MsgTypeInfo); else obj.VarlenSizeStore.resetMsgTypeInfo(msgTypes{i}); end end end if obj.TruncateAction.IsDirty modelDirty = true; obj.VarlenSizeStore.setTruncateAction(obj.TruncateAction.CurrentState); end if modelDirty obj.VarlenSizeStore.updateModel(); end catch ME disp(ME.getReport); % Absorb all errors. If they are propagated back to % DDG, this causes MATLAB to crash, (Can't convert to % warnings are not as they are not displayed either). end end function dlgstruct = getDialogSchema(obj) assert(obj.NumMsgTypesInModel > 0 && obj.NumVarLenMsgTypesInModel > 0); if isempty(obj.SelectedMsgTypeIndex) obj.SelectedMsgTypeIndex = 1; end helptext.Name = message('robotics:robotslros:arraysizemgr:DialogInfo').getString; helptext.Type = 'text'; helptext.WordWrap = true; helptext.Tag = 'rosmsghelp'; modelname.Name = message('robotics:robotslros:arraysizemgr:ModelName', obj.ModelName).getString(); modelname.Type = 'text'; modelname.WordWrap = false; modelname.Bold = true; modelname.RowSpan = [1 1]; modelname.ColSpan = [1 1]; modelname.Tag = 'modelname'; modelInfoContainer.Type = 'panel'; modelInfoContainer.Name = ''; modelInfoContainer.LayoutGrid = [1 2]; % [numrows numcolumns] modelInfoContainer.ColStretch = [1 3]; % [numrows numcolumns] modelInfoContainer.Items = {modelname}; modelInfoContainer.Flat = true; modelInfoContainer.Visible = 1; truncateAction.Name = message('robotics:robotslros:arraysizemgr:TruncateActionPrompt').getString(); truncateAction.Type = 'combobox'; truncateAction.NameLocation = 1; truncateAction.Entries = {... message('robotics:robotslros:arraysizemgr:TruncateActionWarn').getString() message('robotics:robotslros:arraysizemgr:TruncateActionNone').getString() }; if obj.TruncateAction.CurrentState == ... robotics.slros.internal.bus.VarLenArrayTruncationAction.EmitWarning truncateAction.Value = 0; else truncateAction.Value = 1; end truncateAction.Tag = 'truncateaction'; truncateAction.ObjectMethod = 'truncateActionDropdownCallback'; % call method on UDD source object truncateAction.MethodArgs = {'%dialog', '%tag', '%value'}; % '%handle ' is implicit as first arg truncateAction.ArgDataTypes = {'handle', 'string', 'mxArray'}; truncateAction.Alignment = 1; % top-left availableMsgs.Name = message('robotics:robotslros:arraysizemgr:MessageTypesPrompt').getString(); availableMsgs.Type = 'listbox'; availableMsgs.RowSpan = [1 2]; availableMsgs.ColSpan = [1 1]; availableMsgs.MultiSelect = false; availableMsgs.Entries = obj.MsgVarLenInfo.keys(); availableMsgs.Alignment = 2; availableMsgs.Value = obj.SelectedMsgTypeIndex-1; % convert to zero-based index availableMsgs.ObjectMethod = 'msgTypeChangedCallback'; % call method on UDD source object availableMsgs.MethodArgs = {'%dialog', '%tag', '%value'}; % '%handle ' is implicit as first arg availableMsgs.ArgDataTypes = {'handle', 'string', 'mxarray'}; availableMsgs.Tag = 'availablemsgs'; msgdata = obj.MsgVarLenInfo( obj.MsgTypeList{obj.SelectedMsgTypeIndex} ); msginfo = msgdata.MsgTypeInfo; numVarLenArraysInMsg = numel(msginfo.ArrayProps); tabledata = cell(numVarLenArraysInMsg, 3); for k=1:numel(msginfo.ArrayProps) if msgdata.UserSpecified backgroundcolor = [255 255 255]; else backgroundcolor = [230 230 230]; end propinfo = msginfo.ArrayProps(k); tabledata{k,1}.Type = 'edit'; tabledata{k,1}.Value = propinfo.PropertyName; tabledata{k,1}.Enabled = false; tabledata{k,1}.BackgroundColor = backgroundcolor; tabledata{k,2}.Type = 'edit'; tabledata{k,2}.Value = propinfo.DataType; tabledata{k,2}.Enabled = false; tabledata{k,2}.BackgroundColor = backgroundcolor; tabledata{k,3}.Type = 'edit'; tabledata{k,3}.Value = sprintf('%d', propinfo.MaxLength); tabledata{k,3}.BackgroundColor = backgroundcolor; tabledata{k,3}.Enabled = msgdata.UserSpecified; end mytable.Type = 'table'; mytable.Name = ''; mytable.Size = [numVarLenArraysInMsg 3]; % colums: variable name, type, max length (editable) mytable.Data = tabledata; mytable.Grid = 1; if msgdata.UserSpecified mytable.ReadOnlyColumns = [0 1]; else mytable.ReadOnlyColumns = [0 1 2]; end mytable.HeaderVisibility = [0 1]; mytable.Editable = 1; mytable.ColHeader = { message('robotics:robotslros:arraysizemgr:ColumnHdrPropName').getString() ... message('robotics:robotslros:arraysizemgr:ColumnHdrPropType').getString() ... message('robotics:robotslros:arraysizemgr:ColumnHdrMaxItems').getString() }; % mytable.ColumnCharacterWidth = [15 9 11 11 10]; mytable.ValueChangedCallback = @obj.tableChangedCallback; mytable.Tag = 'rostable'; mytable.RowSpan = [2 2]; mytable.ColSpan = [3 4]; % enabling this also turns makes column headers boldface % mytable.SelectionBehavior = 'row'; useDefaultsCheckbox.Name = message('robotics:robotslros:arraysizemgr:MsgActionUseDefault').getString(); useDefaultsCheckbox.Type = 'checkbox'; useDefaultsCheckbox.RowSpan = [1 1]; useDefaultsCheckbox.ColSpan = [3 4]; if msgdata.UserSpecified useDefaultsCheckbox.Value = 0; else useDefaultsCheckbox.Value = 1; end useDefaultsCheckbox.Tag = 'modifydefaults'; useDefaultsCheckbox.ObjectMethod = 'useDefaultsCheckboxCallback'; % call method on UDD source object useDefaultsCheckbox.MethodArgs = {'%dialog', '%tag', '%value'}; % '%handle ' is implicit as first arg useDefaultsCheckbox.ArgDataTypes = {'handle', 'string', 'mxArray'}; tablecontainer.Name = ''; tablecontainer.Type = 'group'; tablecontainer.LayoutGrid = [2 4]; % tablecontainer.ColStretch = [0 1 1 1 1 1 1]; tablecontainer.Items = {availableMsgs, useDefaultsCheckbox, mytable}; tablecontainer.Visible = 1; tablecontainer.Alignment = 0; % container mycontainer.Type = 'panel'; mycontainer.Name = ''; mycontainer.Items = {modelInfoContainer, helptext, truncateAction, tablecontainer}; mycontainer.Visible = 1; % Main dialog dlgstruct.DialogTitle = message('robotics:robotslros:arraysizemgr:DialogTitle').getString; dlgstruct.HelpMethod = 'robotics.slros.internal.helpview'; dlgstruct.HelpArgs = {'rosManageSizesDlg'}; % doc topic id dlgstruct.CloseMethod = 'dlgClose'; dlgstruct.CloseMethodArgs = {'%closeaction'}; dlgstruct.CloseMethodArgsDT = {'string'}; % dlgstruct.Sticky = true; % make this dialog modal wrt to other DDG dialogs (doesn't block MATLAB command line) % Buttons to show on dialog (these are options to pass to DDG, % not the final strings, so there is no need to use message % catalog) dlgstruct.StandaloneButtonSet = ... {'Ok', 'Cancel', 'Help'}; % also available: 'Revert', 'Apply' dlgstruct.Items = {mycontainer}; dlgstruct.Geometry = [obj.Position 750 450]; % xpos ypos width height dlgstruct.DialogTag = 'slros_arraysizemgr'; end end methods(Static) function launch(modelname) % Convenience function for opening the dialog mgr = robotics.slros.internal.dlg.ArraySizeManager(modelname); mgr.openDialog(); end end end