blob: d376e74f50718af92e8a8c553291ea378d504151 [file] [log] [blame]
Jack Jansend0fc42f2001-08-19 22:05:06 +00001"""aetypes - Python objects representing various AE types."""
2
Jack Jansen5a6fdcd2001-08-25 12:15:04 +00003from Carbon.AppleEvents import *
Jack Jansend0fc42f2001-08-19 22:05:06 +00004import struct
5from types import *
6import string
7
8#
9# convoluted, since there are cyclic dependencies between this file and
10# aetools_convert.
11#
Jack Jansen8b777672002-08-07 14:49:00 +000012def pack(*args, **kwargs):
Jack Jansend0fc42f2001-08-19 22:05:06 +000013 from aepack import pack
Jack Jansen8b777672002-08-07 14:49:00 +000014 return apply(pack, args, kwargs)
Jack Jansend0fc42f2001-08-19 22:05:06 +000015
16def 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
28def 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
32def nice(s):
33 """'nice' representation of an object"""
34 if type(s) is StringType: return repr(s)
35 else: return str(s)
36
37class 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
50class 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
65def IsEnum(x):
66 return IsInstance(x, Enum)
67
68def mkenum(enum):
69 if IsEnum(enum): return enum
70 return Enum(enum)
71
Jack Jansen8b777672002-08-07 14:49:00 +000072# Jack changed the way this is done
73class 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:
86def beginning(of):
87 return InsertionLoc(of, Enum('bgng'))
88
89def end(of):
90 return InsertionLoc(of, Enum('end '))
91
Jack Jansend0fc42f2001-08-19 22:05:06 +000092class 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
110def IsBoolean(x):
111 return IsInstance(x, Boolean)
112
113def mkboolean(bool):
114 if IsBoolean(bool): return bool
115 return Boolean(bool)
116
117class 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
132def IsType(x):
133 return IsInstance(x, Type)
134
135def mktype(type):
136 if IsType(type): return type
137 return Type(type)
138
139
140class 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
155def IsKeyword(x):
156 return IsInstance(x, Keyword)
157
158class 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
174def IsRange(x):
175 return IsInstance(x, Range)
176
177class 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
197def IsComparison(x):
198 return IsInstance(x, Comparison)
199
200class 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
206class 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
222def IsOrdinal(x):
223 return IsInstance(x, Ordinal)
224
225class 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
231class 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
252def IsLogical(x):
253 return IsInstance(x, Logical)
254
255class 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
271def IsStyledText(x):
272 return IsInstance(x, StyledText)
273
274class 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
292def IsAEText(x):
293 return IsInstance(x, AEText)
294
295class 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
313def IsIntlText(x):
314 return IsInstance(x, IntlText)
315
316class 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
333def IsIntlWritingCode(x):
334 return IsInstance(x, IntlWritingCode)
335
336class 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
353def IsQDPoint(x):
354 return IsInstance(x, QDPoint)
355
356class 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
376def IsQDRectangle(x):
377 return IsInstance(x, QDRectangle)
378
379class 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
397def IsRGBColor(x):
398 return IsInstance(x, RGBColor)
399
400class 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
446def IsObjectSpecifier(x):
447 return IsInstance(x, ObjectSpecifier)
448
449
450# Backwards compatability, sigh...
451class 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
469class 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
498class 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
517class 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
557class 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
571template = """
572class %s(ComponentItem): want = '%s'
573"""
574
575exec template % ("Text", 'text')
576exec template % ("Character", 'cha ')
577exec template % ("Word", 'cwor')
578exec template % ("Line", 'clin')
579exec template % ("paragraph", 'cpar')
580exec template % ("Window", 'cwin')
581exec template % ("Document", 'docu')
582exec template % ("File", 'file')
583exec template % ("InsertionPoint", 'cins')
584