function Data=objbrwser(Action,Data,varargin)
%OBJBRWSER Helper functions for the object browsers
%   objbrwser contains helper functions for the object browsers
%   on the Alignment Tool, Callback Editor and Property Editor.

%   Loren Dean
%   Copyright (c) 1984-98 by The MathWorks, Inc.
%   $Revision: 1.49 $ $Date: 1998/06/08 12:57:02 $

switch Action,
  case 'ButtonDown',      % BrowserHandle Browser Type
    [ListVal,Data]=LocalButtonDown(Data,varargin{[1 3]});
    String=get(Data.All.Browser.Handles(1),'String');    
        
    if ~isempty(ListVal) & ListVal==1 & strcmp(String,' '),return,end
    
    Value=Data.All.Mapping.Complete(ListVal);

    switch get(varargin{2},'SelectionType'),
      case 'open',        
        % Check to make sure that something can be selected.  If not,
        % just exit out.        
        if ~isempty(Data.All.StringInfo),
          if Data.All.StringInfo(Value,3), % it's expanded or childless
            
            if Data.All.StringInfo(Value,4), %it's got children,collapse it 
              Data=LocalCollapseTree(Data,Value);

            % It's root and has no children
            elseif (Value==1)&(~Data.All.StringInfo(Value,4)), 
              Data=LocalExpandTree(Data,Value,0);

            end % if Data.All.StringInfo

          else, % it's collapsed and has children
            Data=LocalExpandTree(Data,Value,0);
          end % if Data.All.StringInfo
        end % if ~isempty          

      %case 'alt',
      %  helpfun('Object Browser',Data);

      otherwise, % Normal Selection
        Data=guide('SelectionUpdate',Data,varargin{1});
    end % switch

  case 'CreateInfo',
    Data=LocalCreateInfo(Data);
    
  case 'CreateInitialMapping',
    Temp=Data.All.HandleList;  
    Data=LocalCreateInfo(Data);
    
    % LocalCreateString clears out Data.All.HandleList when initializing
    Data=LocalCreateString(Data,'All');

    % So to do the right thing, Data.All.HandleList is stuck back in here
    % and everything works right.    
    Data.All.HandleList=Temp;    
    Data=LocalSelectionUpdate(Data,[]);

  case 'HandleUpdate',
    % Perform actions for a handle update
    Data=LocalCreateInfo(Data); 
    Temp=Data.All.HandleList;  
    Data=LocalCreateString(Data,'All');
    Data.All.HandleList=Temp;    
    Data=LocalSelectionUpdate(Data,[]);
          
  case 'SelectionUpdate',
    Data=LocalSelectionUpdate(Data,varargin{1});  

  case 'SetBrowserString',
    Data=LocalCreateString(Data,varargin{1});
    Data=LocalSelectionUpdate(Data,[]);
      
  case 'Update',
    % Perform actions for a string update
    Data=LocalCreateInfo(Data);
    Temp=Data.All.HandleList;  
    Data=LocalCreateString(Data,'All');
    Data.All.HandleList=Temp;    
    Data=LocalSelectionUpdate(Data,[]);

end % switch

%%%%%%%%%%%%%%%%%%%%%%%
%%% LocalButtonDown %%%
%%%%%%%%%%%%%%%%%%%%%%%
function [ComListVal,Data]=LocalButtonDown(Data,BrowserHandle,ListType)

% Perform actions for a buttondown event 
if ~isempty(Data.All.StringInfo),
  Loc=~ishandle(Data.All.StringInfo(:,1));
  if any(Loc),
    set(BrowserHandle,'Value',1,'ListboxTop',1);  
    Data=guide('HandleUpdate',Data);
  end    
end  

