help-octave
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: findobj.m


From: David Bateman
Subject: Re: findobj.m
Date: Thu, 27 Sep 2007 01:56:15 +0200
User-agent: Thunderbird 1.5.0.7 (X11/20060921)

Ben Abbott wrote:
> I've written a Octave script that is intended to mirror the functionality of 
> Matlab's findobj function. 
> 
> Assuming there is no Octave version of findobj at the present time, I'm happy 
> to submit it for that purpose.
> 
> Although I did make a modest attempt to include the proper copyright and help 
> at the top of the script, I expect some additional effort is required to 
> bring it up to standards. 
> 
> In any event, it is attached.
> 
> 
> 

Well, some points..

1) The help string should be in texinfo as this is a core function and
needs to be formated for the Octave manual itself
2) You should use "#" as the comment character. "##" for comments
aligned with the code and "#" for indented comments.
3) I doubt the depth of 1e9 will ever be reach but using NaN instead for
the depth would be cleaner and the > and < operators always return false
for expressions involving NaN
4) Use "!=" and not "~=".
5) I think in the "strcmpi(args{na}, '-property')" if statement you had
a "np=np+1" that is redundant as it is replicated outside the if statement.
6) Although there is no coding style guide for Octave, there are fairly
strict ideas about what functions in Octave itself should look like.
Some examples

* No camelcase argument name Depth should be depth
* spacing between arguments of functions
* Use of the block specific terminations of Octave, endif, endfor, etc
* Functions must be terminated with endfunction

There are others I'm sure, and if you look at some of the function in
Octave you'll get the idea of what they are

I've tried to do these conversions to your code, but haven't tested the
function afterwards. In any case I wonder how fast this function will
be? Matlab has implemented this as a builtin function, maybe it should
be for Octave as well.

I'm not sure the regexp code works as expected, as some test cases I
tried didn't give the expected results as they returned objects that
didn't even have the property..

D.
## Copyright (C) 2007   Ben Abbott  <address@hidden>
##
## This program is free software; you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation; either version 2 of the License, or
## (at your option) any later version.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with this program; if not, write to the Free Software
## Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  
## 02110-1301  USA

## -*- texinfo -*-
## @deftypefn {Function File} address@hidden =} findobj ()
## @deftypefnx {Function File} address@hidden =} findobj (@var{propName}, 
@var{propValue})
## @deftypefnx {Function File} address@hidden =} findobj ('-property', 
@var{propName})
## @deftypefnx {Function File} address@hidden =} findobj ('-regexp', 
@var{propName},, @var{pattern})
## @deftypefnx {Function File} address@hidden =} findobj ('flat', @dots{})
## @deftypefnx {Function File} address@hidden =} findobj (@var{h}, @dots{})
## @deftypefnx {Function File} address@hidden =} findobj (@var{h}, '-depth', 
@var{d}, @dots{})
## Find object with specified property values. The simpliest form is
##
## @example
## findobj (@var{propName}, @var{propValue})
## @end example
##
## @noindent
## which returns all of the handles to the objects with the name 
## @var{propName} and the name @var{propValue}. The search can be limited
## to a particular object or set of objects and their descendants by 
## passing a handle or set of handles @var{h} as the first argument to 
## @code{findobj}.
##
## The depth of hierarchy of objects to which to search to can be limited
## with the '-depth' argument. To limit the number depth of the hierarchy
## to search to @var{d} generations of children, and example is
##
## @example
## findobj (@var{h}, '-depth', @var{d}, @var{propName}, @var{propValue})
## @end example
##
## Specifying a depth @var{d} of 0, limits the search to the set of object
## passed in @var{h}. A depth @var{d} of 0 is equivalent to the '-flat'
## argument. 
##
## A specified logical operator may be applied to the pairs of @var{propName}
## and @var{propValue}. The supported logical operators are '-and', '-or', 
## '-xor', '-not'.
##
## The objects may also be matched by comparing a regular expression to the 
## property values, where property values that match @code{regexp 
## (@var{propValue}, @var{pattern})} are returned.  Finally, objects may be 
## matched by property name only, using the '-property' option.
## @seealso{get, set}
## @end deftypefn

