def generate_buffer_content(self): b=self.textview.get_buffer() # Clear the buffer begin,end=b.get_bounds() b.delete(begin, end) l=list(self.model) for a in l: if self.options['display-time']: b.insert_at_cursor("[%s]" % helper.format_time(a.begin)) mark = b.create_mark("b_%s" % a.id, b.get_iter_at_mark(b.get_insert()), left_gravity=True) mark.set_visible(self.options['display-bounds']) b.insert_at_cursor(unicode(self.representation(a))) mark = b.create_mark("e_%s" % a.id, b.get_iter_at_mark(b.get_insert()), left_gravity=True) mark.set_visible(self.options['display-bounds']) if self.options['display-time']: b.insert_at_cursor("[%s]" % helper.format_time(a.end)) b.insert_at_cursor(self.options['separator']) return
def formatted (target, context): """Return a formatted timestamp as hh:mm:ss.mmmm This method applies to either integers (in this case, it directly returns the formated string), or to fragments. It returns a dictionary with begin, end and duration keys. """ import advene.model.fragment from advene.util.helper import format_time import time if isinstance(target, int) or isinstance(target, long): return format_time(target) if not isinstance(target, advene.model.fragment.MillisecondFragment): return None res = { 'begin': u'--:--:--.---', 'end' : u'--:--:--.---', 'duration': u'--:--:--.---' } for k in res.keys(): t=getattr(target, k) res[k] = format_time(t) return res
def build_pixbuf(self): if self.annotation is None: pixbuf=png_to_pixbuf(self.controller.package.imagecache.not_yet_available_image, width=self.width) elif 'overlay' in self.presentation: pixbuf=overlay_svg_as_pixbuf(self.annotation.rootPackage.imagecache[self.annotation.fragment.begin], self.annotation.content.data, width=self.width) elif 'snapshot' in self.presentation: if 'timestamp' in self.presentation: pixbuf=overlay_svg_as_pixbuf(self.annotation.rootPackage.imagecache[self.annotation.fragment.begin], helper.format_time(self.annotation.fragment.begin), width=self.width) else: pixbuf=png_to_pixbuf(self.annotation.rootPackage.imagecache[self.annotation.fragment.begin], width=self.width) elif 'timestamp' in self.presentation: # Generate only a timestamp pixbuf = self.render_text(helper.format_time(self.annotation.fragment.begin)) elif 'content' in self.presentation: # Display text pixbuf = self.render_text(self.controller.get_title(self.annotation)) else: pixbuf=png_to_pixbuf(self.controller.package.imagecache.not_yet_available_image, width=self.width) pixbuf.as_html=self.as_html pixbuf._placeholder=self pixbuf._tag='span' pixbuf._attr=[] return pixbuf
def build_model(self, elements, custom_data=None): """Build the ListStore containing the data. See set_element docstring for the custom_data method explanation. """ if custom_data is not None: custom = custom_data else: def custom(a): return tuple() args = (object, str, str, str, int, int, str, str, str, GdkPixbuf.Pixbuf, str, str) + custom(None) l=Gtk.ListStore(*args) if not elements: return l for a in elements: if isinstance(a, Annotation): l.append( (a, self.controller.get_title(a), self.controller.get_title(a.type), a.id, a.fragment.begin, a.fragment.end, helper.format_time(a.fragment.duration), helper.format_time(a.fragment.begin), helper.format_time(a.fragment.end), png_to_pixbuf(self.controller.get_snapshot(annotation=a), height=32), self.controller.get_element_color(a), a.ownerPackage.getTitle() ) + custom(a), ) return l
def build_model(self, elements, custom_data=None): """Build the ListStore containing the data. See set_element docstring for the custom_data method explanation. """ if custom_data is not None: custom = custom_data else: def custom(a): return tuple() args = (object, str, str, str, int, int, str, str, str, GdkPixbuf.Pixbuf, str, str) + custom(None) l = Gtk.ListStore(*args) if not elements: return l for a in elements: if isinstance(a, Annotation): l.append( (a, self.controller.get_title(a), self.controller.get_title(a.type), a.id, a.fragment.begin, a.fragment.end, helper.format_time(a.fragment.duration), helper.format_time( a.fragment.begin), helper.format_time(a.fragment.end), png_to_pixbuf(self.controller.get_snapshot(annotation=a), height=32), self.controller.get_element_color(a), a.ownerPackage.getTitle()) + custom(a), ) return l
def formatted (target, context): """Return a formatted timestamp as hh:mm:ss.mmmm This method applies to either integers (in this case, it directly returns the formated string), or to fragments. It returns a dictionary with begin, end and duration keys. """ import advene.model.fragment from advene.util.helper import format_time if isinstance(target, int): return format_time(target) if not isinstance(target, advene.model.fragment.MillisecondFragment): return None res = { 'begin': '--:--:--.---', 'end' : '--:--:--.---', 'duration': '--:--:--.---' } for k in res: t=getattr(target, k) res[k] = format_time(t) res['begin_s'] = target.begin / 1000. res['end_s'] = target.end / 1000. return res
def extract_fragment(self, m, ann): """Extract the fragment corresponding to an annotation. """ title = self.controller.get_title(ann) begin = helper.format_time(ann.fragment.begin) end = helper.format_time(ann.fragment.end) self.controller.gui.render_montage_dialog([ ann ], basename = ann.id + "-" + helper.title2id(title) + ".ogv", title = _("Extracting %s") % title, label = _("Exporting annotation %(title)s\nfrom %(begin)s to %(end)s\nto %%(filename)s") % locals()) return True
def display_stats(self, m, at): """Display statistics about the annotation type. """ msg=_("<b>Statistics about %s</b>\n\n") % self.controller.get_title(at) msg += "%d annotations\n" % len(at.annotations) msg += "Min duration : %s\n" % helper.format_time(min( a.duration for a in at.annotations)) msg += "Max duration : %s\n" % helper.format_time(max( a.duration for a in at.annotations)) msg += "Mean duration : %s\n" % helper.format_time(sum( a.duration for a in at.annotations) / len(at.annotations)) msg += "Total duration : %s\n" % helper.format_time(sum( a.duration for a in at.annotations)) dialog.message_dialog(msg) return True
def set_cursor(wid, t=None, precision=None): if t is None: t = self.annotation if precision is None: precision = config.data.preferences[ 'bookmark-snapshot-precision'] if self.no_image_pixbuf is None: self.no_image_pixbuf = png_to_pixbuf( self.controller.get_snapshot(position=-1), width=config.data.preferences['drag-snapshot-width']) if not t == w._current: if isinstance(t, int): snap = self.controller.get_snapshot( position=t, annotation=self.annotation, precision=precision) if snap.is_default: pixbuf = self.no_image_pixbuf else: pixbuf = png_to_pixbuf( snap, width=config.data. preferences['drag-snapshot-width']) begin.set_from_pixbuf(pixbuf) if resize: end.set_from_pixbuf(resize_pixbuf[resize]) l.set_text(helper.format_time(t)) else: end.hide() padding.hide() l.set_text(helper.format_time(t)) elif isinstance(t, Annotation): # It can be an annotation begin.set_from_pixbuf( png_to_pixbuf( self.controller.get_snapshot(annotation=t), width=config.data. preferences['drag-snapshot-width'])) end.set_from_pixbuf( png_to_pixbuf(self.controller.get_snapshot( annotation=t, position=t.fragment.end), width=config.data. preferences['drag-snapshot-width'])) end.show() padding.show() if widgets: l.set_text(_("Set of %s annotations") % len(widgets)) else: l.set_text(self.controller.get_title(t)) wid._current = t return True
def on_bus_message(self, bus, message): def finalize(): """Finalize data creation. """ GObject.idle_add( lambda: self.pipeline.set_state(Gst.State.NULL) and False) self.generate_annotations() if self.end_callback: self.end_callback() return False s = message.get_structure() if message.type == Gst.MessageType.EOS: finalize() elif s: logger.debug("MSG ", s.get_name(), s.to_string()) if s.get_name() == 'progress' and self.progress is not None: if not self.progress( s['percent-double'] / 100, _("%(count)d utterances until %(time)s") % { 'count': len(self.buffer_list), 'time': helper.format_time(s['current'] * 1000) }): finalize() return True
def refresh(self): """Update the display of the widget according to self._value and self.width """ if self._value is None: v=-1 else: v=self._value if self.width < 9: self.image.hide() self.set_size_request(6, 12) else: png = self.controller.get_snapshot(position=v, media=self._media, precision=self.precision) self.valid_screenshot = not png.is_default self.image.set_from_pixbuf(png_to_pixbuf(bytes(png), width=self.width)) self.set_size_request(-1, -1) self.image.show() ts=helper.format_time(self._value) self.label.set_markup(self._text % { 'timestamp': ts }) self.label.get_style_context().add_class("timestamp_label") if self.visible_label and self.label.get_child_requisition().width <= 1.2 * self.image.get_child_requisition().width: self.label.show() else: self.label.hide() self.set_tooltip_text(ts) return True
def set_cursor(wid, t=None, precision=None): if t is None: t = self.annotation if precision is None: precision = config.data.preferences['bookmark-snapshot-precision'] if self.no_image_pixbuf is None: self.no_image_pixbuf = png_to_pixbuf(self.controller.get_snapshot(position=-1), width=config.data.preferences['drag-snapshot-width']) if not t == w._current: if isinstance(t, int): snap = self.controller.get_snapshot(position=t, annotation=self.annotation, precision=precision) if snap.is_default: pixbuf = self.no_image_pixbuf else: pixbuf = png_to_pixbuf(snap, width=config.data.preferences['drag-snapshot-width']) begin.set_from_pixbuf(pixbuf) end.hide() padding.hide() l.set_text(helper.format_time(t)) elif isinstance(t, Annotation): # It can be an annotation begin.set_from_pixbuf(png_to_pixbuf(self.controller.get_snapshot(annotation=t), width=config.data.preferences['drag-snapshot-width'])) end.set_from_pixbuf(png_to_pixbuf(self.controller.get_snapshot(annotation=t, position=t.fragment.end), width=config.data.preferences['drag-snapshot-width'])) end.show() padding.show() if widgets: l.set_text(_("Set of %s annotations") % len(widgets)) else: l.set_text(self.controller.get_title(t)) wid._current=t return True
def add_data(self, message, position, url=None): # Check for identical data already pushed l = [t for t in self.data if t[2] == message and t[3] == url] if l: return True hb = Gtk.HBox() b = Gtk.Button(message) # Make the message left-aligned b.get_child().set_alignment(0.0, 0.5) b.connect('clicked', self.goto_url, url) b.set_tooltip_text(_("Go to %s") % url) hb.add(b) b = Gtk.Button(helper.format_time(position)) b.get_child().set_alignment(0.0, 0.5) b.connect('clicked', self.goto_position, position) b.set_tooltip_text(_("Go to the given position")) hb.pack_start(b, False, True, 0) hb.show_all() self.datawidget.pack_start(hb, False, True, 0) self.data.append((time.time(), position, message, url, hb)) return True
def add_data(self, message, position, url=None): # Check for identical data already pushed l=[ t for t in self.data if t[2] == message and t[3] == url ] if l: return True hb=Gtk.HBox() b=Gtk.Button(message) # Make the message left-aligned b.get_child().set_alignment(0.0, 0.5) b.connect('clicked', self.goto_url, url) b.set_tooltip_text(_("Go to %s") % url) hb.add(b) b=Gtk.Button(helper.format_time(position)) b.get_child().set_alignment(0.0, 0.5) b.connect('clicked', self.goto_position, position) b.set_tooltip_text(_("Go to the given position")) hb.pack_start(b, False, True, 0) hb.show_all() self.datawidget.pack_start(hb, False, True, 0) self.data.append( (time.time(), position, message, url, hb) ) return True
def on_bus_message(self, bus, message): def finalize(): """Finalize data creation. """ gobject.idle_add( lambda: self.pipeline.set_state(gst.STATE_NULL) and False) self.generate_annotations() if self.end_callback: self.end_callback() return False if message.type == gst.MESSAGE_EOS: finalize() elif message.structure: s = message.structure #print "MSG " + s.get_name() + ": " + s.to_string() if s.get_name() == 'progress' and self.progress is not None: if not self.progress( s['percent-double'] / 100, _("%(count)d utterances until %(time)s") % { 'count': len(self.buffer_list), 'time': helper.format_time(s['current'] * 1000) }): finalize() return True
def set_cursor(wid, t=None, precision=None): if t is None: t=self.annotation if precision is None: precision=config.data.preferences['bookmark-snapshot-precision'] cache=self.controller.package.imagecache if self.no_image_pixbuf is None: self.no_image_pixbuf=png_to_pixbuf(ImageCache.not_yet_available_image, width=config.data.preferences['drag-snapshot-width']) if not t == w._current: if isinstance(t, long) or isinstance(t, int): if cache.is_initialized(t, epsilon=precision): begin.set_from_pixbuf(png_to_pixbuf (cache.get(t, epsilon=precision), width=config.data.preferences['drag-snapshot-width'])) elif begin.get_pixbuf() != self.no_image_pixbuf: begin.set_from_pixbuf(self.no_image_pixbuf) end.hide() padding.hide() l.set_text(helper.format_time(t)) elif isinstance(t, Annotation): # It can be an annotation begin.set_from_pixbuf(png_to_pixbuf (cache.get(t.fragment.begin), width=config.data.preferences['drag-snapshot-width'])) end.set_from_pixbuf(png_to_pixbuf (cache.get(t.fragment.end), width=config.data.preferences['drag-snapshot-width'])) end.show() padding.show() if widgets: l.set_text(_("Set of %s annotations") % len(widgets)) else: l.set_text(self.controller.get_title(t)) wid._current=t return True
def position_update(self): s = self.get_stream_information () if s.position == 0: # Try again once. timestamp sometimes goes through 0 when # modifying the player position. s = self.get_stream_information() self.status = s.status self.stream_duration = s.length self.current_position_value = int(s.position) if self.caption.text and (s.position < self.caption.begin or s.position > self.caption.end): self.display_text('', -1, -1) if self.overlay.data and (s.position < self.overlay.begin or s.position > self.overlay.end): self.imageoverlay.props.data=None self.overlay.begin=-1 self.overlay.end=-1 self.overlay.data=None elif not self.overlay.data and self.imageoverlay is not None and self.is_fullscreen() and config.data.player.get('fullscreen-timestamp', False): t = time.time() # Update timestamp every half second if t - self.last_timestamp_update > .5 and abs(s.position - self.last_timestamp) > 10: self.imageoverlay.props.data = '''<svg:svg width="640pt" height="480pt" preserveAspectRatio="xMinYMin meet" version="1" viewBox="0 0 640 480" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:svg="http://www.w3.org/2000/svg"> <text fill="white" stroke="white" style="stroke-width:1; font-family: sans-serif; font-size: 22" x="5" y="475">%s</text> </svg:svg>''' % format_time(s.position) self.last_timestamp = s.position self.last_timestamp_update = t
def refresh(self): """Update the display of the widget according to self._value and self.width """ if self._value is None: v=-1 else: v=self._value if self.width < 9: self.image.hide() self.set_size_request(6, 12) else: ic=self.controller.package.imagecache png = ic.get(v, epsilon=self.epsilon) if png == ic.not_yet_available_image and 'async-snapshot' in self.controller.player.player_capabilities: self.controller.queue_action(self.controller.update_snapshot, v) self.image.set_from_pixbuf(png_to_pixbuf(png, width=self.width)) self.set_size_request(-1, -1) self.image.show() ts=helper.format_time(self._value) self.label.set_markup(self._text % { 'timestamp': ts }) if self.visible_label and self.label.get_child_requisition()[0] <= 1.2 * self.image.get_child_requisition()[0]: self.label.show() else: self.label.hide() self.set_tooltip_text(ts) return True
def position_update(self): s = self.get_stream_information() if s.position == 0: # Try again once. timestamp sometimes goes through 0 when # modifying the player position. s = self.get_stream_information() self.status = s.status self.stream_duration = s.length self.current_position_value = int(s.position) if self.caption.text and (s.position < self.caption.begin or s.position > self.caption.end): self.display_text('', -1, -1) if self.overlay.data and (s.position < self.overlay.begin or s.position > self.overlay.end): self.imageoverlay.props.data = None self.overlay.begin = -1 self.overlay.end = -1 self.overlay.data = None elif not self.overlay.data and self.imageoverlay is not None and self.is_fullscreen( ) and config.data.player.get('fullscreen-timestamp', False): t = time.time() # Update timestamp every half second if t - self.last_timestamp_update > .5 and abs( s.position - self.last_timestamp) > 10: self.imageoverlay.props.data = '''<svg:svg width="640pt" height="480pt" preserveAspectRatio="xMinYMin meet" version="1" viewBox="0 0 640 480" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:svg="http://www.w3.org/2000/svg"> <text fill="white" stroke="white" style="stroke-width:1; font-family: sans-serif; font-size: 22" x="5" y="475">%s</text> </svg:svg>''' % format_time(s.position) self.last_timestamp = s.position self.last_timestamp_update = t
def refresh(self): """Update the display of the widget according to self._value and self.width """ if self._value is None: v = -1 else: v = self._value if self.width < 9: self.image.hide() self.set_size_request(6, 12) else: png = self.controller.get_snapshot(position=v, media=self._media, precision=self.precision) self.valid_screenshot = not png.is_default self.image.set_from_pixbuf( png_to_pixbuf(bytes(png), width=self.width)) self.set_size_request(-1, -1) self.image.show() ts = helper.format_time(self._value) self.label.set_markup(self._text % {'timestamp': ts}) self.label.get_style_context().add_class("timestamp_label") if (self.visible_label and self.label.get_child_requisition().width <= 1.2 * self.image.get_child_requisition().width): self.label.show() else: self.label.hide() self.set_tooltip_text(ts) return True
def refresh(self): """Update the display of the widget according to self._value and self.width """ if self._value is None: v=-1 else: v=self._value if self.width < 9: self.image.hide() self.set_size_request(6, 12) else: ic=self.controller.gui.imagecache if ic is None: png=ImageCache.not_yet_available_image else: png=ic.get(v, epsilon=self.epsilon) if png == ImageCache.not_yet_available_image and 'async-snapshot' in self.controller.player.player_capabilities: self.controller.queue_action(self.controller.update_snapshot, v) self.image.set_from_pixbuf(png_to_pixbuf(png, width=self.width)) self.set_size_request(-1, -1) self.image.show() ts=helper.format_time(self._value) self.label.set_markup(self._text % { 'timestamp': ts }) if self.visible_label and self.label.get_child_requisition()[0] <= 1.2 * self.image.get_child_requisition()[0]: self.label.show() else: self.label.hide() self.set_tooltip_text(ts) return True
def set_cursor(wid, t=None, precision=None): if t is None: t=self.annotation if precision is None: precision=config.data.preferences['bookmark-snapshot-precision'] # FIXME not multi-media compatible cache=self.controller.gui.imagecache if self.no_image_pixbuf is None: self.no_image_pixbuf=png_to_pixbuf(ImageCache.not_yet_available_image, width=config.data.preferences['drag-snapshot-width']) if not t == w._current: if isinstance(t, long) or isinstance(t, int): if cache.is_initialized(t, epsilon=precision): begin.set_from_pixbuf(png_to_pixbuf (cache.get(t, epsilon=precision), width=config.data.preferences['drag-snapshot-width'])) elif begin.get_pixbuf() != self.no_image_pixbuf: begin.set_from_pixbuf(self.no_image_pixbuf) end.hide() padding.hide() l.set_text(helper.format_time(t)) elif isinstance(t, Annotation): cache=self.controller.imagecache[t.media.url] # It can be an annotation begin.set_from_pixbuf(png_to_pixbuf (cache.get(t.begin), width=config.data.preferences['drag-snapshot-width'])) end.set_from_pixbuf(png_to_pixbuf (cache.get(t.end), width=config.data.preferences['drag-snapshot-width'])) end.show() padding.show() if widgets: l.set_text(_("Set of %s annotations") % len(widgets)) else: l.set_text(self.controller.get_title(t)) wid._current=t return True
def as_html(self): if self.annotation is None: return """<span advene:error="Non-existent annotation"></span>""" ctx = self.controller.build_context(self.annotation) d = { 'id': self.annotation.id, 'href': self.controller.get_urlbase() + ctx.evaluateValue('here/player_url'), 'imgurl': self.controller.get_urlbase() + ctx.evaluateValue('here/snapshot_url'), 'timestamp': helper.format_time(self.annotation.fragment.begin), 'content': self.controller.get_title(self.annotation), 'urlbase': self.controller.get_urlbase().rstrip('/'), } data = [ """<span class="advene:annotation" advene:annotation="%s" advene:presentation="%s">""" % (self.annotation.id, ':'.join(self.presentation)) ] if 'link' in self.presentation: data.append( """<a title="Click to play the movie in Advene" tal:attributes="href package/annotations/%(id)s/player_url" href="%(href)s">""" % d) if 'overlay' in self.presentation: data.append( """<img title="Click here to play" width="160" height="100" src="%(urlbase)s/media/overlay/advene/%(id)s"></img>""" % d) elif 'snapshot' in self.presentation: if 'timestamp' in self.presentation: data.append( """<img title="Click here to play" width="160" height="100" src="%(urlbase)s/media/overlay/advene/%(id)s/fragment/formatted/begin"></img>""" % d) else: data.append( """<img title="Click here to play" width="160" height="100" tal:attributes="src package/annotations/%(id)s/snapshot_url" src="%(imgurl)s" ></img>""" % d) elif 'timestamp' in self.presentation: # timestamp without snapshot or overlay data.append( """<em tal:content="package/annotations/%(id)s/fragment/formatted/begin">%(timestamp)s</em><br>""" % d) elif 'content' in self.presentation: data.append( """<span tal:content="package/annotations/%(id)s/representation">%(content)s</span>""" % d) if 'link' in self.presentation: data.append('</a>') data.append('</span>') return "".join(data)
def generate_transcription(self): last=None for d in self.parse_transcription(show_ignored=True, strip_blank=False): if d['ignored']: yield '[I%s]' % helper.format_time(d['begin']) yield d['content'] yield '[%s]' % helper.format_time(d['end']) elif last != d['begin']: yield '[%s]' % helper.format_time(d['begin']) yield d['content'] yield '[%s]' % helper.format_time(d['end']) else: yield d['content'] yield '[%s]' % helper.format_time(d['end']) last=d['end']
def iterator(self): for b in self.elements: yield { 'begin': b.value, 'end': b.value + self.duration, 'content': b.comment or "Bookmark %s" % helper.format_time(b.value), 'notify': True, 'complete': False, }
def editor_drag_received(self, widget, context, x, y, selection, targetType, time): """Handle the drop from an annotation to the editor. """ # FIXME: Upon DND, TextView receives the event twice. Some # posts from 2004 signal the same problem, some hacks can be # found in existing code : # widget.emit_stop_by_name ("drag-data-received") # context.finish(False, False, time) # widget.stop_emission("drag-data-received") # but none of them seems to work here. Just use a basic approach, # imagining that nobody is fast enough to really do two DNDs # at the same time. # But on win32, timestamp is always 0. So we must use x and y information as well. if time == self.last_dndtime and x == self.last_x and y == self.last_y: return True self.last_dndtime=time self.last_x=x self.last_y=y x, y = self.editor.window_to_buffer_coords(gtk.TEXT_WINDOW_TEXT, *widget.get_pointer()) it = self.editor.get_iter_at_location(x, y) self.editor.get_buffer().place_cursor(it) if targetType == config.data.target_type['annotation']: for uri in unicode(selection.data, 'utf8').split('\n'): source=self.controller.package.annotations.get(uri) if source is None: return True m=gtk.Menu() for (title, choice) in ( (_("Snapshot only"), ['link', 'snapshot', ]), (_("Overlayed snapshot only"), ['link', 'overlay', ]), (_("Timestamp only"), ['link', 'timestamp', ]), (_("Snapshot+timestamp"), ['link', 'snapshot', 'timestamp']), ): i=gtk.MenuItem(title) i.connect('activate', (lambda it, ann, data: self.insert_annotation_content(data, ann, focus=True)), source, choice) m.append(i) m.show_all() m.popup(None, None, None, 0, gtk.get_current_event_time()) return True elif targetType == config.data.target_type['annotation-type']: # FIXME: use splitlines() source=self.controller.package.get(unicode(selection.data, 'utf8')) # FIXME: propose various choices (insert all annotations, insert title, etc) self.editor.get_buffer().insert_at_cursor(source.title) return True elif targetType == config.data.target_type['timestamp']: data=decode_drop_parameters(selection.data) t=long(data['timestamp']) # FIXME: propose various choices (insert timestamp, insert snapshot, etc) self.editor.get_buffer().insert_at_cursor(helper.format_time(t)) return True else: print "Unknown target type for drop: %d" % targetType return False
def popup_modify(win, t): timestamp=child.value + t child.set_tooltip_text("%s" % helper.format_time(timestamp)) # FIXME: find a way to do this in the new Gtk.Tooltip API? #if self.tooltips.active_tips_data is None: # button.emit('show-help', Gtk.WIDGET_HELP_TOOLTIP) child.value=timestamp if self.options['play-on-scroll']: popup_goto(child, timestamp) return True
def on_bus_message(self, bus, message): def finalize(): GObject.idle_add( lambda: self.pipeline.set_state(Gst.State.NULL) and False) # Add last buffer data if self.buffer: # There is some data left. self.buffer_list.append( (self.first_item_time, self.first_item_time + len(self.buffer) * self.interval, list(self.buffer))) self.generate_normalized_annotations() self.end_callback() return True s = message.get_structure() if message.type == Gst.MessageType.EOS: finalize() elif message.type == Gst.MessageType.ERROR: title, message = message.parse_error() logger.error("%s: %s", title, message) elif message.type == Gst.MessageType.WARNING: title, message = message.parse_warning() logger.warn("%s: %s", title, message) elif s: if s.get_name() == 'progress' and self.progress is not None: if not self.progress( s['percent-double'] / 100, _("At %s") % helper.format_time(s['current'] * 1000)): finalize() elif s.get_name() == 'level': if not self.buffer: self.first_item_time = s['stream-time'] / Gst.MSECOND rms = s['rms'] v = rms[0] if len(rms) > 1: if self.channel == 'right': v = rms[1] elif self.channel == 'both': v = (rms[0] + rms[1]) / 2 if isinf(v) or isnan(v) or v < self.lower_db_limit: v = self.lastval if v < self.min: self.min = v elif v > self.max: self.max = v self.lastval = v self.buffer.append(v) if len(self.buffer) >= self.count: self.buffer_list.append( (self.first_item_time, s['endtime'] / Gst.MSECOND, list(self.buffer))) self.buffer = [] return True
def as_html(self, with_timestamp=True): """Return a HTML representation of the widget. """ data={ 'image_url': 'http:/media/snapshot/advene/%d' % self._value, 'player_url': 'http:/media/play/%d' % self._value, 'timestamp': helper.format_time(self._value) } ret="""<a href="%(player_url)s"><img width="120" border="0" src="%(image_url)s" alt="" /></a>""" % data if with_timestamp: ret = ''.join( (ret, """<br /><em><a href="%(player_url)s">%(timestamp)s</a></em>""" % data) ) return ret
def title (self, node): title=None if self.controller: title=self.controller.get_title(node) if not title: title = "???" try: title=node.id except AttributeError: pass # FIXME: bad hardcoded value #if len(title) > 50: # title=title[:50] if isinstance(node, Annotation): title="%s (%s, %s)" % (title, helper.format_time(node.fragment.begin), helper.format_time(node.fragment.end)) if ((hasattr(node, 'isImported') and node.isImported()) or (hasattr(node, 'schema') and node.schema.isImported())): title += " (*)" return title
def drag_sent(self, widget, context, selection, targetType, eventTime): """Handle the drag-sent event. """ if targetType == config.data.target_type['timestamp']: selection.set(selection.target, 8, encode_drop_parameters(timestamp=self.value)) return True elif targetType in ( config.data.target_type['text-plain'], config.data.target_type['TEXT'], config.data.target_type['STRING'] ): selection.set(selection.target, 8, helper.format_time(self.value)) return True return False
def title(self, node): title = None if self.controller: title = self.controller.get_title(node) if not title: title = "???" try: title = node.id except AttributeError: pass # FIXME: bad hardcoded value #if len(title) > 50: # title=title[:50] if isinstance(node, Annotation): title = "%s (%s, %s)" % (title, helper.format_time(node.fragment.begin), helper.format_time(node.fragment.end)) if ((hasattr(node, 'isImported') and node.isImported()) or (hasattr(node, 'schema') and node.schema.isImported())): title += " (*)" return title
def generate_buffer_content(self): b = self.textview.get_buffer() # Clear the buffer begin, end = b.get_bounds() b.delete(begin, end) def insert_at_cursor_with_tags_by_name(text, *tags): b.insert_with_tags_by_name(b.get_iter_at_mark(b.get_insert()), text, *tags) l = list(self.model) l.sort(key=lambda a: a.fragment.begin) for a in l: if self.options['display-time']: insert_at_cursor_with_tags_by_name( "[%s]" % helper.format_time(a.fragment.begin), "bound") mark = b.create_mark("b_%s" % a.id, b.get_iter_at_mark(b.get_insert()), left_gravity=True) mark.set_visible(self.options['display-bounds']) # Put a 0-width char to make it easier to edit annotations insert_at_cursor_with_tags_by_name(ZERO_WIDTH_NOBREAK_SPACE, "bound") b.insert_at_cursor(str(self.representation(a))) insert_at_cursor_with_tags_by_name(ZERO_WIDTH_NOBREAK_SPACE, "bound") mark = b.create_mark("e_%s" % a.id, b.get_iter_at_mark(b.get_insert()), left_gravity=True) mark.set_visible(self.options['display-bounds']) if self.options['display-time']: insert_at_cursor_with_tags_by_name( "[%s]" % helper.format_time(a.fragment.end), "bound") insert_at_cursor_with_tags_by_name(self.options['separator'], "bound") return
def refresh(self, *p): self.mainbox.foreach(self.mainbox.remove) self.append_dropzone(0) duration = 0 for i, a in enumerate(self.contents): self.append_repr(a) self.append_dropzone(i + 1) duration += a.annotation.fragment.duration self.mainbox.show_all() self.duration = duration self.duration_label.set_text(helper.format_time(duration)) return True
def refresh(self, *p): self.mainbox.foreach(self.mainbox.remove) self.append_dropzone(0) duration=0 for i, a in enumerate(self.contents): self.append_repr(a) self.append_dropzone(i+1) duration += a.annotation.fragment.duration self.mainbox.show_all() self.duration=duration self.duration_label.set_text(helper.format_time(duration)) return True
def drag_sent(self, widget, context, selection, targetType, eventTime): """Handle the drag-sent event. """ if targetType == config.data.target_type['timestamp']: selection.set(selection.target, 8, encode_drop_parameters(timestamp=self.value)) return True elif targetType in (config.data.target_type['text-plain'], config.data.target_type['TEXT'], config.data.target_type['STRING']): selection.set(selection.target, 8, helper.format_time(self.value)) return True return False
def build_model(self, elements): """Build the ListStore containing the data. """ l=gtk.ListStore(object, str, str, str, long, long, str, str, str, gtk.gdk.Pixbuf, str) if not elements: return l for a in elements: if isinstance(a, Annotation): l.append( (a, self.controller.get_title(a), self.controller.get_title(a.type), a.id, a.begin, a.end, helper.format_time(a.duration), helper.format_time(a.begin), helper.format_time(a.end), png_to_pixbuf(self.controller.imagecache[a.media.url][a.begin], height=32), self.controller.get_element_color(a), ) ) return l
def build_pixbuf(self): if self.annotation is None: pixbuf=png_to_pixbuf(self.controller.gui.imagecache.not_yet_available_image, width=self.width) elif 'overlay' in self.presentation: pixbuf=overlay_svg_as_pixbuf(self.controller.imagecache[self.annotation.media.url][self.annotation.begin], self.annotation.content.data, width=self.width) elif 'snapshot' in self.presentation: if 'timestamp' in self.presentation: pixbuf=overlay_svg_as_pixbuf(self.controller.imagecache[self.annotation.media.url][self.annotation.begin], helper.format_time(self.annotation.begin), width=self.width) else: pixbuf=png_to_pixbuf(self.controller.imagecache[self.annotation.media.url][self.annotation.begin], width=self.width) elif 'timestamp' in self.presentation: # Generate only a timestamp # FIXME: hardcoded value in viewBox is bad... We should find out the appropriate size. loader = gtk.gdk.PixbufLoader('svg') loader.write("""<svg version='1'> preserveAspectRatio="xMinYMin meet" viewBox="0 0 220 20"> <text x='0' y='10' fill="black" font-size="12" stroke="black" font-family="sans-serif"> %s </text> </svg> """ % helper.format_time(self.annotation.begin)) loader.close () pixbuf = loader.get_pixbuf () else: pixbuf=png_to_pixbuf(self.controller.gui.imagecache.not_yet_available_image, width=self.width) pixbuf.as_html=self.as_html pixbuf._placeholder=self pixbuf._tag='span' pixbuf._attr=[] return pixbuf
def generate_buffer_content(self): b=self.textview.get_buffer() # Clear the buffer begin, end = b.get_bounds() b.delete(begin, end) def insert_at_cursor_with_tags_by_name(text, *tags): b.insert_with_tags_by_name(b.get_iter_at_mark(b.get_insert()), text, *tags) l=list(self.model) l.sort(key=lambda a: a.fragment.begin) for a in l: if self.options['display-time']: insert_at_cursor_with_tags_by_name("[%s]" % helper.format_time(a.fragment.begin), "bound") mark = b.create_mark("b_%s" % a.id, b.get_iter_at_mark(b.get_insert()), left_gravity=True) mark.set_visible(self.options['display-bounds']) # Put a 0-width char to make it easier to edit annotations insert_at_cursor_with_tags_by_name(ZERO_WIDTH_NOBREAK_SPACE, "bound") b.insert_at_cursor(str(self.representation(a))) insert_at_cursor_with_tags_by_name(ZERO_WIDTH_NOBREAK_SPACE, "bound") mark = b.create_mark("e_%s" % a.id, b.get_iter_at_mark(b.get_insert()), left_gravity=True) mark.set_visible(self.options['display-bounds']) if self.options['display-time']: insert_at_cursor_with_tags_by_name("[%s]" % helper.format_time(a.fragment.end), "bound") insert_at_cursor_with_tags_by_name(self.options['separator'], "bound") return
def on_bus_message(self, bus, message): def finalize(): pos = self.pipeline.query_position( gst.FORMAT_TIME)[0] / gst.MSECOND gobject.idle_add( lambda: self.pipeline.set_state(gst.STATE_NULL) and False) self.convert({ 'begin': begin, 'end': end, 'content': 'sound', } for begin, end in self.buffer) self.end_callback() return True if message.type == gst.MESSAGE_EOS: finalize() ##elif message.type == gst.MESSAGE_STATE_CHANGED: ## old, new, pending = message.parse_state_changed() ## if old == gst.STATE_READY and new == gst.STATE_PAUSED: ## # There has been a problem. Cancel. ## self.progress(1.0, _("Problem when running detection")) ## print "Undetermined problem when running silence detection." ## self.end_callback() ## gobject.idle_add(lambda: self.pipeline.set_state(gst.STATE_NULL) and False) ## #if new == gst.STATE_NULL: ## # self.end_callback() elif message.structure: s = message.structure #print "MSG " + bus.get_name() + ": " + s.to_string() if s.get_name() == 'progress' and self.progress is not None: if not self.progress( s['percent-double'] / 100, _("Detected %(count)d segments until %(time)s") % { 'count': len(self.buffer), 'time': helper.format_time(s['current'] * 1000) }): finalize() elif s.get_name() == 'cutter': t = s['timestamp'] / gst.MSECOND if s['above']: self.last_above = t else: if self.last_above is not None: self.buffer.append((self.last_above, t)) else: print "Error: not above without matching above" self.last_above = t return True
def on_bus_message(self, bus, message): def finalize(): GObject.idle_add(lambda: self.pipeline.set_state(Gst.State.NULL) and False) # Add last buffer data if self.buffer: # There is some data left. self.buffer_list.append((self.first_item_time, self.first_item_time + len(self.buffer) * self.interval, list(self.buffer))) self.generate_normalized_annotations() self.end_callback() return True s = message.get_structure() if message.type == Gst.MessageType.EOS: finalize() elif message.type == Gst.MessageType.ERROR: title, message = message.parse_error() logger.error("%s: %s", title, message) elif message.type == Gst.MessageType.WARNING: title, message = message.parse_warning() logger.warn("%s: %s", title, message) elif s: if s.get_name() == 'progress' and self.progress is not None: if not self.progress(s['percent-double'] / 100, _("At %s") % helper.format_time(s['current'] * 1000)): finalize() elif s.get_name() == 'level': if not self.buffer: self.first_item_time = s['stream-time'] / Gst.MSECOND rms = s['rms'] v = rms[0] if len(rms) > 1: if self.channel == 'right': v = rms[1] elif self.channel == 'both': v = (rms[0] + rms[1]) / 2 if isinf(v) or isnan(v) or v < self.lower_db_limit: v = self.lastval if v < self.min: self.min = v elif v > self.max: self.max = v self.lastval = v self.buffer.append(v) if len(self.buffer) >= self.count: self.buffer_list.append((self.first_item_time, s['endtime'] / Gst.MSECOND, list(self.buffer))) self.buffer = [] return True
def on_bus_message(self, bus, message): def finalize(): pos = self.pipeline.query_position( gst.FORMAT_TIME)[0] / gst.MSECOND gobject.idle_add( lambda: self.pipeline.set_state(gst.STATE_NULL) and False) # Add last buffer data self.buffer_list.append( (self.first_item_time, pos, list(self.buffer))) self.generate_normalized_annotations() self.end_callback() return True if message.type == gst.MESSAGE_EOS: finalize() elif message.structure: s = message.structure #print "MSG " + bus.get_name() + ": " + s.to_string() if s.get_name() == 'progress' and self.progress is not None: if not self.progress( s['percent-double'] / 100, _("At %s") % helper.format_time(s['current'] * 1000)): finalize() elif s.get_name() == 'level': if not self.buffer: self.first_item_time = s['stream-time'] / gst.MSECOND rms = s['rms'] v = rms[0] if len(rms) > 1: if self.channel == 'right': v = rms[1] elif self.channel == 'both': v = (rms[0] + rms[1]) / 2 if isinf(v) or isnan(v): v = self.lastval if v < self.min: self.min = v elif v > self.max: self.max = v self.lastval = v self.buffer.append(v) if len(self.buffer) >= self.count: self.buffer_list.append( (self.first_item_time, s['endtime'] / gst.MSECOND, list(self.buffer))) self.buffer = [] return True
def validate_and_next(self, new): """Validate the current annotation and display the next one. """ i = self.index annotation = self.annotations[i] batch=object() event = Gtk.get_current_event() if event.get_state().state & Gdk.ModifierType.CONTROL_MASK: # Control-key is held. Split the annotation. if new > annotation.fragment.begin and new < annotation.fragment.end: self.controller.split_annotation(annotation, new) self.message(_("Split annotation #%(current)d into #%(current)d and #%(next)d") % { 'current': i + 1, 'next': i + 2 }) else: self.message(_("Cannot split annotation #%(current)d: out of bounds.") % { 'current': i + 1, }) return True if new != annotation.fragment.begin: logger.debug("Updating annotation begin from %s to %s", helper.format_time(annotation.fragment.begin), helper.format_time_reference(new)) self.controller.notify('EditSessionStart', element=annotation, immediate=True) annotation.fragment.begin = new self.controller.notify('AnnotationEditEnd', annotation=annotation, batch=batch) self.controller.notify('EditSessionEnd', element=annotation) self.undo_button.set_sensitive(True) # Update previous annotation end. if i > 0: annotation = self.annotations[i - 1] if new != annotation.fragment.end: self.controller.notify('EditSessionStart', element=annotation, immediate=True) annotation.fragment.end = new self.controller.notify('AnnotationEditEnd', annotation=annotation, batch=batch) self.controller.notify('EditSessionEnd', element=annotation) self.message(_("Changed cut between #%(first)d and %(second)d") % { 'first': i + 1, 'second': i + 2 }) else: self.message(_("Changed begin time for first annotation")) self.set_index(i + 1) return True
def set_time(self, attr): """Sets the time of the current annotation to the current player time. """ an, an_path = self.get_selected_node(with_path=True) if an is None: return current_time = self.controller.player.current_position_value confirm = True if self.options['confirm-time-update']: confirm = dialog.message_dialog(_("Set %(attr)s time to %(time)s") % { 'attr': _(attr), 'time': helper.format_time(current_time) }, icon=Gtk.MessageType.QUESTION) if confirm: self.last_edited_path = an_path self.controller.notify('EditSessionStart', element=an, immediate=True) setattr(an.fragment, attr, current_time) self.controller.notify("AnnotationEditEnd", annotation=an) self.controller.notify('EditSessionEnd', element=an)
def handle_scroll_event(button, event): if not (event.get_state() & Gdk.ModifierType.CONTROL_MASK): return False if event.get_state() & Gdk.ModifierType.SHIFT_MASK: i='second-scroll-increment' else: i='scroll-increment' if event.direction == Gdk.ScrollDirection.DOWN or event.direction == Gdk.ScrollDirection.RIGHT: button.value -= config.data.preferences[i] elif event.direction == Gdk.ScrollDirection.UP or event.direction == Gdk.ScrollDirection.LEFT: button.value += config.data.preferences[i] button.set_tooltip_text("%s" % helper.format_time(button.value)) # FIXME: find a way to do this in the new Gtk.Tooltip API? #if self.tooltips.active_tips_data is None: # button.emit('show-help', Gtk.WIDGET_HELP_TOOLTIP) self.timestamp_play = button.value button.grab_focus() return True
def on_bus_message(self, bus, message): def finalize(): """Finalize data creation. """ gobject.idle_add(lambda: self.pipeline.set_state(gst.STATE_NULL) and False) self.generate_annotations() if self.end_callback: self.end_callback() return False if message.type == gst.MESSAGE_EOS: finalize() elif message.structure: s = message.structure #print "MSG " + s.get_name() + ": " + s.to_string() if s.get_name() == 'progress' and self.progress is not None: if not self.progress(s['percent-double'] / 100, _("%(count)d utterances until %(time)s") % { 'count': len(self.buffer_list), 'time': helper.format_time(s['current'] * 1000) }): finalize() return True
def on_bus_message(self, bus, message): def finalize(): """Finalize data creation. """ GObject.idle_add(lambda: self.pipeline.set_state(Gst.State.NULL) and False) self.generate_annotations() if self.end_callback: self.end_callback() return False s = message.get_structure() if message.type == Gst.MessageType.EOS: finalize() elif s: logger.debug("MSG ", s.get_name(), s.to_string()) if s.get_name() == 'progress' and self.progress is not None: if not self.progress(s['percent-double'] / 100, _("%(count)d utterances until %(time)s") % { 'count': len(self.buffer_list), 'time': helper.format_time(s['current'] * 1000) }): finalize() return True
def on_bus_message(self, bus, message): def finalize(): pos = self.pipeline.query_position(gst.FORMAT_TIME)[0] / gst.MSECOND gobject.idle_add(lambda: self.pipeline.set_state(gst.STATE_NULL) and False) # Add last buffer data self.buffer_list.append((self.first_item_time, pos, list(self.buffer))) self.generate_normalized_annotations() self.end_callback() return True if message.type == gst.MESSAGE_EOS: finalize() elif message.structure: s=message.structure #print "MSG " + bus.get_name() + ": " + s.to_string() if s.get_name() == 'progress' and self.progress is not None: if not self.progress(s['percent-double'] / 100, _("At %s") % helper.format_time(s['current'] * 1000)): finalize() elif s.get_name() == 'level': if not self.buffer: self.first_item_time = s['stream-time'] / gst.MSECOND rms = s['rms'] v = rms[0] if len(rms) > 1: if self.channel == 'right': v = rms[1] elif self.channel == 'both': v = (rms[0] + rms[1]) / 2 if isinf(v) or isnan(v): v = self.lastval if v < self.min: self.min = v elif v > self.max: self.max = v self.lastval = v self.buffer.append(v) if len(self.buffer) >= self.count: self.buffer_list.append((self.first_item_time, s['endtime'] / gst.MSECOND, list(self.buffer))) self.buffer = [] return True
def set_time(self, attr): """Sets the time of the current annotation to the current player time. """ an, an_path = self.get_selected_node(with_path=True) if an is None: return current_time = self.controller.player.current_position_value confirm = True if self.options['confirm-time-update']: confirm = dialog.message_dialog( _("Set %(attr)s time to %(time)s") % { 'attr': _(attr), 'time': helper.format_time(current_time) }, icon=Gtk.MessageType.QUESTION) if confirm: self.last_edited_path = an_path self.controller.notify('EditSessionStart', element=an, immediate=True) setattr(an.fragment, attr, current_time) self.controller.notify("AnnotationEditEnd", annotation=an) self.controller.notify('EditSessionEnd', element=an)
def get_view(self, compact=False): """Generate a view widget for editing SVG.""" vbox = Gtk.VBox() if self.parent is not None and hasattr(self.parent, 'fragment'): i = image_from_position(self.controller, position=self.parent.fragment.begin, media=self.parent.media) vi = self.controller.package.imagecache.video_info self.view = ShapeEditor(background=i, icon_dir=config.data.advenefile('pixmaps'), default_size=(vi.get('width', 320), vi.get('height', 200))) def snapshot_update_cb(context, target): if context.globals['media'] != self.parent.media: return True pos = self.get_background_position() if context.globals['position'] == pos: # Refresh image i = image_from_position(self.controller, position=pos, media=self.parent.media) self.view.set_background(i) return True self.rules.append( self.controller.event_handler.internal_rule( event='SnapshotUpdate', method=snapshot_update_cb)) def annotation_update_cb(context, target): self.view.background_adj.set_value(0) return True self.rules.append( self.controller.event_handler.internal_rule( event='AnnotationEditEnd', method=annotation_update_cb)) else: self.view = ShapeEditor(icon_dir=config.data.advenefile('pixmaps')) self.parse_svg() self.view.drawer.widget.connect('drag-data-received', self.drawer_drag_received) self.view.drawer.widget.drag_dest_set( Gtk.DestDefaults.MOTION | Gtk.DestDefaults.HIGHLIGHT | Gtk.DestDefaults.ALL, config.data.get_target_types('view', 'annotation', 'uri-list'), Gdk.DragAction.COPY | Gdk.DragAction.LINK) def edit_svg(b=None): vbox.foreach(vbox.remove) vbox.add(self.view.widget) self.editing_source = False vbox.show_all() return True def edit_xml(b=None): if self.sourceview is None: self.sourceview = TextContentHandler( element=self.element, controller=self.controller, parent=self.parent) self.sourceview.widget = self.sourceview.get_view() b = get_pixmap_toolbutton('xml.png', edit_svg) b.set_tooltip_text(_("Graphical editor")) self.sourceview.toolbar.insert(b, 0) vbox.foreach(vbox.remove) vbox.add(self.sourceview.widget) self.editing_source = True vbox.show_all() return True # Insert "View source" button in Shapewidget toolbar b = get_pixmap_toolbutton('xml.png', edit_xml) b.set_tooltip_text(_("Edit XML")) self.view.toolbar.insert(b, 0) def update_background(adj): pos = self.get_background_position() i = image_from_position(self.controller, position=pos, media=self.parent.media) self.view.set_background(i) return True self.view.background_adj = Gtk.Adjustment.new(value=0, lower=0, upper=1.0, step_increment=0.1, page_increment=0.2, page_size=0.2) slider = Gtk.HScale.new(self.view.background_adj) slider.connect( "format-value", lambda s, v: helper.format_time(self.parent.fragment.begin + int( v * self.parent.fragment.duration))) ti = Gtk.ToolItem() ti.add(slider) ti.set_expand(True) self.view.toolbar.insert(ti, -1) self.view.background_adj.connect('value-changed', update_background) if config.data.preferences['prefer-wysiwyg']: edit_svg() else: edit_xml() return vbox
def update_display(self): """Updates the value displayed in the entry according to the current value.""" self.entry.set_text(helper.format_time(self.value)) self.image.value = self.value
def make_widget(self): def refresh_snapshot(item): self.image.refresh_snapshot() return True def image_button_clicked(button): event = Gtk.get_current_event() if event.get_state().state & Gdk.ModifierType.CONTROL_MASK: self.use_current_position(button) return True else: self.play_from_here(button) return True def image_button_press(button, event): if event.button == 3 and event.type == Gdk.EventType.BUTTON_PRESS: # Display the popup menu menu = Gtk.Menu() item = Gtk.MenuItem(_("Refresh snapshot")) item.connect('activate', refresh_snapshot) menu.append(item) menu.show_all() menu.popup_at_pointer(None) return True return False def make_button(incr_value, pixmap): """Helper function to build the buttons.""" b = Gtk.Button() i = Gtk.Image() i.set_from_file(config.data.advenefile(('pixmaps', pixmap))) b.set_image(i) def increment_value_cb(widget, increment): self.set_value(self.value + increment) return True b.connect('clicked', increment_value_cb, incr_value) if incr_value < 0: tip = _("Decrement value by %.2f s") % (incr_value / 1000.0) else: tip = _("Increment value by %.2f s") % (incr_value / 1000.0) b.set_tooltip_text(tip) return b vbox = Gtk.VBox() hbox = Gtk.HBox() hbox.set_homogeneous(False) if self.editable: vb = Gtk.VBox() b = make_button(-self.large_increment, "2leftarrow.png") vb.pack_start(b, False, True, 0) b = make_button(-self.small_increment, "1leftarrow.png") vb.pack_start(b, False, True, 0) hbox.pack_start(vb, False, True, 0) if self.compact: width = 50 else: width = 100 self.image = TimestampRepresentation(self.value, None, self.controller, width, visible_label=False, callback=self.set_value) self.image.connect('button-press-event', image_button_press) self.image.connect('clicked', image_button_clicked) self.image.set_tooltip_text( _("Click to play\nControl+click to set to current time\nScroll to modify value (with control/shift)\nRight-click to invalidate screenshot" )) hbox.pack_start(self.image, False, True, 0) if self.editable: vb = Gtk.VBox() b = make_button(self.large_increment, "2rightarrow.png") vb.pack_start(b, False, True, 0) b = make_button(self.small_increment, "1rightarrow.png") vb.pack_start(b, False, True, 0) hbox.pack_start(vb, False, True, 0) hb = Gtk.HBox() if self.editable: self.entry = Gtk.Entry() self.entry.set_tooltip_text( _("Enter a timecode.\nAn integer value will be considered as milliseconds.\nA float value (12.2) will be considered as seconds.\nHH:MM:SS.sss values are possible." )) # Default width of the entry field self.entry.set_width_chars(len(helper.format_time(0.0))) self.entry.connect('activate', self.convert_entered_value) self.entry.connect('focus-out-event', self.convert_entered_value) self.entry.set_editable(self.editable) hb.pack_start(self.entry, False, True, 0) else: self.entry = None if self.editable: current_pos = Gtk.Button() i = Gtk.Image() i.set_from_file( config.data.advenefile(('pixmaps', 'set-to-now.png'))) current_pos.set_tooltip_text(_("Set to current player position")) current_pos.add(i) current_pos.connect('clicked', self.use_current_position) hb.pack_start(current_pos, False, True, 0) vbox.pack_start(hbox, False, True, 0) vbox.pack_start(hb, False, True, 0) hb.set_style(self.image.box.get_style()) #self.entry.set_style(self.image.box.get_style()) vbox.set_style(self.image.box.get_style()) vbox.show_all() hb.set_no_show_all(True) hbox.set_no_show_all(True) self.image.label.hide() hb.show() def handle_scroll_event(button, event): if event.get_state() & Gdk.ModifierType.CONTROL_MASK: i = config.data.preferences['scroll-increment'] elif event.get_state() & Gdk.ModifierType.SHIFT_MASK: i = config.data.preferences['second-scroll-increment'] else: # 1 frame i = self.controller.frame2time(1) if event.direction == Gdk.ScrollDirection.DOWN or event.direction == Gdk.ScrollDirection.LEFT: incr = -i elif event.direction == Gdk.ScrollDirection.UP or event.direction == Gdk.ScrollDirection.RIGHT: incr = i if not self.set_value(self.value + incr): return True return True if self.editable: # The widget can receive drops from annotations vbox.connect('drag-data-received', self.drag_received) vbox.drag_dest_set( Gtk.DestDefaults.MOTION | Gtk.DestDefaults.HIGHLIGHT | Gtk.DestDefaults.ALL, config.data.get_target_types('annotation', 'timestamp'), Gdk.DragAction.LINK) vbox.connect('scroll-event', handle_scroll_event) vbox.show_all() return vbox
def make_annotation_menu(self, element, menu): def add_item(*p, **kw): self.add_menuitem(menu, *p, **kw) def loop_on_annotation(menu, ann): self.controller.gui.loop_on_annotation_gui(ann, goto=True) return True def save_snapshot(menu, ann): self.controller.gui.save_snapshot_as(ann.fragment.begin) return True add_item(_("Go to..."), self.goto_annotation, element) add_item(_("Loop"), loop_on_annotation, element) add_item(_("Duplicate"), self.duplicate_annotation, element) item = gtk.MenuItem(_("Highlight"), use_underline=False) item.set_submenu(self.activate_submenu(element)) menu.append(item) add_item(_("Save snapshot..."), save_snapshot, element) if 'montagerenderer' in self.controller.generic_features: add_item(_("Extract video fragment"), self.extract_fragment, element) def build_submenu(submenu, el, items): """Build the submenu for the given element. """ if submenu.get_children(): # The submenu was already populated. return False if len(items) == 1: # Only 1 elements, do not use an intermediary menu m = Menu(element=items[0], controller=self.controller) for c in m.menu.get_children(): m.menu.remove(c) submenu.append(c) else: for i in items: item = gtk.MenuItem(self.get_title(i), use_underline=False) m = Menu(element=i, controller=self.controller) item.set_submenu(m.menu) submenu.append(item) submenu.show_all() return False def build_related(submenu, el): """Build the related annotations submenu for the given element. """ if submenu.get_children(): # The submenu was already populated. return False if el.incomingRelations: i = gtk.MenuItem(_("Incoming")) submenu.append(i) i = gtk.SeparatorMenuItem() submenu.append(i) for t, l in el.typedRelatedIn.iteritems(): at = self.controller.package.get_element_by_id(t) m = gtk.MenuItem(self.get_title(at), use_underline=False) amenu = gtk.Menu() m.set_submenu(amenu) amenu.connect('map', build_submenu, at, l) submenu.append(m) if submenu.get_children(): # There were incoming annotations. Use a separator i = gtk.SeparatorMenuItem() submenu.append(i) if el.outgoingRelations: i = gtk.MenuItem(_("Outgoing")) submenu.append(i) i = gtk.SeparatorMenuItem() submenu.append(i) for t, l in el.typedRelatedOut.iteritems(): at = self.controller.package.get_element_by_id(t) m = gtk.MenuItem(self.get_title(at), use_underline=False) amenu = gtk.Menu() m.set_submenu(amenu) amenu.connect('map', build_submenu, at, l) submenu.append(m) submenu.show_all() return False if element.relations: i = gtk.MenuItem(_("Related annotations"), use_underline=False) submenu = gtk.Menu() i.set_submenu(submenu) submenu.connect('map', build_related, element) menu.append(i) if element.incomingRelations: i = gtk.MenuItem(_("Incoming relations"), use_underline=False) submenu = gtk.Menu() i.set_submenu(submenu) submenu.connect('map', build_submenu, element, element.incomingRelations) menu.append(i) if element.outgoingRelations: i = gtk.MenuItem(_("Outgoing relations"), use_underline=False) submenu = gtk.Menu() i.set_submenu(submenu) submenu.connect('map', build_submenu, element, element.outgoingRelations) menu.append(i) add_item("") item = gtk.MenuItem() item.add( image_from_position(self.controller, position=element.fragment.begin, height=60)) item.connect('activate', self.goto_annotation, element) menu.append(item) #add_item(element.content.data[:40]) add_item( _('Begin: %s') % helper.format_time(element.fragment.begin), lambda i: self.controller.gui.adjust_annotation_bound( element, 'begin')) add_item( _('End: %s') % helper.format_time(element.fragment.end), lambda i: self.controller.gui.adjust_annotation_bound( element, 'end')) add_item( _('Duration: %s') % helper.format_time(element.fragment.duration)) return
def on_bus_message(self, bus, message): def finalize(): GObject.idle_add(lambda: self.pipeline.set_state(Gst.State.NULL) and False) self.convert( { 'begin': begin, 'end': end, 'content': 'sound', } for begin, end in self.buffer ) self.end_callback() return True s = message.get_structure() if message.type == Gst.MessageType.EOS: finalize() ##elif message.type == Gst.MessageType.STATE_CHANGED: ## old, new, pending = message.parse_state_changed() ## if old == Gst.State.READY and new == Gst.State.PAUSED: ## # There has been a problem. Cancel. ## self.progress(1.0, _("Problem when running detection")) ## print "Undetermined problem when running silence detection." ## self.end_callback() ## GObject.idle_add(lambda: self.pipeline.set_state(Gst.State.NULL) and False) ## #if new == Gst.State.NULL: ## # self.end_callback() elif s: logger.debug("MSG %s: %s", bus.get_name(), s.to_string()) if s.get_name() == 'progress' and self.progress is not None: if not self.progress(s['percent-double'] / 100, _("Detected %(count)d segments until %(time)s") % { 'count': len(self.buffer), 'time': helper.format_time(s['current'] * 1000) }): finalize() elif s.get_name() == 'cutter': t = s['timestamp'] / Gst.MSECOND if s['above']: self.last_above = t else: if self.last_above is not None: self.buffer.append( (self.last_above, t) ) else: logger.error("Error: not above without matching above") self.last_above = t return True