switch ListType,
  case 'Complete',
    ListVal=get(BrowserHandle,'Value');
    ComListVal=ListVal;  
    SqrListVal=find(ismember(Data.All.Mapping.Square,ListVal));
    MenuListVal=find(ismember(Data.All.Mapping.Menu,ListVal));
    
  case 'Square',
    ListVal=get(BrowserHandle,'Value');
    SqrListVal=ListVal;
    ComListVal=Data.All.Mapping.Square(ListVal);  
    MenuListVal=find(ismember(Data.All.Mapping.Menu,ComListVal));
    
  case 'Menu',
    ListVal=get(BrowserHandle,'Value');
    MenuListVal=ListVal;
    ComListVal=Data.All.Mapping.Menu(ListVal);  
    SqrListVal=find(ismember(Data.All.Mapping.Square,ComListVal));

  case 'Figure',    
    if isempty(Data.All.StringInfo),
      ListVal=[];ComListVal=[];SqrListVal=[];MenuListVal=[];      
    else,      
      ListVal=find(ismember(Data.All.StringInfo(:,1), ...
                           Data.All.HandleList));
      ListVal=find(ismember(Data.All.Mapping.Complete,ListVal));
      ComListVal=ListVal;  
      SqrListVal=find(ismember(Data.All.Mapping.Square,ListVal));
      MenuListVal=find(ismember(Data.All.Mapping.Menu,ListVal));
    end      
      
end % switch

CTopDispValue=get(Data.All.Browser.Complete,{'ListboxTop'});
STopDispValue=get(Data.All.Browser.Square,{'ListboxTop'});
MTopDispValue=get(Data.All.Browser.Menu,{'ListboxTop'});

if strcmp(ListType,'Figure'),
  if ~isempty(CTopDispValue) & ~isempty(ComListVal),
    CTopDispValue(:)={max(1,min(ComListVal)-1)};
  end % if ~isempty
  
  if ~isempty(STopDispValue) & ~isempty(SqrListVal),
    STopDispValue(:)={max(1,min(SqrListVal)-1)};
  end % if ~isempty

  if ~isempty(MTopDispValue) & ~isempty(MenuListVal),
    MTopDispValue(:)={max(1,min(MenuListVal)-1)};
  end % if ~isempty
  
end % if strcmp

set(Data.All.Browser.Complete,'Value',ComListVal,{'ListboxTop'},CTopDispValue);
set(Data.All.Browser.Square,'Value',SqrListVal,{'ListboxTop'},STopDispValue);
set(Data.All.Browser.Menu,'Value',MenuListVal,{'ListboxTop'},MTopDispValue);

if ~isempty(Data.All.Mapping.Complete),
  Value=Data.All.Mapping.Complete(ComListVal);
  Data.All.HandleList=Data.All.StringInfo(Value,1);
end  

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%% LocalCollapseTree %%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function Data=LocalCollapseTree(Data,Value)
% Collapse the Tree

Data.All.StringInfo(Value,3)=0;
Data=LocalCreateString(Data,'All');

%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%% LocalCreateInfo %%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%
function Data=LocalCreateInfo(Data)

OldData=Data.All.StringInfo;

% Handle Level ExpandFlag ChildFlag CustomFlag Type
% Type = Root          R
%        Figure        F
%        UIContextMenu U
%        UIMenu        M
%        UIControl     C 
%        Axes          A 
%        Text          T
%        Line          L
%        Image         I
%        Patch         P
%        Surface       S
%        Light         G
%        Rectangle     E
%        Axes Label (XLabel, YLabel, ZLabel, Title) X
%

if Data.All.GuideFlag,
  AllHandles=Data.All.ControlInfo.AllObjects.Handle;
  % Fix problem of handles being created behind guide's back
  % This does not address the problem of new handles appearing
  % while keeping all of the old handles the same.  
  if ~all(ishandle(AllHandles)),
    Data=guide('HandleUpdate',Data);
  end
  AllHandles=Data.All.ControlInfo.AllObjects.Handle;
  
else,
    
  Figures=allchild(0);     
  Figures(find(ismember(Figures,Data.All.Figs.Handles)))=[];  
  Figures=gnrlfun('RemoveSpecialHandles',Figures);

  Axes=findall(Figures,'Type','axes');
  % Force labels to appear on axes  
  get(Axes,{'XLabel','YLabel','ZLabel','Title'});  
  AllHandles=[0;findall(Figures)];
  AllHandles=gnrlfun('RemoveToolbarHandles',AllHandles);
   
end