function h = findobj (varargin)

  depth = NaN;
  if (nargin == 0)
    handles = 0;
    n1 = 0;
  else
    if (ishandle (varargin{1}(1)))
      handles = varargin{1};
      n1 = 2;
    else
      handles = 0;
      n1 = 1;
    end
    if (n1 <= nargin)
      if (ischar (varargin{n1}))
        if (strcmpi (varargin{n1}, 'flat'))
          depth = 0;
          n1 = n1 + 1;
        elseif (strcmpi(varargin{n1}, '-depth'))
          depth = varargin{n1+1};
          n1 = n1 + 2;
        endif
      else
        error ("findobj: properties and options must be strings");
      endif
    endif
  endif

  if (n1 <= nargin && nargin > 0)
    args = varargin(n1 : nargin);
  else
    args = {};
  endif

  regularexpression = [];
  property          = [];
  logicaloperator   = {};
  pname             = {};
  pvalue            = {};
  np = 1;
  na = 1;

  while (na <= numel (args))
    regularexpression(np) = 0;
    property(np) = 0;
    logicaloperator{np} = 'and';
    if (ischar (args {na}))
      if (strcmpi(args{na}, '-regexp'))
        regularexpression(np) = 1;
        na = na + 1;
      elseif (strcmpi(args{na}, '-property'))
        na = na + 1;
        property(np) = 1;
        pname{np} = args{na};
        na = na + 1;
        pvalue{np} = [];
      elseif (! strcmp (args{na}(1), '-')) # parameter/value pairs
        pname{np} = args{na};
        na = na + 1;
        pvalue{np} = args{na};
        na = na + 1;
        if (na <= numel(args))
          if (ischar (args{na}))
            if strcmpi(args{na}, '-and')
              logicaloperator{np} = 'and';
              na = na+1;
            elseif strcmpi(args{na}, '-or')
              logicaloperator{np} = 'or';
              na = na+1;
            elseif strcmpi(args{na}, '-xor')
              logicaloperator{np} = 'xor';
              na = na+1;
            elseif strcmpi(args{na}, '-not')
              logicaloperator{np} = 'not';
              na = na+1;
            endif
          else
            error ("findobj: properties and options must be strings");
          endif
        else
          logicaloperator{np} = 'and';
        endif
        np = np + 1;
      else
        ## this is sloppy ... but works like matlab
        if strcmpi(args{na}, '-not')
          h = [];
          return
        endif
        na = na + 1;
      endif
    else
      error ("findobj: properties and options must be strings");
    endif
  endwhile

  numpairs = np - 1
  
  ## load all objects which qualify for being searched
  idepth = 0;
  h = handles;
  while (numel (handles) && ! (idepth >= depth))
    children = [];
    for n = 1 : numel (handles)
      children = union (children, get(handles(n), 'children'));
    endfor 
    handles = children;
    h = union (h, children);
    idepth = idepth + 1;
  endwhile

  keepers = ones (size (h));
  if (numpairs > 0)
    for nh = 1 : numel(h)
      p = get (h (nh));
      for np = 1 : numpairs
        fields = fieldnames (p);
        fieldindex = find (strcmpi (fields, pname{np}), 1);
        if (numel (fieldindex))
          pname{np} = fields{fieldindex};
          if (property(np))
            match = 1;
          else
            if (regularexpression(np))
              match = regexp (p.(pname{np}), pvalue{np});
            elseif (numel (p.(pname{np})) == numel (pvalue{np}))
              if (ischar (pvalue{np}))
                match = strcmpi (pvalue{np}, p.(pname{np}));
              else
                match = (pvalue{np} == p.(pname{np}));
              endif
            else
              match = 0;
            endif
            match = all (match);
          end
          if (strcmpi (logicaloperator{np}, 'not'))
            keepers(nh) = ! keepers(nh) & ! match;
          else
            keepers(nh) = feval (logicaloperator{np}, keepers(nh), match);
          endif
        endif
      endfor
    endfor
  endif

  h = h (keepers != 0);
  h = reshape (h, [numel(h), 1]);
endfunction

reply via email to

[Prev in Thread] Current Thread [Next in Thread]