def __init__(self, bash_cmd_event): self.bash_cmd_event = bash_cmd_event # BashCommandEvent instance self.cmd_str = ' '.join(bash_cmd_event.cmd) self.annotator = AnnotationComponent(WINDOW_WIDTH-50, bash_cmd_event) command_context_menu = gtk.Menu() cc_item1 = gtk.MenuItem('Copy command') cc_item1.connect("activate", self.copy_cmd) cc_item2 = gtk.MenuItem('Copy event hashtag') cc_item2.connect("activate", self.copy_event_hashtag) add_comment_item = gtk.MenuItem('Annotate invocation') add_comment_item.connect("activate", self.annotator.show_comment_box) command_context_menu.append(cc_item1) command_context_menu.append(cc_item2) command_context_menu.append(add_comment_item) cmd_label = gtk.Label(self.cmd_str) cmd_label.modify_font(pango.FontDescription("monospace 8")) cmd_label_box = create_clickable_event_box(cmd_label, command_context_menu) cmd_label_box.set_has_tooltip(True) cmd_label_box.connect('query-tooltip', show_tooltip, self.cmd_str) cmd_lalign = create_alignment(cmd_label_box, ptop=2, pbottom=2, pleft=2) cmd_vbox = create_vbox((cmd_lalign, self.annotator.get_widget())) show_all_local_widgets(locals()) self.widget = cmd_vbox
class WebpageDisplay: def __init__(self, webpage_event): self.webpage_event = webpage_event # WebpageVisitEvent instance self.annotator = AnnotationComponent(WINDOW_WIDTH-50, webpage_event) webpage_context_menu = gtk.Menu() hashtag_item = gtk.MenuItem('Copy event hashtag') hashtag_item.connect("activate", self.copy_event_hashtag) add_comment_item = gtk.MenuItem('Annotate web visit') add_comment_item.connect("activate", self.annotator.show_comment_box) webpage_context_menu.append(hashtag_item) webpage_context_menu.append(add_comment_item) # make the domain name concise: domain_name = urlparse(webpage_event.url).netloc if domain_name.startswith('www.'): domain_name = domain_name[len('www.'):] domain_display = gtk.Label() domain_display.set_markup('<span font_family="sans" size="8000" foreground="#666666">[%s] </span>' % domain_name) domain_display_box = create_clickable_event_box(domain_display, webpage_context_menu) domain_display_box.set_has_tooltip(True) domain_display_box.connect('query-tooltip', show_tooltip, webpage_event.url) link_display = gtk.Label() encoded_url = webpage_event.url.replace('&', '&') encoded_title = webpage_event.title.replace('&', '&') link_display.set_markup('<span font_family="sans" size="8000"><a href="%s">%s</a></span>' % (encoded_url, encoded_title)) domain_and_link_display = create_hbox((domain_display_box, link_display)) webpage_display_lalign = create_alignment(domain_and_link_display, ptop=2, pbottom=1, pleft=1) disp_vbox = create_vbox((webpage_display_lalign, self.annotator.get_widget())) show_all_local_widgets(locals()) self.widget = disp_vbox def copy_event_hashtag(self, _ignore): g_clipboard.set_text(self.webpage_event.get_hashtag()) def get_widget(self): return self.widget
def render_table_row(self, tbl, row_index): XPADDING=8 YPADDING=15 # using "yoptions=gtk.SHRINK" in table.attach seems to do the trick # in not having the table cells expand vertically like nuts # Print source file diffs sd = self.start_timestamp.strftime('%Y-%m-%d') ed = self.end_timestamp.strftime('%Y-%m-%d') st = self.start_timestamp.strftime('%H:%M:%S') et = self.end_timestamp.strftime('%H:%M:%S') # If the days are the same, then don't duplicate: if sd == ed: date_str = '%s to %s (%s)' % (st, et, sd) else: date_str = '%s %s to %s %s' % (sd, st, ed, et) date_lab = gtk.Label(date_str) date_lab.modify_font(pango.FontDescription("sans 8")) date_lab_lalign = create_alignment(date_lab, pbottom=3) diff_result_str = self.diff() # TODO: adjust height based on existing height of row/column text_widget = create_simple_text_view_widget(diff_result_str, 450, 200) source_file_vbox = create_vbox([date_lab_lalign, text_widget]) tbl.attach(source_file_vbox, 0, 1, row_index, row_index+1, xpadding=XPADDING + 5, ypadding=YPADDING, yoptions=gtk.SHRINK) # Print co-reads: # 1.) webpages visited # 2.) other vim files read # 3.) other non-vim files read co_read_widgets = [] # TODO: make these labels clickable with pop-up context menus for (fn, timestamp) in self.other_vim_files_read.items() + \ self.non_vim_files_read.items(): lab = gtk.Label(prettify_filename(fn)) lab.modify_font(pango.FontDescription("monospace 9")) lab.set_selectable(True) lab.show() lab_lalign = create_alignment(lab, pbottom=3) lab_lalign.show() co_read_widgets.append(lab_lalign) # de-dup: urls_seen = set() if self.webpages_visited: n = WebpageFeedEvent() for w in self.webpages_visited: if w.url not in urls_seen: urls_seen.add(w.url) n.add_webpage_chron_order(w) n_lalign = create_alignment(n.get_widget(), ptop=3) co_read_widgets.append(n_lalign) co_reads_vbox = create_vbox(co_read_widgets) co_reads_vbox_lalign = create_alignment(co_reads_vbox) tbl.attach(co_reads_vbox_lalign, 1, 2, row_index, row_index+1, xpadding=XPADDING, ypadding=YPADDING, xoptions=gtk.SHRINK, yoptions=gtk.SHRINK) # Print co-writes # 1.) other vim files edited # 2.) doodle events # 3.) happy face events # 4.) sad face events # 5.) status update events co_write_widgets = [] for (fn, timestamp) in self.other_vim_files_edited.iteritems(): lab = gtk.Label(prettify_filename(fn)) lab.modify_font(pango.FontDescription("monospace 9")) lab.set_selectable(True) lab.show() lab_lalign = create_alignment(lab) lab_lalign.show() co_write_widgets.append(lab_lalign) all_feed_evts = [] for e in self.doodle_save_events: d = DoodleFeedEvent(e, self.fvm) d.load_thumbnail() # subtle but dumb!!! all_feed_evts.append(d) for e in self.happy_face_events: all_feed_evts.append(HappyFaceFeedEvent(e)) for e in self.sad_face_events: all_feed_evts.append(SadFaceFeedEvent(e)) for e in self.status_update_events: all_feed_evts.append(StatusUpdateFeedEvent(e)) for e in all_feed_evts: co_write_widgets.append(e.get_widget()) co_writes_vbox = create_vbox(co_write_widgets, [4 for e in co_write_widgets]) co_writes_vbox_lalign = create_alignment(co_writes_vbox) tbl.attach(co_writes_vbox_lalign, 2, 3, row_index, row_index+1, xpadding=XPADDING, ypadding=YPADDING, xoptions=gtk.SHRINK, yoptions=gtk.SHRINK) # Print notes (annotations) # stick the annotation on the FINAL FileWriteEvent in this faux version: annotator = AnnotationComponent(300, self.get_last_write_event(), '<Click to enter a new note>') tbl.attach(annotator.get_widget(), 3, 4, row_index, row_index+1, xpadding=XPADDING, ypadding=YPADDING, yoptions=gtk.SHRINK) show_all_local_widgets(locals())
def render_table_row(self, prev_cmd_invocation, tbl, row_index): XPADDING = 8 YPADDING = 15 # using "yoptions=gtk.SHRINK" in table.attach seems to do the trick # in not having the table cells expand vertically like nuts # Print inputs: widgets = [] for re in self.read_event_lst: lab = gtk.Label(prettify_filename(re.filename)) lab.modify_font(pango.FontDescription("monospace 9")) lab.show() menu = gtk.Menu() view_item = gtk.MenuItem('Open') view_item.connect("activate", self.view_file_version, re) view_item.show() mark_diff_item = gtk.MenuItem('Select for diff') mark_diff_item.connect("activate", self.mark_for_diff, re) mark_diff_item.show() prov_item = gtk.MenuItem('View source file provenance') prov_item.connect("activate", self.view_source_prov, re) prov_item.show() menu.append(view_item) menu.append(mark_diff_item) menu.append(prov_item) global diff_menu_items diff_menu_items.append(mark_diff_item) lab_box = create_clickable_event_box(lab, menu) lab_box.show() lab_align = create_alignment(lab_box, pbottom=5) lab_align.show() widgets.append(lab_align) if prev_cmd_invocation: diff_result_str = self.diff_input_files(prev_cmd_invocation) # TODO: adjust height based on existing height of row/column text_widget = create_simple_text_view_widget( diff_result_str, 400, 200) #text_widget = create_simple_text_view_widget(diff_result_str, 500, 300) widgets.append(text_widget) input_vbox = create_vbox(widgets) tbl.attach(input_vbox, 0, 1, row_index, row_index + 1, xpadding=XPADDING + 5, ypadding=YPADDING, yoptions=gtk.SHRINK) # Print command: # cool that we get to re-use BashFeedEvent objects n = burrito_feed.BashFeedEvent(self.cmd_event.pwd) n.add_command_chron_order(self.cmd_event) # make it not expand like crazy in either the horizontal or vertical directions tbl.attach(n.get_widget(), 1, 2, row_index, row_index + 1, xpadding=XPADDING, ypadding=YPADDING, xoptions=gtk.SHRINK, yoptions=gtk.SHRINK) # Print output: mime_type_guess = mimetypes.guess_type(self.get_output_filename())[0] cur_output_filepath = self.fvm.checkout_file_before_next_write( self.output_event, self.sorted_write_events_lst) if 'image/' in mime_type_guess: output_image = gtk.Image() output_image.set_from_file(cur_output_filepath) tbl.attach(output_image, 2, 3, row_index, row_index + 1, xpadding=XPADDING, ypadding=YPADDING, yoptions=gtk.SHRINK) elif 'text/' in mime_type_guess: if prev_cmd_invocation: str_to_display = self.diff_output_file(cur_output_filepath, prev_cmd_invocation) else: # display entire file contents: str_to_display = open(cur_output_filepath, 'U').read() text_widget = create_simple_text_view_widget( str_to_display, 500, 350) tbl.attach(text_widget, 2, 3, row_index, row_index + 1, xpadding=XPADDING, ypadding=YPADDING, yoptions=gtk.SHRINK) # Print annotations associated with self.output_event: annotator = AnnotationComponent(300, self.output_event, '<Click to enter a new note>') tbl.attach(annotator.get_widget(), 3, 4, row_index, row_index + 1, xpadding=XPADDING, ypadding=YPADDING, yoptions=gtk.SHRINK) show_all_local_widgets(locals())
def __init__(self, file_provenance_event, parent): self.file_provenance_event = file_provenance_event self.parent = parent # sub-class of FileFeedEvent self.fvm = parent.fvm # instance of FileVersionManager self.annotator = AnnotationComponent(WINDOW_WIDTH-50, file_provenance_event) file_context_menu = gtk.Menu() diff_cur_item = gtk.MenuItem('Diff against latest') diff_cur_item.connect("activate", self.diff_with_latest) diff_pred_item = gtk.MenuItem('Diff against predecessor') diff_pred_item.connect("activate", self.diff_with_predecessor) mark_diff = gtk.MenuItem('Select for diff') mark_diff.connect("activate", self.mark_for_diff) global diff_menu_items diff_menu_items.append(mark_diff) view = gtk.MenuItem('Open') view.connect("activate", self.open_to_view, 'current') view_pred = gtk.MenuItem('Open predecessor') view_pred.connect("activate", self.open_to_view, 'predecessor') revert_current = gtk.MenuItem('Revert to current') revert_current.connect("activate", self.revert, 'current') revert_pred = gtk.MenuItem('Revert to predecessor') revert_pred.connect("activate", self.revert, 'predecessor') watch_me = gtk.MenuItem('Watch for changes') watch_me.connect("activate", self.watch_for_changes) view_source_prov = gtk.MenuItem('View source file provenance') view_source_prov.connect("activate", self.view_source_prov) view_output_prov = gtk.MenuItem('View output file provenance') view_output_prov.connect("activate", self.view_output_prov) # not implemented yet item5 = gtk.MenuItem('Ignore file') item6 = gtk.MenuItem('Ignore directory') copy_filename_item = gtk.MenuItem('Copy filename') copy_filename_item.connect("activate", self.copy_filename) hashtag_item = gtk.MenuItem('Copy event hashtag') hashtag_item.connect("activate", self.copy_event_hashtag) add_comment_item = gtk.MenuItem('Annotate file version') add_comment_item.connect("activate", self.annotator.show_comment_box) separator1 = gtk.SeparatorMenuItem() separator2 = gtk.SeparatorMenuItem() separator3 = gtk.SeparatorMenuItem() separator4 = gtk.SeparatorMenuItem() file_context_menu.append(copy_filename_item) file_context_menu.append(hashtag_item) file_context_menu.append(add_comment_item) file_context_menu.append(separator1) file_context_menu.append(diff_cur_item) file_context_menu.append(diff_pred_item) file_context_menu.append(mark_diff) file_context_menu.append(separator2) file_context_menu.append(view) file_context_menu.append(view_pred) file_context_menu.append(watch_me) file_context_menu.append(separator3) file_context_menu.append(revert_current) file_context_menu.append(revert_pred) file_context_menu.append(separator4) file_context_menu.append(view_source_prov) file_context_menu.append(view_output_prov) #file_context_menu.append(item5) #file_context_menu.append(item6) # only show base path in label for brevity file_label = gtk.Label(os.path.basename(self.file_provenance_event.filename)) file_label.modify_font(pango.FontDescription("monospace 8")) file_label_box = create_clickable_event_box(file_label, file_context_menu) # ... but show FULL file path in tooltip file_label_box.set_has_tooltip(True) file_label_box.connect('query-tooltip', show_tooltip, prettify_filename(self.file_provenance_event.filename)) icon_and_label_box = gtk.HBox() icon_and_label_box.pack_end(file_label_box, expand=False) file_lalign = create_alignment(icon_and_label_box, ptop=2, pbottom=2, pleft=2) file_vbox = create_vbox((file_lalign, self.annotator.get_widget())) show_all_local_widgets(locals()) self.widget = file_vbox self.icon_and_label_box = icon_and_label_box self.watchme_icon_alignment = None # lazily allocate to save memory global watch_files try: old_version_path = watch_files[self.file_provenance_event.filename].checkout_and_get_path() if os.path.exists(old_version_path): if not filecmp.cmp(old_version_path, self.file_provenance_event.filename): # there's a diff! changed_icon = gtk.Image() changed_icon.set_from_file('red-exclamation-point-16x16.png') changed_icon.show() changed_icon_alignment = create_alignment(changed_icon, pright=3) changed_icon_alignment.show() self.icon_and_label_box.pack_end(changed_icon_alignment) file_label.modify_fg(gtk.STATE_NORMAL, gtk.gdk.Color('#800517')) # make it red! else: # 'passed' the informal regression test set by watchfile test_pass_icon = gtk.Image() test_pass_icon.set_from_file('tasque-check-box.png') test_pass_icon.show() test_pass_icon_alignment = create_alignment(test_pass_icon, pright=3) test_pass_icon_alignment.show() self.icon_and_label_box.pack_end(test_pass_icon_alignment) except KeyError: pass
class FileEventDisplay: def __init__(self, file_provenance_event, parent): self.file_provenance_event = file_provenance_event self.parent = parent # sub-class of FileFeedEvent self.fvm = parent.fvm # instance of FileVersionManager self.annotator = AnnotationComponent(WINDOW_WIDTH-50, file_provenance_event) file_context_menu = gtk.Menu() diff_cur_item = gtk.MenuItem('Diff against latest') diff_cur_item.connect("activate", self.diff_with_latest) diff_pred_item = gtk.MenuItem('Diff against predecessor') diff_pred_item.connect("activate", self.diff_with_predecessor) mark_diff = gtk.MenuItem('Select for diff') mark_diff.connect("activate", self.mark_for_diff) global diff_menu_items diff_menu_items.append(mark_diff) view = gtk.MenuItem('Open') view.connect("activate", self.open_to_view, 'current') view_pred = gtk.MenuItem('Open predecessor') view_pred.connect("activate", self.open_to_view, 'predecessor') revert_current = gtk.MenuItem('Revert to current') revert_current.connect("activate", self.revert, 'current') revert_pred = gtk.MenuItem('Revert to predecessor') revert_pred.connect("activate", self.revert, 'predecessor') watch_me = gtk.MenuItem('Watch for changes') watch_me.connect("activate", self.watch_for_changes) view_source_prov = gtk.MenuItem('View source file provenance') view_source_prov.connect("activate", self.view_source_prov) view_output_prov = gtk.MenuItem('View output file provenance') view_output_prov.connect("activate", self.view_output_prov) # not implemented yet item5 = gtk.MenuItem('Ignore file') item6 = gtk.MenuItem('Ignore directory') copy_filename_item = gtk.MenuItem('Copy filename') copy_filename_item.connect("activate", self.copy_filename) hashtag_item = gtk.MenuItem('Copy event hashtag') hashtag_item.connect("activate", self.copy_event_hashtag) add_comment_item = gtk.MenuItem('Annotate file version') add_comment_item.connect("activate", self.annotator.show_comment_box) separator1 = gtk.SeparatorMenuItem() separator2 = gtk.SeparatorMenuItem() separator3 = gtk.SeparatorMenuItem() separator4 = gtk.SeparatorMenuItem() file_context_menu.append(copy_filename_item) file_context_menu.append(hashtag_item) file_context_menu.append(add_comment_item) file_context_menu.append(separator1) file_context_menu.append(diff_cur_item) file_context_menu.append(diff_pred_item) file_context_menu.append(mark_diff) file_context_menu.append(separator2) file_context_menu.append(view) file_context_menu.append(view_pred) file_context_menu.append(watch_me) file_context_menu.append(separator3) file_context_menu.append(revert_current) file_context_menu.append(revert_pred) file_context_menu.append(separator4) file_context_menu.append(view_source_prov) file_context_menu.append(view_output_prov) #file_context_menu.append(item5) #file_context_menu.append(item6) # only show base path in label for brevity file_label = gtk.Label(os.path.basename(self.file_provenance_event.filename)) file_label.modify_font(pango.FontDescription("monospace 8")) file_label_box = create_clickable_event_box(file_label, file_context_menu) # ... but show FULL file path in tooltip file_label_box.set_has_tooltip(True) file_label_box.connect('query-tooltip', show_tooltip, prettify_filename(self.file_provenance_event.filename)) icon_and_label_box = gtk.HBox() icon_and_label_box.pack_end(file_label_box, expand=False) file_lalign = create_alignment(icon_and_label_box, ptop=2, pbottom=2, pleft=2) file_vbox = create_vbox((file_lalign, self.annotator.get_widget())) show_all_local_widgets(locals()) self.widget = file_vbox self.icon_and_label_box = icon_and_label_box self.watchme_icon_alignment = None # lazily allocate to save memory global watch_files try: old_version_path = watch_files[self.file_provenance_event.filename].checkout_and_get_path() if os.path.exists(old_version_path): if not filecmp.cmp(old_version_path, self.file_provenance_event.filename): # there's a diff! changed_icon = gtk.Image() changed_icon.set_from_file('red-exclamation-point-16x16.png') changed_icon.show() changed_icon_alignment = create_alignment(changed_icon, pright=3) changed_icon_alignment.show() self.icon_and_label_box.pack_end(changed_icon_alignment) file_label.modify_fg(gtk.STATE_NORMAL, gtk.gdk.Color('#800517')) # make it red! else: # 'passed' the informal regression test set by watchfile test_pass_icon = gtk.Image() test_pass_icon.set_from_file('tasque-check-box.png') test_pass_icon.show() test_pass_icon_alignment = create_alignment(test_pass_icon, pright=3) test_pass_icon_alignment.show() self.icon_and_label_box.pack_end(test_pass_icon_alignment) except KeyError: pass def get_widget(self): return self.widget def get_filename(self): return self.file_provenance_event.filename def copy_filename(self, _ignore): g_clipboard.set_text(self.file_provenance_event.filename) def copy_event_hashtag(self, _ignore): g_clipboard.set_text(self.file_provenance_event.get_hashtag()) def checkout_and_get_path(self): return self.fvm.checkout_file_before_next_write(self.file_provenance_event, sorted_write_events[self.file_provenance_event.filename]) # to find the predecessor, simply check out the file one second # before the write occurred ... # # TODO: this isn't exactly correct, since you could've had a bunch # of coalesced writes, so you might want to get the version BEFORE # the series of coalesced writes. def checkout_predecessor_and_get_path(self): return self.fvm.checkout_file(self.get_filename(), self.file_provenance_event.timestamp - ONE_SEC) def diff_with_latest(self, _ignore): # requires the 'meld' visual diff tool to be installed old_version_path = self.checkout_and_get_path() fn = self.file_provenance_event.filename os.system('meld "%s" "%s" &' % (old_version_path, fn)) def diff_with_predecessor(self, _ignore): post_write_path = self.checkout_and_get_path() predecessor_path = self.checkout_predecessor_and_get_path() os.system('meld "%s" "%s" &' % (predecessor_path, post_write_path)) def mark_for_diff(self, _ignore): global diff_left_half, diff_menu_items # KLUDGY! if diff_left_half: diff_right_half_path = self.checkout_and_get_path() diff_left_half_path = diff_left_half.checkout_and_get_path() os.system('meld "%s" "%s" &' % (diff_left_half_path, diff_right_half_path)) # RESET! diff_left_half = None for e in diff_menu_items: e.set_label('Select for diff') else: diff_left_half = self for e in diff_menu_items: e.set_label('Diff against selected file') def open_to_view(self, _ignore, option): if option == 'current': old_version_path = self.checkout_and_get_path() elif option == 'predecessor': old_version_path = self.checkout_predecessor_and_get_path() else: assert False # gnome-open to the rescue!!! uses a file's type to determine the # proper viewer application :) if not os.path.isfile(old_version_path): create_popup_error_dialog("File not found:\n" + old_version_path) else: os.system('gnome-open "%s" &' % old_version_path) def view_source_prov(self, _ignore): global cur_session spv = source_file_prov_viewer.SourceFileProvViewer(self.get_filename(), cur_session, self.fvm) def view_output_prov(self, _ignore): global cur_session # KLUDGY! print 'view_output_prov:', self.get_filename(), cur_session opv = output_file_prov_viewer.OutputFileProvViewer(self.get_filename(), cur_session, self.fvm) def watch_for_changes(self, _ignore): global watch_files fn = self.file_provenance_event.filename if fn in watch_files: # un-watch the other file: other = watch_files[fn] assert other.watchme_icon_alignment other.icon_and_label_box.remove(other.watchme_icon_alignment) # if other is actually self, then un-watch! if other == self: del watch_files[fn] return # PUNTTT! watch_files[fn] = self # "freeze" the enclosing FileMutatedFeedEvent object when you # create a watchpoint so that subsequent writes don't coalesce into # this FileMutatedFeedEvent entry and possibly destroy the current # FileEventDisplay object in the # process! self.parent.frozen = True watchme_icon = gtk.Image() watchme_icon.set_from_file('magnifying-glass-16x16.png') watchme_icon.show() self.watchme_icon_alignment = create_alignment(watchme_icon, pright=3) self.watchme_icon_alignment.show() self.icon_and_label_box.pack_end(self.watchme_icon_alignment) # option = 'current' or 'predecessor' def revert(self, _ignore, option): if option == 'current': old_version_path = self.checkout_and_get_path() elif option == 'predecessor': old_version_path = self.checkout_predecessor_and_get_path() else: assert False if not os.path.isfile(old_version_path): create_popup_error_dialog("File not found:\n" + old_version_path) else: # pop-up a confirmation dialog before taking drastic action! d = gtk.MessageDialog(None, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_QUESTION, gtk.BUTTONS_YES_NO, message_format="Are you sure you want to revert\n\n %s\n\nto\n\n %s" % \ (self.get_filename(), old_version_path)) d.show() response = d.run() d.destroy() if response == gtk.RESPONSE_YES: # VERY INTERESTING: the 'cp' command sometimes doesn't work # for NILFS, since it thinks that the snapshot version is # IDENTICAL to the latest current version of the file and will # thus refuse to do the copy even though their contents are # clearly different. # # Thus, we will do a super-hack where we copy the file to # tmp_blob and then rename it to the real filename ... tmp_blob = '/tmp/tmp-reverted-file' revert_cmd = "cp '%s' '%s'; mv '%s' '%s'" % (old_version_path, tmp_blob, tmp_blob, self.get_filename()) os.system(revert_cmd)
def render_table_row(self, tbl, row_index): XPADDING = 8 YPADDING = 15 # using "yoptions=gtk.SHRINK" in table.attach seems to do the trick # in not having the table cells expand vertically like nuts # Print source file diffs sd = self.start_timestamp.strftime('%Y-%m-%d') ed = self.end_timestamp.strftime('%Y-%m-%d') st = self.start_timestamp.strftime('%H:%M:%S') et = self.end_timestamp.strftime('%H:%M:%S') # If the days are the same, then don't duplicate: if sd == ed: date_str = '%s to %s (%s)' % (st, et, sd) else: date_str = '%s %s to %s %s' % (sd, st, ed, et) date_lab = gtk.Label(date_str) date_lab.modify_font(pango.FontDescription("sans 8")) date_lab_lalign = create_alignment(date_lab, pbottom=3) diff_result_str = self.diff() # TODO: adjust height based on existing height of row/column text_widget = create_simple_text_view_widget( diff_result_str, 450, 200) source_file_vbox = create_vbox([date_lab_lalign, text_widget]) tbl.attach(source_file_vbox, 0, 1, row_index, row_index + 1, xpadding=XPADDING + 5, ypadding=YPADDING, yoptions=gtk.SHRINK) # Print co-reads: # 1.) webpages visited # 2.) other vim files read # 3.) other non-vim files read co_read_widgets = [] # TODO: make these labels clickable with pop-up context menus for (fn, timestamp) in self.other_vim_files_read.items() + \ self.non_vim_files_read.items(): lab = gtk.Label(prettify_filename(fn)) lab.modify_font(pango.FontDescription("monospace 9")) lab.set_selectable(True) lab.show() lab_lalign = create_alignment(lab, pbottom=3) lab_lalign.show() co_read_widgets.append(lab_lalign) # de-dup: urls_seen = set() if self.webpages_visited: n = WebpageFeedEvent() for w in self.webpages_visited: if w.url not in urls_seen: urls_seen.add(w.url) n.add_webpage_chron_order(w) n_lalign = create_alignment(n.get_widget(), ptop=3) co_read_widgets.append(n_lalign) co_reads_vbox = create_vbox(co_read_widgets) co_reads_vbox_lalign = create_alignment(co_reads_vbox) tbl.attach(co_reads_vbox_lalign, 1, 2, row_index, row_index + 1, xpadding=XPADDING, ypadding=YPADDING, xoptions=gtk.SHRINK, yoptions=gtk.SHRINK) # Print co-writes # 1.) other vim files edited # 2.) doodle events # 3.) happy face events # 4.) sad face events # 5.) status update events co_write_widgets = [] for (fn, timestamp) in self.other_vim_files_edited.iteritems(): lab = gtk.Label(prettify_filename(fn)) lab.modify_font(pango.FontDescription("monospace 9")) lab.set_selectable(True) lab.show() lab_lalign = create_alignment(lab) lab_lalign.show() co_write_widgets.append(lab_lalign) all_feed_evts = [] for e in self.doodle_save_events: d = DoodleFeedEvent(e, self.fvm) d.load_thumbnail() # subtle but dumb!!! all_feed_evts.append(d) for e in self.happy_face_events: all_feed_evts.append(HappyFaceFeedEvent(e)) for e in self.sad_face_events: all_feed_evts.append(SadFaceFeedEvent(e)) for e in self.status_update_events: all_feed_evts.append(StatusUpdateFeedEvent(e)) for e in all_feed_evts: co_write_widgets.append(e.get_widget()) co_writes_vbox = create_vbox(co_write_widgets, [4 for e in co_write_widgets]) co_writes_vbox_lalign = create_alignment(co_writes_vbox) tbl.attach(co_writes_vbox_lalign, 2, 3, row_index, row_index + 1, xpadding=XPADDING, ypadding=YPADDING, xoptions=gtk.SHRINK, yoptions=gtk.SHRINK) # Print notes (annotations) # stick the annotation on the FINAL FileWriteEvent in this faux version: annotator = AnnotationComponent(300, self.get_last_write_event(), '<Click to enter a new note>') tbl.attach(annotator.get_widget(), 3, 4, row_index, row_index + 1, xpadding=XPADDING, ypadding=YPADDING, yoptions=gtk.SHRINK) show_all_local_widgets(locals())
def render_table_row(self, prev_cmd_invocation, tbl, row_index): XPADDING=8 YPADDING=15 # using "yoptions=gtk.SHRINK" in table.attach seems to do the trick # in not having the table cells expand vertically like nuts # Print inputs: widgets = [] for re in self.read_event_lst: lab = gtk.Label(prettify_filename(re.filename)) lab.modify_font(pango.FontDescription("monospace 9")) lab.show() menu = gtk.Menu() view_item = gtk.MenuItem('Open') view_item.connect("activate", self.view_file_version, re) view_item.show() mark_diff_item = gtk.MenuItem('Select for diff') mark_diff_item.connect("activate", self.mark_for_diff, re) mark_diff_item.show() prov_item = gtk.MenuItem('View source file provenance') prov_item.connect("activate", self.view_source_prov, re) prov_item.show() menu.append(view_item) menu.append(mark_diff_item) menu.append(prov_item) global diff_menu_items diff_menu_items.append(mark_diff_item) lab_box = create_clickable_event_box(lab, menu) lab_box.show() lab_align = create_alignment(lab_box, pbottom=5) lab_align.show() widgets.append(lab_align) if prev_cmd_invocation: diff_result_str = self.diff_input_files(prev_cmd_invocation) # TODO: adjust height based on existing height of row/column text_widget = create_simple_text_view_widget(diff_result_str, 400, 200) #text_widget = create_simple_text_view_widget(diff_result_str, 500, 300) widgets.append(text_widget) input_vbox = create_vbox(widgets) tbl.attach(input_vbox, 0, 1, row_index, row_index+1, xpadding=XPADDING + 5, ypadding=YPADDING, yoptions=gtk.SHRINK) # Print command: # cool that we get to re-use BashFeedEvent objects n = burrito_feed.BashFeedEvent(self.cmd_event.pwd) n.add_command_chron_order(self.cmd_event) # make it not expand like crazy in either the horizontal or vertical directions tbl.attach(n.get_widget(), 1, 2, row_index, row_index+1, xpadding=XPADDING, ypadding=YPADDING, xoptions=gtk.SHRINK, yoptions=gtk.SHRINK) # Print output: mime_type_guess = mimetypes.guess_type(self.get_output_filename())[0] cur_output_filepath = self.fvm.checkout_file_before_next_write(self.output_event, self.sorted_write_events_lst) if 'image/' in mime_type_guess: output_image = gtk.Image() output_image.set_from_file(cur_output_filepath) tbl.attach(output_image, 2, 3, row_index, row_index+1, xpadding=XPADDING, ypadding=YPADDING, yoptions=gtk.SHRINK) elif 'text/' in mime_type_guess: if prev_cmd_invocation: str_to_display = self.diff_output_file(cur_output_filepath, prev_cmd_invocation) else: # display entire file contents: str_to_display = open(cur_output_filepath, 'U').read() text_widget = create_simple_text_view_widget(str_to_display, 500, 350) tbl.attach(text_widget, 2, 3, row_index, row_index+1, xpadding=XPADDING, ypadding=YPADDING, yoptions=gtk.SHRINK) # Print annotations associated with self.output_event: annotator = AnnotationComponent(300, self.output_event, '<Click to enter a new note>') tbl.attach(annotator.get_widget(), 3, 4, row_index, row_index+1, xpadding=XPADDING, ypadding=YPADDING, yoptions=gtk.SHRINK) show_all_local_widgets(locals())