class CtxAnnotator(gtk.VBox): def __init__(self): self.policy = ScalePolicy() self.displays = [] self.xmax = None self.xmin = None self.annotations = Annotations() self.annotations.connect('context-added',self.add_context_button) self.annotations.connect('context-removed',self.remove_context_button) self.buttons = dict() self.display_box = gtk.VBox() self.context_box = gtk.HBox() self.input_state = InputState(self.annotations) self.input_state.connect('select-selection',self.show_selection_menu) self.input_state.connect('select-annotation',self.show_annotation_menu) add_button = gtk.Button(stock='gtk-add') add_button.connect('clicked',lambda but: self.create_context()) self.context_box.pack_start(add_button,expand=False,fill=True) scr_win = gtk.ScrolledWindow() scr_win.add_with_viewport(self.display_box) scr_win.set_policy(gtk.POLICY_NEVER,gtk.POLICY_AUTOMATIC) self.adjustment = gtk.Adjustment() self.adjustment.connect('value-changed',self.update_pos) self.scroller = gtk.HScrollbar(self.adjustment) self.scroller.hide() gtk.VBox.__init__(self) self.pack_start(scr_win,expand=True,fill=True) self.pack_start(self.scroller,expand=False,fill=True) self.pack_end(self.context_box,expand=False,fill=True) def update_pos(self,adj): self.policy.update_pos(adj.value) for d in self.displays: d.update_zoom(self.policy) def find_annotation(self,x): hits = self.annotations.find_annotation(x) if len(hits) is 0: return None else: return hits[0] def bigger(self): self.policy.biggerx() self.update_zoom() def smaller(self): self.policy.smallerx() self.update_zoom() def update_zoom(self): if self.xmax is None: self.scroller.hide() return max = self.xmax - self.policy.get_window() self.adjustment.lower = self.xmin self.adjustment.upper = max if max < self.adjustment.value: self.adjustment.value = max if self.xmin > self.adjustment.value: self.adjustment.value = self.xmin if self.xmin < max: self.scroller.show() else: self.scroller.hide() self.adjustment.step_increment = self.policy.get_steps() self.adjustment.page_increment = self.policy.get_pages() self.adjustment.changed() for d in self.displays: d.update_zoom(self.policy) def recalculate(self): xmin = None xmax = None for d in self.displays: min,max = d.src.get_time_bounds() if xmin is None or min < xmin: xmin = min if xmax is None or max > xmax: xmax = max ann_l,ann_r = self.annotations.bounds() if ann_l is not None and ann_l < xmin: xmin = ann_l if ann_r is not None and ann_r > xmax: xmax = ann_r self.xmin = xmin self.xmax = xmax if xmin is not None: self.policy.update_min(xmin) self.update_zoom() def add_source(self,src): disp = Display(src,self.annotations,self.input_state) self.displays.append(disp) frame = gtk.Table(3,2) cont = gtk.Frame() cont.set_shadow_type(gtk.SHADOW_ETCHED_OUT) cont.add(disp) frame.attach(cont,0,1,1,3,gtk.EXPAND|gtk.FILL,gtk.EXPAND|gtk.FILL) lbl = gtk.Label() lbl.set_markup("<b>"+src.get_name()+"</b>") lbl.set_alignment(0.0,0.5) frame.attach(lbl,0,1,0,1,gtk.EXPAND|gtk.FILL,gtk.SHRINK|gtk.FILL) rem_but = gtk.Button() rem_but.set_image(gtk.image_new_from_stock(gtk.STOCK_DELETE,gtk.ICON_SIZE_MENU)) rem_but.connect('clicked',self.remove_source_handler,frame,disp) frame.attach(rem_but,1,2,1,2,gtk.SHRINK|gtk.FILL,gtk.SHRINK|gtk.FILL) frame.attach(gtk.VBox(),1,2,2,3,gtk.SHRINK,gtk.EXPAND) frame.show_all() self.display_box.pack_start(frame,expand=True,fill=True) self.recalculate() def remove_source_handler(self,but,frame,display): self.display_box.remove(frame) self.displays.remove(display) frame.destroy() self.recalculate() def add_context(self,name): self.annotations.add_context(name) def add_context_button(self,model,name,color): but = ContextButton(name,color,self) but.show_all() self.context_box.pack_start(but,expand=False,fill=True) self.buttons[name] = but def remove_context_button(self,model,name): but = self.buttons[name] self.context_box.remove(but) del self.buttons[name] def remove_context(self,name): self.annotations.remove_context(name) def create_context(self): dialog = gtk.MessageDialog(None, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_QUESTION, gtk.BUTTONS_OK, None) dialog.set_markup(_("Please enter the <b>name</b> of the context")) entry = gtk.Entry() entry.connect("activate", lambda wid: dialog.response(gtk.RESPONSE_OK)) dialog.vbox.pack_end(entry,expand=True,fill=True) dialog.show_all() dialog.run() self.add_context(entry.get_text()) dialog.destroy() def add_annotation(self,name,start,end): self.annotations.add_annotation(name,start,end) def create_annotation(self,name): if self.input_state.selection is not None: (start,end) = self.input_state.selection self.add_annotation(name,start,end) def show_selection_menu(self,state,display,boundl,boundr,time): menu = SelectionMenu(self,display) menu.show_all() menu.popup(None,None,None,3,time) def show_annotation_menu(self,state,display,id,time): menu = AnnotationMenu(self,id) menu.show_all() menu.popup(None,None,None,3,time) def remove_annotation(self,id): self.annotations.remove_annotation(id) def write_out(self,fn): pkg = AnnPkg([(disp.src,None) for disp in self.displays], [ann for ann in self.annotations]) pkg.write(fn) def read_in(self,fn): pkg = AnnPkg.load(fn) for (name,start,end) in pkg.annotations: self.annotations.add_annotation(name,start,end) for (src,anns) in pkg.sources: if src is not None: self.add_source(src) def export(self,fn,cb=None,end_cb=None): pkg = AnnPkg([(disp.src,None) for disp in self.displays], [ann for ann in self.annotations]) pkg.export(fn,cb,end_cb) def importer(self,fn): pkg = import_file(fn) for (name,start,end) in pkg.annotations: self.annotations.add_annotation(name,start,end) for (src,anns) in pkg.sources: if src is not None: self.add_source(src) def read_annotations(self,fn): try: self.annotations.read(fn) except Exception as e: warning = gtk.MessageDialog(type=gtk.MESSAGE_ERROR, buttons=gtk.BUTTONS_OK, message_format=str(e)) warning.run() warning.destroy()