Package advene :: Package model :: Package core :: Module annotation
[hide private]
[frames] | no frames]

Source Code for Module advene.model.core.annotation

  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 # attributes that do not prevent annotations to be volatile 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 # we have the instance, let's cache it now 60 r._media = media 61 return r
62
63 - def _update_caches(self, old_idref, new_idref, element, relation):
64 """ 65 :see-also: `advene.model.core.element.PackageElement._update_caches` 66 """ 67 if relation == ("media"): 68 self._media_id = new_idref 69 else: 70 super(Annotation, self) \ 71 ._update_caches(old_idref, new_idref, element, relation)
72
73 - def __str__(self):
74 return "Annotation(%s,%s,%s)" % \ 75 (self._media_id, self._begin, self._end)
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
88 - def __lt__(self, other):
89 return getattr(other, "ADVENE_TYPE", None) is ANNOTATION \ 90 and self._cmp(other) < 0
91
92 - def __le__(self, other):
93 return getattr(other, "ADVENE_TYPE", None) is ANNOTATION \ 94 and self._cmp(other) <= 0
95
96 - def __gt__(self, other):
97 return getattr(other, "ADVENE_TYPE", None) is ANNOTATION \ 98 and self._cmp(other) > 0
99
100 - def __ge__(self, other):
101 return getattr(other, "ADVENE_TYPE", None) is ANNOTATION \ 102 and self._cmp(other) >= 0
103
104 - def __contains__(self, other):
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
111 - def get_media(self, default=None):
112 """Return the media associated to this annotation. 113 114 If the media is unreachable, the ``default`` value is returned. 115 116 See also `media` and `media_id`. 117 """ 118 r = self._media 119 if r is None: 120 r = self._media = \ 121 self._owner.get_element(self._media_id, default) 122 return r
123 124 @autoproperty
125 - def _get_media(self):
126 """Return the media associated to this annotation. 127 128 If the media instance is unreachable, an exception is raised. 129 130 See also `get_media` and `media_id`. 131 """ 132 return self.get_media(_RAISE)
133 134 @autoproperty
135 - def _set_media(self, media):
136 mid = self._check_reference(self._owner, media, MEDIA, True) 137 self.emit("pre-modified::media", "media", media) 138 self._media_id = mid 139 self._media = media 140 self.__store() 141 self.emit("modified::media", "media", media)
142 143 @autoproperty
144 - def _get_media_id(self):
145 """The id-ref of this annotation's media. 146 147 This is a read-only property giving the id-ref of the resource held 148 by `media`. 149 150 Note that this property is accessible even if the corresponding 151 media is unreachable. 152 153 See also `get_media` and `media`. 154 """ 155 return self._media_id
156 157 @autoproperty
158 - def _get_begin(self):
159 return self._begin
160 161 @autoproperty
162 - def _set_begin(self, val):
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
169 - def _get_end(self):
170 return self._end
171 172 @autoproperty
173 - def _set_end(self, val):
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
180 - def _get_duration(self):
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
193 - def _set_duration(self, val):
194 self._set_end(self._begin + val)
195
196 - def __store(self):
197 o = self._owner 198 o._backend.update_annotation(o._id, self._id, 199 self._media_id, self._begin, self._end)
200 201 # relation management shortcuts 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
228 - def count_relations(self, package=None, position=None):
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
246 - def relations(annotation):
247 class AnnotationRelations(ElementCollection): 248 __iter__ = annotation.iter_relations 249 __len__ = annotation.count_relations 250 def __contains__(self, r): 251 return getattr(r, "ADVENE_TYPE", None) == RELATION \ 252 and annotation in r
253 return AnnotationRelations(session.package) 254 255 @property
256 - def incoming_relations(self):
257 """List of incoming relations. 258 """ 259 return self.relations.filter(position=0)
260 261 @property
262 - def outgoing_relations(self):
263 """List of outgoing relations. 264 """ 265 return self.relations.filter(position=1)
266 267 @property
268 - def related(self):
269 """List (iterator) of related annotations 270 """ 271 return itertools.chain( 272 (r[1] for r in self.incoming_relations), 273 (r[0] for r in self.outgoing_relations) 274 )
275 276 @property 282 283 @property 289 290 @tales_property 291 @tales_use_as_context("package")
292 - def _tales_relations(annotation, 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
305 - def _tales_incoming_relations(self, context):
306 return self._tales_relations(context).filter(position=0)
307 308 @tales_property
309 - def _tales_outgoing_relations(self, context):
310 return self._tales_relations(context).filter(position=1)
311 312 @tales_property 317 318 @tales_property 323 324 @tales_property
325 - def _tales_snapshot_url(self, context):
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
338 - def _tales_player_url(self, context):
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