Commit 674e8839 authored by Stephen Kennedy's avatar Stephen Kennedy

Bug 362528 – replace the find dialog box with a find bar

svn path=/trunk/; revision=1264
parent 5446e1c2
......@@ -103,11 +103,11 @@ class FileDiff(melddoc.MeldDoc, gnomeglade.Component):
self.textview_overwrite_handlers = [ t.connect("toggle-overwrite", self.on_textview_toggle_overwrite) for t in self.textview ]
self.textbuffer = [v.get_buffer() for v in self.textview]
self.bufferdata = [MeldBufferData() for b in self.textbuffer]
self.vscroll = [w.get_vscrollbar() for w in self.scrolledwindow]
for i in range(3):
w = self.scrolledwindow[i]
w.get_vadjustment().connect("value-changed", self._sync_vscroll )
w.get_hadjustment().connect("value-changed", self._sync_hscroll )
w.get_vscrollbar().connect_after("expose-event", self.on_vscroll__expose_event)
self._connect_buffer_handlers()
self._sync_vscroll_lock = False
self._sync_hscroll_lock = False
......@@ -152,10 +152,10 @@ class FileDiff(melddoc.MeldDoc, gnomeglade.Component):
self.actiongroup = gtk.ActionGroup('FilediffPopupActions')
self.actiongroup.set_translation_domain("meld")
self.actiongroup.add_actions(actions)
self.find_dialog = None
self.last_search = None
self.set_num_panes(num_panes)
gobject.idle_add( lambda *args: self.load_font()) # hack around Bug 316730
gnomeglade.connect_signal_handlers(self)
self.findbar = self.findbar.get_data("pyobject")
def on_container_switch_in_event(self, ui):
melddoc.MeldDoc.on_container_switch_in_event(self, ui)
......@@ -207,6 +207,7 @@ class FileDiff(melddoc.MeldDoc, gnomeglade.Component):
self._update_cursor_status(buffer)
def on_textview_focus_in_event(self, view, event):
self.textview_focussed = view
self.findbar.textview = view
self._update_cursor_status(view.get_buffer())
def _after_text_modified(self, buffer, startline, sizechange):
......@@ -330,6 +331,8 @@ class FileDiff(melddoc.MeldDoc, gnomeglade.Component):
w = self.pixbuf_copy0.get_width()
l.queue_draw_area(0, 0, w, a[3])
l.queue_draw_area(a[2]-w, 0, w, a[3])
elif event.keyval == gtk.keysyms.Escape:
self.findbar.hide()
def on_key_release_event(self, object, event):
x = self.keylookup.get(event.keyval, 0)
......@@ -425,50 +428,23 @@ class FileDiff(melddoc.MeldDoc, gnomeglade.Component):
return None
def on_find_activate(self, *args):
self.findbar.start_find( self.textview_focussed )
self.keymask = 0
self.queue_draw()
def on_replace_activate(self, *args):
self.findbar.start_replace( self.textview_focussed )
self.keymask = 0
self.queue_draw()
if self.find_dialog:
self.find_dialog.raise_and_focus()
else:
class FindDialog(gnomeglade.Component):
def __init__(self, app, text=None):
self.parent = app
gladefile = paths.share_dir("glade2/filediff.glade")
gnomeglade.Component.__init__(self, gladefile, "finddialog")
self.widget.set_transient_for(app.widget.get_toplevel())
self.gnome_entry_search_for.child.connect("activate", self.on_entry_search_for_activate)
if text:
self.gnome_entry_search_for.get_entry().set_text(text)
self.widget.show_all()
self.raise_and_focus()
def raise_and_focus(self):
entry = self.gnome_entry_search_for.get_entry()
entry.grab_focus()
entry.select_region(0, -1)
self.widget.present()
def on_destroy(self, *args):
self.parent.find_dialog = None
self.widget.destroy()
def on_entry_search_for_activate(self, *args):
search_text = self.gnome_entry_search_for.get_active_text()
self.gnome_entry_search_for.prepend_text(search_text)
self.parent._find_text(search_text,
self.check_case.get_active(),
self.check_word.get_active(),
self.check_wrap.get_active(),
self.check_regex.get_active() )
return 1
self.find_dialog = FindDialog(self, self.get_selected_text())
def on_find_next_activate(self, *args):
if self.last_search:
s = self.last_search
self._find_text(s.text, s.case, s.word, s.wrap, s.regex)
else:
self.on_find_activate()
self.findbar.start_find_next( self.textview_focussed )
self.keymask = 0
self.queue_draw()
def on_filediff__key_press_event(self, entry, event):
if event.keyval == gtk.keysyms.Escape:
self.findbar.hide()
def popup_in_pane(self, pane):
self.actiongroup.get_action("CopyAllLeft").set_sensitive(pane > 0)
......@@ -492,40 +468,6 @@ class FileDiff(melddoc.MeldDoc, gnomeglade.Component):
self.textview_overwrite_handlers = [ t.connect("toggle-overwrite", self.on_textview_toggle_overwrite) for t in self.textview ]
self._update_cursor_status(view.get_buffer())
#
# find/replace buffer
#
def _find_text(self, tofind_utf8, match_case=0, entire_word=0, wrap=1, regex=0):
self.last_search = misc.struct(text=tofind_utf8, case=match_case, word=entire_word, wrap=wrap, regex=regex)
pane = self._get_focused_pane()
if pane == -1:
pane = 0
buf = self.textbuffer[pane]
insert = buf.get_iter_at_mark( buf.get_insert() )
tofind = tofind_utf8.decode("utf-8") # tofind is utf-8 encoded
text = buf.get_text(*buf.get_bounds() ).decode("utf-8") # as is buffer
if not regex:
tofind = re.escape(tofind)
if entire_word:
tofind = r'\b' + tofind + r'\b'
try:
pattern = re.compile( tofind, (match_case and re.M or (re.M|re.I)) )
except re.error, e:
misc.run_dialog( _("Regular expression error\n'%s'") % e, self, messagetype=gtk.MESSAGE_ERROR)
else:
match = pattern.search(text, insert.get_offset()+1)
if match == None and wrap:
match = pattern.search(text, 0)
if match:
it = buf.get_iter_at_offset( match.start() )
buf.place_cursor( it )
it.forward_chars( match.end() - match.start() )
buf.move_mark( buf.get_selection_bound(), it )
self.textview[pane].scroll_to_mark(buf.get_insert(), 0)
elif regex:
misc.run_dialog( _("The regular expression '%s' was not found.") % tofind_utf8, self, messagetype=gtk.MESSAGE_INFO)
else:
misc.run_dialog( _("The text '%s' was not found.") % tofind_utf8, self, messagetype=gtk.MESSAGE_INFO)
#
# text buffer loading/saving
......@@ -928,6 +870,12 @@ class FileDiff(melddoc.MeldDoc, gnomeglade.Component):
return i
return -1
def _get_focused_textview(self):
for i in range(self.num_panes):
if self.textview[i].is_focus():
return self.textview[i]
return self.textview[1] if len(self.textview)>1 else self.textview[0]
def copy_selected(self, direction):
assert direction in (-1,1)
src_pane = self._get_focused_pane()
......
### Copyright (C) 2002-2009 Stephen Kennedy <stevek@gnome.org>
### This program is free software; you can redistribute it and/or modify
### it under the terms of the GNU General Public License as published by
### the Free Software Foundation; either version 2 of the License, or
### (at your option) any later version.
### This program is distributed in the hope that it will be useful,
### but WITHOUT ANY WARRANTY; without even the implied warranty of
### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
### GNU General Public License for more details.
### You should have received a copy of the GNU General Public License
### along with this program; if not, write to the Free Software
### Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
import gnomeglade
import paths
import misc
import gtk
import re
def _(x): return x
class FindBar(gnomeglade.Component):
def __init__(self):
gnomeglade.Component.__init__(self, paths.share_dir("glade2/findbar.glade"), "findbar")
gnomeglade.connect_signal_handlers(self)
self.textview = None
def hide(self):
self.textview = None
self.widget.hide()
def start_find(self, textview):
self.textview = textview
self.replace_label.hide()
self.replace_entry.hide()
self.replace_button.hide()
self.replace_all_button.hide()
self.replace_filler.hide()
self.widget.show()
self.find_entry.grab_focus()
def start_find_next(self, textview):
self.textview = textview
if self.find_entry.get_text():
self.find_button.activate()
else:
self.start_find(self.textview)
def start_replace(self, textview):
self.textview = textview
self.widget.show_all()
self.find_entry.grab_focus()
def on_find_entry__activate(self, entry):
self.find_button.activate()
def on_replace_entry__activate(self, entry):
self.replace_button.activate()
def on_find_button__activate(self, button):
self._find_text()
def on_replace_button__activate(self, entry):
buf = self.textview.get_buffer()
oldpos = buf.props.cursor_position
self._find_text(0)
if buf.props.cursor_position == oldpos:
buf.begin_user_action()
buf.delete_selection(False,False)
buf.insert_at_cursor( self.replace_entry.get_text() )
self._find_text( 0 )
buf.end_user_action()
#
# find/replace buffer
#
def _find_text(self, start_offset=1):
match_case = self.match_case.get_active()
whole_word = self.whole_word.get_active()
wrap = 1
regex = self.regex.get_active()
assert self.textview
buf = self.textview.get_buffer()
insert = buf.get_iter_at_mark( buf.get_insert() )
tofind_utf8 = self.find_entry.get_text()
tofind = tofind_utf8.decode("utf-8") # tofind is utf-8 encoded
text = buf.get_text(*buf.get_bounds() ).decode("utf-8") # as is buffer
if not regex:
tofind = re.escape(tofind)
if whole_word:
tofind = r'\b' + tofind + r'\b'
try:
pattern = re.compile( tofind, (match_case and re.M or (re.M|re.I)) )
except re.error, e:
misc.run_dialog( _("Regular expression error\n'%s'") % e, self, messagetype=gtk.MESSAGE_ERROR)
else:
match = pattern.search(text, insert.get_offset() + start_offset)
if match == None and wrap:
match = pattern.search(text, 0)
if match:
it = buf.get_iter_at_offset( match.start() )
buf.place_cursor( it )
it.forward_chars( match.end() - match.start() )
buf.move_mark( buf.get_selection_bound(), it )
self.textview.scroll_to_mark(buf.get_insert(), 0.25)
elif regex:
misc.run_dialog( _("The regular expression '%s' was not found.") % tofind_utf8, self, messagetype=gtk.MESSAGE_INFO)
else:
misc.run_dialog( _("The text '%s' was not found.") % tofind_utf8, self, messagetype=gtk.MESSAGE_INFO)
def findbar_create(str1, str2, int1, int2):
return FindBar().widget
This diff is collapsed.
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
<!--Generated with glade3 3.4.5 on Sun Mar 15 19:50:53 2009 -->
<glade-interface>
<widget class="GtkWindow" id="window1">
<child>
<widget class="GtkTable" id="findbar">
<property name="n_rows">2</property>
<property name="n_columns">6</property>
<child>
<placeholder/>
</child>
<child>
<widget class="GtkLabel" id="replace_filler">
<property name="visible">True</property>
</widget>
<packing>
<property name="left_attach">5</property>
<property name="right_attach">6</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="y_options">GTK_FILL</property>
</packing>
</child>
<child>
<widget class="GtkButton" id="replace_button">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="label" translatable="yes">_Replace</property>
<property name="use_underline">True</property>
<property name="response_id">0</property>
</widget>
<packing>
<property name="left_attach">3</property>
<property name="right_attach">4</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options">GTK_FILL</property>
</packing>
</child>
<child>
<widget class="GtkButton" id="find_button">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="label" translatable="yes">Find</property>
<property name="response_id">0</property>
</widget>
<packing>
<property name="left_attach">3</property>
<property name="right_attach">4</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options">GTK_FILL</property>
</packing>
</child>
<child>
<widget class="GtkButton" id="replace_all_button">
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="no_show_all">True</property>
<property name="label" translatable="yes">Replace _All</property>
<property name="use_underline">True</property>
<property name="response_id">0</property>
</widget>
<packing>
<property name="left_attach">4</property>
<property name="right_attach">5</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options">GTK_FILL</property>
</packing>
</child>
<child>
<widget class="GtkHBox" id="find_options">
<property name="visible">True</property>
<child>
<widget class="GtkCheckButton" id="match_case">
<property name="visible">True</property>
<property name="label" translatable="yes">_Match Case</property>
<property name="use_underline">True</property>
<property name="focus_on_click">False</property>
<property name="response_id">0</property>
<property name="draw_indicator">True</property>
</widget>
<packing>
<property name="expand">False</property>
</packing>
</child>
<child>
<widget class="GtkCheckButton" id="whole_word">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="label" translatable="yes">Who_le word</property>
<property name="use_underline">True</property>
<property name="focus_on_click">False</property>
<property name="response_id">0</property>
<property name="draw_indicator">True</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="position">1</property>
</packing>
</child>
<child>
<widget class="GtkCheckButton" id="regex">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="label" translatable="yes">Regular E_xpression</property>
<property name="use_underline">True</property>
<property name="focus_on_click">False</property>
<property name="response_id">0</property>
<property name="draw_indicator">True</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="position">2</property>
</packing>
</child>
</widget>
<packing>
<property name="left_attach">4</property>
<property name="right_attach">6</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options">GTK_FILL</property>
<property name="x_padding">7</property>
</packing>
</child>
<child>
<widget class="GtkEntry" id="replace_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
</widget>
<packing>
<property name="left_attach">2</property>
<property name="right_attach">3</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="y_options">GTK_FILL</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="replace_label">
<property name="visible">True</property>
<property name="label" translatable="yes">Replace _With</property>
<property name="use_underline">True</property>
<property name="mnemonic_widget">replace_entry</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options">GTK_FILL</property>
<property name="x_padding">3</property>
</packing>
</child>
<child>
<widget class="GtkEntry" id="find_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
</widget>
<packing>
<property name="left_attach">2</property>
<property name="right_attach">3</property>
<property name="y_options">GTK_FILL</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="find_label">
<property name="visible">True</property>
<property name="label" translatable="yes">_Search for</property>
<property name="use_underline">True</property>
<property name="mnemonic_widget">find_entry</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options">GTK_FILL</property>
<property name="x_padding">3</property>
</packing>
</child>
<child>
<widget class="GtkButton" id="findbar_close">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="focus_on_click">False</property>
<property name="response_id">0</property>
<child>
<widget class="GtkImage" id="image2">
<property name="visible">True</property>
<property name="stock">gtk-cancel</property>
<property name="icon_size">1</property>
</widget>
</child>
</widget>
<packing>
<property name="x_options">GTK_FILL</property>
<property name="y_options">GTK_FILL</property>
</packing>
</child>
</widget>
</child>
</widget>
</glade-interface>
......@@ -18,6 +18,7 @@
<separator/>
<menuitem action="Find"/>
<menuitem action="FindNext"/>
<menuitem action="Replace"/>
<separator/>
<menuitem action="Down"/>
<menuitem action="Up"/>
......
......@@ -520,6 +520,7 @@ class MeldApp(gnomeglade.Component):
("Paste", gtk.STOCK_PASTE, None, None, _("Paste the clipboard"), self.on_menu_paste_activate),
("Find", gtk.STOCK_FIND, None, None, _("Search for text"), self.on_menu_find_activate),
("FindNext", None, _("Find Ne_xt"), "<control>G", _("Search forwards for the same text"), self.on_menu_find_next_activate),
("Replace", gtk.STOCK_FIND_AND_REPLACE, _("_Replace"), "<control>H", _("Find and replace text"), self.on_menu_replace_activate),
("Down", gtk.STOCK_GO_DOWN, None, "<control>D", _("Go to the next difference"), self.on_menu_edit_down_activate),
("Up", gtk.STOCK_GO_UP, None, "<control>E", _("Go to the previous difference"), self.on_menu_edit_up_activate),
("Preferences", gtk.STOCK_PREFERENCES, _("Prefere_nces"), None, _("Configure the application"), self.on_menu_preferences_activate),
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment