class ThreePaneViewer (Viewer): """A viewer with a treeview, listview, and editor""" def __init__(self, app, main_window, viewerid=None): Viewer.__init__(self, app, main_window, viewerid, viewer_name="three_pane_viewer") self._ui_ready = False # node selections self._current_page = None # current page in editor self._treeview_sel_nodes = [] # current selected nodes in treeview self._queue_list_select = [] # nodes to select in listview after treeview change self._new_page_occurred = False self.back_button = None self._view_mode = DEFAULT_VIEW_MODE self.connect("history-changed", self._on_history_changed) #========================================= # widgets # treeview self.treeview = KeepNoteTreeView() self.treeview.set_get_node(self._app.get_node) self.treeview.connect("select-nodes", self._on_tree_select) self.treeview.connect("delete-node", self.on_delete_node) self.treeview.connect("error", lambda w,t,e: self.emit("error", t, e)) self.treeview.connect("edit-title", self._on_edit_title) self.treeview.connect("goto-node", self.on_goto_node) self.treeview.connect("activate-node", self.on_activate_node) self.treeview.connect("drop-file", self._on_attach_file) # listview self.listview = KeepNoteListView() self.listview.set_get_node(self._app.get_node) self.listview.connect("select-nodes", self._on_list_select) self.listview.connect("delete-node", self.on_delete_node) self.listview.connect("goto-node", self.on_goto_node) self.listview.connect("activate-node", self.on_activate_node) self.listview.connect("goto-parent-node", lambda w: self.on_goto_parent_node()) self.listview.connect("error", lambda w,t,e: self.emit("error", t, e)) self.listview.connect("edit-title", self._on_edit_title) self.listview.connect("drop-file", self._on_attach_file) self.listview.on_status = self.set_status # TODO: clean up # editor #self.editor = KeepNoteEditor(self._app) #self.editor = RichTextEditor(self._app) self.editor = ContentEditor(self._app) rich_editor = RichTextEditor(self._app) self.editor.add_editor("text/xhtml+xml", rich_editor) self.editor.add_editor("text", TextEditor(self._app)) self.editor.set_default_editor(rich_editor) self.editor.connect("view-node", self._on_editor_view_node) self.editor.connect("child-activated", self._on_child_activated) self.editor.connect("visit-node", lambda w, n: self.goto_node(n, False)) self.editor.connect("error", lambda w,t,e: self.emit("error", t, e)) self.editor.connect("window-request", lambda w,t: self.emit("window-request", t)) self.editor.view_pages([]) self.editor_pane = gtk.VBox(False, 5) self.editor_pane.pack_start(self.editor, True, True, 0) #===================================== # layout # TODO: make sure to add underscore for these variables # create a horizontal paned widget self.hpaned = gtk.HPaned() self.pack_start(self.hpaned, True, True, 0) self.hpaned.set_position(DEFAULT_HSASH_POS) # layout major widgets self.paned2 = gtk.VPaned() self.hpaned.add2(self.paned2) self.paned2.set_position(DEFAULT_VSASH_POS) # treeview and scrollbars sw = gtk.ScrolledWindow() sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) sw.set_shadow_type(gtk.SHADOW_IN) sw.add(self.treeview) self.hpaned.add1(sw) # listview with scrollbars self.listview_sw = gtk.ScrolledWindow() self.listview_sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) self.listview_sw.set_shadow_type(gtk.SHADOW_IN) self.listview_sw.add(self.listview) self.paned2.add1(self.listview_sw) #self.paned2.child_set_property(self.listview_sw, "shrink", True) # layout editor self.paned2.add2(self.editor_pane) self.treeview.grab_focus() def set_notebook(self, notebook): """Set the notebook for the viewer""" # add/remove reference to notebook self._app.ref_notebook(notebook) if self._notebook is not None: self._app.unref_notebook(self._notebook) # deregister last notebook, if it exists if self._notebook: self._notebook.node_changed.remove( self.on_notebook_node_changed) # setup listeners if notebook: notebook.node_changed.add(self.on_notebook_node_changed) # set notebook self._notebook = notebook self.editor.set_notebook(notebook) self.listview.set_notebook(notebook) self.treeview.set_notebook(notebook) if self.treeview.get_popup_menu(): self.treeview.get_popup_menu().iconmenu.set_notebook(notebook) self.listview.get_popup_menu().iconmenu.set_notebook(notebook) # restore selections self._load_selections() # put focus on treeview self.treeview.grab_focus() def load_preferences(self, app_pref, first_open=False): """Load application preferences""" p = app_pref.get("viewers", "three_pane_viewer", define=True) self.set_view_mode(p.get("view_mode", DEFAULT_VIEW_MODE)) self.paned2.set_property("position-set", True) self.hpaned.set_property("position-set", True) self.paned2.set_position(p.get("vsash_pos", DEFAULT_VSASH_POS)) self.hpaned.set_position(p.get("hsash_pos", DEFAULT_HSASH_POS)) self.listview.set_date_formats(app_pref.get("timestamp_formats")) self.listview.set_rules_hint( app_pref.get("look_and_feel", "listview_rules", default=True)) try: # if this version of GTK doesn't have tree-lines, ignore it self.treeview.set_property( "enable-tree-lines", app_pref.get("look_and_feel", "treeview_lines", default=True)) except: pass self.editor.load_preferences(app_pref, first_open) # reload ui if self._ui_ready: self.remove_ui(self._main_window) self.add_ui(self._main_window) def save_preferences(self, app_pref): """Save application preferences""" p = app_pref.get("viewers", "three_pane_viewer") p["view_mode"] = self._view_mode p["vsash_pos"] = self.paned2.get_position() p["hsash_pos"] = self.hpaned.get_position() self.editor.save_preferences(app_pref) def save(self): """Save the current notebook""" self.editor.save() self._save_selections() def on_notebook_node_changed(self, nodes): """Callback for when notebook node is changed""" #if self._current_page in nodes: # self.emit("current-node", self._current_page) self.emit("modified", True) def undo(self): """Undo the last action in the viewer""" self.editor.undo() def redo(self): """Redo the last action in the viewer""" self.editor.redo() def get_editor(self): return self.editor def set_status(self, text, bar="status"): """Set a status message""" self.emit("status", text, bar) def set_view_mode(self, mode): """ Sets view mode for ThreePaneViewer modes: "vertical" "horizontal" """ vsash = self.paned2.get_position() # detach widgets self.paned2.remove(self.listview_sw) self.paned2.remove(self.editor_pane) self.hpaned.remove(self.paned2) # remake paned2 if mode == "vertical": # create a vertical paned widget self.paned2 = gtk.VPaned() else: # create a horizontal paned widget self.paned2 = gtk.HPaned() self.paned2.set_position(vsash) self.paned2.show() self.hpaned.add2(self.paned2) self.hpaned.show() self.paned2.add1(self.listview_sw) self.paned2.add2(self.editor_pane) # record preference self._view_mode = mode def _load_selections(self): """Load previous node selections from notebook preferences""" if self._notebook: info = self._notebook.pref.get("viewers", "ids", self._viewerid, define=True) # load selections nodes = [node for node in ( self._notebook.get_node_by_id(i) for i in info.get( "selected_treeview_nodes", [])) if node is not None] self.treeview.select_nodes(nodes) nodes = [node for node in ( self._notebook.get_node_by_id(i) for i in info.get( "selected_listview_nodes", [])) if node is not None] self.listview.select_nodes(nodes) def _save_selections(self): """Save node selections into notebook preferences""" if self._notebook is not None: info = self._notebook.pref.get("viewers", "ids", self._viewerid, define=True) # save selections info["selected_treeview_nodes"] = [ node.get_attr("nodeid") for node in self.treeview.get_selected_nodes()] info["selected_listview_nodes"] = [ node.get_attr("nodeid") for node in self.listview.get_selected_nodes()] self._notebook.set_preferences_dirty() #=============================================== # node operations def get_current_page(self): """Returns the currently focused page""" return self._current_page def get_selected_nodes(self): """ Returns a list of selected nodes. """ if self.treeview.is_focus(): return self.treeview.get_selected_nodes() else: nodes = self.listview.get_selected_nodes() if len(nodes) == 0: return self.treeview.get_selected_nodes() else: return nodes def _on_history_changed(self, viewer, history): """Callback for when node browse history changes""" if self._ui_ready and self.back_button: self.back_button.set_sensitive(history.has_back()) self.forward_button.set_sensitive(history.has_forward()) def get_focused_widget(self, default=None): """Returns the currently focused widget""" if self.treeview.is_focus(): return self.treeview if self.listview.is_focus(): return self.listview else: return default def on_delete_node(self, widget, nodes=None): """Callback for deleting a node""" # get node to delete if nodes is None: nodes = self.get_selected_nodes() if len(nodes) == 0: return if self._main_window.confirm_delete_nodes(nodes): # change selection if len(nodes) == 1: node = nodes[0] widget = self.get_focused_widget(self.listview) parent = node.get_parent() children = parent.get_children() i = children.index(node) if i < len(children) - 1: widget.select_nodes([children[i+1]]) else: widget.select_nodes([parent]) else: widget = self.get_focused_widget(self.listview) widget.select_nodes([]) # perform delete try: for node in nodes: node.trash() except NoteBookError, e: self.emit("error", e.msg, e)
class ThreePaneViewer (Viewer): """A viewer with a treeview, listview, and editor""" def __init__(self, app, main_window, viewerid=None): Viewer.__init__(self, app, main_window, viewerid, viewer_name="three_pane_viewer") self._ui_ready = False # node selections self._current_page = None # current page in editor self._treeview_sel_nodes = [] # current selected nodes in treeview self._queue_list_select = [] # nodes to select in listview after treeview change self._new_page_occurred = False self.back_button = None self._view_mode = DEFAULT_VIEW_MODE self.connect("history-changed", self._on_history_changed) #========================================= # widgets # treeview self.treeview = KeepNoteTreeView() self.treeview.connect("select-nodes", self._on_tree_select) self.treeview.connect("delete-node", self.on_delete_node) self.treeview.connect("error", lambda w,t,e: self.emit("error", t, e)) self.treeview.connect("edit-title", self._on_edit_title) self.treeview.connect("goto-node", self.on_goto_node) self.treeview.connect("activate-node", self.on_activate_node) self.treeview.connect("drop-file", self._on_attach_file) # listview self.listview = KeepNoteListView() self.listview.connect("select-nodes", self._on_list_select) self.listview.connect("delete-node", self.on_delete_node) self.listview.connect("goto-node", self.on_goto_node) self.listview.connect("activate-node", self.on_activate_node) self.listview.connect("goto-parent-node", lambda w: self.on_goto_parent_node()) self.listview.connect("error", lambda w,t,e: self.emit("error", t, e)) self.listview.connect("edit-title", self._on_edit_title) self.listview.connect("drop-file", self._on_attach_file) self.listview.on_status = self.set_status # TODO: clean up # editor #self.editor = KeepNoteEditor(self._app) #self.editor = RichTextEditor(self._app) self.editor = ContentEditor(self._app) rich_editor = RichTextEditor(self._app) self.editor.add_editor("text/xhtml+xml", rich_editor) self.editor.add_editor("text", TextEditor(self._app)) self.editor.set_default_editor(rich_editor) self.editor.connect("view-node", self._on_editor_view_node) self.editor.connect("child-activated", self._on_child_activated) self.editor.connect("visit-node", lambda w, n: self.goto_node(n, False)) self.editor.connect("error", lambda w,t,e: self.emit("error", t, e)) self.editor.connect("window-request", lambda w,t: self.emit("window-request", t)) self.editor.view_pages([]) self.editor_pane = gtk.VBox(False, 5) self.editor_pane.pack_start(self.editor, True, True, 0) #===================================== # layout # TODO: make sure to add underscore for these variables # create a horizontal paned widget self.hpaned = gtk.HPaned() self.pack_start(self.hpaned, True, True, 0) self.hpaned.set_position(DEFAULT_HSASH_POS) # layout major widgets self.paned2 = gtk.VPaned() self.hpaned.add2(self.paned2) self.paned2.set_position(DEFAULT_VSASH_POS) # treeview and scrollbars sw = gtk.ScrolledWindow() sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) sw.set_shadow_type(gtk.SHADOW_IN) sw.add(self.treeview) self.hpaned.add1(sw) # listview with scrollbars self.listview_sw = gtk.ScrolledWindow() self.listview_sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) self.listview_sw.set_shadow_type(gtk.SHADOW_IN) self.listview_sw.add(self.listview) self.paned2.add1(self.listview_sw) # layout editor self.paned2.add2(self.editor_pane) self.treeview.grab_focus() def set_notebook(self, notebook): """Set the notebook for the viewer""" # add/remove reference to notebook self._app.ref_notebook(notebook) if self._notebook is not None: self._app.unref_notebook(self._notebook) # deregister last notebook, if it exists if self._notebook: self._notebook.node_changed.remove( self.on_notebook_node_changed) # setup listeners if notebook: notebook.node_changed.add(self.on_notebook_node_changed) # set notebook self._notebook = notebook self.editor.set_notebook(notebook) self.listview.set_notebook(notebook) self.treeview.set_notebook(notebook) if self.treeview.get_popup_menu(): self.treeview.get_popup_menu().iconmenu.set_notebook(notebook) self.listview.get_popup_menu().iconmenu.set_notebook(notebook) # restore selections self._load_selections() # put focus on treeview self.treeview.grab_focus() def load_preferences(self, app_pref, first_open=False): """Load application preferences""" p = app_pref.get("viewers", "three_pane_viewer", define=True) self.set_view_mode(p.get("view_mode", DEFAULT_VIEW_MODE)) self.paned2.set_position(p.get("vsash_pos", DEFAULT_VSASH_POS)) self.hpaned.set_position(p.get("hsash_pos", DEFAULT_HSASH_POS)) self.listview.set_date_formats(app_pref.get("timestamp_formats")) self.listview.set_rules_hint( app_pref.get("look_and_feel", "listview_rules", default=True)) try: # if this version of GTK doesn't have tree-lines, ignore it self.treeview.set_property( "enable-tree-lines", app_pref.get("look_and_feel", "treeview_lines", default=True)) except: pass self.editor.load_preferences(app_pref, first_open) # reload ui if self._ui_ready: self.remove_ui(self._main_window) self.add_ui(self._main_window) def save_preferences(self, app_pref): """Save application preferences""" p = app_pref.get("viewers", "three_pane_viewer") p["view_mode"] = self._view_mode p["vsash_pos"] = self.paned2.get_position() p["hsash_pos"] = self.hpaned.get_position() self.editor.save_preferences(app_pref) def save(self): """Save the current notebook""" self.editor.save() self._save_selections() def on_notebook_node_changed(self, nodes, recurse): """Callback for when notebook node is changed""" #if self._current_page in nodes: # self.emit("current-node", self._current_page) self.emit("modified", True) def undo(self): """Undo the last action in the viewer""" self.editor.undo() def redo(self): """Redo the last action in the viewer""" self.editor.redo() def set_status(self, text, bar="status"): """Set a status message""" self.emit("status", text, bar) def set_view_mode(self, mode): """ Sets view mode for ThreePaneViewer modes: "vertical" "horizontal" """ vsash = self.paned2.get_position() # detach widgets self.paned2.remove(self.listview_sw) self.paned2.remove(self.editor_pane) self.hpaned.remove(self.paned2) # remake paned2 if mode == "vertical": # create a vertical paned widget self.paned2 = gtk.VPaned() else: # create a horizontal paned widget self.paned2 = gtk.HPaned() self.paned2.set_position(vsash) self.paned2.show() self.hpaned.add2(self.paned2) self.hpaned.show() self.paned2.add1(self.listview_sw) self.paned2.add2(self.editor_pane) # record preference self._view_mode = mode def _load_selections(self): """Load previous node selections from notebook preferences""" if self._notebook: info = self._notebook.pref.get("viewers", "ids", self._viewerid, define=True) # load selections nodes = [node for node in ( self._notebook.get_node_by_id(i) for i in info.get( "selected_treeview_nodes", [])) if node is not None] self.treeview.select_nodes(nodes) nodes = [node for node in ( self._notebook.get_node_by_id(i) for i in info.get( "selected_listview_nodes", [])) if node is not None] self.listview.select_nodes(nodes) def _save_selections(self): """Save node selections into notebook preferences""" if self._notebook is not None: info = self._notebook.pref.get("viewers", "ids", self._viewerid, define=True) # save selections info["selected_treeview_nodes"] = [ node.get_attr("nodeid") for node in self.treeview.get_selected_nodes()] info["selected_listview_nodes"] = [ node.get_attr("nodeid") for node in self.listview.get_selected_nodes()] self._notebook.set_preferences_dirty() #=============================================== # node operations def get_current_page(self): """Returns the currently focused page""" return self._current_page def get_selected_nodes(self): """ Returns a list of selected nodes. """ if self.treeview.is_focus(): return self.treeview.get_selected_nodes() else: nodes = self.listview.get_selected_nodes() if len(nodes) == 0: return self.treeview.get_selected_nodes() else: return nodes def _on_history_changed(self, viewer, history): """Callback for when node browse history changes""" if self._ui_ready and self.back_button: self.back_button.set_sensitive(history.has_back()) self.forward_button.set_sensitive(history.has_forward()) def get_focused_widget(self, default=None): """Returns the currently focused widget""" if self.treeview.is_focus(): return self.treeview if self.listview.is_focus(): return self.listview else: return default def on_delete_node(self, widget, nodes=None): """Callback for deleting a node""" # get node to delete if nodes is None: nodes = self.get_selected_nodes() if len(nodes) == 0: return if self._main_window.confirm_delete_nodes(nodes): # change selection if len(nodes) == 1: node = nodes[0] widget = self.get_focused_widget() parent = node.get_parent() children = parent.get_children() i = children.index(node) if i < len(children) - 1: widget.select_nodes([children[i+1]]) else: widget.select_nodes([parent]) else: widget = self.get_focused_widget() widget.select_nodes([]) # perform delete try: for node in nodes: node.trash() except NoteBookError, e: self.emit("error", e.msg, e)