Ejemplo n.º 1
0
class AdvancedFindWindowHelper:
    def __init__(self, plugin, window):
        self._window = window
        self._plugin = plugin
        self.find_ui = None
        self.find_history = []
        self.replace_history = []
        self.file_type_history = []
        self.file_path_history = []
        self.current_search_pattern = ""
        self.current_replace_text = ""
        #self.current_file_pattern = ""
        #self.current_path = ""
        self.forwardFlg = True
        self.scopeFlg = 0
        '''
		self.result_highlight_tag = gtk.TextTag('result_highlight')
		self.result_highlight_tag.set_properties(foreground='yellow',background='red')
		self.result_highlight_tag.set_property('family', 'Serif')
		self.result_highlight_tag.set_property('size-points', 12)
		self.result_highlight_tag.set_property('weight', pango.WEIGHT_BOLD)
		self.result_highlight_tag.set_property('underline', pango.UNDERLINE_DOUBLE)
		self.result_highlight_tag.set_property('style', pango.STYLE_ITALIC)
		#'''

        configfile = os.path.join(os.path.dirname(__file__), "config.xml")
        self.config_manager = config_manager.ConfigManager(configfile)
        self.find_options = self.config_manager.load_configure('FindOption')
        self.config_manager.to_bool(self.find_options)

        self.find_dlg_setting = self.config_manager.load_configure('FindGUI')
        self.config_manager.to_bool(self.find_dlg_setting)

        self.shortcuts = self.config_manager.load_configure('Shortcut')
        self.result_highlight = self.config_manager.load_configure(
            'ResultDisplay')

        self.result_gui_settings = self.config_manager.load_configure(
            'ResultGUI')
        self.config_manager.to_bool(self.result_gui_settings)

        self.find_history = self.config_manager.load_list('FindHistory')
        self.replace_history = self.config_manager.load_list('ReplaceHistory')
        self.file_type_history = self.config_manager.load_list('FilterHistory')
        self.file_path_history = self.config_manager.load_list('PathHistory')

        self._results_view = FindResultView(window, self.result_gui_settings)
        self._window.get_bottom_panel().add_item(self._results_view,
                                                 _("Advanced Find/Replace"),
                                                 "gtk-find-and-replace")

        self.msgDialog = gtk.MessageDialog(
            self._window, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
            gtk.MESSAGE_INFO, gtk.BUTTONS_CLOSE, None)

        # Insert menu items
        self._insert_menu()

    def deactivate(self):
        # Remove any installed menu items
        self._remove_menu()

        self.config_manager.update_configure('FindOption', self.find_options)
        self.config_manager.update_configure('FindGUI', self.find_dlg_setting)
        #self.config_manager.update_configure('Shortcut', self.shortcuts)
        self.config_manager.update_configure('ResultDisplay',
                                             self.result_highlight)
        self.result_gui_settings.update(
            self._results_view.get_show_button_option())
        self.config_manager.update_configure('ResultGUI',
                                             self.result_gui_settings)
        self.config_manager.update_list('FindHistory', self.find_history)
        self.config_manager.update_list('ReplaceHistory', self.replace_history)
        self.config_manager.update_list('FilterHistory',
                                        self.file_type_history)
        self.config_manager.update_list('PathHistory', self.file_path_history)
        self.config_manager.update_config_file(self.config_manager.config_file)

        self._window = None
        self._plugin = None
        self.find_ui = None
        self.find_history = None
        self.replace_history = None
        self.file_type_history = None
        self.file_path_history = None
        self._result_view = None

    def _insert_menu(self):
        # Get the GtkUIManager
        manager = self._window.get_ui_manager()

        # Create a new action group
        self._action_group = gtk.ActionGroup("AdvancedFindReplaceActions")
        self._action_group.add_actions([
            ("advanced_find_active", gtk.STOCK_FIND,
             _("Advanced Find/Replace"), self.shortcuts['ACTIVATE'],
             _("Advanced Find/Replace"), self.advanced_find_active),
            ("find_next", gtk.STOCK_GO_FORWARD, _("Find Next"),
             self.shortcuts['FIND_NEXT'], _("Find Next"), self.find_next),
            ("find_previous", None,
             _("Find Previous"), self.shortcuts['FIND_PREVIOUS'],
             _("Find Previous"), self.find_previous),
            ("select_find_next", gtk.STOCK_MEDIA_PLAY,
             _("Select and Find Next"), self.shortcuts['SELECT_FIND_NEXT'],
             _("Select and Find Next"), self.select_find_next),
            ("select_find_previous", None, _("Select and Find Previous"),
             self.shortcuts['SELECT_FIND_PREVIOUS'],
             _("Select and Find Previous"), self.select_find_previous),
            ("select_find_all", gtk.STOCK_MEDIA_FORWARD,
             _("Select and Find all"), None, _("Select and Find All"),
             self.select_find_all),
        ])

        # Insert the action group
        manager.insert_action_group(self._action_group, -1)

        # Merge the UI
        self._ui_id = manager.add_ui_from_string(ui_str)

    def _remove_menu(self):
        # Get the GtkUIManager
        manager = self._window.get_ui_manager()

        # Remove the ui
        manager.remove_ui(self._ui_id)

        # Remove the action group
        manager.remove_action_group(self._action_group)

        # Make sure the manager updates
        manager.ensure_update()

    def update_ui(self):
        self._action_group.set_sensitive(
            self._window.get_active_document() != None)

    def show_message_dialog(self, dlg, text):
        dlg.set_property('text', text)
        dlg.run()
        dlg.hide()

    def advanced_find_active(self, action):
        doc = self._window.get_active_document()
        if not doc:
            return

        try:
            start, end = doc.get_selection_bounds()
            search_text = unicode(doc.get_text(start, end))
        except:
            search_text = self.current_search_pattern

        if self.find_ui == None:
            self.find_ui = AdvancedFindUI(self._plugin)
        else:
            self.find_ui.findDialog.present()
            self.find_ui.findTextEntry.grab_focus()

        if search_text != "":
            self.find_ui.findTextEntry.child.set_text(search_text)

        if self.current_replace_text != "":
            self.find_ui.replaceTextEntry.child.set_text(
                self.current_replace_text)
        '''	
		if self.current_file_pattern != "":
			self.find_ui.filterComboboxentry.child.set_text(self.current_file_pattern)
			
		if self.current_path != "":
			self.find_ui.pathComboboxentry.child.set_text(self.current_path)
		#'''

    def create_regex(self, pattern, find_options):
        if find_options['REGEX_SEARCH'] == False:
            pattern = re.escape(unicode(r'%s' % pattern, "utf-8"))
        else:
            pattern = unicode(r'%s' % pattern, "utf-8")

        if find_options['MATCH_WHOLE_WORD'] == True:
            pattern = r'\b%s\b' % pattern

        if find_options['MATCH_CASE'] == True:
            regex = re.compile(pattern, re.MULTILINE)
        else:
            regex = re.compile(pattern, re.IGNORECASE | re.MULTILINE)

        return regex

    def advanced_find_in_doc(self,
                             doc,
                             search_pattern,
                             find_options,
                             forward_flg=True,
                             replace_flg=False,
                             around_flg=False):
        if search_pattern == "":
            return

        regex = self.create_regex(search_pattern, find_options)

        if doc.get_has_selection():
            sel_start, sel_end = doc.get_selection_bounds()
            match = regex.search(doc.get_text(sel_start, sel_end))
            if match and replace_flg == True:
                if find_options['REGEX_SEARCH'] == False:
                    replace_text = unicode(
                        self.find_ui.replaceTextEntry.get_active_text(),
                        'utf-8')
                else:
                    replace_text = match.expand(
                        unicode(
                            self.find_ui.replaceTextEntry.get_active_text(),
                            'utf-8'))
                doc.delete_selection(False, False)
                doc.insert_at_cursor(replace_text)
                replace_flg = False
            else:
                if forward_flg == True:
                    doc.place_cursor(sel_end)
                else:
                    doc.place_cursor(sel_start)

        view = self._window.get_active_view()
        start, end = doc.get_bounds()
        text = unicode(doc.get_text(start, end), 'utf-8')
        around_flg = False

        if forward_flg == True:
            start_pos = doc.get_iter_at_mark(doc.get_insert()).get_offset()
            end_pos = doc.get_end_iter().get_offset()
            match = regex.search(text, start_pos, end_pos)
            if match:
                result_start = doc.get_iter_at_offset(match.start())
                result_end = doc.get_iter_at_offset(match.end())
                doc.select_range(result_start, result_end)
                view.scroll_to_cursor()
        else:
            start_pos = doc.get_start_iter().get_offset()
            end_pos = doc.get_iter_at_mark(doc.get_insert()).get_offset()
            results = []
            match = regex.search(text, start_pos, end_pos)
            while match:
                results.append(match.span())
                start_pos = match.end() + 1
                match = regex.search(text, start_pos, end_pos)
            results_len = len(results)
            if results_len > 0:
                result_start = doc.get_iter_at_offset(results[results_len -
                                                              1][0])
                result_end = doc.get_iter_at_offset(results[results_len -
                                                            1][1])
                doc.select_range(result_start, result_end)
                view.scroll_to_cursor()

        if not doc.get_has_selection():
            if find_options['WRAP_AROUND'] == True and around_flg == False:
                if forward_flg == True:
                    doc.place_cursor(doc.get_start_iter())
                else:
                    doc.place_cursor(doc.get_end_iter())
                self.advanced_find_in_doc(doc, search_pattern, find_options,
                                          forward_flg, replace_flg, True)
            else:
                self.show_message_dialog(self.msgDialog,
                                         _("Nothing is found."))

        if replace_flg == True and doc.get_has_selection():
            if find_options['REGEX_SEARCH'] == False:
                replace_text = unicode(
                    self.find_ui.replaceTextEntry.get_active_text(), 'utf-8')
            else:
                replace_text = match.expand(
                    unicode(self.find_ui.replaceTextEntry.get_active_text(),
                            'utf-8'))
            doc.delete_selection(False, False)
            doc.insert_at_cursor(replace_text)
            replace_end = doc.get_iter_at_mark(doc.get_insert())
            replace_start = doc.get_iter_at_offset(replace_end.get_offset() -
                                                   len(replace_text))
            doc.select_range(replace_start, replace_end)
            view.scroll_to_cursor()

    def auto_select_word(self, pattern=r'[_a-zA-Z][_a-zA-Z0-9]*'):
        doc = self._window.get_active_document()
        if doc.get_has_selection():
            start, end = doc.get_selection_bounds()
            return doc.get_text(start, end)
        else:
            current_iter = doc.get_iter_at_mark(doc.get_insert())
            line_num = current_iter.get_line()
            line_start = doc.get_iter_at_line(line_num)
            line_text = doc.get_text(line_start,
                                     doc.get_iter_at_line(line_num + 1))
            line_start_pos = line_start.get_offset()
            matches = re.finditer(pattern, line_text)
            for match in matches:
                if current_iter.get_offset() in range(
                        line_start_pos + match.start(),
                        line_start_pos + match.end() + 1):
                    return match.group(0)
            return ''

    def find_next(self, action):
        self.advanced_find_in_doc(self._window.get_active_document(),
                                  self.current_search_pattern,
                                  self.find_options, True, False, False)

    def find_previous(self, action):
        self.advanced_find_in_doc(self._window.get_active_document(),
                                  self.current_search_pattern,
                                  self.find_options, False, False, False)

    def select_find_next(self, action):
        #print self.auto_select_word()
        self.advanced_find_in_doc(self._window.get_active_document(),
                                  self.auto_select_word(), self.find_options,
                                  True, False, False)

    def select_find_previous(self, action):
        #print self.auto_select_word()
        self.advanced_find_in_doc(self._window.get_active_document(),
                                  self.auto_select_word(), self.find_options,
                                  False, False, False)

    def select_find_all(self, action):
        #print self.auto_select_word()
        search_pattern = self.auto_select_word()
        it = self._results_view.append_find_pattern(search_pattern)
        self.advanced_find_all_in_doc(it, self._window.get_active_document(),
                                      search_pattern, self.find_options)
        self._results_view.show_find_result()
        self.show_bottom_panel()

    def advanced_find_all_in_doc(self,
                                 parent_it,
                                 doc,
                                 search_pattern,
                                 find_options,
                                 replace_flg=False,
                                 selection_only=False):
        if search_pattern == "":
            return

        regex = self.create_regex(search_pattern, find_options)

        self.result_highlight_off(doc)
        start, end = doc.get_bounds()
        text = unicode(doc.get_text(start, end), 'utf-8')

        start_pos = 0
        end_pos = end.get_offset()

        if selection_only == True:
            try:
                sel_start, sel_end = doc.get_selection_bounds()
            except:
                return

            if sel_start and sel_end:
                start_pos = sel_start.get_offset()
                end_pos = sel_end.get_offset()
            else:
                return

        tree_it = None
        match = regex.search(text, start_pos, end_pos)
        if match:
            if not tree_it:
                doc_uri = doc.get_uri()
                if doc_uri == None:
                    uri = ''
                else:
                    uri = urllib.unquote(doc.get_uri()).decode('utf-8')
                tab = gedit.tab_get_from_document(doc)
                tree_it = self._results_view.append_find_result_filename(
                    parent_it, doc.get_short_name_for_display(), tab, uri)

            if replace_flg == False:
                while (match):
                    line_num = doc.get_iter_at_offset(match.start()).get_line()
                    line_start_pos = doc.get_iter_at_line(
                        line_num).get_offset()
                    '''
					line_end_pos = doc.get_iter_at_line(doc.get_iter_at_offset(match.end()).get_line()+1).get_offset()
					if line_end_pos == line_start_pos:
						line_end_pos = end_pos
					#'''
                    match_end_line_cnt = doc.get_iter_at_offset(
                        match.end()).get_line() + 1
                    if match_end_line_cnt == doc.get_line_count():
                        line_end_pos = end_pos
                    else:
                        line_end_pos = doc.get_iter_at_line(
                            match_end_line_cnt).get_offset()
                    line_text = text[line_start_pos:line_end_pos]
                    self._results_view.append_find_result(
                        tree_it, str(line_num + 1), line_text, match.start(),
                        match.end() - match.start(), "", line_start_pos)
                    if match.start() == match.end():
                        start_pos = match.end() + 1
                    else:
                        start_pos = match.end()
                    if start_pos > end_pos:
                        #print 'EOF'
                        break
                    match = regex.search(text, start_pos, end_pos)
            else:
                results = []
                replace_offset = 0
                doc.begin_user_action()
                while (match):
                    if find_options['REGEX_SEARCH'] == False:
                        replace_text = unicode(
                            self.find_ui.replaceTextEntry.get_active_text(),
                            'utf-8')
                    else:
                        replace_text = match.expand(
                            unicode(
                                self.find_ui.replaceTextEntry.get_active_text(
                                ), 'utf-8'))
                    if match.start() == match.end():
                        break
                    replace_start_pos = match.start() + replace_offset
                    replace_end_pos = match.end() + replace_offset
                    replace_start = doc.get_iter_at_offset(replace_start_pos)
                    replace_end = doc.get_iter_at_offset(replace_end_pos)
                    doc.delete(replace_start, replace_end)
                    doc.insert(replace_start, replace_text)
                    replace_text_len = len(replace_text)
                    results.append([replace_start_pos, replace_text_len])
                    replace_offset += replace_text_len - (match.end() -
                                                          match.start())
                    start_pos = match.end()
                    if start_pos > end_pos:
                        #print 'EOF'
                        break
                    match = regex.search(text, start_pos, end_pos)
                doc.end_user_action()

                start, end = doc.get_bounds()
                text = unicode(doc.get_text(start, end), 'utf-8')

                for result in results:
                    line_num = doc.get_iter_at_offset(result[0]).get_line()
                    line_start_pos = doc.get_iter_at_line(
                        line_num).get_offset()
                    #line_end_pos = result[0]+result[1]
                    '''
					line_end_pos = doc.get_iter_at_line(doc.get_iter_at_offset(result[0]+result[1]).get_line()+1).get_offset()
					if line_end_pos == line_start_pos:
						line_end_pos = end_pos
					#'''
                    match_end_line_cnt = doc.get_iter_at_offset(
                        result[0] + result[1]).get_line() + 1
                    if match_end_line_cnt == doc.get_line_count():
                        line_end_pos = end_pos
                    else:
                        line_end_pos = doc.get_iter_at_line(
                            match_end_line_cnt).get_offset()
                    line_text = text[line_start_pos:line_end_pos]
                    self._results_view.append_find_result(
                        tree_it, str(line_num + 1), line_text, result[0],
                        result[1], "", line_start_pos, True)

        self.result_highlight_on(tree_it)

    def check_file_pattern(self, path, pattern_text):
        pattern_list = re.split('\s*\|\s*', pattern_text)
        for pattern in pattern_list:
            if fnmatch.fnmatch(os.path.basename(path).strip(), pattern):
                return True
        return False

    def find_all_in_dir(self,
                        parent_it,
                        dir_path,
                        file_pattern,
                        search_pattern,
                        find_options,
                        replace_flg=False):
        #start_time = time.time()
        if search_pattern == "":
            return

        #d_list = []
        file_list = []

        if find_options['INCLUDE_SUBFOLDER'] == True:
            grep_cmd = ['grep', '-E', '-l', '-R', search_pattern, dir_path]
        else:
            grep_cmd = ['grep', '-E', '-l', search_pattern, dir_path]
        p = subprocess.Popen(grep_cmd, stdout=subprocess.PIPE)
        for f in p.stdout:
            if self.check_file_pattern(f, unicode(file_pattern, 'utf-8')):
                file_list.append(f[:-1])
        '''
		for root, dirs, files in os.walk(unicode(dir_path, 'utf-8')):
			for d in dirs:
				d_list.append(os.path.join(root, d))
			for f in files:
				if self.check_file_pattern(f, unicode(file_pattern, 'utf-8')):
					if find_options['INCLUDE_SUBFOLDER'] == True:
						file_list.append(os.path.join(root, f))
					else:
						if os.path.dirname(f) not in d_list:
							file_list.append(os.path.join(root, f))
				self.find_ui.do_events()
		#'''

        #mid_time = time.time()
        #print 'Use ' + str(mid_time-start_time) + ' seconds to find files.'

        for file_path in file_list:
            if os.path.isfile(file_path):
                temp_doc = gedit.Document()
                #file_uri = "file://" + urllib.pathname2url(file_path.encode('utf-8'))
                #file_uri = ('file://' + file_path).encode('utf-8')
                file_uri = gnomevfs.get_uri_from_local_path(file_path)
                try:
                    temp_doc.load(file_uri,
                                  gedit.encoding_get_from_charset('utf-8'), 0,
                                  False)
                except:
                    print 'Can not open ' + file_uri + '.'
                    continue
                f_temp = open(file_path, 'r')
                try:
                    text = unicode(f_temp.read(), 'utf-8')
                except:
                    text = f_temp.read()
                f_temp.close()
                temp_doc.set_text(text)

                self.advanced_find_all_in_doc(parent_it, temp_doc,
                                              search_pattern, find_options,
                                              replace_flg)
                self.find_ui.do_events()

        #end_time = time.time()
        #print 'Use ' + str(end_time-mid_time) + ' seconds to find results.'
        #print 'Total use ' + str(end_time-start_time) + ' seconds.'

    def result_highlight_on(self, file_it):
        if file_it == None:
            return

        if self._results_view.findResultTreemodel.iter_has_child(file_it):
            tab = self._results_view.findResultTreemodel.get_value(file_it, 3)
            if not tab:
                return
            for n in range(
                    0,
                    self._results_view.findResultTreemodel.iter_n_children(
                        file_it)):
                it = self._results_view.findResultTreemodel.iter_nth_child(
                    file_it, n)

                result_start = self._results_view.findResultTreemodel.get_value(
                    it, 4)
                result_len = self._results_view.findResultTreemodel.get_value(
                    it, 5)
                doc = tab.get_document()
                if doc.get_tag_table().lookup('result_highlight') == None:
                    tag = doc.create_tag(
                        "result_highlight",
                        foreground=self.result_highlight['FOREGROUND_COLOR'],
                        background=self.result_highlight['BACKGROUND_COLOR'])
                doc.apply_tag_by_name(
                    'result_highlight', doc.get_iter_at_offset(result_start),
                    doc.get_iter_at_offset(result_start + result_len))

    def result_highlight_off(self, doc):
        start, end = doc.get_bounds()
        if doc.get_tag_table().lookup('result_highlight') == None:
            tag = doc.create_tag(
                "result_highlight",
                foreground=self.result_highlight['FOREGROUND_COLOR'],
                background=self.result_highlight['BACKGROUND_COLOR'])
        doc.remove_tag_by_name('result_highlight', start, end)

    def show_bottom_panel(self):
        panel = self._window.get_bottom_panel()
        if panel.get_property("visible") == False:
            panel.set_property("visible", True)
        panel.activate_item(self._results_view)

    def set_bottom_panel_label(self, text=None, icon=None):
        tab = self._results_view
        if text:
            tab.get_parent().get_tab_label(
                tab).get_children()[0].get_child().get_children()[1].set_text(
                    _(text))
        else:
            tab.get_parent().get_tab_label(
                tab).get_children()[0].get_child().get_children()[1].set_text(
                    _("Advanced Find/Replace"))
        if icon:
            tab.get_parent().get_tab_label(tab).get_children()[0].get_child(
            ).get_children()[0].set_from_animation(icon)
        else:
            tab.get_parent().get_tab_label(tab).get_children()[0].get_child(
            ).get_children()[0].set_from_icon_name('gtk-find-and-replace',
                                                   gtk.ICON_SIZE_MENU)