class ElementsByRange(_MultipleElements): """Form: elementsref.range(start, stop) A reference to a range of elements, where start and stop are relative references to the first and last elements in range (see also 'con'). """ _keyForm = base.packEnum(kAE.formRange) def __init__(self, wantcode, container, key): for item in key: if not isinstance( item, Specifier ): # quick sanity check; normally relative 'con'-based refs, but absolute 'app'-based refs are legal (note: won't catch its-based references, as that'd take more code to check, but we'll just have to trust user isn't that careless) raise TypeError, 'Bad argument in byrange(): %r' % item _PositionSpecifier.__init__(self, wantcode, container.AEM_trueSelf(), key) def __repr__(self): return '%r.byrange(%r, %r)' % ((self._container, ) + self._key) def _packKey(self, codecs): return base.packListAs(kAE.typeRangeDescriptor, [ (kAE.keyAERangeStart, codecs.pack(self._key[0])), (kAE.keyAERangeStop, codecs.pack(self._key[1])), ]) def AEM_resolve(self, obj): return self._container.AEM_resolve(obj).byrange(*self._key)
class AllElements(_MultipleElements): """Form: ref.elements(code) A reference to all elements of container, where code is elements' class code. """ _keyForm = base.packEnum(kAE.formAbsolutePosition) _kAll = base.packAbsoluteOrdinal(kAE.kAEAll) def __init__(self, wantcode, container): # An AllElements object is a wrapper around an UnkeyedElements object; when selecting one or more of these elements, the AllElements wrapper is skipped and the UnkeyedElements object is used as the 'container' for the new specifier. _PositionSpecifier.__init__(self, wantcode, UnkeyedElements(wantcode, container), self._kAll) def __repr__(self): return repr(self._container) def _packKey(self, codecs): return self._kAll def AEM_trueSelf( self ): # override default implementation to return the UnkeyedElements object stored inside of this AllElements instance return self._container def AEM_resolve(self, obj): return self._container.AEM_resolve(obj) # forward to UnkeyedElements
class NOT(_LogicalTest): _operator = base.packEnum(kAE.kAENOT) _name = 'NOT' def __repr__(self): return '%r.NOT' % self._operands[0] def AEM_resolve(self, obj): return self._operands[0].AEM_resolve(obj).NOT
class Property(_PositionSpecifier): """Form: ref.property(code) A reference to a user-defined property, where code is the code identifying the property. """ _by = 'property' _keyForm = base.packEnum(kAE.formPropertyID) def _packKey(self, codecs): return base.packType(self._key) def AEM_resolve(self, obj): return self._container.AEM_resolve(obj).property(self._key)
class UserProperty(_PositionSpecifier): """Form: ref.userproperty(name) A reference to a user-defined property, where name is a string representing the property's name. Scriptable applications shouldn't use this reference form, but OSA script applets can. Note that OSA languages may have additional rules regarding case sensitivity/conversion. """ _by = 'userproperty' _keyForm = base.packEnum('usrp') def _packKey(self, codecs): return codecs.pack(self._key).AECoerceDesc(kAE.typeChar) def AEM_resolve(self, obj): return self._container.AEM_resolve(obj).userproperty(self._key)
class ElementByOrdinal(_SingleElement): """Form: elementsref.first/middle/last/any A reference to first/middle/last/any element. """ _keyForm = base.packEnum(kAE.formAbsolutePosition) def __init__(self, wantcode, container, key, keyname): self._keyname = keyname _SingleElement.__init__(self, wantcode, container, key) def __repr__(self): return '%r.%s' % (self._container, self._keyname) def AEM_resolve(self, obj): return getattr(self._container.AEM_resolve(obj), self._keyname)
class ElementByRelativePosition(_SingleElement): """Form: elementsref.previous/next(code) A relative reference to previous/next element, where code is the class code of element to get. """ _keyForm = base.packEnum(kAE.formRelativePosition) def __init__(self, wantcode, container, key, keyname): # Note: this method overrides _SingleElement.__init__() since we want to keep any AllElements container references as-is, not sub-select them. self._keyname = keyname _PositionSpecifier.__init__(self, wantcode, container, key) def __repr__(self): return '%r.%s(%r)' % (self._container, self._keyname, self.AEM_want) def AEM_resolve(self, obj): return getattr(self._container.AEM_resolve(obj), self._keyname)(self.AEM_want)
class ElementsByFilter(_MultipleElements): """Form: elementsref.filter(expr) A reference to all elements that match a condition, where expr is a relative reference to the object being tested (see also 'its'). """ _keyForm = base.packEnum(kAE.formTest) def __init__(self, wantcode, container, key): if not isinstance(key, testclause.Test): raise TypeError, 'Not a test specifier: %r' % key _PositionSpecifier.__init__(self, wantcode, container.AEM_trueSelf(), key) def __repr__(self): return '%r.byfilter(%r)' % (self._container, self._key) def _packKey(self, codecs): return codecs.pack(self._key) def AEM_resolve(self, obj): return self._container.AEM_resolve(obj).byfilter(self._key)
class EndsWith(_ComparisonTest): _name = 'endswith' _operator = base.packEnum(kAE.kAEEndsWith)
class GreaterThan(_ComparisonTest): _name = 'gt' _operator = base.packEnum(kAE.kAEGreaterThan)
class ElementByID(_SingleElement): """Form: elementsref.byid(anything) A reference to a single element by its id. """ _by = 'byid' _keyForm = base.packEnum(kAE.formUniqueID)
class ElementByIndex(_SingleElement): """Form: elementsref.byindex(i) A reference to a single element by its index, where i is a non-zero whole number. """ _by = 'byindex' _keyForm = base.packEnum(kAE.formAbsolutePosition)
class ElementByName(_SingleElement): """Form: elementsref.byname(text) A reference to a single element by its name, where text is string or unicode. """ _by = 'byname' _keyForm = base.packEnum(kAE.formName)
class GreaterOrEquals(_ComparisonTest): _name = 'ge' _operator = base.packEnum(kAE.kAEGreaterThanEquals)
class Equals(_ComparisonTest): _name = 'eq' _operator = base.packEnum(kAE.kAEEquals)
class _PositionSpecifier(Specifier): """All property and element reference forms inherit from this class. Note that comparison and logic 'operator' methods are implemented on this class - these are only for use in constructing its-based references and shouldn't be used on app- and con-based references. Aem doesn't enforce this rule itself so as to minimise runtime overhead (the target application will raise an error if the user does something foolish). """ _kBeginning = base.packEnum(kAE.kAEBeginning) _kEnd = base.packEnum(kAE.kAEEnd) _kBefore = base.packEnum(kAE.kAEBefore) _kAfter = base.packEnum(kAE.kAEAfter) _kPrevious = base.packEnum(kAE.kAEPrevious) _kNext = base.packEnum(kAE.kAENext) def __init__(self, wantcode, container, key): self.AEM_want = wantcode Specifier.__init__(self, container, key) def __repr__(self): return '%r.%s(%r)' % (self._container, self._by, self._key) def __eq__(self, v): return Specifier.__eq__(self, v) and (self.AEM_want == v.AEM_want) def _packSelf(self, codecs): return base.packListAs(kAE.typeObjectSpecifier, [ (kAE.keyAEDesiredClass, base.packType(self.AEM_want)), (kAE.keyAEKeyForm, self._keyForm), (kAE.keyAEKeyData, self._packKey(codecs)), (kAE.keyAEContainer, self._container.AEM_packSelf(codecs)), ]) # Comparison tests; these should only be used on its-based references: def gt(self, val): """gt(anything) --> is greater than test""" return testclause.GreaterThan(self, val) def ge(self, val): """ge(anything) --> is greater than or equals test""" return testclause.GreaterOrEquals(self, val) def eq(self, val): """eq(anything) --> equals test""" return testclause.Equals(self, val) def ne(self, val): """ne(anything) --> does not equal test""" return testclause.NotEquals(self, val) def lt(self, val): """lt(anything) --> is less than test""" return testclause.LessThan(self, val) def le(self, val): """le(anything) --> is less than or equals test""" return testclause.LessOrEquals(self, val) def startswith(self, val): """startswith(anything) --> starts with test""" return testclause.StartsWith(self, val) def endswith(self, val): """endswith(anything) --> ends with test""" return testclause.EndsWith(self, val) def contains(self, val): """contains(anything) --> contains test""" return testclause.Contains(self, val) def isin(self, val): """isin(anything) --> isin test""" return testclause.IsIn(self, val) # Logic tests; these should only be used on its-based references: # Note: these three methods allow boolean tests to be written in shorthand form; # e.g. 'its.foo.AND(...)' will automatically expand to 'its.foo.eq(True).AND(...)' def AND(self, *operands): """AND(test, ...) --> logical AND test""" return testclause.Equals(self, True).AND(*operands) def OR(self, *operands): """OR(test, ...) --> logical OR test""" return testclause.Equals(self, True).OR(*operands) NOT = property(lambda self: testclause.Equals(self, True).NOT, doc="NOT --> logical NOT test") # Insertion references can be used on any kind of element reference, and also on property references where the property represents a one-to-one relationship, e.g. textedit.documents[1].text.end is valid: start = property( lambda self: InsertionSpecifier(self, self._kBeginning, 'start'), doc="start --> insertion location") end = property(lambda self: InsertionSpecifier(self, self._kEnd, 'end'), doc="end --> insertion location") before = property( lambda self: InsertionSpecifier(self, self._kBefore, 'before'), doc="before --> insertion location") after = property( lambda self: InsertionSpecifier(self, self._kAfter, 'after'), doc="after --> insertion location") # Property and element references can be used on any type of object reference: def property(self, propertycode): """property(propertycode) --> property""" return Property(kAE.cProperty, self, propertycode) def userproperty(self, name): """property(name) --> property""" return UserProperty(kAE.cProperty, self, name) def elements(self, elementcode): """elements(elementcode) --> all elements""" return AllElements(elementcode, self) # Relative position references are unlikely to work on one-to-one relationships - but what the hey, it simplifies the class structure a bit. def previous(self, elementcode): """previous(elementcode) --> element""" return ElementByRelativePosition(elementcode, self, self._kPrevious, 'previous') def next(self, elementcode): """next(elementcode) --> element""" return ElementByRelativePosition(elementcode, self, self._kNext, 'next')
class OR(_LogicalTest): _operator = base.packEnum(kAE.kAEOR) _name = 'OR'
class NotEquals(Equals): _name = 'ne' _operatorNOT = base.packEnum(kAE.kAENOT) def AEM_packSelf(self, codecs): return self._operand1.eq(self._operand2).NOT.AEM_packSelf(codecs)
class StartsWith(_ComparisonTest): _name = 'startswith' _operator = base.packEnum(kAE.kAEBeginsWith)
class LessOrEquals(_ComparisonTest): _name = 'le' _operator = base.packEnum(kAE.kAELessThanEquals)
class LessThan(_ComparisonTest): _name = 'lt' _operator = base.packEnum(kAE.kAELessThan)
class Contains(_ComparisonTest): _name = 'contains' _operator = base.packEnum(kAE.kAEContains)
class AND(_LogicalTest): _operator = base.packEnum(kAE.kAEAND) _name = 'AND'