classdef CheckboxTree < uiextras.jTree.Tree % CheckboxTree - Class definition for CheckboxTree % The CheckboxTree object places a checkbox tree control within a % figure or container. % % Syntax: % tObj = uiextras.jTree.CheckboxTree % tObj = uiextras.jTree.CheckboxTree('Property','Value',...) % % The CheckboxTree contains all properties and methods of the % uiextras.jTree.Tree, plus the following: % % CheckboxTree Properties: % % CheckboxClickedCallback - callback when a checkbox value is changed % % ClickInCheckBoxOnly - if false, clicking on the node's label also % toggles the checkbox value, instead of selecting the node % % DigIn - controls whether checkbox selection of a branch also checks % all children % % CheckedNodes - tree nodes that are currently checked. In DigIn % mode, this will not contain the children of fully selected % branches. (read-only) % % % CheckboxTree Example: % % %% Create the figure and display the tree % f = figure; % t = CheckboxTree('Parent',f,... % 'SelectionChangeFcn','disp(''SelectionChangeFcn triggered'')',... % 'MultiSelect','on'); % % %% Create tree nodes % Node1 = uiextras.jTree.CheckboxTreeNode('Name','Node_1','Parent',t.Root); % Node1_1 = uiextras.jTree.CheckboxTreeNode('Name','Node_1_1','Parent',Node1); % Node1_2 = uiextras.jTree.CheckboxTreeNode('Name','Node_1_2','Parent',Node1); % Node2 = uiextras.jTree.CheckboxTreeNode('Name','Node_2','Parent',t.Root); % % %% Set an icon % RootIcon = which('matlabicon.gif'); % setIcon(Node1,RootIcon) % % %% Move nodes around % Node1_2.Parent = t; % % %% Disable the tree % t.Enable = 'off'; % % %% Enable the tree % t.Enable = 'on'; % % See also: uiextras.jTree.Tree, uiextras.jTree.TreeNode, % uiextras.jTree.CheckboxTreeNode % Copyright 2012-2014 The MathWorks, Inc. % % Auth/Revision: % MathWorks Consulting % $Author: rjackey $ % $Revision: 109 $ $Date: 2014-09-30 16:42:51 -0400 (Tue, 30 Sep 2014) $ % --------------------------------------------------------------------- % DEVELOPER NOTE: Java objects that may be used in a callback must be % put on the EDT to make them thread-safe in MATLAB. Otherwise, they % could execute along side a MATLAB command and get into a thread-lock % situation. Methods of the objects put on the EDT will be executed on % the thread-safe EDT. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Properties %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% properties (SetAccess=public, GetAccess=public) CheckboxClickedCallback %callback when a checkbox value is changed end properties (Dependent=true, SetAccess=public, GetAccess=public) ClickInCheckBoxOnly %clicking on label toggles checkbox DigIn %selection of a branch also checks all children end properties (Dependent=true, SetAccess=immutable, GetAccess=public) CheckedNodes %in DigIn, returns highest level that's fully checked end properties (SetAccess=protected, GetAccess=protected) jCBoxSelModel %Java checkbox selection model (internal) end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Constructor %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % A constructor method is a special function that creates an instance % of the class. Typically, constructor methods accept input arguments % to assign the data stored in properties and always return an % initialized object. methods function tObj = CheckboxTree(varargin) % CheckboxTree - Constructor for CheckboxTree % ------------------------------------------------------------------------- % Abstract: Constructs a new CheckboxTree object. No special % action is taken. % % Syntax: % tObj = uiextras.jTree.CheckboxTree('p1',v1,...) % % Inputs: % Property-value pairs % % Outputs: % tObj - uiextras.jTree.CheckboxTree object % % Examples: % hFig = figure; % tObj = CheckboxTree('Parent',hFig) % % Call superclass constructor tObj = tObj@uiextras.jTree.Tree(varargin{:}); end end %methods %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Public Methods %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Methods are functions that implement the operations performed on % objects of a class. They may be stored within the classdef file or as % separate files in a @classname folder. methods function s = getJavaObjects(tObj) s = getJavaObjects@uiextras.jTree.Tree(tObj); s.jCBoxSelModel = tObj.jCBoxSelModel; end end %public methods %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Protected Methods %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% methods (Access = protected) function createTree(tObj) % Override the createTree method to make a checkbox tree % Create the root node tObj.Root = uiextras.jTree.CheckboxTreeNode('Name','Root','Tree',tObj); % Create the tree if isempty(tObj.Root) tObj.jTree = javaObjectEDT('UIExtrasTree.CheckBoxTree'); else tObj.jTree = javaObjectEDT('UIExtrasTree.CheckBoxTree',tObj.Root.jNode); end % Store the model tObj.jModel = tObj.jTree.getModel(); javaObjectEDT(tObj.jModel); % Put it on the EDT % Store the selection model tObj.jSelModel = tObj.jTree.getSelectionModel(); javaObjectEDT(tObj.jSelModel); % Put it on the EDT % Store the checkbox selection model tObj.jCBoxSelModel = tObj.jTree.getCheckBoxTreeSelectionModel(); %tObj.jCBoxSelModel.setSingleEventMode(1); javaObjectEDT(tObj.jCBoxSelModel); end function createTreeCustomizations(tObj) % customize the tree for checkboxes % Call the superclass method createTreeCustomizations@uiextras.jTree.Tree(tObj) % Use the custom renderer setCellRenderer(tObj.jTree, UIExtrasTree.TreeCellRenderer); % Set the callbacks CbProps = handle(tObj.jCBoxSelModel,'CallbackProperties'); set(CbProps,'ValueChangedCallback',@(src,e)onCheckboxClicked(tObj,e)); end function onCheckboxClicked(tObj,e) if callbacksEnabled(tObj) %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Prepare event data for user callback %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % In non DigIn mode, provide the node that was changed. In % DigIn mode, the java event is difficult to use because we % get multiple events in some cases. (Single event mode did % not work correctly.) The events may come in the wrong % order, giving wrong information. So instead, we just % provide the selection paths. if tObj.DigIn % Filter out clicks that trigger two events by checking % for changes in the selection path. Note equals is % defined as long as jOldSelPath is nonempty. jNewSelPath = e.getNewLeadSelectionPath(); jOldSelPath = e.getOldLeadSelectionPath(); if ~isempty(jOldSelPath) && equals(jOldSelPath,jNewSelPath) return end % Prepare the event data e1 = struct('SelectionPaths',tObj.CheckedNodes); else %not DigIn mode % Figure out what paths were added or removed by eventdata jChangedPath = e.getPath; jPath = jChangedPath.getLastPathComponent(); ChangedPath = get(jPath,'TreeNode'); % Prepare the event data e1 = struct(... 'Nodes',ChangedPath,... 'SelectionPaths',tObj.CheckedNodes); end %if tObj.DigIn % Is there a custom CheckboxClickedCallback? if ~isempty(tObj.CheckboxClickedCallback) % Call the custom callback hgfeval(tObj.CheckboxClickedCallback,tObj,e1); end %if ~isempty(tObj.CheckboxClickedCallback) end %if callbacksEnabled(tObj) end end %protected methods %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Special Access Methods %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% methods (Access={?uiextras.jTree.Tree, ?uiextras.jTree.TreeNode}) function tf = isNodeChecked(tObj,nObj) jTreePath = nObj.jNode.getTreePath; if nObj.Tree == tObj tf = tObj.jCBoxSelModel.isPathSelected(jTreePath,tObj.DigIn); else tf = NaN; end end function tf = isNodePartiallyChecked(tObj,nObj) jTreePath = nObj.jNode.getTreePath; if nObj.Tree == tObj tf = tObj.jCBoxSelModel.isPartiallySelected(jTreePath); else tf = NaN; end end function setChecked(tObj,nObj,value) validateattributes(nObj,{'uiextras.jTree.TreeNode'},{'vector'}); validateattributes(value,{'numeric','logical'},{'vector'}); if isequal(size(value),size(nObj)) value = logical(value); elseif numel(value)==1 value = repmat(logical(value),size(nObj)); else error('CheckboxTree:setChecked:inputs',... 'Size of value must match size of input nodes to be set.'); end RemNodes = nObj(~value); AddNodes = nObj(value); if ~isempty(RemNodes) for idx = numel(RemNodes):-1:1 %backwards to preallocate RemPaths(idx) = RemNodes(idx).jNode.getTreePath(); end tObj.jCBoxSelModel.removeSelectionPaths(RemPaths); end if ~isempty(AddNodes) for idx = numel(AddNodes):-1:1 %backwards to preallocate AddPaths(idx) = AddNodes(idx).jNode.getTreePath(); end tObj.jCBoxSelModel.addSelectionPaths(AddPaths); end end end %special access methods %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Get and Set Methods %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Get and set methods customize the behavior that occurs when code gets % or sets a property value. methods % ClickInCheckBoxOnly function value = get.ClickInCheckBoxOnly(nObj) value = get(nObj.jTree,'ClickInCheckBoxOnly'); end function set.ClickInCheckBoxOnly(nObj,value) validateattributes(value,{'numeric','logical'},{'scalar'}); nObj.jTree.setClickInCheckBoxOnly(logical(value)); end % DigIn function value = get.DigIn(nObj) value = get(nObj.jTree,'DigIn'); end function set.DigIn(nObj,value) validateattributes(value,{'numeric','logical'},{'scalar'}); nObj.jTree.setDigIn(logical(value)); end % CheckedNodes function value = get.CheckedNodes(nObj) p = nObj.jCBoxSelModel.getSelectionPaths; value = uiextras.jTree.TreeNode.empty(0,1); for idx = 1:numel(p) nObj = get(p(idx).getLastPathComponent(),'TreeNode'); value(end+1) = nObj; %#ok end end end %get/set methods end %classdef