Am Fr, 25.07.2008 um 13:37 schrieb "Diego Escalante Urrelo" <diegoe gnome org>: > I tried to port it too, but just forgot about finishing it :) > > >From my half ported t-o-t-v: > self.treemodel.insert(page_num, [tab, tab.get_property("title"), > tab.get_icon()]) > tab.connect('notify::title', self.update_tab_title) thanks - that helped! I managed to port it - but with one drawback: embed (a child from the notebook and the widget you get from attach_tab()) is of type __main__.MozillaEmbed but I can't use that to create a ListStore. At the moment I create it with: gtk.ListStore(first_child_of_notebook.__class__,str,gtk.gdk.Pixbuf) but this has the problem that the first child does not exist where I first start the browser and the plugin is called via attach_window(). So I have to wait for the first call to attach_tab(). I saw in the code, that MozillaEmbed is a struct - is there any elegant way to get this into python? cu /Steffen PS: first ugly version attached - I made 2 improvements: 1) middle click to close 2) scroll to change the "tab" At the moment it is "without" a license - I'm trying to contact the author for the original license! There bug with a disappearing website when enabling or disabling the extension - just change to another tab and everything is fine! -- /"\ \ / ASCII Ribbon Campaign | "The best way to predict X * NO HTML/RTF in e-mail | the future is to invent it." / \ * NO MSWord docs in e-mail| -- Alan Kay
import gtk import pango import epiphany import gconf base_gconf_path="/apps/epiphany/general/" class TreeviewTabs: treeview_popup_xml = """ <ui> <popup name="TabsOnTreeviewPopup"> <menuitem action="TabsOnTreeviewLeft"/> <menuitem action="TabsOnTreeviewRight" /> </popup> </ui> """ actiongroupdef = [ ('TabsOnTreeviewLeft', None, 'Left Sidebar', None, 'Move sidebar to the left', False), ('TabsOnTreeviewRight', None, 'Right Sidebar', None, 'Move sidebar to the right', True) ] def __init__(self, window, gconf, always_show_tabs_bar, sidebar_on_right): self.window = window self.notebook = window.get_notebook() self.no_update = False self.no_update_left = False self.no_update_right = False self.gconf = gconf self.always_show_tabs_bar = always_show_tabs_bar self.sidebar_on_right = sidebar_on_right self.sidebar_width = self.gconf.get_int(base_gconf_path+"sidebar_width") self.fertig = False self.treemodel = gtk.ListStore(int, str, gtk.gdk.Pixbuf) def toggle_sidebar_side_cb(self, first, second): self.gconf.set_bool(base_gconf_path+"sidebar_on_right", first.get_current_value()) def on_selection_change(self, treeselection): treemodel, iter = treeselection.get_selected() if iter and not self.no_update: path = treemodel.get_path(iter) self.notebook.set_current_page(self.get_pos(path)) def move_tab(self, treemodel, path, iter): tab = self.treemodel.get_value(iter, 0) self.notebook.reorder_child(tab, self.get_pos(path)) def setup_drag(self): self.TARGETS = [ ('TVEXT_TREE_MODEL_ROW_INTERNAL', gtk.TARGET_SAME_WIDGET, 0), ('TVEXT_TREE_MODEL_ROW_EXTERNAL', 0, 1), ('text/plain', 0, 2), ('TEXT', 0, 3), ('STRING', 0, 4) ] self.treeview.enable_model_drag_source(gtk.gdk.BUTTON1_MASK, self.TARGETS, gtk.gdk.ACTION_DEFAULT | gtk.gdk.ACTION_COPY | gtk.gdk.ACTION_MOVE) self.treeview.enable_model_drag_dest(self.TARGETS, gtk.gdk.ACTION_DEFAULT | gtk.gdk.ACTION_MOVE) self.treeview.connect("drag_data_get", self.drag_data_get_data) self.treeview.connect("drag_data_received", self.drag_data_received_data) def drag_data_get_data(self, treeview, context, selection, info, etime): treeselection = treeview.get_selection() model, iter = treeselection.get_selected() if info == 0: data = model.get_string_from_iter(iter) selection.set(selection.target, 8, data) elif info == 1: data = str(model.get_value(iter, 0).get_address()) selection.set(selection.target, 8, data) self.window.get_active_tab().get_embed().close() else: data = str(model.get_value(iter, 0).get_address()) selection.set_text(data) def get_pos(self, path): return list(path)[0] def drag_data_received_data(self, treeview, context, x, y, selection, info, etime): data = selection.data drop_info = treeview.get_dest_row_at_pos(x, y) model = treeview.get_model() if info == 0: # Internal move iter = model.get_iter_from_string(data) rowdata = model.get_value(iter, 0), model.get_value(iter, 1), model.get_value(iter, 2) if drop_info: path, position = drop_info if (position == gtk.TREE_VIEW_DROP_AFTER or position == gtk.TREE_VIEW_DROP_INTO_OR_AFTER): old_pos = self.get_pos(model.get_path(iter)) if old_pos >= self.get_pos(path): path = model.get_path(model.iter_next(model.get_iter(path))) self.move_tab(model, path, iter) else: dest = model.iter_nth_child(None, model.iter_n_children(None)-1) self.move_tab(model, model.get_path(dest), iter) else: if drop_info: path, position = drop_info iter = model.get_iter(path) source_tab = model.get_value(iter, 0) new_tab = self.window.open(data, source_tab, 2) tabrow = self.find_tab_row(new_tab) if (position == gtk.TREE_VIEW_DROP_AFTER or position == gtk.TREE_VIEW_DROP_INTO_OR_AFTER): iter = model.iter_next(iter) path = model.get_path(iter) self.move_tab(model, path, tabrow) self.notebook.set_current_page( self.get_pos(path)) else: iter = model.iter_nth_child(None, model.iter_n_children(None)-1) source_tab = model.get_value(iter, 0) self.window.open(data, source_tab, 2) path = model.get_path(iter) self.notebook.set_current_page(self.get_pos(path)+1) if info == 1: context.finish(True, True, etime) def treeview_click_cb(self, treeview, event): if event.button == 3: pos_info = treeview.get_dest_row_at_pos(int(event.x), int(event.y)) if pos_info: path, position = pos_info self.notebook.set_current_page(self.get_pos(path)) self.show_tab_popup(event.get_time()) return True else: self.show_sidebar_popup(event.get_time()) def treeview_middleclick_cb(self, treeview, event): if event.button == 2: pos_info = treeview.get_dest_row_at_pos(int(event.x), int(event.y)) if pos_info: path, position = pos_info e = self.notebook.get_nth_page(self.get_pos(path)) e.close() return True def treeview_scroll_cb(self, treeview, event): if event.direction == gtk.gdk.SCROLL_UP: self.notebook.prev_page() if event.direction == gtk.gdk.SCROLL_DOWN: self.notebook.next_page() return True def build_custom(self,class_of_embed): self.custom_part = gtk.HPaned() self.custom_part.pack2(gtk.HPaned(), True) self.treemodel = gtk.ListStore(class_of_embed, str, gtk.gdk.Pixbuf) self.treeview = gtk.TreeView(self.treemodel) self.treeview.set_headers_visible(False) self.treeview.get_selection().set_mode(gtk.SELECTION_BROWSE) self.setup_drag() # self.treeview.set_reorderable(True) title_cell = gtk.CellRendererText() title_cell.set_property("ellipsize", pango.ELLIPSIZE_END) icon_cell = gtk.CellRendererPixbuf() self.column = gtk.TreeViewColumn('Tab icon') self.column.pack_start(icon_cell, False) self.column.set_attributes(icon_cell, pixbuf=2) self.column.pack_start(title_cell) self.column.set_attributes(title_cell, text=1) self.treeview.append_column(self.column) self.treeview.connect('button-press-event', self.treeview_click_cb) self.treeview.connect('button-release-event', self.treeview_middleclick_cb) self.treeview.connect('scroll-event', self.treeview_scroll_cb) self.treeview.get_selection().connect('changed', self.on_selection_change) self.treemodel.connect('row-changed', self.move_tab) scrolled = gtk.ScrolledWindow() scrolled.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC) scrolled.set_shadow_type(gtk.SHADOW_IN) scrolled.add(self.treeview) label = gtk.Label("Opened Pages") label.set_justify(gtk.JUSTIFY_LEFT) label.set_ellipsize(pango.ELLIPSIZE_END) label.set_alignment(0.0, 0.5) label.set_padding(3, 0) close_button = gtk.Button() close_button.set_relief(gtk.RELIEF_NONE) close_image = gtk.image_new_from_stock(gtk.STOCK_CLOSE, gtk.ICON_SIZE_MENU) close_button.set_image(close_image) close_button.connect("clicked", self.close_clicked) title_hbox = gtk.HBox() title_hbox.pack_start(label, True) title_hbox.pack_end(close_button, False) self.vbox = gtk.VBox() self.vbox.pack_start(title_hbox, False) self.vbox.pack_start(scrolled, True) self.spacer = gtk.Alignment(xscale=1.0, yscale=1.0) self.spacer.add(self.vbox) self.spacer_update() self.secondary_pack(self.spacer) self.main_pack(self.notebook) self.custom_part.show() self.custom_part.get_child2().show() self.custom_part.connect("notify::position", self.sidebar_width_changed1_cb) self.custom_part.get_child2().connect("notify::position", self.sidebar_width_changed2_cb) # Best way I found to be informed when the window has finalized its size self.rs_hack = self.custom_part.get_child2().connect("notify::max-position", self.right_sidebar_hack_cb) def right_sidebar_hack_cb(self, paned, position): self.sidebar_width_update() self.custom_part.get_child2().disconnect(self.rs_hack) def window_focus_cb(self, window, value): # The saved width is the width of the last focused window if window.is_active(): self.sidebar_width_save() def sidebar_width_changed1_cb(self, paned, position): if not self.no_update: self.sidebar_width = paned.get_position() self.sidebar_width_save() def sidebar_width_changed2_cb(self, paned, position): if not self.no_update: paned = self.custom_part.get_child2() self.sidebar_width = paned.get_allocation().width-paned.get_position()-6 self.sidebar_width_save() def sidebar_width_save(self): self.gconf.set_int(base_gconf_path+"sidebar_width", self.sidebar_width) def sidebar_width_update(self): self.no_update = True if self.sidebar_on_right: paned = self.custom_part.get_child2() paned.set_position(self.window.get_allocation().width-self.sidebar_width-6) else: self.custom_part.set_position(self.sidebar_width) self.no_update = False def spacer_update(self): if self.sidebar_on_right: self.spacer.set_padding(0, 4, 0, 4) else: self.spacer.set_padding(0, 4, 4, 0) def separator_update(self): hbchilds = self.custom_part.get_child2().get_child1().get_children() if self.sidebar_on_right: hbchilds[0].hide() hbchilds[2].show() else: hbchilds[0].show() hbchilds[2].hide() def main_pack(self, widget): hbox = gtk.HBox() sep1 = gtk.VSeparator() sep2 = gtk.VSeparator() hbox.pack_start(sep1, False) hbox.pack_start(widget, True) hbox.pack_start(sep2, False) self.custom_part.get_child2().pack1(hbox, True, True) hbox.show_all() self.separator_update() def secondary_pack(self, widget): if self.sidebar_on_right: self.custom_part.get_child2().pack2(widget, False, False) else: self.custom_part.pack1(widget, False, False) widget.show_all() def secondary_unpack(self): widget = self.get_secondary() widget.get_parent().remove(widget) return widget def get_main(self): return self.custom_part.get_child2().get_child1().get_children()[1] def get_secondary(self): if self.sidebar_on_right: return self.custom_part.get_child2().get_child2() else: return self.custom_part.get_child1() def get_separator(self): if self.sidebar_on_right: return self.custom_part.get_child2().get_child1().get_children()[2] else: return self.custom_part.get_child2().get_child1().get_children()[0] def show_tab_popup(self,etime): popupmenu = self.uimanager.get_widget("/EphyNotebookPopup") popupmenu.popup(None, None, None, 2, etime) def show_sidebar_popup(self, etime): popupmenu = self.uimanager.get_widget("/TabsOnTreeviewPopup") popupmenu.popup(None, None, None, 2, etime) def close_clicked(self, button): self.window.get_active_tab().get_embed().close() def show_sidebar(self): self.get_secondary().show() self.get_separator().show() self.force_hidden_tabs(self.notebook, True) def hide_sidebar(self): self.get_secondary().hide() self.get_separator().hide() def update_tab_order(self, notebook, child, page_num): tabrow = self.find_tab_row(child) if tabrow: dest = self.treemodel.iter_nth_child(None, page_num) old_num = self.get_pos(self.treemodel.get_path(tabrow)) if old_num > page_num: self.treemodel.move_before(tabrow, dest) else: self.treemodel.move_after(tabrow, dest) # Workaround for bug: #169116 # def workaround_embed(self): # if self.window.get_active_tab(): # self.window.get_active_tab().get_embed().hide() # self.window.get_active_tab().get_embed().show() def attach_window(self): pass def attach_window2(self): winvbox = self.window.get_children()[0] page = self.notebook.get_nth_page(0) self.notebook.get_parent().remove(self.notebook) self.build_custom(page.__class__) winvbox.pack_start(self.custom_part, True) winvbox.reorder_child(self.custom_part, 1) self.notebook.connect('switch_page', self.update_current_tab) self.notebook.connect('page_reordered', self.update_tab_order) self.fhidden_cb_handle = self.notebook.connect('notify::show-tabs', self.force_hidden_tabs) #self.workaround_embed() self.uimanager = self.window.get_ui_manager() self.ui_id = self.uimanager.add_ui_from_string(self.treeview_popup_xml) self.actiongroup = gtk.ActionGroup('TabsOnTreeview') self.actiongroup.add_radio_actions(self.actiongroupdef, self.sidebar_on_right, self.toggle_sidebar_side_cb) self.uimanager.insert_action_group(self.actiongroup, 0) self.sidebar_width_update() self.window.connect("notify::is-active", self.window_focus_cb) def force_hidden_tabs(self, notebook, visible): if visible: notebook.set_show_tabs(False) def detach_window(self): winvbox = self.window.get_children()[0] self.notebook.get_parent().remove(self.notebook) self.custom_part.get_parent().remove(self.custom_part) winvbox.pack_start(self.notebook, True) winvbox.reorder_child(self.notebook, 1) self.notebook.disconnect(self.fhidden_cb_handle) self.notebook.set_show_tabs(True) self.notebook.show() # self.workaround_embed() self.uimanager.remove_ui(self.ui_id) self.uimanager.remove_action_group(self.actiongroup) self.uimanager.ensure_update() def update_current_tab(self, notebook, page, page_num): self.no_update = True self.treeview.set_cursor(int(page_num)) self.no_update = False def find_tab_row(self, embed): iter = self.treemodel.get_iter_first() while iter: if self.treemodel.get_value(iter, 0) == embed: return iter iter = self.treemodel.iter_next(iter) return None def update_tab_title(self, embed,data): tabrow = self.find_tab_row(embed) if tabrow: self.treemodel.set_value(tabrow, 1, embed.get_property("title")) def update_tab_favicon(self, embed, pspec): tabrow = self.find_tab_row(embed) if tabrow: self.treemodel.set_value(tabrow, 2, embed.get_icon()) def attach_tab(self, embed): if not self.fertig: self.fertig=True self.attach_window2() page_num = self.notebook.page_num(embed) self.treemodel.insert(page_num, [embed, embed.get_property("title"), embed.get_icon()]) embed.connect('notify::title', self.update_tab_title) embed.connect('notify::icon', self.update_tab_favicon) if self.notebook.get_n_pages() == 1 and not self.always_show_tabs_bar: self.hide_sidebar() else: self.show_sidebar() def detach_tab(self, embed): if self.find_tab_row(embed): self.treemodel.remove(self.find_tab_row(embed)) if self.notebook.get_n_pages() < 2 and not self.always_show_tabs_bar: self.hide_sidebar() def set_always_show_tabs_bar(self, active): self.always_show_tabs_bar = active if not active and self.notebook.get_n_pages() < 2 : self.hide_sidebar() else: self.show_sidebar() def set_sidebar_on_right(self, value): secondary = self.secondary_unpack() self.sidebar_on_right = value self.secondary_pack(secondary) self.spacer_update() self.separator_update() self.sidebar_width_update() toggle = self.uimanager.get_widget("/TabsOnTreeviewPopup/TabsOnTreeviewRight") toggle.set_active(self.sidebar_on_right) class TreeviewTabsDispatch: def __init__(self): self.winlist = {} self.gconf = gconf.client_get_default() self.always_show_tabs_bar = self.gconf.get_bool("/apps/epiphany/general/always_show_tabs_bar") self.sidebar_on_right = self.gconf.get_bool(base_gconf_path+"sidebar_on_right") self.gconf.notify_add("/apps/epiphany/general/always_show_tabs_bar", self.always_show_tabs_bar_cb) self.gconf.notify_add(base_gconf_path+"sidebar_on_right", self.sidebar_on_right_cb) def always_show_tabs_bar_cb(self, client, a_number, entry, a_list): active = entry.value.get_bool() for window in self.winlist: self.winlist[window].set_always_show_tabs_bar(active) self.always_show_tabs_bar = active def sidebar_on_right_cb(self, client, a_number, entry, a_list): active = entry.value.get_bool() for window in self.winlist: self.winlist[window].set_sidebar_on_right(active) self.sidebar_on_right = active def attach_window(self, window): self.winlist[window] = TreeviewTabs(window, self.gconf, self.always_show_tabs_bar, self.sidebar_on_right) self.winlist[window].attach_window() def attach_tab(self, window, embed): self.winlist[window].attach_tab(embed) def detach_tab(self, window, embed): self.winlist[window].detach_tab(embed) def detach_window(self, window): self.winlist[window].detach_window() del self.winlist[window] treeview_extension = TreeviewTabsDispatch() attach_window = treeview_extension.attach_window detach_window = treeview_extension.detach_window attach_tab = treeview_extension.attach_tab detach_tab = treeview_extension.detach_tab
Attachment:
tabs_on_treeview.ephy-extension
Description: Binary data
Attachment:
signature.asc
Description: PGP signature