]>
git.saurik.com Git - wxWidgets.git/blob - wxPython/samples/pydocview/FindService.py
1 #----------------------------------------------------------------------------
3 # Purpose: Find Service for pydocview
5 # Author: Peter Yared, Morgan Hua
9 # Copyright: (c) 2003-2005 ActiveGrid, Inc.
10 # License: wxWindows License
11 #----------------------------------------------------------------------------
15 import wx
.lib
.pydocview
20 #----------------------------------------------------------------------------
22 #----------------------------------------------------------------------------
23 FIND_MATCHPATTERN
= "FindMatchPattern"
24 FIND_MATCHREPLACE
= "FindMatchReplace"
25 FIND_MATCHCASE
= "FindMatchCase"
26 FIND_MATCHWHOLEWORD
= "FindMatchWholeWordOnly"
27 FIND_MATCHREGEXPR
= "FindMatchRegularExpr"
28 FIND_MATCHWRAP
= "FindMatchWrap"
29 FIND_MATCHUPDOWN
= "FindMatchUpDown"
37 #----------------------------------------------------------------------------
39 #----------------------------------------------------------------------------
41 class FindService(wx
.lib
.pydocview
.DocService
):
43 #----------------------------------------------------------------------------
45 #----------------------------------------------------------------------------
46 FIND_ID
= wx
.NewId() # for bringing up Find dialog box
47 FINDONE_ID
= wx
.NewId() # for doing Find
48 FIND_PREVIOUS_ID
= wx
.NewId() # for doing Find Next
49 FIND_NEXT_ID
= wx
.NewId() # for doing Find Prev
50 REPLACE_ID
= wx
.NewId() # for bringing up Replace dialog box
51 REPLACEONE_ID
= wx
.NewId() # for doing a Replace
52 REPLACEALL_ID
= wx
.NewId() # for doing Replace All
53 GOTO_LINE_ID
= wx
.NewId() # for bringing up Goto dialog box
55 # Extending bitmasks: wx.FR_WHOLEWORD, wx.FR_MATCHCASE, and wx.FR_DOWN
56 FR_REGEXP
= max([wx
.FR_WHOLEWORD
, wx
.FR_MATCHCASE
, wx
.FR_DOWN
]) << 1
57 FR_WRAP
= FR_REGEXP
<< 1
61 self
._replaceDialog
= None
62 self
._findDialog
= None
63 self
._findReplaceData
= wx
.FindReplaceData()
64 self
._findReplaceData
.SetFlags(wx
.FR_DOWN
)
67 def InstallControls(self
, frame
, menuBar
= None, toolBar
= None, statusBar
= None, document
= None):
68 """ Install Find Service Menu Items """
69 editMenu
= menuBar
.GetMenu(menuBar
.FindMenu(_("&Edit")))
70 editMenu
.AppendSeparator()
71 editMenu
.Append(FindService
.FIND_ID
, _("&Find...\tCtrl+F"), _("Finds the specified text"))
72 wx
.EVT_MENU(frame
, FindService
.FIND_ID
, frame
.ProcessEvent
)
73 wx
.EVT_UPDATE_UI(frame
, FindService
.FIND_ID
, frame
.ProcessUpdateUIEvent
)
74 editMenu
.Append(FindService
.FIND_PREVIOUS_ID
, _("Find &Previous\tShift+F3"), _("Finds the specified text"))
75 wx
.EVT_MENU(frame
, FindService
.FIND_PREVIOUS_ID
, frame
.ProcessEvent
)
76 wx
.EVT_UPDATE_UI(frame
, FindService
.FIND_PREVIOUS_ID
, frame
.ProcessUpdateUIEvent
)
77 editMenu
.Append(FindService
.FIND_NEXT_ID
, _("Find &Next\tF3"), _("Finds the specified text"))
78 wx
.EVT_MENU(frame
, FindService
.FIND_NEXT_ID
, frame
.ProcessEvent
)
79 wx
.EVT_UPDATE_UI(frame
, FindService
.FIND_NEXT_ID
, frame
.ProcessUpdateUIEvent
)
80 editMenu
.Append(FindService
.REPLACE_ID
, _("R&eplace...\tCtrl+H"), _("Replaces specific text with different text"))
81 wx
.EVT_MENU(frame
, FindService
.REPLACE_ID
, frame
.ProcessEvent
)
82 wx
.EVT_UPDATE_UI(frame
, FindService
.REPLACE_ID
, frame
.ProcessUpdateUIEvent
)
83 editMenu
.Append(FindService
.GOTO_LINE_ID
, _("&Go to Line...\tCtrl+G"), _("Goes to a certain line in the file"))
84 wx
.EVT_MENU(frame
, FindService
.GOTO_LINE_ID
, frame
.ProcessEvent
)
85 wx
.EVT_UPDATE_UI(frame
, FindService
.GOTO_LINE_ID
, frame
.ProcessUpdateUIEvent
)
87 # wxBug: wxToolBar::GetToolPos doesn't exist, need it to find cut tool and then insert find in front of it.
88 toolBar
.InsertTool(6, FindService
.FIND_ID
, getFindBitmap(), shortHelpString
= _("Find"), longHelpString
= _("Finds the specified text"))
89 toolBar
.InsertSeparator(6)
92 frame
.Bind(wx
.EVT_FIND
, frame
.ProcessEvent
)
93 frame
.Bind(wx
.EVT_FIND_NEXT
, frame
.ProcessEvent
)
94 frame
.Bind(wx
.EVT_FIND_REPLACE
, frame
.ProcessEvent
)
95 frame
.Bind(wx
.EVT_FIND_REPLACE_ALL
, frame
.ProcessEvent
)
98 def ProcessUpdateUIEvent(self
, event
):
100 if (id == FindService
.FIND_ID
101 or id == FindService
.FIND_PREVIOUS_ID
102 or id == FindService
.FIND_NEXT_ID
103 or id == FindService
.REPLACE_ID
104 or id == FindService
.GOTO_LINE_ID
):
111 def ShowFindReplaceDialog(self
, findString
="", replace
= False):
112 """ Display find/replace dialog box.
114 Parameters: findString is the default value shown in the find/replace dialog input field.
115 If replace is True, the replace dialog box is shown, otherwise only the find dialog box is shown.
118 if self
._findDialog
!= None:
119 # No reason to have both find and replace dialogs up at the same time
120 self
._findDialog
.DoClose()
121 self
._findDialog
= None
123 self
._replaceDialog
= FindReplaceDialog(self
.GetDocumentManager().FindSuitableParent(), -1, _("Replace"), size
=(320,200), findString
=findString
)
124 self
._replaceDialog
.Show(True)
126 if self
._replaceDialog
!= None:
127 # No reason to have both find and replace dialogs up at the same time
128 self
._replaceDialog
.DoClose()
129 self
._replaceDialog
= None
131 self
._findDialog
= FindDialog(self
.GetDocumentManager().FindSuitableParent(), -1, _("Find"), size
=(320,200), findString
=findString
)
132 self
._findDialog
.Show(True)
136 def OnFindClose(self
, event
):
137 """ Cleanup handles when find/replace dialog is closed """
138 if self
._findDialog
!= None:
139 self
._findDialog
= None
140 elif self
._replaceDialog
!= None:
141 self
._replaceDialog
= None
144 def GetCurrentDialog(self
):
145 """ return handle to either the find or replace dialog """
146 if self
._findDialog
!= None:
147 return self
._findDialog
148 return self
._replaceDialog
151 def GetLineNumber(self
, parent
):
152 """ Display Goto Line Number dialog box """
154 dialog
= wx
.TextEntryDialog(parent
, _("Enter line number to go to:"), _("Go to Line"))
155 if dialog
.ShowModal() == wx
.ID_OK
:
157 line
= int(dialog
.GetValue())
163 # This one is ugly: wx.GetNumberFromUser("", _("Enter line number to go to:"), _("Go to Line"), 1, min = 1, max = 65535, parent = parent)
167 def DoFind(self
, findString
, replaceString
, text
, startLoc
, endLoc
, down
, matchCase
, wholeWord
, regExpr
= False, replace
= False, replaceAll
= False, wrap
= False):
168 """ Do the actual work of the find/replace.
170 Returns the tuple (count, start, end, newText).
171 count = number of string replacements
172 start = start position of found string
173 end = end position of found string
174 newText = new replaced text
180 pattern
= re
.escape(findString
) # Treat the strings as a literal string
182 flags
= re
.IGNORECASE
184 pattern
= r
"\b%s\b" % pattern
187 reg
= re
.compile(pattern
, flags
)
189 # syntax error of some sort
191 msgTitle
= wx
.GetApp().GetAppName()
193 msgTitle
= _("Regular Expression Search")
194 wx
.MessageBox(_("Invalid regular expression \"%s\". %s") % (pattern
, sys
.exc_value
),
196 wx
.OK | wx
.ICON_EXCLAMATION
,
198 return FIND_SYNTAXERROR
, None, None, None
201 newText
, count
= reg
.subn(replaceString
, text
)
203 return -1, None, None, None
205 return count
, None, None, newText
209 match
= reg
.search(text
, endLoc
)
211 if wrap
: # try again, but this time from top of file
212 match
= reg
.search(text
, 0)
214 return -1, None, None, None
216 return -1, None, None, None
217 start
= match
.start()
220 match
= reg
.search(text
)
222 return -1, None, None, None
225 while i
< startLoc
and j
<= startLoc
:
229 match
= reg
.search(text
, j
)
234 if wrap
: # try again, but this time from bottom of file
235 match
= reg
.search(text
, startLoc
)
237 return -1, None, None, None
241 while i
< end
and j
<= end
:
245 match
= reg
.search(text
, j
)
250 return -1, None, None, None
252 return -1, None, None, None
253 start
= found
.start()
256 if replace
and start
!= -1:
257 newText
, count
= reg
.subn(replaceString
, text
, 1)
258 return count
, start
, end
, newText
260 return 0, start
, end
, None
263 def SaveFindConfig(self
, findString
, wholeWord
, matchCase
, regExpr
= None, wrap
= None, upDown
= None, replaceString
= None):
264 """ Save find/replace patterns and search flags to registry.
266 findString = search pattern
267 wholeWord = match whole word only
268 matchCase = match case
269 regExpr = use regular expressions in search pattern
270 wrap = return to top/bottom of file on search
271 upDown = search up or down from current cursor position
272 replaceString = replace string
274 config
= wx
.ConfigBase_Get()
276 config
.Write(FIND_MATCHPATTERN
, findString
)
277 config
.WriteInt(FIND_MATCHCASE
, matchCase
)
278 config
.WriteInt(FIND_MATCHWHOLEWORD
, wholeWord
)
279 if replaceString
!= None:
280 config
.Write(FIND_MATCHREPLACE
, replaceString
)
282 config
.WriteInt(FIND_MATCHREGEXPR
, regExpr
)
284 config
.WriteInt(FIND_MATCHWRAP
, wrap
)
286 config
.WriteInt(FIND_MATCHUPDOWN
, upDown
)
289 def GetFindString(self
):
290 """ Load the search pattern from registry """
291 return wx
.ConfigBase_Get().Read(FIND_MATCHPATTERN
, "")
294 def GetReplaceString(self
):
295 """ Load the replace pattern from registry """
296 return wx
.ConfigBase_Get().Read(FIND_MATCHREPLACE
, "")
300 """ Load search parameters from registry """
301 config
= wx
.ConfigBase_Get()
304 if config
.ReadInt(FIND_MATCHWHOLEWORD
, False):
305 flags
= flags | wx
.FR_WHOLEWORD
306 if config
.ReadInt(FIND_MATCHCASE
, False):
307 flags
= flags | wx
.FR_MATCHCASE
308 if config
.ReadInt(FIND_MATCHUPDOWN
, False):
309 flags
= flags | wx
.FR_DOWN
310 if config
.ReadInt(FIND_MATCHREGEXPR
, False):
311 flags
= flags | FindService
.FR_REGEXP
312 if config
.ReadInt(FIND_MATCHWRAP
, False):
313 flags
= flags | FindService
.FR_WRAP
317 class FindDialog(wx
.Dialog
):
318 """ Find Dialog with regular expression matching and wrap to top/bottom of file. """
320 def __init__(self
, parent
, id, title
, size
, findString
=None):
321 wx
.Dialog
.__init
__(self
, parent
, id, title
, size
=size
)
323 config
= wx
.ConfigBase_Get()
324 borderSizer
= wx
.BoxSizer(wx
.VERTICAL
)
325 gridSizer
= wx
.GridBagSizer(SPACE
, SPACE
)
327 lineSizer
= wx
.BoxSizer(wx
.HORIZONTAL
)
328 lineSizer
.Add(wx
.StaticText(self
, -1, _("Find what:")), 0, wx
.ALIGN_CENTER_VERTICAL|wx
.RIGHT
, SPACE
)
330 findString
= config
.Read(FIND_MATCHPATTERN
, "")
331 self
._findCtrl
= wx
.TextCtrl(self
, -1, findString
, size
=(200,-1))
332 lineSizer
.Add(self
._findCtrl
, 0)
333 gridSizer
.Add(lineSizer
, pos
=(0,0), span
=(1,2))
334 choiceSizer
= wx
.BoxSizer(wx
.VERTICAL
)
335 self
._wholeWordCtrl
= wx
.CheckBox(self
, -1, _("Match whole word only"))
336 self
._wholeWordCtrl
.SetValue(config
.ReadInt(FIND_MATCHWHOLEWORD
, False))
337 self
._matchCaseCtrl
= wx
.CheckBox(self
, -1, _("Match case"))
338 self
._matchCaseCtrl
.SetValue(config
.ReadInt(FIND_MATCHCASE
, False))
339 self
._regExprCtrl
= wx
.CheckBox(self
, -1, _("Regular expression"))
340 self
._regExprCtrl
.SetValue(config
.ReadInt(FIND_MATCHREGEXPR
, False))
341 self
._wrapCtrl
= wx
.CheckBox(self
, -1, _("Wrap"))
342 self
._wrapCtrl
.SetValue(config
.ReadInt(FIND_MATCHWRAP
, False))
343 choiceSizer
.Add(self
._wholeWordCtrl
, 0, wx
.BOTTOM
, SPACE
)
344 choiceSizer
.Add(self
._matchCaseCtrl
, 0, wx
.BOTTOM
, SPACE
)
345 choiceSizer
.Add(self
._regExprCtrl
, 0, wx
.BOTTOM
, SPACE
)
346 choiceSizer
.Add(self
._wrapCtrl
, 0)
347 gridSizer
.Add(choiceSizer
, pos
=(1,0), span
=(2,1))
349 self
._radioBox
= wx
.RadioBox(self
, -1, _("Direction"), choices
= ["Up", "Down"])
350 self
._radioBox
.SetSelection(config
.ReadInt(FIND_MATCHUPDOWN
, 1))
351 gridSizer
.Add(self
._radioBox
, pos
=(1,1), span
=(2,1))
353 buttonSizer
= wx
.BoxSizer(wx
.VERTICAL
)
354 findBtn
= wx
.Button(self
, FindService
.FINDONE_ID
, _("Find Next"))
356 wx
.EVT_BUTTON(self
, FindService
.FINDONE_ID
, self
.OnActionEvent
)
357 cancelBtn
= wx
.Button(self
, wx
.ID_CANCEL
)
358 wx
.EVT_BUTTON(self
, wx
.ID_CANCEL
, self
.OnClose
)
359 buttonSizer
.Add(findBtn
, 0, wx
.BOTTOM
, HALF_SPACE
)
360 buttonSizer
.Add(cancelBtn
, 0)
361 gridSizer
.Add(buttonSizer
, pos
=(0,2), span
=(3,1))
363 borderSizer
.Add(gridSizer
, 0, wx
.ALL
, SPACE
)
365 self
.Bind(wx
.EVT_CLOSE
, self
.OnClose
)
367 self
.SetSizer(borderSizer
)
369 self
._findCtrl
.SetFocus()
371 def SaveConfig(self
):
372 """ Save find patterns and search flags to registry. """
373 findService
= wx
.GetApp().GetService(FindService
)
375 findService
.SaveFindConfig(self
._findCtrl
.GetValue(),
376 self
._wholeWordCtrl
.IsChecked(),
377 self
._matchCaseCtrl
.IsChecked(),
378 self
._regExprCtrl
.IsChecked(),
379 self
._wrapCtrl
.IsChecked(),
380 self
._radioBox
.GetSelection(),
389 def OnClose(self
, event
):
390 findService
= wx
.GetApp().GetService(FindService
)
392 findService
.OnFindClose(event
)
396 def OnActionEvent(self
, event
):
399 if wx
.GetApp().GetDocumentManager().GetFlags() & wx
.lib
.docview
.DOC_MDI
:
400 if wx
.GetApp().GetTopWindow().ProcessEvent(event
):
403 view
= wx
.GetApp().GetDocumentManager().GetLastActiveView()
404 if view
and view
.ProcessEvent(event
):
409 class FindReplaceDialog(FindDialog
):
410 """ Find/Replace Dialog with regular expression matching and wrap to top/bottom of file. """
412 def __init__(self
, parent
, id, title
, size
, findString
=None):
413 wx
.Dialog
.__init
__(self
, parent
, id, title
, size
=size
)
415 config
= wx
.ConfigBase_Get()
416 borderSizer
= wx
.BoxSizer(wx
.VERTICAL
)
417 gridSizer
= wx
.GridBagSizer(SPACE
, SPACE
)
419 gridSizer2
= wx
.GridBagSizer(SPACE
, SPACE
)
420 gridSizer2
.Add(wx
.StaticText(self
, -1, _("Find what:")), flag
=wx
.ALIGN_CENTER_VERTICAL
, pos
=(0,0))
422 findString
= config
.Read(FIND_MATCHPATTERN
, "")
423 self
._findCtrl
= wx
.TextCtrl(self
, -1, findString
, size
=(200,-1))
424 gridSizer2
.Add(self
._findCtrl
, pos
=(0,1))
425 gridSizer2
.Add(wx
.StaticText(self
, -1, _("Replace with:")), flag
=wx
.ALIGN_CENTER_VERTICAL
, pos
=(1,0))
426 self
._replaceCtrl
= wx
.TextCtrl(self
, -1, config
.Read(FIND_MATCHREPLACE
, ""), size
=(200,-1))
427 gridSizer2
.Add(self
._replaceCtrl
, pos
=(1,1))
428 gridSizer
.Add(gridSizer2
, pos
=(0,0), span
=(1,2))
429 choiceSizer
= wx
.BoxSizer(wx
.VERTICAL
)
430 self
._wholeWordCtrl
= wx
.CheckBox(self
, -1, _("Match whole word only"))
431 self
._wholeWordCtrl
.SetValue(config
.ReadInt(FIND_MATCHWHOLEWORD
, False))
432 self
._matchCaseCtrl
= wx
.CheckBox(self
, -1, _("Match case"))
433 self
._matchCaseCtrl
.SetValue(config
.ReadInt(FIND_MATCHCASE
, False))
434 self
._regExprCtrl
= wx
.CheckBox(self
, -1, _("Regular expression"))
435 self
._regExprCtrl
.SetValue(config
.ReadInt(FIND_MATCHREGEXPR
, False))
436 self
._wrapCtrl
= wx
.CheckBox(self
, -1, _("Wrap"))
437 self
._wrapCtrl
.SetValue(config
.ReadInt(FIND_MATCHWRAP
, False))
438 choiceSizer
.Add(self
._wholeWordCtrl
, 0, wx
.BOTTOM
, SPACE
)
439 choiceSizer
.Add(self
._matchCaseCtrl
, 0, wx
.BOTTOM
, SPACE
)
440 choiceSizer
.Add(self
._regExprCtrl
, 0, wx
.BOTTOM
, SPACE
)
441 choiceSizer
.Add(self
._wrapCtrl
, 0)
442 gridSizer
.Add(choiceSizer
, pos
=(1,0), span
=(2,1))
444 self
._radioBox
= wx
.RadioBox(self
, -1, _("Direction"), choices
= ["Up", "Down"])
445 self
._radioBox
.SetSelection(config
.ReadInt(FIND_MATCHUPDOWN
, 1))
446 gridSizer
.Add(self
._radioBox
, pos
=(1,1), span
=(2,1))
448 buttonSizer
= wx
.BoxSizer(wx
.VERTICAL
)
449 findBtn
= wx
.Button(self
, FindService
.FINDONE_ID
, _("Find Next"))
451 wx
.EVT_BUTTON(self
, FindService
.FINDONE_ID
, self
.OnActionEvent
)
452 cancelBtn
= wx
.Button(self
, wx
.ID_CANCEL
)
453 wx
.EVT_BUTTON(self
, wx
.ID_CANCEL
, self
.OnClose
)
454 replaceBtn
= wx
.Button(self
, FindService
.REPLACEONE_ID
, _("Replace"))
455 wx
.EVT_BUTTON(self
, FindService
.REPLACEONE_ID
, self
.OnActionEvent
)
456 replaceAllBtn
= wx
.Button(self
, FindService
.REPLACEALL_ID
, _("Replace All"))
457 wx
.EVT_BUTTON(self
, FindService
.REPLACEALL_ID
, self
.OnActionEvent
)
458 buttonSizer
.Add(findBtn
, 0, wx
.BOTTOM
, HALF_SPACE
)
459 buttonSizer
.Add(replaceBtn
, 0, wx
.BOTTOM
, HALF_SPACE
)
460 buttonSizer
.Add(replaceAllBtn
, 0, wx
.BOTTOM
, HALF_SPACE
)
461 buttonSizer
.Add(cancelBtn
, 0)
462 gridSizer
.Add(buttonSizer
, pos
=(0,2), span
=(3,1))
464 borderSizer
.Add(gridSizer
, 0, wx
.ALL
, SPACE
)
466 self
.Bind(wx
.EVT_CLOSE
, self
.OnClose
)
468 self
.SetSizer(borderSizer
)
470 self
._findCtrl
.SetFocus()
473 def SaveConfig(self
):
474 """ Save find/replace patterns and search flags to registry. """
475 findService
= wx
.GetApp().GetService(FindService
)
477 findService
.SaveFindConfig(self
._findCtrl
.GetValue(),
478 self
._wholeWordCtrl
.IsChecked(),
479 self
._matchCaseCtrl
.IsChecked(),
480 self
._regExprCtrl
.IsChecked(),
481 self
._wrapCtrl
.IsChecked(),
482 self
._radioBox
.GetSelection(),
483 self
._replaceCtrl
.GetValue()
487 #----------------------------------------------------------------------------
488 # Menu Bitmaps - generated by encode_bitmaps.py
489 #----------------------------------------------------------------------------
490 from wx
import ImageFromStream
, BitmapFromImage
496 '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\
497 \x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\
498 \x00\x00\x81IDAT8\x8d\xa5S\xc1\x16\xc0\x10\x0ckk\xff\xff\xc7d\x87\xad^U\r\
499 \x93S\xe5U$\n\xb3$:\xc1e\x17(\x19Z\xb3$\x9e\xf1DD\xe2\x15\x01x\xea\x93\xef\
500 \x04\x989\xea\x1b\xf2U\xc0\xda\xb4\xeb\x11\x1f:\xd8\xb5\xff8\x93\xd4\xa9\xae\
501 @/S\xaaUwJ3\x85\xc0\x81\xee\xeb.q\x17C\x81\xd5XU \x1a\x93\xc6\x18\x8d\x90\
502 \xe8}\x89\x00\x9a&\x9b_k\x94\x0c\xdf\xd78\xf8\x0b\x99Y\xb4\x08c\x9e\xfe\xc6\
503 \xe3\x087\xf9\xd0D\x180\xf1#\x8e\x00\x00\x00\x00IEND\xaeB`\x82'
507 return BitmapFromImage(getFindImage())
511 stream
= cStringIO
.StringIO(getFindData())
512 return ImageFromStream(stream
)