Jack Jansen | d0fc42f | 2001-08-19 22:05:06 +0000 | [diff] [blame] | 1 | """aetypes - Python objects representing various AE types.""" |
| 2 | |
Jack Jansen | 5a6fdcd | 2001-08-25 12:15:04 +0000 | [diff] [blame] | 3 | from Carbon.AppleEvents import * |
Jack Jansen | d0fc42f | 2001-08-19 22:05:06 +0000 | [diff] [blame] | 4 | import struct |
| 5 | from types import * |
| 6 | import string |
| 7 | |
| 8 | # |
| 9 | # convoluted, since there are cyclic dependencies between this file and |
| 10 | # aetools_convert. |
| 11 | # |
Jack Jansen | 8b77767 | 2002-08-07 14:49:00 +0000 | [diff] [blame] | 12 | def pack(*args, **kwargs): |
Jack Jansen | d0fc42f | 2001-08-19 22:05:06 +0000 | [diff] [blame] | 13 | from aepack import pack |
Jack Jansen | 8b77767 | 2002-08-07 14:49:00 +0000 | [diff] [blame] | 14 | return apply(pack, args, kwargs) |
Jack Jansen | d0fc42f | 2001-08-19 22:05:06 +0000 | [diff] [blame] | 15 | |
| 16 | def IsSubclass(cls, base): |
| 17 | """Test whether CLASS1 is the same as or a subclass of CLASS2""" |
| 18 | # Loop to optimize for single inheritance |
| 19 | while 1: |
| 20 | if cls is base: return 1 |
| 21 | if len(cls.__bases__) <> 1: break |
| 22 | cls = cls.__bases__[0] |
| 23 | # Recurse to cope with multiple inheritance |
| 24 | for c in cls.__bases__: |
| 25 | if IsSubclass(c, base): return 1 |
| 26 | return 0 |
| 27 | |
| 28 | def IsInstance(x, cls): |
| 29 | """Test whether OBJECT is an instance of (a subclass of) CLASS""" |
| 30 | return type(x) is InstanceType and IsSubclass(x.__class__, cls) |
| 31 | |
| 32 | def nice(s): |
| 33 | """'nice' representation of an object""" |
| 34 | if type(s) is StringType: return repr(s) |
| 35 | else: return str(s) |
| 36 | |
| 37 | class Unknown: |
| 38 | """An uninterpreted AE object""" |
| 39 | |
| 40 | def __init__(self, type, data): |
| 41 | self.type = type |
| 42 | self.data = data |
| 43 | |
| 44 | def __repr__(self): |
| 45 | return "Unknown(%s, %s)" % (`self.type`, `self.data`) |
| 46 | |
| 47 | def __aepack__(self): |
| 48 | return pack(self.data, self.type) |
| 49 | |
| 50 | class Enum: |
| 51 | """An AE enumeration value""" |
| 52 | |
| 53 | def __init__(self, enum): |
| 54 | self.enum = "%-4.4s" % str(enum) |
| 55 | |
| 56 | def __repr__(self): |
| 57 | return "Enum(%s)" % `self.enum` |
| 58 | |
| 59 | def __str__(self): |
| 60 | return string.strip(self.enum) |
| 61 | |
| 62 | def __aepack__(self): |
| 63 | return pack(self.enum, typeEnumeration) |
| 64 | |
| 65 | def IsEnum(x): |
| 66 | return IsInstance(x, Enum) |
| 67 | |
| 68 | def mkenum(enum): |
| 69 | if IsEnum(enum): return enum |
| 70 | return Enum(enum) |
| 71 | |
Jack Jansen | 8b77767 | 2002-08-07 14:49:00 +0000 | [diff] [blame] | 72 | # Jack changed the way this is done |
| 73 | class InsertionLoc: |
| 74 | def __init__(self, of, pos): |
| 75 | self.of = of |
| 76 | self.pos = pos |
| 77 | |
| 78 | def __repr__(self): |
| 79 | return "InsertionLoc(%s, %s)" % (`self.of`, `self.pos`) |
| 80 | |
| 81 | def __aepack__(self): |
| 82 | rec = {'kobj': self.of, 'kpos': self.pos} |
| 83 | return pack(rec, forcetype='insl') |
| 84 | |
| 85 | # Convenience functions for dsp: |
| 86 | def beginning(of): |
| 87 | return InsertionLoc(of, Enum('bgng')) |
| 88 | |
| 89 | def end(of): |
| 90 | return InsertionLoc(of, Enum('end ')) |
| 91 | |
Jack Jansen | d0fc42f | 2001-08-19 22:05:06 +0000 | [diff] [blame] | 92 | class Boolean: |
| 93 | """An AE boolean value""" |
| 94 | |
| 95 | def __init__(self, bool): |
| 96 | self.bool = (not not bool) |
| 97 | |
| 98 | def __repr__(self): |
| 99 | return "Boolean(%s)" % `self.bool` |
| 100 | |
| 101 | def __str__(self): |
| 102 | if self.bool: |
| 103 | return "True" |
| 104 | else: |
| 105 | return "False" |
| 106 | |
| 107 | def __aepack__(self): |
| 108 | return pack(struct.pack('b', self.bool), 'bool') |
| 109 | |
| 110 | def IsBoolean(x): |
| 111 | return IsInstance(x, Boolean) |
| 112 | |
| 113 | def mkboolean(bool): |
| 114 | if IsBoolean(bool): return bool |
| 115 | return Boolean(bool) |
| 116 | |
| 117 | class Type: |
| 118 | """An AE 4-char typename object""" |
| 119 | |
| 120 | def __init__(self, type): |
| 121 | self.type = "%-4.4s" % str(type) |
| 122 | |
| 123 | def __repr__(self): |
| 124 | return "Type(%s)" % `self.type` |
| 125 | |
| 126 | def __str__(self): |
| 127 | return string.strip(self.type) |
| 128 | |
| 129 | def __aepack__(self): |
| 130 | return pack(self.type, typeType) |
| 131 | |
| 132 | def IsType(x): |
| 133 | return IsInstance(x, Type) |
| 134 | |
| 135 | def mktype(type): |
| 136 | if IsType(type): return type |
| 137 | return Type(type) |
| 138 | |
| 139 | |
| 140 | class Keyword: |
| 141 | """An AE 4-char keyword object""" |
| 142 | |
| 143 | def __init__(self, keyword): |
| 144 | self.keyword = "%-4.4s" % str(keyword) |
| 145 | |
| 146 | def __repr__(self): |
| 147 | return "Keyword(%s)" % `self.keyword` |
| 148 | |
| 149 | def __str__(self): |
| 150 | return string.strip(self.keyword) |
| 151 | |
| 152 | def __aepack__(self): |
| 153 | return pack(self.keyword, typeKeyword) |
| 154 | |
| 155 | def IsKeyword(x): |
| 156 | return IsInstance(x, Keyword) |
| 157 | |
| 158 | class Range: |
| 159 | """An AE range object""" |
| 160 | |
| 161 | def __init__(self, start, stop): |
| 162 | self.start = start |
| 163 | self.stop = stop |
| 164 | |
| 165 | def __repr__(self): |
| 166 | return "Range(%s, %s)" % (`self.start`, `self.stop`) |
| 167 | |
| 168 | def __str__(self): |
| 169 | return "%s thru %s" % (nice(self.start), nice(self.stop)) |
| 170 | |
| 171 | def __aepack__(self): |
| 172 | return pack({'star': self.start, 'stop': self.stop}, 'rang') |
| 173 | |
| 174 | def IsRange(x): |
| 175 | return IsInstance(x, Range) |
| 176 | |
| 177 | class Comparison: |
| 178 | """An AE Comparison""" |
| 179 | |
| 180 | def __init__(self, obj1, relo, obj2): |
| 181 | self.obj1 = obj1 |
| 182 | self.relo = "%-4.4s" % str(relo) |
| 183 | self.obj2 = obj2 |
| 184 | |
| 185 | def __repr__(self): |
| 186 | return "Comparison(%s, %s, %s)" % (`self.obj1`, `self.relo`, `self.obj2`) |
| 187 | |
| 188 | def __str__(self): |
| 189 | return "%s %s %s" % (nice(self.obj1), string.strip(self.relo), nice(self.obj2)) |
| 190 | |
| 191 | def __aepack__(self): |
| 192 | return pack({'obj1': self.obj1, |
| 193 | 'relo': mkenum(self.relo), |
| 194 | 'obj2': self.obj2}, |
| 195 | 'cmpd') |
| 196 | |
| 197 | def IsComparison(x): |
| 198 | return IsInstance(x, Comparison) |
| 199 | |
| 200 | class NComparison(Comparison): |
| 201 | # The class attribute 'relo' must be set in a subclass |
| 202 | |
| 203 | def __init__(self, obj1, obj2): |
| 204 | Comparison.__init__(obj1, self.relo, obj2) |
| 205 | |
| 206 | class Ordinal: |
| 207 | """An AE Ordinal""" |
| 208 | |
| 209 | def __init__(self, abso): |
| 210 | # self.obj1 = obj1 |
| 211 | self.abso = "%-4.4s" % str(abso) |
| 212 | |
| 213 | def __repr__(self): |
| 214 | return "Ordinal(%s)" % (`self.abso`) |
| 215 | |
| 216 | def __str__(self): |
| 217 | return "%s" % (string.strip(self.abso)) |
| 218 | |
| 219 | def __aepack__(self): |
| 220 | return pack(self.abso, 'abso') |
| 221 | |
| 222 | def IsOrdinal(x): |
| 223 | return IsInstance(x, Ordinal) |
| 224 | |
| 225 | class NOrdinal(Ordinal): |
| 226 | # The class attribute 'abso' must be set in a subclass |
| 227 | |
| 228 | def __init__(self): |
| 229 | Ordinal.__init__(self, self.abso) |
| 230 | |
| 231 | class Logical: |
| 232 | """An AE logical expression object""" |
| 233 | |
| 234 | def __init__(self, logc, term): |
| 235 | self.logc = "%-4.4s" % str(logc) |
| 236 | self.term = term |
| 237 | |
| 238 | def __repr__(self): |
| 239 | return "Logical(%s, %s)" % (`self.logc`, `self.term`) |
| 240 | |
| 241 | def __str__(self): |
| 242 | if type(self.term) == ListType and len(self.term) == 2: |
| 243 | return "%s %s %s" % (nice(self.term[0]), |
| 244 | string.strip(self.logc), |
| 245 | nice(self.term[1])) |
| 246 | else: |
| 247 | return "%s(%s)" % (string.strip(self.logc), nice(self.term)) |
| 248 | |
| 249 | def __aepack__(self): |
| 250 | return pack({'logc': mkenum(self.logc), 'term': self.term}, 'logi') |
| 251 | |
| 252 | def IsLogical(x): |
| 253 | return IsInstance(x, Logical) |
| 254 | |
| 255 | class StyledText: |
| 256 | """An AE object respresenting text in a certain style""" |
| 257 | |
| 258 | def __init__(self, style, text): |
| 259 | self.style = style |
| 260 | self.text = text |
| 261 | |
| 262 | def __repr__(self): |
| 263 | return "StyledText(%s, %s)" % (`self.style`, `self.text`) |
| 264 | |
| 265 | def __str__(self): |
| 266 | return self.text |
| 267 | |
| 268 | def __aepack__(self): |
| 269 | return pack({'ksty': self.style, 'ktxt': self.text}, 'STXT') |
| 270 | |
| 271 | def IsStyledText(x): |
| 272 | return IsInstance(x, StyledText) |
| 273 | |
| 274 | class AEText: |
| 275 | """An AE text object with style, script and language specified""" |
| 276 | |
| 277 | def __init__(self, script, style, text): |
| 278 | self.script = script |
| 279 | self.style = style |
| 280 | self.text = text |
| 281 | |
| 282 | def __repr__(self): |
| 283 | return "AEText(%s, %s, %s)" % (`self.script`, `self.style`, `self.text`) |
| 284 | |
| 285 | def __str__(self): |
| 286 | return self.text |
| 287 | |
| 288 | def __aepack__(self): |
| 289 | return pack({keyAEScriptTag: self.script, keyAEStyles: self.style, |
| 290 | keyAEText: self.text}, typeAEText) |
| 291 | |
| 292 | def IsAEText(x): |
| 293 | return IsInstance(x, AEText) |
| 294 | |
| 295 | class IntlText: |
| 296 | """A text object with script and language specified""" |
| 297 | |
| 298 | def __init__(self, script, language, text): |
| 299 | self.script = script |
| 300 | self.language = language |
| 301 | self.text = text |
| 302 | |
| 303 | def __repr__(self): |
| 304 | return "IntlText(%s, %s, %s)" % (`self.script`, `self.language`, `self.text`) |
| 305 | |
| 306 | def __str__(self): |
| 307 | return self.text |
| 308 | |
| 309 | def __aepack__(self): |
| 310 | return pack(struct.pack('hh', self.script, self.language)+self.text, |
| 311 | typeIntlText) |
| 312 | |
| 313 | def IsIntlText(x): |
| 314 | return IsInstance(x, IntlText) |
| 315 | |
| 316 | class IntlWritingCode: |
| 317 | """An object representing script and language""" |
| 318 | |
| 319 | def __init__(self, script, language): |
| 320 | self.script = script |
| 321 | self.language = language |
| 322 | |
| 323 | def __repr__(self): |
| 324 | return "IntlWritingCode(%s, %s)" % (`self.script`, `self.language`) |
| 325 | |
| 326 | def __str__(self): |
| 327 | return "script system %d, language %d"%(self.script, self.language) |
| 328 | |
| 329 | def __aepack__(self): |
| 330 | return pack(struct.pack('hh', self.script, self.language), |
| 331 | typeIntlWritingCode) |
| 332 | |
| 333 | def IsIntlWritingCode(x): |
| 334 | return IsInstance(x, IntlWritingCode) |
| 335 | |
| 336 | class QDPoint: |
| 337 | """A point""" |
| 338 | |
| 339 | def __init__(self, v, h): |
| 340 | self.v = v |
| 341 | self.h = h |
| 342 | |
| 343 | def __repr__(self): |
| 344 | return "QDPoint(%s, %s)" % (`self.v`, `self.h`) |
| 345 | |
| 346 | def __str__(self): |
| 347 | return "(%d, %d)"%(self.v, self.h) |
| 348 | |
| 349 | def __aepack__(self): |
| 350 | return pack(struct.pack('hh', self.v, self.h), |
| 351 | typeQDPoint) |
| 352 | |
| 353 | def IsQDPoint(x): |
| 354 | return IsInstance(x, QDPoint) |
| 355 | |
| 356 | class QDRectangle: |
| 357 | """A rectangle""" |
| 358 | |
| 359 | def __init__(self, v0, h0, v1, h1): |
| 360 | self.v0 = v0 |
| 361 | self.h0 = h0 |
| 362 | self.v1 = v1 |
| 363 | self.h1 = h1 |
| 364 | |
| 365 | def __repr__(self): |
| 366 | return "QDRectangle(%s, %s, %s, %s)" % (`self.v0`, `self.h0`, |
| 367 | `self.v1`, `self.h1`) |
| 368 | |
| 369 | def __str__(self): |
| 370 | return "(%d, %d)-(%d, %d)"%(self.v0, self.h0, self.v1, self.h1) |
| 371 | |
| 372 | def __aepack__(self): |
| 373 | return pack(struct.pack('hhhh', self.v0, self.h0, self.v1, self.h1), |
| 374 | typeQDRectangle) |
| 375 | |
| 376 | def IsQDRectangle(x): |
| 377 | return IsInstance(x, QDRectangle) |
| 378 | |
| 379 | class RGBColor: |
| 380 | """An RGB color""" |
| 381 | |
| 382 | def __init__(self, r, g, b): |
| 383 | self.r = r |
| 384 | self.g = g |
| 385 | self.b = b |
| 386 | |
| 387 | def __repr__(self): |
| 388 | return "RGBColor(%s, %s, %s)" % (`self.r`, `self.g`, `self.b`) |
| 389 | |
| 390 | def __str__(self): |
| 391 | return "0x%x red, 0x%x green, 0x%x blue"% (self.r, self.g, self.b) |
| 392 | |
| 393 | def __aepack__(self): |
| 394 | return pack(struct.pack('hhh', self.r, self.g, self.b), |
| 395 | typeRGBColor) |
| 396 | |
| 397 | def IsRGBColor(x): |
| 398 | return IsInstance(x, RGBColor) |
| 399 | |
| 400 | class ObjectSpecifier: |
| 401 | |
| 402 | """A class for constructing and manipulation AE object specifiers in python. |
| 403 | |
| 404 | An object specifier is actually a record with four fields: |
| 405 | |
| 406 | key type description |
| 407 | --- ---- ----------- |
| 408 | |
| 409 | 'want' type 4-char class code of thing we want, |
| 410 | e.g. word, paragraph or property |
| 411 | |
| 412 | 'form' enum how we specify which 'want' thing(s) we want, |
| 413 | e.g. by index, by range, by name, or by property specifier |
| 414 | |
| 415 | 'seld' any which thing(s) we want, |
| 416 | e.g. its index, its name, or its property specifier |
| 417 | |
| 418 | 'from' object the object in which it is contained, |
| 419 | or null, meaning look for it in the application |
| 420 | |
| 421 | Note that we don't call this class plain "Object", since that name |
| 422 | is likely to be used by the application. |
| 423 | """ |
| 424 | |
| 425 | def __init__(self, want, form, seld, fr = None): |
| 426 | self.want = want |
| 427 | self.form = form |
| 428 | self.seld = seld |
| 429 | self.fr = fr |
| 430 | |
| 431 | def __repr__(self): |
| 432 | s = "ObjectSpecifier(%s, %s, %s" % (`self.want`, `self.form`, `self.seld`) |
| 433 | if self.fr: |
| 434 | s = s + ", %s)" % `self.fr` |
| 435 | else: |
| 436 | s = s + ")" |
| 437 | return s |
| 438 | |
| 439 | def __aepack__(self): |
| 440 | return pack({'want': mktype(self.want), |
| 441 | 'form': mkenum(self.form), |
| 442 | 'seld': self.seld, |
| 443 | 'from': self.fr}, |
| 444 | 'obj ') |
| 445 | |
| 446 | def IsObjectSpecifier(x): |
| 447 | return IsInstance(x, ObjectSpecifier) |
| 448 | |
| 449 | |
| 450 | # Backwards compatability, sigh... |
| 451 | class Property(ObjectSpecifier): |
| 452 | |
| 453 | def __init__(self, which, fr = None, want='prop'): |
| 454 | ObjectSpecifier.__init__(self, want, 'prop', mktype(which), fr) |
| 455 | |
| 456 | def __repr__(self): |
| 457 | if self.fr: |
| 458 | return "Property(%s, %s)" % (`self.seld.type`, `self.fr`) |
| 459 | else: |
| 460 | return "Property(%s)" % `self.seld.type` |
| 461 | |
| 462 | def __str__(self): |
| 463 | if self.fr: |
| 464 | return "Property %s of %s" % (str(self.seld), str(self.fr)) |
| 465 | else: |
| 466 | return "Property %s" % str(self.seld) |
| 467 | |
| 468 | |
| 469 | class NProperty(ObjectSpecifier): |
| 470 | # Subclasses *must* self baseclass attributes: |
| 471 | # want is the type of this property |
| 472 | # which is the property name of this property |
| 473 | |
| 474 | def __init__(self, fr = None): |
| 475 | #try: |
| 476 | # dummy = self.want |
| 477 | #except: |
| 478 | # self.want = 'prop' |
| 479 | self.want = 'prop' |
| 480 | ObjectSpecifier.__init__(self, self.want, 'prop', |
| 481 | mktype(self.which), fr) |
| 482 | |
| 483 | def __repr__(self): |
| 484 | rv = "Property(%s"%`self.seld.type` |
| 485 | if self.fr: |
| 486 | rv = rv + ", fr=%s" % `self.fr` |
| 487 | if self.want != 'prop': |
| 488 | rv = rv + ", want=%s" % `self.want` |
| 489 | return rv + ")" |
| 490 | |
| 491 | def __str__(self): |
| 492 | if self.fr: |
| 493 | return "Property %s of %s" % (str(self.seld), str(self.fr)) |
| 494 | else: |
| 495 | return "Property %s" % str(self.seld) |
| 496 | |
| 497 | |
| 498 | class SelectableItem(ObjectSpecifier): |
| 499 | |
| 500 | def __init__(self, want, seld, fr = None): |
| 501 | t = type(seld) |
| 502 | if t == StringType: |
| 503 | form = 'name' |
| 504 | elif IsRange(seld): |
| 505 | form = 'rang' |
| 506 | elif IsComparison(seld) or IsLogical(seld): |
| 507 | form = 'test' |
| 508 | elif t == TupleType: |
| 509 | # Breakout: specify both form and seld in a tuple |
| 510 | # (if you want ID or rele or somesuch) |
| 511 | form, seld = seld |
| 512 | else: |
| 513 | form = 'indx' |
| 514 | ObjectSpecifier.__init__(self, want, form, seld, fr) |
| 515 | |
| 516 | |
| 517 | class ComponentItem(SelectableItem): |
| 518 | # Derived classes *must* set the *class attribute* 'want' to some constant |
| 519 | # Also, dictionaries _propdict and _elemdict must be set to map property |
| 520 | # and element names to the correct classes |
| 521 | |
| 522 | def __init__(self, which, fr = None): |
| 523 | SelectableItem.__init__(self, self.want, which, fr) |
| 524 | |
| 525 | def __repr__(self): |
| 526 | if not self.fr: |
| 527 | return "%s(%s)" % (self.__class__.__name__, `self.seld`) |
| 528 | return "%s(%s, %s)" % (self.__class__.__name__, `self.seld`, `self.fr`) |
| 529 | |
| 530 | def __str__(self): |
| 531 | seld = self.seld |
| 532 | if type(seld) == StringType: |
| 533 | ss = repr(seld) |
| 534 | elif IsRange(seld): |
| 535 | start, stop = seld.start, seld.stop |
| 536 | if type(start) == InstanceType == type(stop) and \ |
| 537 | start.__class__ == self.__class__ == stop.__class__: |
| 538 | ss = str(start.seld) + " thru " + str(stop.seld) |
| 539 | else: |
| 540 | ss = str(seld) |
| 541 | else: |
| 542 | ss = str(seld) |
| 543 | s = "%s %s" % (self.__class__.__name__, ss) |
| 544 | if self.fr: s = s + " of %s" % str(self.fr) |
| 545 | return s |
| 546 | |
| 547 | def __getattr__(self, name): |
| 548 | if self._elemdict.has_key(name): |
| 549 | cls = self._elemdict[name] |
| 550 | return DelayedComponentItem(cls, self) |
| 551 | if self._propdict.has_key(name): |
| 552 | cls = self._propdict[name] |
| 553 | return cls(self) |
| 554 | raise AttributeError, name |
| 555 | |
| 556 | |
| 557 | class DelayedComponentItem: |
| 558 | def __init__(self, compclass, fr): |
| 559 | self.compclass = compclass |
| 560 | self.fr = fr |
| 561 | |
| 562 | def __call__(self, which): |
| 563 | return self.compclass(which, self.fr) |
| 564 | |
| 565 | def __repr__(self): |
| 566 | return "%s(???, %s)" % (self.__class__.__name__, `self.fr`) |
| 567 | |
| 568 | def __str__(self): |
| 569 | return "selector for element %s of %s"%(self.__class__.__name__, str(self.fr)) |
| 570 | |
| 571 | template = """ |
| 572 | class %s(ComponentItem): want = '%s' |
| 573 | """ |
| 574 | |
| 575 | exec template % ("Text", 'text') |
| 576 | exec template % ("Character", 'cha ') |
| 577 | exec template % ("Word", 'cwor') |
| 578 | exec template % ("Line", 'clin') |
| 579 | exec template % ("paragraph", 'cpar') |
| 580 | exec template % ("Window", 'cwin') |
| 581 | exec template % ("Document", 'docu') |
| 582 | exec template % ("File", 'file') |
| 583 | exec template % ("InsertionPoint", 'cins') |
| 584 | |