classdef GUI < handle properties % vertical grid Grid2 = []; % horizontal grid Grid1 = []; %output grid Grid0 = []; main_fig = []; frame = []; fig = []; scroll_v = []; edit_tog = []; save_pb = []; pvs_pb = []; close_pb = []; save_ext_pb = []; check_pb = []; input_pb = []; settings_pb = []; function_name_control = []; function_name_text = []; function_inputs_text = []; function_inputs_control = []; edit = 1; initialized = 0; block_handle = []; settings = []; % height of header where buttons and text is header_height = 100; % window size fig_height = 600; fig_width = 800; % space inbetween buttons in header pb_offset = 5; % width of push buttons in header pb_width = 80; % height of push buttons in header pb_height = 40; % width of text boxes text_width = 250; name_label = []; input_label = []; Data = []; PVS = []; pvs_checked = []; mode = []; end methods %% GUI % constructor % inputs: % h:double - handle to Tabular block in model % outputs; % obj:GUI - object that is created function obj = GUI(h,mode) obj.block_handle = h; obj.mode = mode; end function [] = setData(obj,Data) obj.Data = Data; obj.Grid0 = Data.Grid0; obj.Grid1 = Data.Grid1; obj.Grid2 = Data.Grid2; obj.pvs_checked = Data.checked; obj.function_name_text = Data.function_name; obj.function_inputs_text = Data.function_inputs; obj.settings = Data.settings; end %% init % initialize the gui % inputs: % obj:GUI - GUI object % outputs; % none function [] = init(obj) % create the handles for the gui objects if obj.mode == 1 name = get_param(obj.block_handle,'Name'); elseif obj.mode == 0 name = 'Table Tool'; end % main figure obj.fig = figure('units','pixels',... 'position',[0 0 obj.fig_width obj.fig_height],... 'menubar','none',... 'name','Table Tool',... 'numbertitle','off',... 'resize','on',... 'Name',name,... 'CloseRequestFcn',@(src,event)close_fig(obj,src,event),... 'ResizeFcn',@(src,event)resize_fig(obj,src,event)); % edit button obj.edit_tog = uicontrol('style','toggle',... 'units','pix',... 'string','Edit',... 'HorizontalAlign','left',... 'Parent',obj.fig,... 'Value',obj.edit,... 'callback',@(src,event)edit_tog_call(obj,src,event)); % Save button obj.save_pb = uicontrol('style','push',... 'units','pix',... 'string','Save',... 'HorizontalAlign','left',... 'Parent',obj.fig,... 'callback',@(src,event)save_call(obj,src,event)); % Close button obj.close_pb = uicontrol('style','push',... 'units','pix',... 'string','Close',... 'HorizontalAlign','left',... 'Parent',obj.fig,... 'callback',@(src,event)close_fig(obj,src,event)); % Save external button obj.save_ext_pb = uicontrol('style','push',... 'units','pix',... 'string','Save Ext',... 'HorizontalAlign','left',... 'Parent',obj.fig,... 'callback',@(src,event)save_ext_call(obj,src,event)); % PVS button obj.pvs_pb = uicontrol('style','push',... 'units','pix',... 'string','PVS',... 'HorizontalAlign','left',... 'Parent',obj.fig,... 'callback',@(src,event)pvs_ext_call(obj,src,event)); % Check button obj.check_pb = uicontrol('style','push',... 'units','pix',... 'string','Check',... 'HorizontalAlign','left',... 'Parent',obj.fig,... 'callback',@(src,event)check_call(obj,src,event)); % Input/Output button obj.input_pb = uicontrol('style','push',... 'units','pix',... 'string','Ports',... 'HorizontalAlign','left',... 'Parent',obj.fig,... 'callback',@(src,event)input_call(obj,src,event)); % Input/Output button obj.settings_pb = uicontrol('style','push',... 'units','pix',... 'string','Settings',... 'HorizontalAlign','left',... 'Parent',obj.fig,... 'callback',@(src,event)settings_call(obj,src,event)); % Expression Name Label obj.name_label = uicontrol('style','text',... 'string','Expression Name',... 'HorizontalAlign','right',... 'BackgroundColor',get(obj.fig,'Color')); % Expression Name Edit box obj.function_name_control = uicontrol('style','edit',... 'units','pix',... 'Parent',obj.fig,... 'HorizontalAlign','center',... 'FontWeight','bold',... 'FontSize',12,... 'Max',2.0,... 'BackgroundColor',[1 1 1]); % input list label obj.input_label = uicontrol('style','text',... 'string','Inputs',... 'HorizontalAlign','right',... 'BackgroundColor',get(obj.fig,'Color')); % input list edit box obj.function_inputs_control = uicontrol('style','edit',... 'units','pix',... 'Parent',obj.fig,... 'HorizontalAlign','center',... 'FontWeight','bold',... 'Max',2.0,... 'FontSize',12,... 'BackgroundColor',[1 1 1]); % load the function name and inputs if (~isempty(obj.function_name_text)) set(obj.function_name_control,'String',obj.function_name_text); end if (~isempty(obj.function_inputs_text)) set(obj.function_inputs_control,'String',obj.function_inputs_text); end % Set up Menu filemenu = uimenu('Label','File'); editmenu = uimenu('Label','Edit'); pvsmenu = uimenu('Label','PVS'); uimenu(filemenu,'Label','New','Accelerator','n','Callback',@(src,event)new_call(obj,src,event)); uimenu(filemenu,'Label','Open...'); uimenu(filemenu,'Label','Save to Block','Separator','on','Accelerator','s','Callback',@(src,event)save_call(obj,src,event)); uimenu(filemenu,'Label','Save to M-File','Callback',@(src,event)save_ext_call(obj,src,event)); uimenu(filemenu,'Label','Close','Accelerator','w','Separator','on','Callback',@(src,event)close_fig(obj,src,event)); uimenu(editmenu,'Label','Show edit controls','Checked','on'); uimenu(pvsmenu,'Label','Typecheck','Accelerator','t','Callback',@(src,event)pvs_ext_call(obj,src,event)); uimenu(pvsmenu,'Label','PVS Settings','Callback',@(src,event)settings_call(obj,src,event)); obj.set_command_pos; obj.reset_wh(); obj.draw_allgrids(1); obj.setPBenable; obj.settings = Settings(); if isfield(obj.Data.settings,'set') obj.settings.setvalues(obj.Data.settings); else obj.settings.init(); end obj.update_Statusbar; obj.PVS = PVS_checker(obj,obj.settings); obj.initialized = 1; obj.Data.open = 1; obj.Data.fig = obj.fig; end function [] = update_Statusbar(object) warning off MATLAB:HandleGraphics:ObsoletedProperty:JavaFrame % statusbar depends on JavaFrame which may be obsolete in % future versions of Matlab, can still use in old versions try if (object.pvs_checked == 0) sb = statusbar(object.fig, 'Status: Not Typechecked'); set(sb.TextPanel,'Foreground',[1,0,0]); elseif (object.pvs_checked == 1) sb = statusbar(object.fig, 'Status: Typechecked'); set(sb.TextPanel,'Foreground',[0,1,0]); end catch exception end end function [] = new_call(object,src,event) TableToolMatlab end %% set_command_pos % sets the location of all the command buttons, labels and edit % boxes, places objects at the top of the figure which it % determines by looking at the height of the figure handle % inputs: % obj:GUI - current GUI object % outputs; % none function [] = set_command_pos(obj) figpos = get(obj.fig,'Position'); % figure out the height of the figure l_fig_height = figpos(4); set(obj.edit_tog,'Position',[obj.pb_offset l_fig_height-obj.pb_offset-obj.pb_height obj.pb_width obj.pb_height]) set(obj.save_pb,'Position',[obj.pb_offset*2+obj.pb_width,l_fig_height-obj.pb_offset-obj.pb_height,obj.pb_width,obj.pb_height]) set(obj.close_pb,'Position',[obj.pb_offset*3+obj.pb_width*2,l_fig_height-obj.pb_offset-obj.pb_height,obj.pb_width,obj.pb_height]) set(obj.save_ext_pb,'Position',[obj.pb_offset*4+obj.pb_width*3,l_fig_height-obj.pb_offset-obj.pb_height,obj.pb_width,obj.pb_height]) set(obj.check_pb,'Position',[obj.pb_offset*5+obj.pb_width*4,l_fig_height-obj.pb_offset-obj.pb_height,obj.pb_width,obj.pb_height]) set(obj.pvs_pb,'Position',[obj.pb_offset*6+obj.pb_width*5,l_fig_height-obj.pb_offset-obj.pb_height,obj.pb_width,obj.pb_height]) set(obj.input_pb,'Position',[obj.pb_offset*7+obj.pb_width*6,l_fig_height-obj.pb_offset-obj.pb_height,obj.pb_width,obj.pb_height]) set(obj.settings_pb,'Position',[obj.pb_offset*8+obj.pb_width*7,l_fig_height-obj.pb_offset-obj.pb_height,obj.pb_width,obj.pb_height]) set(obj.name_label,'Position',[obj.pb_offset l_fig_height-obj.pb_offset*3-obj.pb_height-obj.pb_height obj.pb_width obj.pb_height]); set(obj.function_name_control,'Position',[obj.pb_offset*2+obj.pb_width l_fig_height-obj.pb_offset*3-obj.pb_height-obj.pb_height obj.text_width obj.pb_height]); set(obj.input_label,'Position',[obj.pb_offset*2+obj.pb_width+obj.text_width l_fig_height-obj.pb_offset*3-obj.pb_height-obj.pb_height obj.pb_width obj.pb_height]); set(obj.function_inputs_control,'Position',[obj.pb_offset*3+obj.pb_width*2+obj.text_width l_fig_height-obj.pb_offset*3-obj.pb_height-obj.pb_height obj.text_width obj.pb_height]); end %% resize_fig % callback function that is called whenever the main figure is % resized. Ensures that the commands remain at the top of the % screen and the grid below them. % inputs: % object:GUI - current GUI object % src:double - source of the callback calling % event:eventdata - event that triggered the callback % outputs; % none function [] = resize_fig(object,src,event) if(object.initialized == 1) object.draw_allgrids(0); object.set_command_pos; end end %% save_ext_call % callback function that is called whenever the save ext button % is pressed. This function will generate the code for the table % and output it to an external embedded matlab file which can % then be used in other functions. Filename of new file will be % the same as the expression name, currently this function will % overwrite an existing file of the same name. % inputs: % object:GUI - current GUI object % src:double - source of the callback calling % event:eventdata - event that triggered the callback % outputs; % none function [] = save_ext_call(object,src,event) % file name will be expression_name.m fileid = fopen([get(object.function_name_control,'String') '.m'],'w'); code = []; code = sprintf('function output = %s(%s)\n%s\noutput=0;\n',get(object.function_name_control,'String'),get(object.function_inputs_control,'String'),'%%#eml'); code = [code object.generate_code(object.Grid1,object.Grid2,0)]; fprintf(fileid,code); % save an extra file called expression_name.data which % contains a binary representation of the current gui object. filename = [get(object.function_name_control,'String') '.data']; %save(filename,'object'); object.save_settings; object.Data.save; fclose(fileid); end %% function [] = input_call(object,src,event) %da = DAStudio.ModelExplorer %dataddg modelddg(object.block_handle) %da.show; %da = DAStudio.DiagnosticViewer('test'); end %% function [] = settings_call(object,src,event) object.settings.show; end %% pvs_ext_call function [] = pvs_ext_call(object,src,event) error = object.check_call; if (~error) check = object.PVS.pvs_check; if (check == 1) msgbox('table is valid') end object.pvs_checked = check; object.update_Statusbar; end end %% msgbox_scroll function [] = msgbox_scroll(obj,msg) fig = figure('units','pixels',... 'position',[0 0 700 500],... 'menubar','none',... 'name','PVS Report',... 'numbertitle','off'); uicontrol('style','edit',... 'units','pix',... 'Parent',fig,... 'HorizontalAlign','center',... 'FontWeight','bold',... 'FontSize',12,... 'Max',2.0,... 'HorizontalAlign','left',... 'String',msg,... 'Position',[1 1 698 498],... 'BackgroundColor',[1 1 1]); end %% save_call % callback function that is called whenever the save button is % pressed. This function will generate code and store it in the % embedded matlab block, it will then generate the corresponding % input and output ports and connect them to the embedded matlab % block. % inputs: % object:GUI - current GUI object % src:double - source of the callback calling % event:eventdata - event that triggered the callback % outputs; % none function [] = save_call(object,src,event) if object.mode == 0 model = gcs; %make sure we are not looking at the library model %if (strcmp(model,'eml_lib') || strcmp(model,'simulink')) %create a new model found = any(ismember(find_system('type', 'block_diagram'),'Table')) if found == 0 new_system('Table','Model') end model = 'Table' %end open_system(model); load_system('TableLibrary'); new_block = add_block('TableLibrary/Tabular Expression',[model '/' get(object.function_name_control,'String')]); set_param(new_block,'UserData',object.Data) set_param(new_block, 'UserDataPersistent', 'on'); object.mode = 1; object.block_handle = new_block; object.save_call([],[]); elseif object.mode == 1 load_system('simulink') % generate the code code = []; %generate input list parsed_input = object.parse_inputs(get(object.function_inputs_control,'string')); input = []; for i= 1:size(parsed_input,2) input = [input char(parsed_input{i}(1)) ',']; end code = sprintf('function output = %s(%s)\n',get(object.function_name_control,'String'),input); % simulink forces you to have an output for all execution paths % since it can't compute completness and disjointness we need % to have a default value, if the user builds the table % properly the default value will never be used. since % different types might have a different default value, the % temporary solution is just to use one of the outputs from our % table, we will use the first cell because it is guaranteed to % be filled in, regardless of the dimensionality of the table. code = [code sprintf('output=%s;\n',get(object.Grid0.Cells(1).result,'String'))]; code = [code object.generate_code(object.Grid1,object.Grid2,0)]; fprintf('%s',code); % unlink the block from the library, this is necessary if % we % want to change the subsystem of the block. set_param(object.block_handle,'LinkStatus','none') % determine if the name already exists in the model if (~strcmp(get(object.block_handle,'Name'),get(object.function_name_control,'String'))) try set_param(object.block_handle,'Name',get(object.function_name_control,'String')); catch exception msgbox(exception.message); end end % embedded matlab code block store code in stateflow states so % we need to get the root hande S = sfroot; % get the path of the code block code_block = sprintf('%s/code',getfullname(object.block_handle)); % determine if code block already exists code_blocks = find_system(getfullname(object.block_handle),'BlockType','SubSystem','Name','code'); % if the code block does not already exists we need to create a % new one if (isempty(code_blocks)) add_block('simulink/User-Defined Functions/Embedded MATLAB Function',code_block); end % find the state of the code block and update it to the new % code myState = S.find('-isa','Stateflow.EMChart', '-and', 'Path', code_block); % find which one we want to edit if (~isempty(myState)) myState.Script = sprintf('%s',code); end % delete any lines that are unconnected and one end or both % code from % http://www.mathworks.com/matlabcentral/fileexchange/12352-delete-unconnected-lines % Copyright (c) 2009, Per-Anders Ekström % delete all the lines lines = find_system( getfullname(object.block_handle), ... 'LookUnderMasks', 'all', ... 'FindAll', 'on', ... 'Type', 'line' ) ; % for each line, call delete_recursive if handle still exist for i=1:length( lines ) if ishandle( lines( i ) ) object.delete_recursive( lines( i ) ) end end % end copyright % we need to determine which of the inports and outports we % need to create and delete. Whenever we delete a port anything % connected with this port is unconnected, other blocks, scopes % etc. We would like to avoid this if possible because it can % be quite annoying. % First loop through all the inport blocks, if there does not % exists an inport in the code block of the same name then % delete the inport block inports = find_system(getfullname(object.block_handle),'BlockType','Inport'); for i=1:size(inports,1) found = 0; in_handles=find_system(code_block, 'SearchDepth',1,'FindAll','On','FollowLinks','On','LookUnderMasks','All','BlockType','Inport'); for j=1:size(in_handles,1) if strcmp(get_param(inports(i),'Name'),get_param(in_handles(j),'Name')) found = 1; end end if (~found) % old inport no longer exists delete_block(inports(i)); end end % now we loop through all the inports in the code block if % there is an inport block of the same name then connect them, % else create a new inport block and connect them in_handles=find_system(code_block, 'SearchDepth',1,'FindAll','On','FollowLinks','On','LookUnderMasks','All','BlockType','Inport'); for j = 1:size(in_handles,1) found = 0; inports = find_system(getfullname(object.block_handle),'BlockType','Inport'); for i = 1:size(inports,1) if strcmp(get_param(inports(i),'Name'),get_param(in_handles(j),'Name')) found = 1; % draw the line new_port_num = sprintf('%s/1',get_param(in_handles(j),'Name')); dest_port = sprintf('%s/%d','code',j); try add_line(getfullname(object.block_handle),new_port_num,dest_port); end end end if (~found) new_port = sprintf('%s/%s',getfullname(object.block_handle),get_param(in_handles(j),'Name')); add_block('simulink/Sources/In1',new_port) new_port_num = sprintf('%s/1',get_param(in_handles(j),'Name')); dest_port = sprintf('%s/%d','code',j); % sometimes line will be created automatically try add_line(getfullname(object.block_handle),new_port_num,dest_port); end end end % Next we do the same thing with the outputs outports = find_system(getfullname(object.block_handle),'BlockType','Outport'); for i=1:size(outports,1) found = 0; out_handles=find_system(code_block, 'SearchDepth',1,'FindAll','On','FollowLinks','On','LookUnderMasks','All','BlockType','Outport'); for j=1:size(out_handles,1) if strcmp(get_param(outports(i),'Name'),get_param(out_handles(j),'Name')) found = 1; end end if (~found) % old inport no longer exists delete_block(outports(i)); end end out_handles=find_system(code_block, 'SearchDepth',1,'FindAll','On','FollowLinks','On','LookUnderMasks','All','BlockType','Outport'); for j = 1:size(out_handles,1) found = 0; outports = find_system(getfullname(object.block_handle),'BlockType','Outport'); for i = 1:size(outports,1) if strcmp(get_param(outports(i),'Name'),get_param(out_handles(j),'Name')) found = 1; % draw the line new_port_num = sprintf('%s/1',get_param(out_handles(j),'Name')); dest_port = sprintf('%s/%d','code',j); try add_line(getfullname(object.block_handle),dest_port,new_port_num); end end end if (~found) new_port = sprintf('%s/%s',getfullname(object.block_handle),get_param(out_handles(j),'Name')); add_block('simulink/Sinks/Out1',new_port) new_port_num = sprintf('%s/1',get_param(out_handles(j),'Name')); dest_port = sprintf('%s/%d','code',j); try add_line(getfullname(object.block_handle),dest_port,new_port_num); end end end % delete any lines that are unconnected and one end or both % again sometimes extra lines are created % code from % http://www.mathworks.com/matlabcentral/fileexchange/12352-delete-unconnected-lines % Copyright (c) 2009, Per-Anders Ekström % delete all the lines lines = find_system( getfullname(object.block_handle), ... 'LookUnderMasks', 'all', ... 'FindAll', 'on', ... 'Type', 'line' ) ; % for each line, call delete_recursive if handle still exist for i=1:length( lines ) if ishandle( lines( i ) ) object.delete_recursive( lines( i ) ) end end % end copyright % save the text from each of the conditions and results text % boxes. save_conditions(object,object.Grid2); save_conditions(object,object.Grid1); save_results(object,object.Grid0); % save the function name and input text from the respective % edit boxes. object.function_name_text = get(object.function_name_control,'String'); object.function_inputs_text = get(object.function_inputs_control,'String'); end end %% delete_recursive % delete any lines that are unconnected and one end or both % code from % http://www.mathworks.com/matlabcentral/fileexchange/12352-delete-unconnected-lines % Copyright (c) 2009, Per-Anders Ekström function delete_recursive( obj, line ) %DELETE_RECURSIVE( LINE ) Delete line if: % 1) do not have any source-block % 2) do not have any line-children AND no destination-block % otherwise go recursively through all eventual line-children if get( line, 'SrcPortHandle' ) < 0 delete_line( line ) ; return end LineChildren = get( line, 'LineChildren' ) ; if isempty( LineChildren ) if get( line, 'DstPortHandle' ) < 0 delete_line( line ) ; end else for i=1:length( LineChildren ) obj.delete_recursive( LineChildren( i ) ) end end end % end copyright %% check_call % callback function for check pushbutton. compiles a message of % the errors that were detected in each of the grids. outputs the % message to users via a msgbox. % inputs: % object:GUI - current GUI object % src:double - source of the callback calling % event:eventdata - event that triggered the callback % outputs; % none function error = check_call(object,src,event) error = 0; msg = object.check_inputs; if (isempty(msg)) set(object.function_inputs_control,'BackgroundColor',[1 1 1]) msg = object.check_grid_condition(object.Grid2); msg = [msg object.check_grid_condition(object.Grid1)]; msg = [msg object.check_grid_result(object.Grid0)]; else set(object.function_inputs_control,'BackgroundColor',[0.92 0.65 0.65]) end if ~isempty(msg) msgbox(msg); error = 1; end end %% check_grid % check_grid will recursively loop through all the cells of a % grid and call the check_matlab_syntax function for each of the % strings in the cells. if there is an error the cell will % change colours to alert the user where the problem is. % inputs: % object:GUI - current GUI object % grid:Grid - Grid object being checked % outputs; % none function msg = check_grid_condition(object,grid) msg = []; for i = 1:size(grid.cells,2) error = ''; string = get(grid.cells(i).cond,'String'); if ( strcmp(string,'') || isempty(string)) && i == 1 && isempty(grid.parent_grid) && size(grid.cells,2) == 1 break end % if the string is empty indicating that the table is 1 % dimensional or the string is "otherwise" skip the syntax % checking. if(~isempty(string) && ~strcmp(string,'otherwise')) error = object.check_matlab_syntax_condition(char(string),0); end if isempty(error) if (strcmp(string,'') || isempty(string)) error = 'Cell is empty'; end end if ~isempty(error) % generate the message string msg = [msg sprintf('\n')]; msg = [msg 'Condtion -> ' char(string) sprintf('\n')]; msg = [msg error sprintf('\n')]; % set tooltip string of cell to error msg set(grid.cells(i).cond,'TooltipString',error) % change background colour grid.cells(i).flag_cell(1); else % reset tooltip and colour if no error found set(grid.cells(i).cond,'TooltipString','') grid.cells(i).flag_cell(0); %if (~isempty(grid.cells(i).color)) % set(grid.cells(i).cond,'BackgroundColor',grid.cells(i).color) %else % set(grid.cells(i).cond,'BackgroundColor',[1 1 1]) %end end % recurse through subgrid if(~isempty(grid.cells(i).subgrid)) msg = [msg object.check_grid_condition(grid.cells(i).subgrid)]; end end end %% check_grid_result % Similar to above function check_grid_result, will loop through % the cells of the output grid, unline check_grid, does not need to % recurse. % inputs: % object:GUI - current GUI object % grid:RGrid - RGrid object to be checked % outputs; % none function msg = check_grid_result(object,grid) msg = []; for i = 1:size(grid.Cells,2) error = ''; string = get(grid.Cells(i).result,'String'); error = object.check_matlab_syntax_condition(char(string),1); if isempty(error) if (strcmp(string,'') || isempty(string)) error = 'Cell is empty'; end end if ~isempty(error) msg = [msg sprintf('\n')]; msg = [msg 'Result -> ' char(string) sprintf('\n')]; msg = [msg error sprintf('\n')]; set(grid.Cells(i).result,'TooltipString',error) grid.Cells(i).flag_cell(1) else set(grid.Cells(i).result,'TooltipString','') grid.Cells(i).flag_cell(0) end end end %% check_matlab_syntax % this function will check that a string is valid matlab syntax % for the context that it is in. we need to build up the % expression which involves initiallizeing the input variables to % a dummy value and wraping an if statement around conditionals % inputs: % object:GUI - current GUI object % string:string - string to be checked % result:boolean - false if the string is a conditoin true if % the string is an output statement % outputs; % error:string - string containing the error message, empty if % there is no error function error = check_matlab_syntax_condition(obj,string,result) % split the list of inputs to get inputs seperatly parsed_input = obj.parse_inputs(get(obj.function_inputs_control,'string')); %inputs = get(obj.function_inputs_control,'String'); %inputs = regexp(inputs,',','split'); check_string = []; % initialize inputs to zero % functions are assumed to be total, so 0 is just for % convienence for i=1:size(parsed_input,2) % set to zero check_string = [check_string sprintf('%s=0;\n',char(parsed_input{i}(1)))]; end if ~result % the string is a condition we need to evaulate it as it % will be used in the code, as in order for an if statement % to be valid the condition must evaulate to a numeric % value not a structure or something else. we need to have % the 1 in there as a dummy output, which is necesary for % an if statement to be valid in matlab. check_string = [check_string 'if (' string sprintf(')\n1;\nend')]; else % the string is an output statement we can just evaulate the % string on its own. check_string = [check_string string ';' sprintf('\n')]; end % attempt to evaluate the string catch the error. try eval(check_string); error = []; catch exception error = exception.message; % attempt to make one of the common errors slightly less % cryptic. if(strcmp(exception.identifier,'MATLAB:m_invalid_lhs_of_assignment')) error = [error sprintf('\nTo check equality use ==')]; end end end %NEEDS TO BE CLEANED UP! %% generate_code % this function will generate a string that represents the % embedded matlab code. code will have proper syntax % indentations. % inputs: % obj:GUI - current GUI object % g1:Grid - the grid on the top % g2:Grid - the grid on the left % depth:integer - the depth of the current call, incremented % every recursive call, initial value should be 0. used for % indenting the code. % outputs; % error:string - string containing the error message, empty if % there is no error function code = generate_code(obj,g1,g2,depth) space = ''; % space is equal to 2 * depth number of ' ' for i=1:depth space = [space sprintf(' ')]; end code = []; g1cond1 = get(g1.cells(1).cond,'String'); g2cond1 = get(g2.cells(1).cond,'String'); % 1D horizontal table if (isempty(g2cond1) && ~isempty(g1cond1)) found = 0; elsecell = []; for j=1:size(g1.cells,2) g1cond = get(g1.cells(j).cond,'String'); % condition string of otherwise corresponds to an else % statement, we allow this statement to be in any order % in the cells of the grid, so we need to find where it % is, if it exists. if (strcmp(g1cond,'otherwise')) elsecell = g1.cells(j); found = 1; continue end if (j == 1 || (j==2 && found == 1)) code = [code sprintf('%sif(%s)\n',space,strtrim(char(get(g1.cells(j).cond,'String'))))]; else code = [code sprintf('%selseif(%s)\n',space,strtrim(char(get(g1.cells(j).cond,'String'))))]; end cell = obj.Grid0.search_return(g1.cells(j),g2.cells(1)); if(~isempty(cell)) depth = depth + 1; space = []; for k=1:depth space = [space sprintf(' ')]; end code = [code sprintf('%soutput = %s;\n',space,strtrim(char(get(cell.result,'String'))))]; depth = depth - 1; space = []; for k=1:depth space = [space sprintf(' ')]; end else depth = depth + 1; space = []; for k=1:depth space = [space sprintf(' ')]; end code = [code sprintf('%smissing!!!\n',space)]; depth = depth - 1; space = []; for k=1:depth space = [space sprintf(' ')]; end end end if (~isempty(elsecell)) code = [code sprintf('%selse\n',space)]; cell = obj.Grid0.search_return(elsecell,g2.cells(1)); if(~isempty(cell)) depth = depth + 1; space = []; for k=1:depth space = [space sprintf(' ')]; end code = [code sprintf('%soutput = %s;\n',space,strtrim(char(get(cell.result,'String'))))]; depth = depth - 1; space = []; for k=1:depth space = [space sprintf(' ')]; end else depth = depth + 1; space = []; for k=1:depth space = [space sprintf(' ')]; end code = [code sprintf('%smissing!!!\n',space)]; depth = depth - 1; space = []; for k=1:depth space = [space sprintf(' ')]; end end end code = [code sprintf('%send\n',space)]; %either 2D table, 1D vertical table or empty table else found = 0; elsecell = []; for i=1:size(g2.cells,2) g2cond = get(g2.cells(i).cond,'String'); if (strcmp(g2cond,'otherwise')) elsecell = g2.cells(i); elseindex = i; found = 1; continue end if (i == 1 || (i == 2 && found == 1)) code = [code sprintf('%sif(%s)\n',space,strtrim(char(get(g2.cells(i).cond,'String'))))]; else code = [code sprintf('%selseif(%s)\n',space,strtrim(char(get(g2.cells(i).cond,'String'))))]; end if (~isempty(g2.cells(i).subgrid)) code = [code obj.generate_code(g1,g2.cells(i).subgrid,depth+1)]; else depth = depth + 1; space = []; for k=1:depth space = [space sprintf(' ')]; end found1 = 0; elsecell1 = []; for j=1:size(g1.cells,2) g1cond = get(g1.cells(j).cond,'String'); if (strcmp(g1cond,'otherwise')) elsecell1 = g1.cells(j); found1 = 1; continue end if(~isempty(g1.cells(j).subgrid)) %%TODO if add more dimensions to grid1 else if (~isempty(g1cond1)) if (j == 1 || (j==2 && found1 == 1)) code = [code sprintf('%sif(%s)\n',space,strtrim(char(get(g1.cells(j).cond,'String'))))]; else code = [code sprintf('%selseif(%s)\n',space,strtrim(char(get(g1.cells(j).cond,'String'))))]; end end cell = obj.Grid0.search_return(g1.cells(j),g2.cells(i)) if(~isempty(cell)) depth = depth + 1; space = []; for k=1:depth space = [space sprintf(' ')]; end code = [code sprintf('%soutput = %s;\n',space,strtrim(char(get(cell.result,'String'))))]; depth = depth - 1; space = []; for k=1:depth space = [space sprintf(' ')]; end else depth = depth + 1; space = []; for k=1:depth space = [space sprintf(' ')]; end code = [code sprintf('%smissing!!!\n',space)]; depth = depth - 1; space = []; for k=1:depth space = [space sprintf(' ')]; end end end end if(~isempty(g1cond1)) if(size(g1.cells,2)>0) if (~isempty(elsecell1)) code = [code sprintf('%selse\n',space)]; cell = obj.Grid0.search_return(elsecell1,g2.cells(i)) if(~isempty(cell)) depth = depth + 1; space = []; for k=1:depth space = [space sprintf(' ')]; end code = [code sprintf('%soutput = %s;\n',space,strtrim(char(get(cell.result,'String'))))]; depth = depth - 1; space = []; for k=1:depth space = [space sprintf(' ')]; end else depth = depth + 1; space = []; for k=1:depth space = [space sprintf(' ')]; end code = [code sprintf('%smissing!!!\n',space)]; depth = depth - 1; space = []; for k=1:depth space = [space sprintf(' ')]; end end end code = [code sprintf('%send\n',space)]; end end depth = depth - 1; space = []; for k=1:depth space = [space sprintf(' ')]; end end end if(~isempty(elsecell)) code = [code sprintf('%selse\n',space)]; if (~isempty(g2.cells(elseindex).subgrid)) code = [code obj.generate_code(g1,g2.cells(elseindex).subgrid,depth+1)]; else depth = depth + 1; space = []; for k=1:depth space = [space sprintf(' ')]; end found1 = 0; for j=1:size(g1.cells,2) g1cond = get(g1.cells(j).cond,'String'); if (strcmp(g1cond,'otherwise')) elsecell1 = g1.cells(j); found1 = 1; continue end if(~isempty(g1.cells(j).subgrid)) %%TODO if add more dimensions to grid1 else if (~isempty(g1cond1)) if (j == 1 || (j==2 && found1 == 1)) code = [code sprintf('%sif(%s)\n',space,strtrim(char(get(g1.cells(j).cond,'String'))))]; else code = [code sprintf('%selseif(%s)\n',space,strtrim(char(get(g1.cells(j).cond,'String'))))]; end end cell = obj.Grid0.search_return(g1.cells(j),g2.cells(elseindex)); if(~isempty(cell)) depth = depth + 1; space = []; for k=1:depth space = [space sprintf(' ')]; end code = [code sprintf('%soutput = %s;\n',space,strtrim(char(get(cell.result,'String'))))] depth = depth - 1; space = []; for k=1:depth space = [space sprintf(' ')]; end else depth = depth + 1; space = []; for k=1:depth space = [space sprintf(' ')]; end code = [code sprintf('%smissing!!!\n',space)]; depth = depth - 1; space = []; for k=1:depth space = [space sprintf(' ')]; end end end end if(~isempty(g1cond1)) if(size(g1.cells,2)>0) if (~isempty(elsecell1)) code = [code sprintf('%selse\n',space)]; cell = obj.Grid0.search_return(elsecell1,g2.cells(elseindex)); if(~isempty(cell)) depth = depth + 1; space = []; for k=1:depth space = [space sprintf(' ')]; end code = [code sprintf('%soutput = %s;\n',space,strtrim(char(get(cell.result,'String'))))]; depth = depth - 1; space = []; for k=1:depth space = [space sprintf(' ')]; end else depth = depth + 1; space = []; for k=1:depth space = [space sprintf(' ')]; end code = [code sprintf('%smissing!!!\n',space)]; depth = depth - 1; space = []; for k=1:depth space = [space sprintf(' ')]; end end end code = [code sprintf('%send\n',space)]; end end depth = depth - 1; space = []; for k=1:depth space = [space sprintf(' ')]; end end end code = [code sprintf('%send\n',space)]; end end %% save_conditions % this function is used to save the strings that are in each of the % condition edit boxes string field. We do this because when we % want to reopen the gui we want to repopulate these fields but the % handles to the edit boxes will disappear when we close the gui, % so we need to save the strings into variables in each of the Cell % objects. function is recursive. % inputs: % obj:GUI - current GUI object % grid:Grid - grid to be saved. % outputs; % none function [] = save_conditions(obj,grid) for i=1:size(grid.cells,2) if ~isempty(grid.cells(i).subgrid) obj.save_conditions(grid.cells(i).subgrid); end grid.cells(i).cond_text = get(grid.cells(i).cond,'String'); end end %% save_results % Save as save_conditions but for the results grid, since not a % recursive datatype we do not need to recurse. % inputs: % obj:GUI - current GUI object % grid:RGrid - results grid to be saved. % outputs; % none function [] = save_results(obj,grid) for i=1:size(grid.Cells,2) grid.Cells(i).result_text = get(grid.Cells(i).result,'String'); end end %% close_fig % callback function that is called whenever the close button is % pressed. % inputs: % object - current GUI object % src - source of the callback calling % event - event that triggered the callback % outputs; % none function [] = close_fig(object,src,event) % save the relavent edit boxes to respective variables save_conditions(object,object.Grid2); save_conditions(object,object.Grid1); save_results(object,object.Grid0); % depricated object.function_name_text = get(object.function_name_control,'String'); object.function_inputs_text = get(object.function_inputs_control,'String'); % new storage object.Data.function_name = get(object.function_name_control,'String'); object.Data.function_inputs = get(object.function_inputs_control,'String'); object.Data.checked = object.pvs_checked; object.Data.open = 0; object.Data.fig = []; set.set = 1; set.inputs = object.settings.pvs_includes; set.count = object.settings.counter_trials; set.range = object.settings.counter_range; object.Data.settings = set; % delete the figure, closing the window. delete(object.fig); % remove reference to the old figure. object.fig = []; end function [] = save_settings(object) set.set = 1; set.inputs = object.settings.pvs_includes; set.count = object.settings.counter_trials; set.range = object.settings.counter_range; object.Data.settings = set; object.Data.function_name = get(object.function_name_control,'String'); object.Data.function_inputs = get(object.function_inputs_control,'String'); end %% edit_tog_call % callback function for when the edit button is clicked. when % edit is toggled we want to redraw the table with the edit % button visible or not visible % inputs: % object - current GUI object % src - source of the callback calling % event - event that triggered the callback % outputs; % none function [] = edit_tog_call(object,src,event) % save the value of the edit toggle value = get(src,'Value'); object.edit = value; % reset the widths and heights of the grid then redraw all the % grids. object.reset_wh; object.draw_allgrids(0); end %% set_grid % allows accessing objects to set the grid variables to the % inputed objects % inputs: % obj:GUI - current GUI object % grid2:Grid - Grid on the left % grid1:Grid - Grid on the top % grid0:RGrid - Results grid % outputs; % none function [] = set_grid(obj,grid2,grid1,grid0) obj.Grid2 = grid2; obj.Grid1 = grid1; obj.Grid0 = grid0; end %% draw_grid2 % Draws the grid on the left onto the figure. % inputs: % obj:GUI - current GUI object % grid:Grid - grid to be drawn, should be grid on left. % load:boolean - 0 if grid is being refreshed, 1 if grid is being % loaded for the firs time. % outputs; % none function [] = draw_grid2(obj,grid,load) if (~isempty(grid)) % generate a random pastel colour for the background, each % grid has a different colour to help with readability grid_color = [0.9+0.1*rand(1) 0.9+0.1*rand(1) 0.9+0.1*rand(1)]; for i=1:size(grid.cells,2) % check if the grid is the root grid if (~isempty(grid.parent_cell)) % grid is not the root grid location is derived % from its parent. parent_pos = grid.parent_cell.get_pos; if i == 1 % if we are at the first cell, location is the % same as the parent but shifted to the right % by one cell pos(3) = grid.cells(i).width * grid.cells(i).condition_text_width; pos(4) = grid.cells(i).height * grid.cells(i).condition_text_height; pos(1) = parent_pos(1) + parent_pos(3); pos(2) = parent_pos(2) + parent_pos(4) - pos(4); else % if we are not at the first cell, location is % the same as the previous cell but we shift % down by one cell prev_pos = grid.cells(i-1).get_pos; pos(3) = grid.cells(i).width * grid.cells(i).condition_text_width; pos(4) = grid.cells(i).height * grid.cells(i).condition_text_height; pos(1) = parent_pos(1) + parent_pos(3); pos(2) = prev_pos(2) - pos(4); grid_color = grid.cells(i-1).color; end else % grid is the root grid. % position of the first cell is based on % condition_text_x, and condition_text_y, as well % as the height of the figure and header. figpos = get(obj.fig,'position'); pos = [grid.cells(i).condition_text_x figpos(4)-obj.header_height-grid.cells(i).condition_text_y grid.cells(i).condition_text_width grid.cells(i).condition_text_height]; if i == 1 pos(1) = pos(1); pos(4) = grid.cells(i).height * grid.cells(i).condition_text_height; pos(2) = pos(2)-pos(4)-grid.cells(i).condition_text_height-grid.cells(i).condition_text_offset; pos(3) = grid.cells(i).width * grid.cells(i).condition_text_width; pos(4) = grid.cells(i).height * grid.cells(i).condition_text_height; else prev_pos = grid.cells(i-1).get_pos; pos(3) = grid.cells(i).width * grid.cells(i).condition_text_width; pos(4) = grid.cells(i).height * grid.cells(i).condition_text_height; pos(1) = pos(1); pos(2) = prev_pos(2) - pos(4); grid_color = grid.cells(i-1).color; end end % if the edit box does not exist, ie. it is just being % created or we are loading the figure if (isempty(grid.cells(i).cond) || load == 1) % create the new edit box grid.cells(i).cond = obj.create_std_text(obj.fig,pos); % if cell is the first in the grid use the new % colour, else take the colour of the previous cell % in the grid. if(i==1) set(grid.cells(i).cond,'BackgroundColor',grid_color); else set(grid.cells(i).cond,'BackgroundColor',get(grid.cells(i-1).cond,'BackgroundColor')) end grid.cells(i).color = grid_color; % if we are loading the cell set the string of the % edit box to be the value that we saved as a % result of calling save_conditions if (load == 1) set(grid.cells(i).cond,'String',grid.cells(i).cond_text); end else % if the edit box is already created change is % position to newly determined position. grid.cells(i).set_pos(pos); end % determine if we want to draw the new subgrid buttons, % which is located to the right of each of the leaf % cells. if(grid.cells(i).pb_flag == 1 && obj.edit == 1) pb_pos = pos; pb_pos(1) = pos(1)+pos(3); pb_pos(3) = grid.cells(i).grid_push_width; if (ishghandle(grid.cells(i).grid_pb)) set(grid.cells(i).grid_pb,'Visible','on'); end grid.cells(i).set_pb(obj.fig,pb_pos) set(grid.cells(i).grid_pb,'UserData',obj); elseif(grid.cells(i).pb_flag == 1 && obj.edit ~= 1) if (ishghandle(grid.cells(i).grid_pb)) set(grid.cells(i).grid_pb,'Visible','off') end end delete_pb_pos = []; % detemine if we want to draw the new cell buttons, % which are located at the botton of the set of cells. if (i == size(grid.cells,2) && obj.edit == 1) new_pb_pos = pos; new_pb_pos(4) = grid.cells(i).condition_text_height/2; new_pb_pos(3) = pos(3)/2; new_pb_pos(2) = pos(2) - new_pb_pos(4); if (ishghandle(grid.new_cell_pb)) set(grid.new_cell_pb,'Visible','on'); end grid.set_pb(obj.fig,new_pb_pos); set(grid.new_cell_pb,'userdata',obj); delete_pb_pos = new_pb_pos; delete_pb_pos(1) = new_pb_pos(1) + new_pb_pos(3); if (ishghandle(grid.delete_cell_pb)) set(grid.delete_cell_pb,'Visible','on'); end grid.set_delete_pb(obj.fig,delete_pb_pos); set(grid.delete_cell_pb,'userdata',obj); elseif (i == size(grid.cells,2) && obj.edit ~= 1) if (ishghandle(grid.new_cell_pb)) set(grid.new_cell_pb,'Visible','off'); end if (ishghandle(grid.delete_cell_pb)) set(grid.delete_cell_pb,'Visible','off'); end end % recursively draw the subgrid of the cell if it % exists. obj.draw_grid2(grid.cells(i).subgrid,load); end end end %% reset_wh % function will call the set_widths and set_heights methods on % the left grid in the table. The height and width values are % used to draw the grid. % inputs: % obj:GUI - current GUI object % outputs; % none function [] = reset_wh(obj) width = obj.Grid2.max_width(1); obj.Grid2.set_widths(width); obj.Grid2.set_heights(obj.edit); end %% draw_grid1 % Draws the grid on the top onto the figure. the current % assumption is that the top grid does not have any subgrids, % inputs: % obj:GUI - current GUI object % grid:Grid - grid to be drawn, should be grid on top. % load:boolean - 0 if grid is being refreshed, 1 if grid is being % loaded for the firs time. % outputs; % none function [] = draw_grid1(obj,grid,load) % assumption grid 1 has no subgrids pos = []; for i=1:size(grid.cells,2) % if we are in edit mode we need to shift over the cells to % accomidate for the new grid buttons in the left grid. if(obj.edit == 1) pb_space = grid.cells(i).grid_push_width; else pb_space = 0; end figpos = get(obj.fig,'position'); % check if grid2 is empty, currently grid 2 will never be % empty, may change in future though. if (isempty(obj.Grid2)) pos = [grid.cells(i).condition_text_x grid.cells(i).condition_text_y grid.cells(i).condition_text_width grid.cells(i).condition_text_height]; else pos = [grid.cells(i).condition_text_x+grid.cells(i).condition_text_width*obj.Grid2.max_width(1) figpos(4)-obj.header_height-grid.cells(i).condition_text_y-grid.cells(i).condition_text_height grid.cells(i).condition_text_width grid.cells(i).condition_text_height]; end % set the x coordinate of the cell pos(1) = pos(1) + (i-1)*grid.cells(i).condition_text_width + grid.cells(i).condition_text_offset + pb_space; % if the edit box does not exist create it, if it does % adjust it's position. if (isempty(grid.cells(i).cond) || load == 1) grid.cells(i).cond = obj.create_std_text(obj.fig,pos); if (load == 1) set(grid.cells(i).cond,'String',grid.cells(i).cond_text); end else grid.cells(i).set_pos(pos); end end % if we are in edit mode, draw the new and delete buttons at % the right of the last cell if( obj.edit == 1) pos(1) = pos(1) + pos(3); pos(2) = pos(2) + 20; pos(4) = 20; pos(3) = 60; grid.set_pb(obj.fig,pos); pos(2) = pos(2) - 20; grid.set_delete_pb(obj.fig,pos); set(grid.delete_cell_pb,'userdata',obj); set(grid.new_cell_pb,'userdata',obj); else delete(grid.new_cell_pb) grid.new_cell_pb = []; delete(grid.delete_cell_pb) grid.delete_cell_pb = []; end if obj.edit ==1 || load == 1 fig_pos = get(obj.fig,'position'); if(pos(1)+pos(3)>fig_pos(3)) fig_pos(3) = pos(1)+pos(3); set(obj.fig,'position',fig_pos); elseif (pos(1) + pos(3)obj.fig_width) fig_pos(3) = pos(1)+pos(3); set(obj.fig,'position',fig_pos); end end end %% draw_grid0 % function will draw the output grid onto the figure % inputs: % obj:GUI - current GUI object % grid:Grid - grid to be drawn, should be grid on left. % load:boolean - 0 if grid is being refreshed, 1 if grid is being % loaded for the firs time. % outputs; % none function [] = draw_grid0(obj,grid,load) % ensure that the results grid is up to date. grid.refresh(); for i=1:size(grid.Cells,2) % get the x coordinate from the associated top grid cell, % get the y coordinate from the associated right grid cell. pos1 = grid.Cells(i).Cell1.get_pos; pos2 = grid.Cells(i).Cell2.get_pos; pos = [0 0 0 0]; pos(1) = pos1(1); pos(2) = pos2(2); pos(3) = pos1(3); pos(4) = pos2(4); if isempty(grid.Cells(i).result) || load == 1 grid.Cells(i).result = obj.create_std_text(obj.fig,pos); % if we are loading the cell, try to restore the text % that was saved using save_results. if load == 1 set(grid.Cells(i).result,'String',grid.Cells(i).result_text); end else set(grid.Cells(i).result,'position',pos); end end end %% draw_allgrids % function will call the draw methods for each of the 3 grids. % inputs: % obj:GUI - current GUI object % load:boolean - 0 if grid is being refreshed, 1 if grid is being % loaded for the firs time. % outputs; % none function [] = draw_allgrids(obj,load) obj.draw_grid2(obj.Grid2,load); obj.draw_grid1(obj.Grid1,load); obj.draw_grid0(obj.Grid0,load); end %% evaluate_counter function [] = evaluate_counter(obj,counter) problem = obj.evaluate_counter_grid(obj.Grid2, counter); if(~problem) obj.evaluate_counter_grid(obj.Grid1, counter) end end %% evaluate_counter_grid % counter has form 'x=0\ny=2' function problem = evaluate_counter_grid(obj,grid,counter) % split the list of inputs to get inputs seperatly inputs = get(obj.function_inputs_control,'String'); inputs = regexp(inputs,',','split'); check_string = []; % keep track of the number of condtitions that evaulate to true true_conds = 0; sub_problem = 0; problem = 0; empty_cell = 0; % initialize inputs to zero % functions are assumed to be total, so 0 is just for % convienence for i=1:size(inputs,2) % set to zero %need to parse the types out of the inputs inputi = regexp(char(inputs(i)),'\w*','match','once'); check_string = [check_string sprintf('%s=0;\n',char(inputi))]; end check_string = [check_string counter sprintf('\n')]; for i=1:size(grid.cells,2) condition_string = get(grid.cells(i).cond,'string'); if(~isempty(condition_string)) eval([check_string 'result =(' char(condition_string) ');']) if(result == 0) grid.cells(i).flag_cell(1); else true_conds = true_conds + 1; grid.cells(i).flag_cell(2); end else empty_cell = 1; end end if (true_conds == 1) for i=1:size(grid.cells,2) condition_string = get(grid.cells(i).cond,'string'); if(~isempty(condition_string)) eval([check_string 'result =(' char(condition_string) ');']) if(result == 0) grid.cells(i).flag_cell(1); else if (~isempty(grid.cells(i).subgrid)) sub_problem = obj.evaluate_counter_grid(grid.cells(i).subgrid,counter); end grid.cells(i).flag_cell(2); end else empty_cell = 1; end end end if (true_conds ~= 1 || sub_problem == 1) problem = 1; end if (empty_cell) problem = 0; end end %% create_std_text % function will create an edit text box used for conditons and % results. we want these to be consistent so its easier for it to % be in one function. % inputs: % obj:GUI - current GUI object % Parent:double - handle to parent figure % position:[double double double double] - position to place edit % box in. % outputs; % control:double - handle pointing to newly created uicontrol function control = create_std_text(obj, Parent, position) control = uicontrol('style','edit',... 'Parent',Parent,... 'units','pix',... 'position',position,... 'min',0,'max',1,... % This is the key to multiline edits. 'string',{''},... 'Max',2.0,... 'Clipping','on',... 'fontweight','bold',... 'BackgroundColor',[1 1 1],... 'horizontalalign','center',... 'KeyPressFcn',@(src,event)textbox_callback(obj,src,event),... 'fontsize',11); end %% function [] = textbox_callback(object,src,event) object.pvs_checked = 0; object.update_Statusbar end %% clone % creates copy of object function copy = clone(obj,handle) % assume that dialog is closed copy = GUI(handle); copy.function_name_text = get(handle,'Name'); copy.function_inputs_text = obj.function_inputs_text; copy.Grid2 = Grid(2,[]); copy.Grid1 = Grid(1,[]); copy.Grid0 = RGrid(copy.Grid1,copy.Grid2); copy.Grid1.set_rGrid(copy.Grid0); copy.Grid2.set_rGrid(copy.Grid0); obj.Grid2.clone(copy.Grid2,obj.Grid2.grid_index,[]) obj.Grid1.clone(copy.Grid1,obj.Grid1.grid_index,[]) obj.copy_results(copy) end function [] = copy_results(obj,dest) for i=1:size(dest.Grid0.Cells,2) for j=1:size(obj.Grid0.Cells,2) if (strcmp(obj.Grid0.Cells(j).Cell1.cond_text,dest.Grid0.Cells(i).Cell1.cond_text) && strcmp(obj.Grid0.Cells(j).Cell2.cond_text,dest.Grid0.Cells(i).Cell2.cond_text)) dest.Grid0.Cells(i).result_text = obj.Grid0.Cells(j).result_text; end end end end %% function revised_input = parse_inputs(obj,input_string) revised_input = []; input_string2 = reshape(input_string',1,size(input_string,1)*size(input_string,2)); inputs = regexprep(input_string2,'\s',''); inputs = regexp(inputs,',','split'); % need to be careful here because pvs dependant types can have % :'s in them % find the first :, any thing before this is considered the % variable any thing following is considered the type c_locations = regexp(inputs,':','start'); for i= 1:size(inputs,2) if size(c_locations{i},2) == 0 sub_input{1} = inputs{i}; new_inputs{i} = sub_input; else sub_input{1} = inputs{i}(1:c_locations{i}(1)-1); sub_input{2} = inputs{i}(c_locations{i}(1)+1:end); new_inputs{i} = sub_input; %new_inputs{i}(1) = inputs{i}(1:c_locations{i}(1)) %new_inputs{i}(2) = inputs{i}(c_locations{i}(1):end) end end %inputs = regexp(inputs,':','split') for i=1:size(new_inputs,2) valid = regexp(new_inputs{i}(1),'[a-zA-Z][_a-zA-Z0-9]*','match'); if ~strcmp(new_inputs{i}(1),valid{1}) new_inputs{i}(2) = {'error'}; %revised_input = cat(2,revised_input,[char(inputs{i}(1)); 'error']) end end if isempty(revised_input) revised_input = new_inputs; end end function error = check_inputs(obj) parsed_input = obj.parse_inputs(get(obj.function_inputs_control,'string')); error = []; for i=1:size(parsed_input,2) if(size(parsed_input{i},2) == 2) if (strcmp(parsed_input{i}(2),'error')) error = [error sprintf('%s is not a valid variable name\n',char(parsed_input{i}(1))) ]; end end end end function [] = setPBenable(obj) if size(obj.Grid1.cells,2) > 1 set(obj.Grid1.delete_cell_pb,'Enable','on'); else set(obj.Grid1.delete_cell_pb,'Enable','off'); end if size(obj.Grid2.cells,2) > 1 set(obj.Grid2.delete_cell_pb,'Enable','on'); else set(obj.Grid2.delete_cell_pb,'Enable','off'); end %set(obj.Grid2.delete_cell_pb,'Enable','off'); %set(obj.Grid1.delete_cell_pb,'Enable','off'); end end end