예제 #1
0
 def __init__(self):
     """
     Constructor.
     """
     super(DocumentManager, self).__init__()
     
     #self.interface = interface
     #self.main_window = interface.main_window
     #self.trigger_manager = TriggerManager(self)
     #self.language_manager = LanguageManager()
     self.preferences_manager = tf.app.preferences_manager
     self.trigger_manager = tf.app.trigger_manager
     self.language_manager = tf.app.language_manager
     self.modification_monitor = ModificationMonitor(self)
     
     self.search_functions = Search(self)
     
     self.set_scrollable(True)
     self.connect("switch-page", self.change_tab)
     
     self.__get_color_styles()
     self.doing_sticky = False
예제 #2
0
class DocumentManager(gtk.Notebook):
    """
    This class has operations to manipulate all documents open.
    """

    __gsignals__ = { "open-file" : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
                                 (Document,)),
                     "save-file" :  (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
                                 (Document,)),
                     "close-file" :  (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
                                 (Document,))}

    def __init__(self):
        """
        Constructor.
        """
        super(DocumentManager, self).__init__()
        
        #self.interface = interface
        #self.main_window = interface.main_window
        #self.trigger_manager = TriggerManager(self)
        #self.language_manager = LanguageManager()
        self.preferences_manager = tf.app.preferences_manager
        self.trigger_manager = tf.app.trigger_manager
        self.language_manager = tf.app.language_manager
        self.modification_monitor = ModificationMonitor(self)
        
        self.search_functions = Search(self)
        
        self.set_scrollable(True)
        self.connect("switch-page", self.change_tab)
        
        self.__get_color_styles()
        self.doing_sticky = False
        
    
    #################### Public Methods ####################

    def open_tab(self, file_uri="", encode=""):
        """
        Open a new tab.
        
        @param file_uri: The file uri of a text file that will be displayed in the open tab.
                         If it's omited a blank tab will be open.
        @type file_uri: A String.
        
        @param encode: The enconding used to display the text.
                       If it's omited a default enconde will be used.
        @param encode: A String.
        """
        
        if file_uri != "":
            # Verifying if the file is already open
            tab_number = self.get_n_pages()
            for number in range(tab_number):
                if self.get_nth_page(number).file_uri == file_uri:
                    self.set_current_page(number)
                    return
                    
            # defining tab label text
            label_text = os.path.basename(file_uri)
        else:
            label_text = constants.MESSAGE_0001
            
            
        #creating label widget
        tab_box = gtk.HBox(False, 4)
        tab_label = gtk.Label(label_text)
        tab_button = CloseButton()
        
        tab_box.pack_start(tab_label, True, True, 0)
        tab_box.pack_start(tab_button, False, False, 0)
        tab_box.show_all()
        
        try:
            document = self.__create_document(file_uri, encode)
        except UnicodeDecodeError:
            encoding = self.__show_encoding_dialog()

            if encoding is not None:
                self.open_tab(file_uri, encoding)
                
        except IOError:
            self.__show_error_dialog(constants.MESSAGE_0033 % file_uri,
                                     constants.MESSAGE_0034)
            
        else:
            child = self.get_nth_page(0)
            
            if self.get_n_pages() == 1:
                if child.get_file_uri() == "" and child.get_text() == "":
                    if document.get_file_uri() != "":
                        self.__remove_tab(child)
            
            if file_uri != "":
                if self.preferences_manager.get_value("open_save/auto_save"):
                    self.add_to_autosave(document)
            
            self.append_page(document, tab_box)
            self.set_tab_reorderable(document, True)
            self.set_current_page(-1) #negative number == last tab
            tab_button.connect('clicked', self.close_tab_button, document)
            document.view.buffer.connect('changed', self.buffer_change, document, tab_label)
            self.emit("open-file", document)
            
            document.view.grab_focus()

    def close_tab(self, document):
        """
        Close a document tab.
        
        @param document: The document that will be closed.
        @type document: A Document object.
        """
        
        if not isinstance(document, Document):
            raise TypeError("The argument must be a Document object")
        
        if not document.is_updated():
            dialog = CloseAlertDialog()
            button_clicked = dialog.run()
            
            dialog.destroy()
            if button_clicked == gtk.RESPONSE_DELETE_EVENT or \
               button_clicked == 2:
                return
            elif button_clicked == 3:
                self.save_tab(document)
            
        self.remove_from_autosave(document)
        self.__remove_tab(document)
        self.emit("close-file", document)
        
        if self.get_n_pages() == 0:
            self.open_tab()
    
    def save_tab(self, document, show_error=True):
        """
        Save a tab that contains a document.
        
        @param document: A document to save.
        @type document: A Document.
        """
        save_file = document.file_uri
        
        if save_file == "":
            save_file = self.__show_save_file_dialog()
            
            if save_file is None:
                return
        
        self.__save_document(document, save_file, show_error)
        
    def save_as_tab(self, document, show_error=True):
        """
        Ask a filename and save a tab that contains a document.
        
        @param document: a document to save.
        @type document: a Document.
        """
        save_file = self.__show_save_file_dialog()
        
        if save_file is None:
            return
        
        self.__save_document(document, save_file, show_error)
        
    def save_all_tabs(self, show_error=True):
        """
        Save all open documents.
        """
        for document in self:
            self.save_tab(document, show_error)
            
    def save_active_tab(self, show_error=True):
        """
        Save the active document.
        """
        document = self.get_active_document()
        self.save_tab(document, show_error)
    
    def get_active_document(self):
        """
        Get the active Document.
        
        @return: The active Document.
        @rtype: A Document object.
        """
        current_page = self.get_current_page()
        
        if current_page == -1:
            return None
        else:
            return self.get_nth_page(current_page)
    
    def get_active_view(self):
        """
        Get the active GtkSourceView2
        
        @return: The active GtkSourceView2.
        @rtype: A GtkSourceView2 object.
        """
        return self.get_active_document().view
    
    def store_tabs(self):
        """
        Store all open documents. They are reopened using open_stored_tabs
        method or on TextFlow startup if the option 'Reopen tabs on program
        initialization' is true in preferences.
        """
        store_file_uri = os.path.join(constants.HOME, ".textflow", "stored_tabs")
        
        try:
            store_file = open(store_file_uri, "w")
        except IOError:
            self.__show_error_dialog(constants.MESSAGE_0035, constants.MESSAGE_0036)
            return
        
        num_pages = self.get_n_pages()
        
        for i in range(num_pages):
            document = self.get_nth_page(i)
            if document.file_uri != "":
                store_file.write(document.file_uri + "\n" + document.encode + "\n")
        
        store_file.close()
        
    def open_stored_tabs(self):
        #TODO: show error if the stored_tabs file exists but it's impossible to read
        """
        Open tabs saved in stored_tabs file. See the store_tabs method.
        """
        
        store_file_uri = os.path.join(constants.HOME, ".textflow", "stored_tabs")
        
        try:
            store_file = open(store_file_uri, "r")
        except IOError:
            return
        else:
            lines = store_file.readlines()
            cont = 0
            while cont < len(lines):
                try:
                    if os.path.exists(lines[cont][:-1]):
                        self.open_tab(lines[cont][:-1], lines[cont+1][:-1])
                except:
                    pass
                
                # jump 2 lines
                cont += 2
            
    def change_encode(self, document, encode):
        #TODO: this method isn't use the document passed argument
        #TODO: what happen if a invalid encoding is passed?
        """
        Change the text encode of a document.
        
        @param document: a document to change the encoding
        @type document: a Document.
        
        @param encode: encode name.
        @type encode: a String.
        """
        
        page_num = self.get_current_page()
        
        if page_num != -1:
            document = self.get_nth_page(page_num)

            if document.encode != encode:
                file_uri = document.file_uri
                
                if file_uri != "":
                    if not document.is_updated():
                        dialog = CloseAlertDialog()
                        dialog.set_markup(constants.MESSAGE_0014)

                        button_clicked = dialog.run()

                        if button_clicked == gtk.RESPONSE_DELETE_EVENT:
                            dialog.destroy()
                            return
                        elif button_clicked == 1:
                            dialog.destroy()
                        elif button_clicked == 2:
                            dialog.destroy()
                            return
                        elif button_clicked == 3:
                            self.save_active_tab(file_uri)
                           
                            dialog.destroy()
                                                       
                        self.__remove_tab(document)
                        self.open_tab(file_uri, encode)
                    else:
                        self.__remove_tab(document)
                        self.open_tab(file_uri, encode)
                        
                    new_page_num = self.get_current_page()
                    document = self.get_nth_page(new_page_num)
                    self.reorder_child(document, page_num)
    
    def add_to_autosave(self, document):
        """
        Add a document to auto save.
        
        @param document: the document added to auto save.
        @type document: a Document.
        """
        minutes = self.preferences_manager.get_value("open_save/auto_save_minutes")
        document.autosave = gobject.timeout_add(minutes*60000, self.__save_document, document,
                                            document.file_uri, priority=gobject.PRIORITY_LOW)

    def remove_from_autosave(self, document):
        """
        Remove a document from auto save.
        
        @param document: the document added to auto save.
        @type document: a Document.
        """
        if not isinstance(document, Document):
            raise TypeError("The argument must be a Document object")
        
        if document.file_uri != "" and document.autosave:
            gobject.source_remove(document.autosave)
            document.autosave = False

    def set_style(self, view, value):
        """
        Set the color style used by a TFSourceView.
        
        @param view: The TFSourceView.
        @type view: A TFSourceView object.
        
        @param value: A color style name.
        @type value: A string.
        """
        
        scheme = self.style_manager.get_scheme(value)
        buffer = view.buffer
        
        if scheme != None:
            buffer.set_style_scheme(scheme)
            
            style_scheme = buffer.get_style_scheme()
            style = style_scheme.get_style("search-match")
            style_sticky = style_scheme.get_style("def:note")
            
            # Set search match color
            if style != None:
                foreground = style.get_property("foreground")
                background = style.get_property("background")
            else:
                foreground = "black"
                background = "lightblue"

            if style_sticky != None:
                foreground_sticky = style_sticky.get_property("foreground")
                background_sticky = style_sticky.get_property("background")
            else:
                foreground_sticky = "black"
                background_sticky = "#ff6100"
            
            tag_table = buffer.get_tag_table()
            tag = tag_table.lookup("searchmatch")
            tag_sticky = tag_table.lookup("sticky")
            
            if foreground != None:
                tag.set_property("foreground", foreground)
                tag_sticky.set_property("foreground", foreground_sticky)
            else:
                tag.set_property("foreground", "black")
                tag_sticky.set_property("foreground", "black")
            
            if background != None:
                tag.set_property("background", background)
                tag_sticky.set_property("background", background_sticky)
            
    def undo(self):
        """
        Undo a action of current view.
        """
        
        document = self.get_active_document()
        view = document.view
        buffer = view.buffer
        can_undo = buffer.can_undo()
        
        if can_undo:
            buffer.undo()
            
            if buffer.can_redo():
                #self.interface.toolbutton_redo.set_sensitive(True)
                tf.app.main_window.toolbutton_redo.set_sensitive(True)
            
            can_undo = buffer.can_undo()
            
            if not can_undo:
                #self.interface.toolbutton_undo.set_sensitive(False)
                tf.app.main_window.toolbutton_undo.set_sensitive(False)
            
            if document.is_updated():
                child = self.get_nth_page(self.get_current_page())
                label_box = self.get_tab_label(child)
                label = label_box.get_children()[0]
                label.set_label(label.get_label()[1:])
                document.modified = False
     
    def redo(self):
        """
        Redo a action of current view.
        """
        
        view = self.get_active_view()
        buffer = view.buffer
        can_redo = buffer.can_redo()
        
        if view != None and can_redo:
            buffer.redo()
            
            if buffer.can_undo():
                #self.interface.toolbutton_undo.set_sensitive(True)
                tf.app.main_window.toolbutton_undo.set_sensitive(True)
            
            can_redo = buffer.can_redo()
            
            if not can_redo:
                #self.interface.toolbutton_redo.set_sensitive(False)
                tf.app.main_window.toolbutton_redo.set_sensitive(False)
        
    #################### Private Methods ####################
    
    def __get_color_styles(self):
        """
        This method gets all available color styles.
        """
        styles_dir = os.getenv("HOME") + "/.textflow/colors"
        self.style_manager = gtksourceview2.StyleSchemeManager()
        self.style_manager.prepend_search_path(styles_dir)
    
    def __create_document(self, file_uri, encode):
        """
        Create a Document and set some properties.
        
        @param file_uri: A file that will be displayed in TFSourceView.
        @type file_uri: A string
        
        @return: The Document created.
        @rtype: A Document object.
        """
        buffer = gtksourceview2.Buffer()
        pm = self.preferences_manager
        
        #Color stuff
        buffer.create_tag("searchmatch", background="lightblue")
        buffer.create_tag("sticky", background="#ff6100")
        buffer.set_highlight_syntax(True)
        
        document = Document(buffer, file_uri, encode)
        view = document.view
        
        #Getting view language id
        language = view.buffer.get_language()
        
        if language != None:
            language_id = language.get_id()
            self.language_manager.change_mode(language_id)
            language_configs = self.language_manager.loaded_configs[language_id]
            view.set_tab_width(language_configs["tab-size"])
        else:
            self.language_manager.change_mode(None)
            view.set_tab_width(pm.get_value("indentation/tab_width"))
        
        # Define view encode to default encoding 
        if document.encode == "":
            document.encode = pm.get_value("open_save/encoding")
        
        #applying properties
        view.modify_font(pango.FontDescription(pm.get_value("font")))
        view.set_insert_spaces_instead_of_tabs(pm.get_value("indentation/use_spaces"))
        view.set_auto_indent(pm.get_value("indentation/automatic"))
        view.set_show_right_margin(pm.get_value("right_margin/display"))
        view.set_right_margin_position(pm.get_value("right_margin/position"))
        view.set_show_line_numbers(pm.get_value("line_numbers"))
        view.set_highlight_current_line(pm.get_value("highlight_current_line"))
        document.set_text_wrapping(pm.get_value("text_wrapping"))
        view.buffer.set_highlight_matching_brackets(pm.get_value("brackets_matching"))
        view.set_smart_home_end(False)
        self.set_style(view, pm.get_value("color_style"))
        
        view.connect('key-press-event', self.pre_key_press)
        view.connect('key-release-event', self.key_release)
        view.connect("drag-motion", self.drag_motion)
        view.connect("drag-drop", self.drag_drop)
        view.connect("drag-data-received", self.drag_data_received)
        view.drag_dest_set(gtk.DEST_DEFAULT_ALL, [("text/uri-list", 0, 1)],
                           gtk.gdk.ACTION_COPY)
        #view.buffer.connect("notify::cursor-position", self.cursor_moved, document,
        #                    self.interface.statusbar)
                            
        view.buffer.connect("notify::cursor-position", self.cursor_moved, document)
                            
        document.show_all()
        return document
    
    def __remove_tab(self, document):
        """
        Remove a Notebook tab.
        """
        page = self.page_num(document)
        
        if page == -1:
            raise ValueError("Document doesn't exist.")
        
        document.word_complete.stop_indexer()
        self.remove_page(page)
    
    def __show_error_dialog(self, main_text, secondary_text):
        error_dialog = ErrorDialog(main_text, secondary_text)
        button_clicked = error_dialog.run()
        
        if button_clicked == gtk.RESPONSE_DELETE_EVENT:
            error_dialog.destroy()
        elif button_clicked == 1:
            error_dialog.destroy()
    
    def __save_document(self, document, save_file, show_error=True):
        
        try:
            text = document.get_text().encode(document.encode)
        except UnicodeEncodeError:
            self.__show_error_dialog(constants.MESSAGE_0018, constants.MESSAGE_0025)
            return
        
        try:
            arquivo = open(save_file, "w")
        except IOError:
            if show_error:
                document.permission = "Read Only"
                tf.app.main_window.statusbar.permission_label.set_text(document.permission)
                self.__show_error_dialog(constants.MESSAGE_0018, constants.MESSAGE_0019)
        else:
            line_ending = self.preferences_manager.get_value("open_save/line_ending")
            
            if line_ending == "CR LF":
                text = text.replace("\n","\r\n")

            if self.preferences_manager.get_value("open_save/save_copy") == True:
                arquivo_copy = open(save_file + "~", "w")
                arquivo_copy.write(text)                
                arquivo_copy.close()
            
            arquivo.write(text)
            arquivo.close()
            
            if document.file_uri == "":
                if self.preferences_manager.get_value("open_save/auto_save"):
                    self.add_to_autosave(document)
            
            document.set_file_uri(save_file)
                
            #Getting view language id
            language = document.view.buffer.get_language()
            
            if language != None:
                language_id = language.get_id()
                
                if self.language_manager.language != language_id:
                    self.language_manager.change_mode(language_id)
                    language_configs = self.language_manager.loaded_configs[language_id]
                    document.view.set_tab_width(language_configs["tab-size"])
            else:
                self.language_manager.change_mode(None)

            tf.app.main_window.statusbar.combobutton_tab_size.set_label(constants.MESSAGE_0026 + " " + str(document.view.get_tab_width()))
            
            
            current_page = self.page_num(document)
            current_child = self.get_nth_page(current_page)
            tab_label = self.get_tab_label(current_child)
            children = tab_label.get_children()
            
            f_list = save_file.split("/")
            file_name = f_list.pop()
            direc = " (" + "/".join(f_list) + ")"
            
            children[0].set_label(file_name)
            
            tf.app.main_window.main_window.set_title(str(file_name) + direc)
            
            self.emit("save-file", document)

            document.modified = False
            document.permission = "Writable"
            #self.interface.statusbar.permission_label.set_text(document.permission)
            tf.app.main_window.statusbar.permission_label.set_text(document.permission)
            
    def __show_encoding_dialog(self):
        """
        Show the choose encoding dialog
        
        @return: if OK button is pressed - selected encoding.
                 if anything else is done - None.
        @rtype: a String.
        """
        dialog_encoding = ChangeEncodingDialog()
        button_clicked = dialog_encoding.run()
        encoding = None
        
        if button_clicked == gtk.RESPONSE_DELETE_EVENT:
            dialog_encoding.destroy()
        elif button_clicked == 1:
            encoding = dialog_encoding.get_encoding()
            dialog_encoding.destroy()
        elif button_clicked == 2:
            dialog_encoding.destroy()
            
        return encoding
    
    def __show_save_file_dialog(self):
        """
        Show a dialog to choose a filename to save the document.
        
        @return: a filename
        @rtype: a String.
        """
        #file_save = SaveFileDialog(constants.MESSAGE_0002, None,
        #                           "", "*", False, self.interface.last_dir)
        file_save = SaveFileDialog(constants.MESSAGE_0002, None,
                                   "", "*", False, tf.app.main_window.last_dir)
        new_file = file_save.run()
        file_save.destroy()
        
        if len(new_file):
            return new_file[0]
        else:
            return None

    #################### Callbacks ####################

    def close_tab_button(self, widget, document):
        """
        Close a tab in the DocumentManager
        
        @param widget: Reference to the widget.
        @type widget: A widget object.
        
        @param swindow: A Document.
        @type swindow: A Document object.
        """
        self.close_tab(document)
    
    def change_tab(self, widget, page, page_num):
        """
        This method does some operations when tabs are changed.
        """
        previous_document = widget.get_active_document()
        if previous_document != None:
            previous_document.word_complete.stop_indexer()
            
        document = self.get_nth_page(page_num) 
        view = document.view
        
        document.word_complete.start_indexer()
        
        self.search_functions.view = view
        self.search_functions.buffer = view.buffer
        
        self.search_functions.cursor_mark = \
        self.search_functions.buffer.get_insert()
         
        title = document.get_file_uri()
        if title == "":
            file_name = constants.MESSAGE_0001
            direc = ""
        else:
            f_list = title.split("/")
            file_name = f_list.pop()
            direc = " (" + "/".join(f_list) + ")"
        
        #self.main_window.set_title(str(file_name) + direc)
        tf.app.main_window.main_window.set_title(str(file_name) + direc)
        begin = view.buffer.get_start_iter()
        end = view.buffer.get_end_iter()
        self.search_functions.update_matches(begin, end)
        
        pos = document.get_cursor_position()
        
        #Getting view language id
        language = view.buffer.get_language()
        
        if language != None:
            language_id = language.get_id()
            self.language_manager.change_mode(language_id)
        else:
            self.language_manager.change_mode(None)
            
        #self.interface.statusbar.set_line_column(pos[0], pos[1])
        #self.interface.statusbar.combobutton_encoding.set_label(document.encode)
        #self.interface.statusbar.permission_label.set_text(document.permission)
        #self.interface.statusbar.combobutton_tab_size.set_label(constants.MESSAGE_0026 + " " + str(view.get_tab_width()))
        
        tf.app.main_window.statusbar.set_line_column(pos[0], pos[1])
        tf.app.main_window.statusbar.combobutton_encoding.set_label(document.encode)
        tf.app.main_window.statusbar.permission_label.set_text(document.permission)
        tf.app.main_window.statusbar.combobutton_tab_size.set_label(constants.MESSAGE_0026 + " " + str(view.get_tab_width()))
    
    def drag_motion(self, textview, context, x, y, time):
        """
        Handles callback when a drag operation begins.
        """
        
        if "text/uri-list" in context.targets:
            return True
        else:
            return False

    def drag_drop(self, textview, context, x, y, time):
        """
        Handles callback when a drop operation begins.
        """
        if "text/uri-list" in context.targets:
            return True
        else:
            return False
        
    def drag_data_received(self, textview, context, xcord, ycord,
                              selection_data, info, timestamp):
        """
        Handles callback when a drop operation finishes.
        """
        
        if not ("text/uri-list" in context.targets):
            return False
        else:
            if info != 1:
                return False
            
            # Load file
            uri_list = list(selection_data.get_uris())
            
            for i in uri_list:
                filepatch = gnomevfs.get_local_path_from_uri(i)
                if os.path.getsize(filepatch) > 5120000:
                    dialog = gtk.MessageDialog(tf.app.main_window.main_window, gtk.DIALOG_MODAL, gtk.MESSAGE_QUESTION, gtk.BUTTONS_YES_NO, (constants.MESSAGE_0030) % filepatch)
                    choice = dialog.run()
                    dialog.destroy()                    
                    if choice == gtk.RESPONSE_YES:
                        self.open_tab(filepatch)
                else:
                    self.open_tab(filepatch)
            
            context.finish(True, False, timestamp)
            return True                         
    
    def cursor_moved(self, buffer, position, document):
        pos = document.get_cursor_position()
        #statusbar.set_line_column(pos[0], pos[1])
        tf.app.main_window.statusbar.set_line_column(pos[0], pos[1])
    
    def key_release(self, widget, event):
        """
        This method does some operations when a key is realeased.
        """
        last = self.trigger_manager.last_shortcut