if ~isempty(AllHandles),
  NumHandles=length(AllHandles);
  ObjType=get(AllHandles,{'Type'});

  ExpandFlag=zeros(NumHandles,1);
  AllChildren = allchild(AllHandles);
  if ~iscell(AllChildren),AllChildren={AllChildren};end  
  EmptyFlag=cell(size(AllChildren));
  for i=1:prod(size(EmptyFlag)),
    EmptyFlag{i} = isempty(AllChildren{i});
  end
  ChildFlag=~cat(1,EmptyFlag{:});
  if AllHandles(1)==0,
    ChildFlag(1)=~isempty(Figures);
  end    
  CustomFlag=zeros(NumHandles,1);

  Type=zeros(NumHandles,1);
  Level=zeros(NumHandles,1);
  %% V5 LPD This needs to be sped up  
  for HLp=1:NumHandles,
    switch ObjType{HLp},
      case 'root'     ,
        Type(HLp,1)=abs('R');
        Level(HLp,1)=0;   
        
      case 'figure'   ,
        Type(HLp,1)=abs('F');
        Level(HLp,1)=1;  
        
      case 'uicontextmenu',
        Type(HLp,1)=abs('U') ;
        Level(HLp,1)=2;  
        
      case 'uimenu'   ,
        Type(HLp,1)=abs('M');
        PHandle=parent(AllHandles(HLp,1));
        PType=get(PHandle,'Type');      
        Level(HLp,1)=2;      
        while ~strcmp(PType,'figure')|strcmp(PType,'uicontextmenu'),
          Level(HLp,1)=Level(HLp,1)+1;
          PHandle=parent(PHandle);
          PType=get(PHandle,'Type');
        end % while        
        if strcmp(PType,'uicontextmenu'),
          Level(HLp,1)=Level(HLp,1)+1;
        end
        
      case 'uicontrol',
        Type(HLp,1)=abs('C') ;
        Level(HLp,1)=2;  
        
      case 'axes'     ,
        Type(HLp,1)=abs('A') ;
        Level(HLp,1)=2;
        
      case 'text'     ,
        Type(HLp,1)=abs('T') ;
        Level(HLp,1)=3;
        
      case 'line'     ,
        Type(HLp,1)=abs('L') ;
        Level(HLp,1)=3;  
        
      case 'image'    ,
        Type(HLp,1)=abs('I') ;
        Level(HLp,1)=3;  
        
      case 'patch'    ,
        Type(HLp,1)=abs('P') ;
        Level(HLp,1)=3;  
        
      case 'surface'  ,
        Type(HLp,1)=abs('S') ;
        Level(HLp,1)=3;  
        
      case 'light'    ,
        Type(HLp,1)=abs('G') ;
        Level(HLp,1)=3;  
        
      case 'rectangle'    ,
        Type(HLp,1)=abs('E') ;
        Level(HLp,1)=3;  
        
    end % switch
  end % for HLp  
  Data.All.StringInfo=[AllHandles Level ExpandFlag ChildFlag CustomFlag Type];
  Loc=find(Type==abs('A')); %axes
  if ~isempty(Loc),  
    Data.All.StringInfo(Loc,4)=1;
    for LLp=1:length(Loc),
      XLabHand=get(Data.All.StringInfo(Loc(LLp),1),'XLabel');
      YLabHand=get(Data.All.StringInfo(Loc(LLp),1),'YLabel');
      ZLabHand=get(Data.All.StringInfo(Loc(LLp),1),'ZLabel');
      TitleHand=get(Data.All.StringInfo(Loc(LLp),1),'Title'); 
      Data.All.StringInfo(Data.All.StringInfo(:,1)==XLabHand ,:)=[];
      Data.All.StringInfo(Data.All.StringInfo(:,1)==YLabHand ,:)=[];
      Data.All.StringInfo(Data.All.StringInfo(:,1)==ZLabHand ,:)=[];
      Data.All.StringInfo(Data.All.StringInfo(:,1)==TitleHand,:)=[];
      Data.All.StringInfo=[Data.All.StringInfo(1:Loc(LLp),:)
                           XLabHand   3 0 0 0 abs('X')      
                           YLabHand   3 0 0 0 abs('X')      
                           ZLabHand   3 0 0 0 abs('X')      
                           TitleHand  3 0 0 0 abs('X')
                           Data.All.StringInfo(Loc(LLp)+1:end,:)
                          ];
      % This is here in case label handles get rearranged thus causing
      % the indices to be rearranged. see g33303
      NewLoc=find(ismember(AllHandles,Data.All.StringInfo(:,1)));
      AllHandles-Data.All.StringInfo(:,1);
      Type=Type(NewLoc);
      Loc=find(Type==abs('A')); %axes
    end % for LLp
  end % if ~isempty

  %%%% Make sure expansions are correct

  if isempty(OldData),
    Data.All.StringInfo(1,3)=1;
  else,
    OldHandleVect=OldData(:,1).*OldData(:,3);
    NewHandleVect=Data.All.StringInfo(:,1);
    Loc=find(ismember(NewHandleVect,OldHandleVect));
    Data.All.StringInfo(Loc,3)=1;
    Data.All.StringInfo(1,3)=OldData(1,3);
  end

  %%% Finish Customization
  if Data.All.CustomFlag,
    for DLp=1:size(Data.All.CustomList,1),
      CustomChild= ...
        findobj(Data.All.StringInfo(:,1),'flat'                    , ...
               'Type'                   ,Data.All.CustomList{DLp}  ...
             );
      if ~isempty(CustomChild),
        for InLp=1:length(CustomChild),
          CustomFlag(Data.All.StringInfo(:,1)==CustomChild(InLp),1)=1;
        end % for InLp
      end % if ~isempty
    end % for DLp
  end % if Data.All.CustomFlag


