1 """
2 I define the class of annotations.
3 """
4
5 import itertools
6
7 from advene.model.consts import _RAISE
8 from advene.model.core.element import PackageElement, ElementCollection, ElementCollectionWrapper, \
9 ANNOTATION, MEDIA, RESOURCE, RELATION
10 from advene.model.core.content import WithContentMixin
11 from advene.model.tales import tales_property, tales_use_as_context
12 from advene.util.autoproperty import autoproperty
13 from advene.util.session import session
14
15
16 -class Annotation(PackageElement, WithContentMixin):
17 """FIXME: missing docstring.
18 """
19
20 ADVENE_TYPE = ANNOTATION
21
22
23 _begin = None
24 _end = None
25 _media_id = None
26 _media = None
27
28 @classmethod
29 - def instantiate(cls, owner, id,
30 media, begin, end, mimetype, model, url, *args):
31 """
32 Factory method to create an instance based on backend data.
33 """
34 r = super(Annotation, cls).instantiate(
35 owner, id, media, begin, end, mimetype, model, url, *args)
36 r._begin = begin
37 r._end = end
38 r._media_id = media
39 r._media = None
40 r._instantiate_content(mimetype, model, url)
41 return r
42
43 @classmethod
44 - def create_new(cls, owner, id,
45 media, begin, end, mimetype, model, url):
46 """
47 Factory method to create a new instance both in memory and backend.
48 """
49 media_id = PackageElement._check_reference(owner, media, MEDIA, True)
50 begin = int(begin)
51 end = int(end)
52 model_id = PackageElement._check_reference(owner, model, RESOURCE)
53 cls._check_content_cls(mimetype, model_id, url)
54 owner._backend.create_annotation(owner._id, id, media_id, begin, end,
55 mimetype, model_id, url)
56 r = cls.instantiate(owner, id, media_id, begin, end,
57 mimetype, model_id, url)
58 if media is not media_id:
59
60 r._media = media
61 return r
62
72
76
77 - def _cmp(self, other):
78 """
79 Common implementation for __lt__, __gt__, __le__ and __ge__.
80
81 Do not rename it to __cmp__ because it would be used for __eq__ as
82 well, which is not what we want.
83 """
84 return self._begin - other._begin \
85 or self._end - other._end \
86 or cmp(self._media_id, other._media_id)
87
89 return getattr(other, "ADVENE_TYPE", None) is ANNOTATION \
90 and self._cmp(other) < 0
91
93 return getattr(other, "ADVENE_TYPE", None) is ANNOTATION \
94 and self._cmp(other) <= 0
95
97 return getattr(other, "ADVENE_TYPE", None) is ANNOTATION \
98 and self._cmp(other) > 0
99
101 return getattr(other, "ADVENE_TYPE", None) is ANNOTATION \
102 and self._cmp(other) >= 0
103
105 if type(self) == type(other):
106 return self.begin <= other.begin and other.end <= self.end
107 else:
108 o = long(other)
109 return self._begin <= other <= self._end
110
123
124 @autoproperty
133
134 @autoproperty
142
143 @autoproperty
156
157 @autoproperty
160
161 @autoproperty
163 self.emit("pre-modified::begin", "begin", val)
164 self._begin = val
165 self.__store()
166 self.emit("modified::begin", "begin", val)
167
168 @autoproperty
171
172 @autoproperty
174 self.emit("pre-modified::end", "end", val)
175 self._end = val
176 self.__store()
177 self.emit("modified::end", "end", val)
178
179 @autoproperty
181 """The duration of this annotation.
182
183 This property is a shortcut for ``self.end - self.begin``. Setting it
184 will update self.end accordingly, leaving self.begin unmodified.
185 return self._end - self._begin.
186
187 This property will also be modified by setting self.begin or self.end,
188 since each one of these properties leaves the other one unmodified when set.
189 """
190 return self._end - self._begin
191
192 @autoproperty
195
200
201
202
203 - def iter_relations(self, package=None, position=None, inherited=True):
204 """
205 Iter over all the relations involving this annotation, from the point of
206 view of `package`.
207
208 If `position` is provided, only the relation where this annotations is
209 in the given position are yielded.
210
211 If `inherited` is True (default), all the relations imported by the
212 package are searched, else only proper relations of the package are
213 searched.
214
215 If ``package`` is not provided, the ``package`` session variable is
216 used. If the latter is unset, a TypeError is raised.
217 """
218 if package is None:
219 package = session.package
220 if package is None:
221 raise TypeError("no package set in session, must be specified")
222 if inherited:
223 g = package.all
224 else:
225 g = package.own
226 return g.iter_relations(member=self, position=position)
227
229 """
230 Count all the relations involving this annotation, from the point of
231 view of `package`.
232
233 If `position` is providsed, only the relation where this annotations is
234 in the given position are counted.
235
236 If ``package`` is not provided, the ``package`` session variable is
237 used. If the latter is unset, a TypeError is raised.
238 """
239 if package is None:
240 package = session.package
241 if package is None:
242 raise TypeError("no package set in session, must be specified")
243 return package.all.count_relations(member=self, position=position)
244
245 @property
253 return AnnotationRelations(session.package)
254
255 @property
257 """List of incoming relations.
258 """
259 return self.relations.filter(position=0)
260
261 @property
263 """List of outgoing relations.
264 """
265 return self.relations.filter(position=1)
266
267 @property
275
276 @property
282
283 @property
289
290 @tales_property
291 @tales_use_as_context("package")
293 p = context_package
294 class TalesAnnotationRelations(ElementCollection):
295 def __iter__(self, position=None):
296 return annotation.iter_relations(p, position)
297 def __len__(self, position=None):
298 return annotation.count_relations(p, position)
299 def __contains__(self, r):
300 return getattr(r, "ADVENE_TYPE", None) == RELATION \
301 and annotation in r
302 return TalesAnnotationRelations(p)
303
304 @tales_property
307
308 @tales_property
311
312 @tales_property
317
318 @tales_property
323
324 @tales_property
326 options=context.globals['options']
327 controller=options['controller']
328 if controller.server is not None:
329 url=controller.server.urlbase
330 else:
331 url='/'
332 url=url + "packages/%s/imagecache/%s/%d" % (options['aliases'][self.owner],
333 self.media.id,
334 self.begin)
335 return url
336
337 @tales_property
339 options=context.globals['options']
340 controller=options['controller']
341 if controller.server is not None:
342 url=controller.server.urlbase
343 else:
344 url='/'
345 url=url + "media/%s/play/%d" % (self.media.id,
346 self.begin)
347 return url
348