#         print "--------------------------"
        #print event.state
        #print event.keyval
#         print "--------------------------"
        if last in self.trigger_manager.sticky_keys:
            if event.state & gtk.gdk.CONTROL_MASK and event.state & gtk.gdk.SHIFT_MASK:
                pass
#                 print "ctrl+shift+" + unichr(event.keyval).lower()
            elif event.state & gtk.gdk.CONTROL_MASK:
                if "ctrl" in last and (event.keyval == 65507 or not (unichr(event.keyval) in self.trigger_manager.sticky_keys[last])):
                    try:
                        self.trigger_manager.sticky_shortcuts[last]()
                    #except KeyError:
                    #    return
                    finally:
                        self.trigger_manager.last_shortcut = None
                        self.doing_sticky = False
    #         elif event.state & gtk.gdk.SHIFT_MASK:
    #             shortcut = "shift+" + unichr(event.keyval).lower()
    #             shortcut2 = unichr(event.keyval).lower()
    #             if shortcut in self.trigger_manager.sticky_shortcuts:
    #                 self.trigger_manager.sticky_shortcuts[shortcut]()
    #             elif shortcut2 in self.trigger_manager.sticky_shortcuts:
    #                 self.trigger_manager.sticky_shortcuts[shortcut2]()
            else:
                shortcut = unichr(event.keyval).lower()
                last_key = last.split("+")[-1]
                if shortcut == last_key:
                    try:
                        self.trigger_manager.sticky_shortcuts[last]()
                    #except KeyError:
                    #    return
                    finally:
                        self.trigger_manager.last_shortcut = None
                        
        view = self.get_active_view()
        view.scroll_mark_onscreen(view.buffer.get_insert())
        
    def pre_key_press(self, widget, event):
        #print event.keyval
        #print event.state
        
        if self.doing_sticky:
            return False
        
        if event.state & gtk.gdk.CONTROL_MASK \
        and event.state & gtk.gdk.SHIFT_MASK:
            shortcut = "ctrl+shift+" + unichr(event.keyval).lower()
            if shortcut in self.trigger_manager.shortcuts:
                r = self.trigger_manager.shortcuts[shortcut]()
                self.trigger_manager.last_shortcut = shortcut
                
                if shortcut in self.trigger_manager.sticky_shortcuts:
                    self.doing_sticky = True
                
                return r
            elif shortcut in self.trigger_manager.language_shortcuts:
                r = self.trigger_manager.language_shortcuts[shortcut]()
                self.trigger_manager.last_shortcut = shortcut
                
                if shortcut in self.trigger_manager.sticky_shortcuts:
                    self.doing_sticky = True
                
                return r
            else:
                return False
        elif event.state & gtk.gdk.CONTROL_MASK:
            shortcut = "ctrl+" + unichr(event.keyval).lower()
            if shortcut in self.trigger_manager.shortcuts:
                r = self.trigger_manager.shortcuts[shortcut]()
                self.trigger_manager.last_shortcut = shortcut
                
                if shortcut in self.trigger_manager.sticky_shortcuts:
                    self.doing_sticky = True
                
                return r
            elif shortcut in self.trigger_manager.language_shortcuts:
                r = self.trigger_manager.language_shortcuts[shortcut]()
                self.trigger_manager.last_shortcut = shortcut
                
                if shortcut in self.trigger_manager.sticky_shortcuts:
                    self.doing_sticky = True
                
                return r
            else:
                return False
        elif event.state & gtk.gdk.SHIFT_MASK:
            shortcut = "shift+" + unichr(event.keyval).lower()
            shortcut2 = unichr(event.keyval).lower()
            if shortcut in self.trigger_manager.shortcuts:
                r = self.trigger_manager.shortcuts[shortcut]()
                self.trigger_manager.last_shortcut = shortcut
                
                if shortcut in self.trigger_manager.sticky_shortcuts:
                    self.doing_sticky = True
                
                return r
            elif shortcut2 in self.trigger_manager.shortcuts:
                r = self.trigger_manager.shortcuts[shortcut2]()
                self.trigger_manager.last_shortcut = shortcut2
                
                if shortcut in self.trigger_manager.sticky_shortcuts:
                    self.doing_sticky = True
                
                return r
            elif shortcut in self.trigger_manager.language_shortcuts:
                r = self.trigger_manager.language_shortcuts[shortcut]()
                self.trigger_manager.last_shortcut = shortcut
                
                if shortcut in self.trigger_manager.sticky_shortcuts:
                    self.doing_sticky = True
                
                return r
            elif shortcut2 in self.trigger_manager.language_shortcuts:
                r = self.trigger_manager.language_shortcuts[shortcut2]()
                self.trigger_manager.last_shortcut = shortcut2
                
                if shortcut in self.trigger_manager.sticky_shortcuts:
                    self.doing_sticky = True
                
                return r
            else:
                return False
        else:
            
            #print self.trigger_manager.language_shortcuts
            shortcut = unichr(event.keyval).lower()
                        
            if shortcut in self.trigger_manager.shortcuts:
                r = self.trigger_manager.shortcuts[shortcut]()
                self.trigger_manager.last_shortcut = shortcut
                
                if shortcut in self.trigger_manager.sticky_shortcuts:
                    self.doing_sticky = True
                
                return r
            elif shortcut in self.trigger_manager.language_shortcuts:
                r = self.trigger_manager.language_shortcuts[shortcut]()
                self.trigger_manager.last_shortcut = shortcut
                
                if shortcut in self.trigger_manager.sticky_shortcuts:
                    self.doing_sticky = True
                
                return r
            else:
                return False
        
    def buffer_change(self, widget, document, label):
        if not document.modified:
            text = label.get_text()
            document.modified = True
            label.set_text("*" + text)
        
        #toolbutton_undo = self.interface.toolbutton_undo 
        #toolbutton_redo = self.interface.toolbutton_redo
         
        toolbutton_undo = tf.app.main_window.toolbutton_undo 
        toolbutton_redo = tf.app.main_window.toolbutton_redo 
        
        if document.view.buffer.can_undo():
            if not toolbutton_undo.get_property("sensitive"):
                #self.interface.toolbutton_undo.set_sensitive(True)
                tf.app.main_window.toolbutton_undo.set_sensitive(True)
        
        if not document.view.buffer.can_redo():
            if toolbutton_redo.get_property("sensitive"):
                #self.interface.toolbutton_redo.set_sensitive(False)
                tf.app.main_window.toolbutton_redo.set_sensitive(False)
        
        self.search_functions.all_search = False
        start, end = document.get_line_iters()
        self.search_functions.update_matches(start, end)