else,
  Data.All.StringInfo=[];  
  
end % if ~isempty

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%% LocalCreateString %%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function Data=LocalCreateString(Data,Type)
% Create the string(s) for the Object Browser(s)
switch Type,
  case 'Complete',
    String=get(Data.All.Browser.Complete(1),'String');  
    TopDispValue=get(Data.All.Browser.Complete,{'ListboxTop'});
    set(Data.All.Browser.Complete, ...
       'String'                  ,String      , ...
       {'ListboxTop'}            ,TopDispValue  ...
       );
    
  case 'Square',
    String=get(Data.All.Browser.Complete(1),'String');  
    TopDispValue=get(Data.All.Browser.Square,{'ListboxTop'});
    set(Data.All.Browser.Square, ...
       'String'                ,String(Data.All.Mapping.Square,:), ...
      {'ListboxTop'}           ,TopDispValue                       ...
       );
    
  case 'Menu',
    String=get(Data.All.Browser.Complete(1),'String');  
    TopDispValue=get(Data.All.Browser.Menu,{'ListboxTop'});
    set(Data.All.Browser.Menu, ...
       'String'              ,String(Data.All.Mapping.Menu,:), ...
      {'ListboxTop'}         ,TopDispValue                     ...
       );
    
  
  case 'All',
    if ~isempty(Data.All.StringInfo),
      Loc=1;
      NumObjs=size(Data.All.StringInfo,1);
      Val=[];

      while Loc<=NumObjs,
        Val=[Val;Loc];
        if Data.All.StringInfo(Loc,3),
          Loc=Loc+1;
        else,
          ValLevel=Data.All.StringInfo(Loc,2);
          FindLevel=find(Data.All.StringInfo((Loc+1):end,2)<=ValLevel);
          if ~isempty(FindLevel),
            Loc=Loc+FindLevel(1);
          else,
            Loc=NumObjs+1;
          end % if ~isempty
        end % if ~Data.All.StringInfo
      end % while

      % This takes care of the fact that menus are flipped
      % wrt child order and how they appear in the object browser
      Data.All.Mapping.Complete = ...
          gnrlfun('FlipMenus',Val,Data.All.StringInfo); 
      
      StringData=Data.All.StringInfo(Data.All.Mapping.Complete,:);

      Data.All.Mapping.Square=sort([find(StringData(:,6)==abs('R')) 
                                    find(StringData(:,6)==abs('F'))           
                                    find(StringData(:,6)==abs('C'))
                                    find(StringData(:,6)==abs('A'))]);         
                                
      Data.All.Mapping.Menu=find(StringData(:,6)==abs('R')| ...
                                 StringData(:,6)==abs('F')| ...
                                 StringData(:,6)==abs('U')| ...
                                 StringData(:,6)==abs('M')  ...
                                 );

      LevelInfo=StringData(:,2);
      NumVal=size(LevelInfo,1);

      TypeInfo=get(StringData(:,1),{'Type'});      
      TagInfo=get(StringData(:,1),{'Tag'});

      %43='+',45='-'
      ExpandCollapse=char(32+StringData(:,4).*((StringData(:,3)*2)+11));
      ExpandCollapse=num2cell(ExpandCollapse,2);

      String=cell(NumVal,1);
      LeftString=String;
      CenterString=String;
      RightString=String;
      space=' ';

      for LLp =1:length(LevelInfo),
        TypeString=TypeInfo{LLp,1};

        LeftString{LLp,1}=[ExpandCollapse{LLp,1}            ...
                          space(ones(1,LevelInfo(LLp)*2+1)) ...
                          TypeString                        ...
                          space                             ...
                            ];
        CenterString{LLp,1}= ...
            gnrlfun('GetGoodObjString',TypeString,StringData(LLp,1));
        
        RightString(LLp,1)=TagInfo(LLp);

      end % for LLp

      String=[char(LeftString)  ...
              char(CenterString) ...
              char(RightString) ...
             ];

    else,
      String=' ';  
      Data.All.Mapping.Complete=[];
      Data.All.Mapping.Square=[];
      Data.All.Mapping.Menu=[];

    end % if ~isempty
    
    set(Data.All.Browser.Complete,'Value',1,'String',String);
    set(Data.All.Browser.Square, ...
       'Value'                 ,1                                , ...       
       'String'                ,String(Data.All.Mapping.Square,:)  ...
       );
    set(Data.All.Browser.Menu, ...
       'Value'               ,1                              , ...       
       'String'              ,String(Data.All.Mapping.Menu,:)  ...
       );
    [ComListVal,Data]=LocalButtonDown(Data,[],'Figure');
    
