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
def edit_source(*p): 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_wysiwyg) b.set_tooltip_text(_("WYSIWYG 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
def get_view (self, compact=False): """Generate a view widget for editing HTML.""" vbox=Gtk.VBox() self.editor=HTMLEditor() self.editor.custom_url_loader=self.custom_url_loader self.editor.register_class_parser(self.class_parser) try: self.editor.set_text(self.element.data) except Exception as e: self.controller.log(_("HTML editor: cannot parse content (%s)") % str(e)) self.editor.connect('drag-data-received', self.editor_drag_received) self.editor.drag_dest_set(Gtk.DestDefaults.MOTION | Gtk.DestDefaults.HIGHLIGHT | Gtk.DestDefaults.ALL, config.data.get_target_types('annotation', 'annotation-type', 'timestamp'), Gdk.DragAction.COPY | Gdk.DragAction.LINK | Gdk.DragAction.ASK ) self.editor.connect('button-press-event', self.button_press_cb) self.view = Gtk.VBox() def sel_copy(i): self.editor.get_buffer().copy_clipboard(get_clipboard()) return True def sel_cut(i): self.editor.get_buffer().cut_clipboard(get_clipboard()) return True def sel_paste(i): self.editor.get_buffer().paste_clipboard(get_clipboard()) return True def refresh(i): self.editor.refresh() return True def display_header_menu(i): m=Gtk.Menu() for h in (1, 2, 3): i=Gtk.MenuItem(_("Heading %d") % h) i.connect('activate', lambda w, level: self.editor.apply_html_tag('h%d' % level), h) m.append(i) m.show_all() m.popup(None, i, None, 1, Gtk.get_current_event_time()) return True tb=Gtk.Toolbar() vbox.toolbar=tb tb.set_style(Gtk.ToolbarStyle.ICONS) for (icon, tooltip, action) in ( (Gtk.STOCK_BOLD, _("Bold"), lambda i: self.editor.apply_html_tag('b')), (Gtk.STOCK_ITALIC, _("Italic"), lambda i: self.editor.apply_html_tag('i')), ("title_icon.png", _("Header"), display_header_menu), (None, None, None), (Gtk.STOCK_COPY, _("Copy"), sel_copy), (Gtk.STOCK_CUT, _("Cut"), sel_cut), (Gtk.STOCK_PASTE, _("Paste"), sel_paste), (None, None, None), (Gtk.STOCK_REFRESH, _("Refresh"), refresh), ): if not config.data.preferences['expert-mode'] and icon == Gtk.STOCK_REFRESH: continue if not icon: b=Gtk.SeparatorToolItem() else: b=get_pixmap_toolbutton(icon, action) b.set_tooltip_text(tooltip) tb.insert(b, -1) b.show() if self.editor.can_undo(): b=Gtk.ToolButton(Gtk.STOCK_UNDO) b.connect('clicked', lambda i: self.editor.undo()) b.set_tooltip_text(_("Undo")) tb.insert(b, -1) b.show() self.view.pack_start(tb, False, True, 0) sw=Gtk.ScrolledWindow() sw.set_policy (Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC) sw.add(self.editor) context_data=ContextDisplay() def cursor_moved(buf, it, mark): if mark.get_name() == 'insert': context_data.set_context(self.editor.get_current_context(it)) return True self.editor.get_buffer().connect('mark-set', cursor_moved) sw2=Gtk.ScrolledWindow() sw2.set_policy (Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC) sw2.add(context_data) p=Gtk.HPaned() p.add1(sw2) p.add2(sw) # Hide by default p.set_position(0) p.show_all() self.view.add(p) def edit_wysiwyg(*p): vbox.foreach(vbox.remove) vbox.add(self.view) self.editing_source=False vbox.show_all() return True def edit_source(*p): 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_wysiwyg) b.set_tooltip_text(_("WYSIWYG 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 b=get_pixmap_toolbutton('xml.png', edit_source) b.set_tooltip_text(_("Edit HTML source")) tb.insert(b, 0) if config.data.preferences['prefer-wysiwyg']: edit_wysiwyg() self.editor.set_modified(False) else: edit_source() self.sourceview.set_modified(False) return vbox
def build_widget(self): v=Gtk.VBox() tb=Gtk.Toolbar() tb.set_style(Gtk.ToolbarStyle.ICONS) v.pack_start(tb, False, True, 0) top_box=Gtk.HBox() v.pack_start(top_box, False, True, 0) if hasattr(self.query, 'container') and self.query.container.id == '_interactive': b=Gtk.Button(_("Edit query again")) b.connect('clicked', self.edit_query) top_box.pack_start(b, False, True, 0) elif isinstance(self.query, SimpleQuery): b=Gtk.Button(_("Edit query")) b.connect('clicked', lambda b: self.controller.gui.edit_element(self.query)) top_box.pack_start(b, False, True, 0) elif isinstance(self.query, Quicksearch): e=Gtk.Entry() e.set_text(self.query.searched) e.set_width_chars(12) e.connect('activate', self.redo_quicksearch, e) b=get_small_stock_button(Gtk.STOCK_FIND, self.redo_quicksearch, e) e.set_tooltip_text(_('String to search')) b.set_tooltip_text(_('Search again')) top_box.pack_start(e, False, True, 0) top_box.pack_start(b, False, True, 0) # Present choices to display the result if not self.result: v.add(Gtk.Label(label=_("Empty result"))) elif (isinstance(self.result, list) or isinstance(self.result, tuple) or isinstance(self.result, AbstractBundle)): # Check if there are annotations l=[ a for a in self.result if isinstance(a, Annotation) ] cr=len(self.result) cl=len(l) if cr == cl: t=_("Result is a list of %d annotations.") % cr else: t=_("Result is a list of %(number)d elements with %(elements)s.") % { 'elements': helper.format_element_name("annotation", len(l)), 'number': len(self.result)} label=Gtk.Label(label=t) label.set_ellipsize(Pango.EllipsizeMode.END) label.set_line_wrap(True) top_box.add(label) def toggle_highlight(b, annotation_list): if not hasattr(b, 'highlight') or b.highlight: event="AnnotationActivate" label= _("Unhighlight annotations") b.highlight=False else: event="AnnotationDeactivate" label=_("Highlight annotations") b.highlight=True b.set_tooltip_text(label) for a in annotation_list: self.controller.notify(event, annotation=a) return True if l: # Instanciate a table view table=AnnotationTable(controller=self.controller, elements=l) if cr == cl: # Only annotations. v.add(table.widget) else: # Mixed annotations + other elements notebook=Gtk.Notebook() notebook.set_tab_pos(Gtk.PositionType.TOP) notebook.popup_disable() v.add(notebook) notebook.append_page(table.widget, Gtk.Label(label=_("Annotations"))) gtable=GenericTable(controller=self.controller, elements=[ e for e in self.result if not isinstance(e, Annotation) ] ) notebook.append_page(gtable.widget, Gtk.Label(label=_("Other elements"))) for (icon, tip, action) in ( ('timeline.png' , _("Display annotations in timeline"), lambda b: self.open_in_timeline(l)), ('transcription.png', _("Display annotations as transcription"), lambda b: self.controller.gui.open_adhoc_view('transcription', label=self._label, destination=self._destination, elements=l)), ('highlight.png', _("Highlight annotations"), lambda b: toggle_highlight(b, l)), (Gtk.STOCK_CONVERT, _("Export table"), lambda b: table.csv_export()), (Gtk.STOCK_NEW, _("Create annotations from the result"), self.create_annotations), ('montage.png', _("Define a montage with the result"), self.create_montage), ('comment.png', _("Create a comment view with the result"), self.create_comment), (Gtk.STOCK_FIND_AND_REPLACE, _("Search and replace strings in the annotations content"), self.search_replace), ): if icon.endswith('.png'): ti=get_pixmap_toolbutton(icon) else: ti=Gtk.ToolButton(stock_id=icon) ti.connect('clicked', action) ti.set_tooltip_text(tip) tb.insert(ti, -1) self.table=table else: # Only Instanciate a generic table view gtable=GenericTable(controller=self.controller, elements=self.result) v.add(gtable.widget) ti=Gtk.ToolButton(Gtk.STOCK_CONVERT) ti.connect('clicked', lambda b: gtable.csv_export()) ti.set_tooltip_text(_("Export table")) tb.insert(ti, -1) self.table=gtable ti=get_pixmap_toolbutton('editaccumulator.png', lambda b: self.open_in_edit_accumulator(self.table.get_elements())) ti.set_tooltip_text(_("Edit elements")) tb.insert(ti, -1) if config.data.preferences['expert-mode']: ti=get_pixmap_toolbutton('python.png', lambda b: self.open_in_evaluator(self.table.get_elements())) ti.set_tooltip_text(_("Open in python evaluator")) tb.insert(ti, -1) else: v.add(Gtk.Label(label=_("Result:\n%s") % str(self.result))) v.show_all() return v
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 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 get_view(self, compact=False): """Generate a view widget for editing HTML.""" vbox = Gtk.VBox() self.editor = HTMLEditor() self.editor.custom_url_loader = self.custom_url_loader self.editor.register_class_parser(self.class_parser) try: self.editor.set_text(self.element.data) except Exception as e: self.controller.log( _("HTML editor: cannot parse content (%s)") % str(e)) self.editor.connect('drag-data-received', self.editor_drag_received) self.editor.drag_dest_set( Gtk.DestDefaults.MOTION | Gtk.DestDefaults.HIGHLIGHT | Gtk.DestDefaults.ALL, config.data.get_target_types('annotation', 'annotation-type', 'timestamp'), Gdk.DragAction.COPY | Gdk.DragAction.LINK | Gdk.DragAction.ASK) self.editor.connect('button-press-event', self.button_press_cb) self.view = Gtk.VBox() def sel_copy(i): self.editor.get_buffer().copy_clipboard(get_clipboard()) return True def sel_cut(i): self.editor.get_buffer().cut_clipboard(get_clipboard()) return True def sel_paste(i): self.editor.get_buffer().paste_clipboard(get_clipboard()) return True def refresh(i): self.editor.refresh() return True def display_header_menu(i): m = Gtk.Menu() for h in (1, 2, 3): i = Gtk.MenuItem(_("Heading %d") % h) i.connect( 'activate', lambda w, level: self.editor.apply_html_tag('h%d' % level), h) m.append(i) m.show_all() m.popup(None, i, None, 1, Gtk.get_current_event_time()) return True tb = Gtk.Toolbar() vbox.toolbar = tb tb.set_style(Gtk.ToolbarStyle.ICONS) for (icon, tooltip, action) in ( (Gtk.STOCK_BOLD, _("Bold"), lambda i: self.editor.apply_html_tag('b')), (Gtk.STOCK_ITALIC, _("Italic"), lambda i: self.editor.apply_html_tag('i')), ("title_icon.png", _("Header"), display_header_menu), (None, None, None), (Gtk.STOCK_COPY, _("Copy"), sel_copy), (Gtk.STOCK_CUT, _("Cut"), sel_cut), (Gtk.STOCK_PASTE, _("Paste"), sel_paste), (None, None, None), (Gtk.STOCK_REFRESH, _("Refresh"), refresh), ): if not config.data.preferences[ 'expert-mode'] and icon == Gtk.STOCK_REFRESH: continue if not icon: b = Gtk.SeparatorToolItem() else: b = get_pixmap_toolbutton(icon, action) b.set_tooltip_text(tooltip) tb.insert(b, -1) b.show() if self.editor.can_undo(): b = Gtk.ToolButton(Gtk.STOCK_UNDO) b.connect('clicked', lambda i: self.editor.undo()) b.set_tooltip_text(_("Undo")) tb.insert(b, -1) b.show() self.view.pack_start(tb, False, True, 0) sw = Gtk.ScrolledWindow() sw.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC) sw.add(self.editor) context_data = ContextDisplay() def cursor_moved(buf, it, mark): if mark.get_name() == 'insert': context_data.set_context(self.editor.get_current_context(it)) return True self.editor.get_buffer().connect('mark-set', cursor_moved) sw2 = Gtk.ScrolledWindow() sw2.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC) sw2.add(context_data) p = Gtk.HPaned() p.add1(sw2) p.add2(sw) # Hide by default p.set_position(0) p.show_all() self.view.add(p) def edit_wysiwyg(*p): vbox.foreach(vbox.remove) vbox.add(self.view) self.editing_source = False vbox.show_all() return True def edit_source(*p): 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_wysiwyg) b.set_tooltip_text(_("WYSIWYG 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 b = get_pixmap_toolbutton('xml.png', edit_source) b.set_tooltip_text(_("Edit HTML source")) tb.insert(b, 0) if config.data.preferences['prefer-wysiwyg']: edit_wysiwyg() self.editor.set_modified(False) else: edit_source() self.sourceview.set_modified(False) return vbox
def build_widget(self): v=Gtk.VBox() hb=Gtk.HBox() hb.set_homogeneous(False) def remove_drag_received(widget, context, x, y, selection, targetType, time): if targetType == config.data.target_type['timestamp']: data=decode_drop_parameters(selection.get_data()) position=int(data['timestamp']) w=self.get_matching_bookmark(position) if position is not None: self.bookmarks.remove(w) self.refresh() return True else: logger.warning("Unknown target type for drop: %d", targetType) return False b=get_small_stock_button(Gtk.STOCK_DELETE) b.set_tooltip_text(_("Drop a position here to remove it from the list")) b.drag_dest_set(Gtk.DestDefaults.MOTION | Gtk.DestDefaults.HIGHLIGHT | Gtk.DestDefaults.ALL, config.data.get_target_types('timestamp'), Gdk.DragAction.LINK | Gdk.DragAction.COPY) b.connect('drag-data-received', remove_drag_received) hb.pack_start(b, False, True, 0) def bookmark_current_time(b): p=self.controller.player if p.is_playing(): self.append(p.current_position_value) return True tb=Gtk.Toolbar() tb.set_style(Gtk.ToolbarStyle.ICONS) for icon, action, tip in ( ('set-to-now.png', bookmark_current_time, _("Insert a bookmark for the current video time")), (Gtk.STOCK_CONVERT, self.convert_to_annotations, _("Convert bookmarks to annotations")), (Gtk.STOCK_SAVE, self.save_view, _("Save view")), ): if icon.endswith('.png'): b=get_pixmap_toolbutton(icon) else: b=Gtk.ToolButton(stock_id=icon) b.set_tooltip_text(tip) b.connect('clicked', action) tb.insert(b, -1) hb.add(tb) v.pack_start(hb, False, True, 0) if self.options['vertical']: mainbox=Gtk.VBox() else: mainbox=Gtk.HBox() sw=Gtk.ScrolledWindow() sw.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC) sw.add_with_viewport(mainbox) self.scrollwindow=sw self.mainbox=mainbox def mainbox_drag_received(widget, context, x, y, selection, targetType, time): if targetType == config.data.target_type['timestamp']: data=decode_drop_parameters(selection.get_data()) position=int(data['timestamp']) comment=data.get('comment', '') self.append(position, comment=comment) return True else: logger.warning("Unknown target type for drop: %d", targetType) return False self.mainbox.drag_dest_set(Gtk.DestDefaults.MOTION | Gtk.DestDefaults.HIGHLIGHT | Gtk.DestDefaults.ALL, config.data.get_target_types('timestamp'), Gdk.DragAction.LINK | Gdk.DragAction.COPY) self.mainbox.connect('drag-data-received', mainbox_drag_received) v.add(sw) return v
class HTMLContentHandler (ContentHandler): """Create a HTML edit form for the given element.""" def can_handle(mimetype): res=0 if mimetype == 'text/html': res=90 return res can_handle=staticmethod(can_handle) def __init__ (self, element, controller=None, parent=None, **kw): self.element = element self.controller=controller self.parent=parent self.editable = True self.fname=None self.last_dndtime=None self.last_x = None self.last_y = None # HTMLEditor component (gtk.Textview subclass) self.editor = None # Widgets holding editors (basic and html) self.view = None self.sourceview=None self.placeholders=[] self.editing_source=False def close(self): for p in self.placeholders: p.cleanup() def set_editable (self, boolean): self.editable = boolean if self.sourceview: self.sourceview.set_editable(boolean) def get_modified(self): if self.editing_source: return self.sourceview.get_modified() else: return self.editor.get_modified() def update_element (self): """Update the element fields according to the values in the view.""" if not self.editable: return False if self.editing_source: self.sourceview.update_element() # We applied our modifications to the HTML source, so # parse the source again in the HTML editor if self.editor is not None: self.editor.set_text(self.element.data) self.editor.set_modified(False) return True if self.editor is None: return True self.element.data = self.editor.get_html() # Update the HTML source representation if self.sourceview is not None: self.sourceview.content_set(self.element.data) self.sourceview.set_modified(False) return True def open_link(self, link=None): if link: pos=re.findall('/media/play/(\d+)', link) if pos: # A position was specified. Directly use it. self.controller.update_status('set', long(pos[0])) else: self.controller.open_url(link) return True def insert_annotation_content(self, choice, annotation, focus=False): """ choice: list of one or more strings: 'snapshot', 'timestamp', 'content', 'overlay' """ a=AnnotationPlaceholder(annotation, self.controller, choice, self.editor.update_pixbuf) self.placeholders.append(a) self.editor.insert_pixbuf(a.pixbuf) if focus: self.grab_focus() return True def insert_annotationtype_content(self, choice, annotationtype, focus=False): """ choice: list of one or more strings: 'list', 'table', 'transcription' """ a=AnnotationTypePlaceholder(annotationtype, self.controller, choice, self.editor.update_pixbuf) self.placeholders.append(a) self.editor.insert_pixbuf(a.pixbuf) if focus: self.grab_focus() return True def grab_focus(self, *p): self.editor.grab_focus() return True 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']), (_("Annotation content"), ['link', 'content']), ): 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']: for uri in unicode(selection.data, 'utf8').split('\n'): source = self.controller.package.annotationTypes.get(uri) if source is None: return True m=gtk.Menu() for (title, choice) in ( (_("as a list"), [ 'list' ]), (_("as a grid"), [ 'grid' ]), (_("as a table"), [ 'table' ]), (_("as a transcription"), ['transcription' ]), ): i=gtk.MenuItem(title) i.connect('activate', (lambda it, at, data: self.insert_annotationtype_content(data, at, 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['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 class_parser(self, tag, attr): if attr['class'] == 'advene:annotation': a=AnnotationPlaceholder(annotation=None, controller=self.controller, update_pixbuf=self.editor.update_pixbuf) self.placeholders.append(a) return a.parse_html(tag, attr) elif attr['class'] == 'advene:annotationtype': a=AnnotationTypePlaceholder(annotationtype=None, controller=self.controller, update_pixbuf=self.editor.update_pixbuf) self.placeholders.append(a) return a.parse_html(tag, attr) return None, None def custom_url_loader(self, url): """Custom URL loader. This method processes URLs internally when possible, instead of going through the webserver. This is at the cost of some code, and possible discrepancies with the original webcherry code. It is absolutely unnecessary on linux/macosx. However, win32 (svg?) pixbuf loader is broken wrt. threads, and this is the solution to have the overlay() code (and thus the pixbuf loader) execute in the main thread. """ m=re.search('/media/overlay/(.+?)/(.+)', url) if m: (alias, element)=m.groups() if '/' in element: # There is a TALES expression specifying the overlayed # content aid, path = element.split('/', 1) else: aid, path = element, None p=self.controller.packages.get(alias) if not p: return None a=p.get_element_by_id(aid) if a is None: return None if path: # There is a TALES expression path='here/'+path ctx=self.controller.build_context(here=a) svg_data=unicode( ctx.evaluateValue(path) ) elif 'svg' in a.content.mimetype: # Overlay svg svg_data=a.content.data else: # Overlay annotation title svg_data=self.controller.get_title(a) png_data=str(p.imagecache[a.fragment.begin]) return self.controller.gui.overlay(png_data, svg_data) m=re.search('/packages/(.+?)/imagecache/(\d+)', url) if m: alias, timestamp = m.groups() p=self.controller.packages.get(alias) if p is None: return None return str(p.imagecache[long(timestamp)]) return None def contextual_popup(self, ctx=None, menu=None): """Popup a contextual menu for the given context. """ if menu is None: menu=gtk.Menu() def open_link(i, l): self.open_link(l) return True def goto_position(i, pos): self.controller.update_status('set', pos) return True def select_presentation(i, ap, modes): ap.presentation = modes[:] ap.refresh() return True def new_menuitem(label, action, *params): item=gtk.MenuItem(label) if action is not None: item.connect('activate', action, *params) item.show() menu.append(item) return item if ctx is None: ctx=self.editor.get_current_context() if ctx: if hasattr(ctx[-1], '_placeholder'): ap=ctx[-1]._placeholder if getattr(ap, 'annotation', None) is not None: new_menuitem(_("Annotation %s") % self.controller.get_title(ap.annotation), None) new_menuitem(_("Play video"), goto_position, ap.annotation.fragment.begin) new_menuitem(_("Show timestamp only"), select_presentation, ap, ['timestamp', 'link']) new_menuitem(_("Show content only"), select_presentation, ap, ['content', 'link']) new_menuitem(_("Show snapshot only"), select_presentation, ap, ['snapshot', 'link']) new_menuitem(_("Show overlayed timestamp"), select_presentation, ap, ['timestamp', 'snapshot', 'link']) new_menuitem(_("Show overlayed content"), select_presentation, ap, ['overlay', 'link']) elif getattr(ap, 'annotationtype', None) is not None: new_menuitem(_("Annotation type %s") % self.controller.get_title(ap.annotationtype), None) new_menuitem(_("display as list"), select_presentation, ap, ['list']) new_menuitem(_("display as grid"), select_presentation, ap, ['grid']) new_menuitem(_("display as table"), select_presentation, ap, ['table']) new_menuitem(_("display as transcription"), select_presentation, ap, ['transcription']) l=[ m for m in ctx if m._tag == 'a' ] if l: link=dict(l[0]._attr).get('href', None) if link: if '/media/play' in link: new_menuitem(_("Play video"), open_link, link) else: new_menuitem(_("Open link"), open_link, link) return menu def button_press_cb(self, textview, event): if not (event.button == 3 or (event.button == 1 and event.type == gtk.gdk._2BUTTON_PRESS)): return False textwin=textview.get_window(gtk.TEXT_WINDOW_TEXT) if event.window != textwin: return False (x, y) = textview.window_to_buffer_coords(gtk.TEXT_WINDOW_TEXT, int(event.x), int(event.y)) it=textview.get_iter_at_location(x, y) if it is None: print "Error in get_iter_at_location" return False ctx=self.editor.get_current_context(it) if not ctx: return False if event.button == 3: # Right button if hasattr(ctx[-1], '_placeholder'): # An annotation placeholder is here. Display popup menu. menu=self.contextual_popup(ctx) menu.popup(None, None, None, 0, event.time) return True else: # Double click with left button if hasattr(ctx[-1], '_placeholder'): # There is an placeholder p = ctx[-1]._placeholder if isinstance(p, AnnotationPlaceholder): a=ctx[-1]._placeholder.annotation if a is not None: self.controller.update_status('set', a.fragment.begin) return False l=[ m for m in ctx if m._tag == 'a' ] if l: link=dict(l[0]._attr).get('href', None) self.open_link(link) return False return False def get_view (self, compact=False): """Generate a view widget for editing HTML.""" vbox=gtk.VBox() self.editor=HTMLEditor() self.editor.custom_url_loader=self.custom_url_loader self.editor.register_class_parser(self.class_parser) try: self.editor.set_text(self.element.data) except Exception, e: self.controller.log(_("HTML editor: cannot parse content (%s)") % unicode(e)) self.editor.connect('drag-data-received', self.editor_drag_received) self.editor.drag_dest_set(gtk.DEST_DEFAULT_MOTION | gtk.DEST_DEFAULT_HIGHLIGHT | gtk.DEST_DEFAULT_ALL, config.data.drag_type['annotation'] + config.data.drag_type['annotation-type'] + config.data.drag_type['timestamp'], gtk.gdk.ACTION_COPY | gtk.gdk.ACTION_LINK | gtk.gdk.ACTION_ASK ) self.editor.connect('button-press-event', self.button_press_cb) self.view = gtk.VBox() def sel_copy(i): self.editor.get_buffer().copy_clipboard(gtk.clipboard_get()) return True def sel_cut(i): self.editor.get_buffer().cut_clipboard(gtk.clipboard_get()) return True def sel_paste(i): self.editor.get_buffer().paste_clipboard(gtk.clipboard_get()) return True def refresh(i): self.editor.refresh() return True def display_header_menu(i): m=gtk.Menu() for h in (1, 2, 3): i=gtk.MenuItem(_("Heading %d") % h) i.connect('activate', lambda w, level: self.editor.apply_html_tag('h%d' % level), h) m.append(i) m.show_all() m.popup(None, i, None, 1, gtk.get_current_event_time()) return True tb=gtk.Toolbar() vbox.toolbar=tb tb.set_style(gtk.TOOLBAR_ICONS) for (icon, tooltip, action) in ( (gtk.STOCK_BOLD, _("Bold"), lambda i: self.editor.apply_html_tag('b')), (gtk.STOCK_ITALIC, _("Italic"), lambda i: self.editor.apply_html_tag('i')), ("title_icon.png", _("Header"), display_header_menu), (None, None, None), (gtk.STOCK_COPY, _("Copy"), sel_copy), (gtk.STOCK_CUT, _("Cut"), sel_cut), (gtk.STOCK_PASTE, _("Paste"), sel_paste), (None, None, None), (gtk.STOCK_REFRESH, _("Refresh"), refresh), ): if not config.data.preferences['expert-mode'] and icon == gtk.STOCK_REFRESH: continue if not icon: b=gtk.SeparatorToolItem() else: b=get_pixmap_toolbutton(icon, action) b.set_tooltip_text(tooltip) tb.insert(b, -1) b.show() if self.editor.can_undo(): b=gtk.ToolButton(gtk.STOCK_UNDO) b.connect('clicked', lambda i: self.editor.undo()) b.set_tooltip_text(_("Undo")) tb.insert(b, -1) b.show() self.view.pack_start(tb, expand=False) sw=gtk.ScrolledWindow() sw.set_policy (gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) sw.add(self.editor) context_data=ContextDisplay() def cursor_moved(buf, it, mark): if mark.get_name() == 'insert': context_data.set_context(self.editor.get_current_context(it)) return True self.editor.get_buffer().connect('mark-set', cursor_moved) sw2=gtk.ScrolledWindow() sw2.set_policy (gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) sw2.add(context_data) p=gtk.HPaned() p.add1(sw2) p.add2(sw) # Hide by default p.set_position(0) p.show_all() self.view.add(p) def edit_wysiwyg(*p): vbox.foreach(vbox.remove) vbox.add(self.view) self.editing_source=False vbox.show_all() return True def edit_source(*p): 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_wysiwyg) b.set_tooltip_text(_("WYSIWYG 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 b=get_pixmap_toolbutton('xml.png', edit_source) b.set_tooltip_text(_("Edit HTML source")) tb.insert(b, 0) if config.data.preferences['prefer-wysiwyg']: edit_wysiwyg() self.editor.set_modified(False) else: edit_source() self.sourceview.set_modified(False) return vbox
def build_widget(self): v=Gtk.VBox() hb=Gtk.HBox() hb.set_homogeneous(False) def remove_drag_received(widget, context, x, y, selection, targetType, time): if targetType == config.data.target_type['timestamp']: data=decode_drop_parameters(selection.get_data()) position=int(data['timestamp']) w=self.get_matching_bookmark(position) if position is not None: self.bookmarks.remove(w) self.refresh() return True else: logger.warn("Unknown target type for drop: %d" % targetType) return False b=get_small_stock_button(Gtk.STOCK_DELETE) b.set_tooltip_text(_("Drop a position here to remove it from the list")) b.drag_dest_set(Gtk.DestDefaults.MOTION | Gtk.DestDefaults.HIGHLIGHT | Gtk.DestDefaults.ALL, config.data.get_target_types('timestamp'), Gdk.DragAction.LINK | Gdk.DragAction.COPY) b.connect('drag-data-received', remove_drag_received) hb.pack_start(b, False, True, 0) def bookmark_current_time(b): p=self.controller.player if p.is_playing(): self.append(p.current_position_value) return True tb=Gtk.Toolbar() tb.set_style(Gtk.ToolbarStyle.ICONS) for icon, action, tip in ( ('set-to-now.png', bookmark_current_time, _("Insert a bookmark for the current video time")), (Gtk.STOCK_CONVERT, self.convert_to_annotations, _("Convert bookmarks to annotations")), (Gtk.STOCK_SAVE, self.save_view, _("Save view")), ): if icon.endswith('.png'): b=get_pixmap_toolbutton(icon) else: b=Gtk.ToolButton(stock_id=icon) b.set_tooltip_text(tip) b.connect('clicked', action) tb.insert(b, -1) hb.add(tb) v.pack_start(hb, False, True, 0) if self.options['vertical']: mainbox=Gtk.VBox() else: mainbox=Gtk.HBox() sw=Gtk.ScrolledWindow() sw.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC) sw.add_with_viewport(mainbox) self.scrollwindow=sw self.mainbox=mainbox def mainbox_drag_received(widget, context, x, y, selection, targetType, time): if targetType == config.data.target_type['timestamp']: data=decode_drop_parameters(selection.get_data()) position=int(data['timestamp']) comment=data.get('comment', '') self.append(position, comment=comment) return True else: logger.warn("Unknown target type for drop: %d" % targetType) return False self.mainbox.drag_dest_set(Gtk.DestDefaults.MOTION | Gtk.DestDefaults.HIGHLIGHT | Gtk.DestDefaults.ALL, config.data.get_target_types('timestamp'), Gdk.DragAction.LINK | Gdk.DragAction.COPY) self.mainbox.connect('drag-data-received', mainbox_drag_received) v.add(sw) return v
def build_widget(self): v=Gtk.VBox() tb=Gtk.Toolbar() tb.set_style(Gtk.ToolbarStyle.ICONS) v.pack_start(tb, False, True, 0) top_box=Gtk.HBox() v.pack_start(top_box, False, True, 0) if hasattr(self.query, 'container') and self.query.container.id == '_interactive': b=Gtk.Button(_("Edit query again")) b.connect('clicked', self.edit_query) top_box.pack_start(b, False, True, 0) elif isinstance(self.query, SimpleQuery): b=Gtk.Button(_("Edit query")) b.connect('clicked', lambda b: self.controller.gui.edit_element(self.query)) top_box.pack_start(b, False, True, 0) elif isinstance(self.query, Quicksearch): e=Gtk.Entry() e.set_text(self.query.searched) e.set_width_chars(12) e.connect('activate', self.redo_quicksearch, e) b=get_small_stock_button(Gtk.STOCK_FIND, self.redo_quicksearch, e) e.set_tooltip_text(_('String to search')) b.set_tooltip_text(_('Search again')) top_box.pack_start(e, False, True, 0) top_box.pack_start(b, False, True, 0) # Present choices to display the result if not self.result: v.add(Gtk.Label(label=_("Empty result"))) elif isinstance(self.result, (list, tuple, AbstractBundle)): # Check if there are annotations l=[ a for a in self.result if isinstance(a, Annotation) ] cr=len(self.result) cl=len(l) if cr == cl: t=_("Result is a list of %d annotations.") % cr else: t=_("Result is a list of %(number)d elements with %(elements)s.") % { 'elements': helper.format_element_name("annotation", len(l)), 'number': len(self.result)} label=Gtk.Label(label=t) label.set_ellipsize(Pango.EllipsizeMode.END) label.set_line_wrap(True) top_box.add(label) def toggle_highlight(b, annotation_list): if not hasattr(b, 'highlight') or b.highlight: event="AnnotationActivate" label= _("Unhighlight annotations") b.highlight=False else: event="AnnotationDeactivate" label=_("Highlight annotations") b.highlight=True b.set_tooltip_text(label) for a in annotation_list: self.controller.notify(event, annotation=a) return True if l: # Instanciate a table view table=AnnotationTable(controller=self.controller, elements=l) if cr == cl: # Only annotations. v.add(table.widget) else: # Mixed annotations + other elements notebook=Gtk.Notebook() notebook.set_tab_pos(Gtk.PositionType.TOP) notebook.popup_disable() v.add(notebook) notebook.append_page(table.widget, Gtk.Label(label=_("Annotations"))) gtable=GenericTable(controller=self.controller, elements=[ e for e in self.result if not isinstance(e, Annotation) ]) notebook.append_page(gtable.widget, Gtk.Label(label=_("Other elements"))) for (icon, tip, action) in ( ('timeline.png' , _("Display annotations in timeline"), lambda b: self.open_in_timeline(l)), ('transcription.png', _("Display annotations as transcription"), lambda b: self.controller.gui.open_adhoc_view('transcription', label=self._label, destination=self._destination, elements=l)), ('highlight.png', _("Highlight annotations"), lambda b: toggle_highlight(b, l)), (Gtk.STOCK_CONVERT, _("Export table"), lambda b: table.csv_export()), (Gtk.STOCK_NEW, _("Create annotations from the result"), self.create_annotations), ('montage.png', _("Define a montage with the result"), self.create_montage), ('comment.png', _("Create a comment view with the result"), self.create_comment), (Gtk.STOCK_FIND_AND_REPLACE, _("Search and replace strings in the annotations content"), self.search_replace), ): if icon.endswith('.png'): ti=get_pixmap_toolbutton(icon) else: ti=Gtk.ToolButton(stock_id=icon) ti.connect('clicked', action) ti.set_tooltip_text(tip) tb.insert(ti, -1) self.table=table else: # Only Instanciate a generic table view gtable=GenericTable(controller=self.controller, elements=self.result) v.add(gtable.widget) ti=Gtk.ToolButton(Gtk.STOCK_CONVERT) ti.connect('clicked', lambda b: gtable.csv_export()) ti.set_tooltip_text(_("Export table")) tb.insert(ti, -1) self.table=gtable ti=get_pixmap_toolbutton('editaccumulator.png', lambda b: self.open_in_edit_accumulator(self.table.get_elements())) ti.set_tooltip_text(_("Edit elements")) tb.insert(ti, -1) if config.data.preferences['expert-mode']: ti=get_pixmap_toolbutton('python.png', lambda b: self.open_in_evaluator(self.table.get_elements())) ti.set_tooltip_text(_("Open in python evaluator")) tb.insert(ti, -1) else: v.add(Gtk.Label(label=_("Result:\n%s") % str(self.result))) v.show_all() return v
def build_widget(self): v=gtk.VBox() hb=gtk.HBox() hb.set_homogeneous(False) def remove_drag_received(widget, context, x, y, selection, targetType, time): if targetType == config.data.target_type['timestamp']: data=decode_drop_parameters(selection.data) position=long(data['timestamp']) w=self.get_matching_bookmark(position) if position is not None: self.bookmarks.remove(w) self.refresh() return True else: print "Unknown target type for drop: %d" % targetType return False b=get_small_stock_button(gtk.STOCK_DELETE) b.set_tooltip_text(_("Drop a position here to remove it from the list")) b.drag_dest_set(gtk.DEST_DEFAULT_MOTION | gtk.DEST_DEFAULT_HIGHLIGHT | gtk.DEST_DEFAULT_ALL, config.data.drag_type['timestamp'], gtk.gdk.ACTION_LINK | gtk.gdk.ACTION_COPY) b.connect('drag-data-received', remove_drag_received) hb.pack_start(b, expand=False) def bookmark_current_time(b): p=self.controller.player if p.status in (p.PlayingStatus, p.PauseStatus): v=p.current_position_value # Make a snapshot self.controller.update_snapshot(v) self.append(v) return True tb=gtk.Toolbar() tb.set_style(gtk.TOOLBAR_ICONS) for icon, action, tip in ( ('set-to-now.png', bookmark_current_time, _("Insert a bookmark for the current video time")), (gtk.STOCK_CONVERT, self.convert_to_annotations, _("Convert bookmarks to annotations")), (gtk.STOCK_SAVE, self.save_view, _("Save view")), ): if icon.endswith('.png'): b=get_pixmap_toolbutton(icon) else: b=gtk.ToolButton(stock_id=icon) b.set_tooltip_text(tip) b.connect('clicked', action) tb.insert(b, -1) hb.add(tb) v.pack_start(hb, expand=False) if self.options['vertical']: mainbox=gtk.VBox() else: mainbox=gtk.HBox() sw=gtk.ScrolledWindow() sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) sw.add_with_viewport(mainbox) self.scrollwindow=sw self.mainbox=mainbox def mainbox_drag_received(widget, context, x, y, selection, targetType, time): if targetType == config.data.target_type['timestamp']: data=decode_drop_parameters(selection.data) position=long(data['timestamp']) comment=data.get('comment', '') self.append(position, comment=comment) return True else: print "Unknown target type for drop: %d" % targetType return False self.mainbox.drag_dest_set(gtk.DEST_DEFAULT_MOTION | gtk.DEST_DEFAULT_HIGHLIGHT | gtk.DEST_DEFAULT_ALL, config.data.drag_type['timestamp'], gtk.gdk.ACTION_LINK | gtk.gdk.ACTION_COPY) self.mainbox.connect('drag-data-received', mainbox_drag_received) v.add(sw) return v
def build_widget(self): v = gtk.VBox() hb = gtk.HBox() hb.set_homogeneous(False) def remove_drag_received(widget, context, x, y, selection, targetType, time): if targetType == config.data.target_type['timestamp']: data = decode_drop_parameters(selection.data) position = long(data['timestamp']) w = self.get_matching_bookmark(position) if position is not None: self.bookmarks.remove(w) self.refresh() return True else: print "Unknown target type for drop: %d" % targetType return False b = get_small_stock_button(gtk.STOCK_DELETE) b.set_tooltip_text( _("Drop a position here to remove it from the list")) b.drag_dest_set( gtk.DEST_DEFAULT_MOTION | gtk.DEST_DEFAULT_HIGHLIGHT | gtk.DEST_DEFAULT_ALL, config.data.drag_type['timestamp'], gtk.gdk.ACTION_LINK | gtk.gdk.ACTION_COPY) b.connect('drag-data-received', remove_drag_received) hb.pack_start(b, expand=False) def bookmark_current_time(b): p = self.controller.player if p.status in (p.PlayingStatus, p.PauseStatus): v = p.current_position_value # Make a snapshot self.controller.update_snapshot(v) self.append(v) return True tb = gtk.Toolbar() tb.set_style(gtk.TOOLBAR_ICONS) for icon, action, tip in ( ('set-to-now.png', bookmark_current_time, _("Insert a bookmark for the current video time")), (gtk.STOCK_CONVERT, self.convert_to_annotations, _("Convert bookmarks to annotations")), (gtk.STOCK_SAVE, self.save_view, _("Save view")), ): if icon.endswith('.png'): b = get_pixmap_toolbutton(icon) else: b = gtk.ToolButton(stock_id=icon) b.set_tooltip_text(tip) b.connect('clicked', action) tb.insert(b, -1) hb.add(tb) v.pack_start(hb, expand=False) if self.options['vertical']: mainbox = gtk.VBox() else: mainbox = gtk.HBox() sw = gtk.ScrolledWindow() sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) sw.add_with_viewport(mainbox) self.scrollwindow = sw self.mainbox = mainbox def mainbox_drag_received(widget, context, x, y, selection, targetType, time): if targetType == config.data.target_type['timestamp']: data = decode_drop_parameters(selection.data) position = long(data['timestamp']) comment = data.get('comment', '') self.append(position, comment=comment) return True else: print "Unknown target type for drop: %d" % targetType return False self.mainbox.drag_dest_set( gtk.DEST_DEFAULT_MOTION | gtk.DEST_DEFAULT_HIGHLIGHT | gtk.DEST_DEFAULT_ALL, config.data.drag_type['timestamp'], gtk.gdk.ACTION_LINK | gtk.gdk.ACTION_COPY) self.mainbox.connect('drag-data-received', mainbox_drag_received) v.add(sw) return v