end % switch  

%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%% LocalExpandTree %%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function Data=LocalExpandTree(Data,Value,StringFlag)
% Expand the Tree

if Value==1,
  if Data.All.GuideFlag,
    set(Data.All.DataHandle,'UserData',Data);    
    ctlpanel Update;
    Data=get(Data.All.DataHandle,'UserData');    
  end
  Data=gnrlfun('TakeGeneralControl',Data);      
  Data=LocalCreateInfo(Data);
end

Data.All.StringInfo(Value,3)=1;

%%% Expand all the way up the tree in case something beneath a 
%%% collapsed branch has been expanded.
Level=Data.All.StringInfo(Value,2);
while Level>=0,
  Levels=find(Data.All.StringInfo(1:Value,2)==(Level-1));
  if ~isempty(Levels),
    Data.All.StringInfo(Levels(end),3)=1;
    Level=Level-1;
  else,
    break;
  end
end

if ~StringFlag,
  Data=LocalCreateString(Data,'All');
end  

%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% LocalSelectionUpdate %%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function Data=LocalSelectionUpdate(Data,BrowserHandle)
% Perform actions for a selection
if ~isempty(Data.All.HandleList),
  Loc=~ishandle(Data.All.HandleList);
  if any(Loc),
    Data=guide('HandleUpdate',Data);    
    return    
  end    
end  

if ~isempty(BrowserHandle), % Browser made selection
  % This is a check in case nothing is already selected  
  if ~isempty(Data.All.StringInfo),  
    ValidHandleLoc=ishandle(Data.All.StringInfo(:,1));  
    set(Data.All.StringInfo(ValidHandleLoc,1),'Selected','off');  
  end    
  set(Data.All.HandleList,'Selected','on');

else, % Figure made selection
  StringLoc=[];

  set(Data.All.HandleList,'Selected','on');
  
  RedoFlag=0;  
  for DLp=1:length(Data.All.HandleList),
    Loc=find(Data.All.StringInfo(:,1)==Data.All.HandleList(DLp));
    if ~isempty(Loc),
      NewLoc=find(Data.All.Mapping.Complete==Loc);
      
      if isempty(NewLoc),
        RedoFlag=1;        
        LocTemp=find(Data.All.StringInfo(:,1)== ...
                  get(Data.All.HandleList(DLp),'Parent'));
               
        Data=LocalExpandTree(Data,LocTemp,1);        
          
      else,
        StringLoc=[StringLoc;NewLoc];
        
      end        
      
    end % if  ~isempty
  end
  
  if RedoFlag,      
    StringLoc=[];    
    Data=LocalCreateString(Data,'All');    
    for DLp=1:length(Data.All.HandleList),
      Loc=find(Data.All.StringInfo(:,1)==Data.All.HandleList(DLp));
      if ~isempty(Loc),
        NewLoc=find(Data.All.Mapping.Complete==Loc);
        StringLoc=[StringLoc;NewLoc];
      end % if ~isempty        
    end % for DLp
  end
  [Value,Data]=LocalButtonDown(Data,[],'Figure');  
end % if
