]>
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
:
103 elif id == FindService
.FIND_PREVIOUS_ID
:
106 elif id == FindService
.FIND_NEXT_ID
:
109 elif id == FindService
.REPLACE_ID
:
112 elif id == FindService
.GOTO_LINE_ID
:
119 def ShowFindReplaceDialog(self
, findString
="", replace
= False):
120 """ Display find/replace dialog box.
122 Parameters: findString is the default value shown in the find/replace dialog input field.
123 If replace is True, the replace dialog box is shown, otherwise only the find dialog box is shown.
126 if self
._findDialog
!= None:
127 # No reason to have both find and replace dialogs up at the same time
128 self
._findDialog
.DoClose()
129 self
._findDialog
= None
131 self
._replaceDialog
= FindReplaceDialog(self
.GetDocumentManager().FindSuitableParent(), -1, _("Replace"), size
=(320,200), findString
=findString
)
132 self
._replaceDialog
.Show(True)
134 if self
._replaceDialog
!= None:
135 # No reason to have both find and replace dialogs up at the same time
136 self
._replaceDialog
.DoClose()
137 self
._replaceDialog
= None
139 self
._findDialog
= FindDialog(self
.GetDocumentManager().FindSuitableParent(), -1, _("Find"), size
=(320,200), findString
=findString
)
140 self
._findDialog
.Show(True)
144 def OnFindClose(self
, event
):
145 """ Cleanup handles when find/replace dialog is closed """
146 if self
._findDialog
!= None:
147 self
._findDialog
= None
148 elif self
._replaceDialog
!= None:
149 self
._replaceDialog
= None
152 def GetCurrentDialog(self
):
153 """ return handle to either the find or replace dialog """
154 if self
._findDialog
!= None:
155 return self
._findDialog
156 return self
._replaceDialog
159 def GetLineNumber(self
, parent
):
160 """ Display Goto Line Number dialog box """
162 dialog
= wx
.TextEntryDialog(parent
, _("Enter line number to go to:"), _("Go to Line"))
163 if dialog
.ShowModal() == wx
.ID_OK
:
165 line
= int(dialog
.GetValue())
171 # This one is ugly: wx.GetNumberFromUser("", _("Enter line number to go to:"), _("Go to Line"), 1, min = 1, max = 65535, parent = parent)
175 def DoFind(self
, findString
, replaceString
, text
, startLoc
, endLoc
, down
, matchCase
, wholeWord
, regExpr
= False, replace
= False, replaceAll
= False, wrap
= False):
176 """ Do the actual work of the find/replace.
178 Returns the tuple (count, start, end, newText).
179 count = number of string replacements
180 start = start position of found string
181 end = end position of found string
182 newText = new replaced text
188 pattern
= re
.escape(findString
) # Treat the strings as a literal string
190 flags
= re
.IGNORECASE
192 pattern
= r
"\b%s\b" % pattern
195 reg
= re
.compile(pattern
, flags
)
197 # syntax error of some sort
199 msgTitle
= wx
.GetApp().GetAppName()
201 msgTitle
= _("Regular Expression Search")
202 wx
.MessageBox(_("Invalid regular expression \"%s\". %s") % (pattern
, sys
.exc_value
),
204 wx
.OK | wx
.ICON_EXCLAMATION
,
206 return FIND_SYNTAXERROR
, None, None, None
209 newText
, count
= reg
.subn(replaceString
, text
)
211 return -1, None, None, None
213 return count
, None, None, newText
217 match
= reg
.search(text
, endLoc
)
219 if wrap
: # try again, but this time from top of file
220 match
= reg
.search(text
, 0)
222 return -1, None, None, None
224 return -1, None, None, None
225 start
= match
.start()
228 match
= reg
.search(text
)
230 return -1, None, None, None
233 while i
< startLoc
and j
<= startLoc
:
237 match
= reg
.search(text
, j
)
242 if wrap
: # try again, but this time from bottom of file
243 match
= reg
.search(text
, startLoc
)
245 return -1, None, None, None
249 while i
< end
and j
<= end
:
253 match
= reg
.search(text
, j
)
258 return -1, None, None, None
260 return -1, None, None, None
261 start
= found
.start()
264 if replace
and start
!= -1:
265 newText
, count
= reg
.subn(replaceString
, text
, 1)
266 return count
, start
, end
, newText
268 return 0, start
, end
, None
271 def SaveFindConfig(self
, findString
, wholeWord
, matchCase
, regExpr
= None, wrap
= None, upDown
= None, replaceString
= None):
272 """ Save find/replace patterns and search flags to registry.
274 findString = search pattern
275 wholeWord = match whole word only
276 matchCase = match case
277 regExpr = use regular expressions in search pattern
278 wrap = return to top/bottom of file on search
279 upDown = search up or down from current cursor position
280 replaceString = replace string
282 config
= wx
.ConfigBase_Get()
284 config
.Write(FIND_MATCHPATTERN
, findString
)
285 config
.WriteInt(FIND_MATCHCASE
, matchCase
)
286 config
.WriteInt(FIND_MATCHWHOLEWORD
, wholeWord
)
287 if replaceString
!= None:
288 config
.Write(FIND_MATCHREPLACE
, replaceString
)
290 config
.WriteInt(FIND_MATCHREGEXPR
, regExpr
)
292 config
.WriteInt(FIND_MATCHWRAP
, wrap
)
294 config
.WriteInt(FIND_MATCHUPDOWN
, upDown
)
297 def GetFindString(self
):
298 """ Load the search pattern from registry """
299 return wx
.ConfigBase_Get().Read(FIND_MATCHPATTERN
, "")
302 def GetReplaceString(self
):
303 """ Load the replace pattern from registry """
304 return wx
.ConfigBase_Get().Read(FIND_MATCHREPLACE
, "")
308 """ Load search parameters from registry """
309 config
= wx
.ConfigBase_Get()
312 if config
.ReadInt(FIND_MATCHWHOLEWORD
, False):
313 flags
= flags | wx
.FR_WHOLEWORD
314 if config
.ReadInt(FIND_MATCHCASE
, False):
315 flags
= flags | wx
.FR_MATCHCASE
316 if config
.ReadInt(FIND_MATCHUPDOWN
, False):
317 flags
= flags | wx
.FR_DOWN
318 if config
.ReadInt(FIND_MATCHREGEXPR
, False):
319 flags
= flags | FindService
.FR_REGEXP
320 if config
.ReadInt(FIND_MATCHWRAP
, False):
321 flags
= flags | FindService
.FR_WRAP
325 class FindDialog(wx
.Dialog
):
326 """ Find Dialog with regular expression matching and wrap to top/bottom of file. """
328 def __init__(self
, parent
, id, title
, size
, findString
=None):
329 wx
.Dialog
.__init
__(self
, parent
, id, title
, size
=size
)
331 config
= wx
.ConfigBase_Get()
332 borderSizer
= wx
.BoxSizer(wx
.VERTICAL
)
333 gridSizer
= wx
.GridBagSizer(SPACE
, SPACE
)
335 lineSizer
= wx
.BoxSizer(wx
.HORIZONTAL
)
336 lineSizer
.Add(wx
.StaticText(self
, -1, _("Find what:")), 0, wx
.ALIGN_CENTER_VERTICAL|wx
.RIGHT
, SPACE
)
338 findString
= config
.Read(FIND_MATCHPATTERN
, "")
339 self
._findCtrl
= wx
.TextCtrl(self
, -1, findString
, size
=(200,-1))
340 lineSizer
.Add(self
._findCtrl
, 0)
341 gridSizer
.Add(lineSizer
, pos
=(0,0), span
=(1,2))
342 choiceSizer
= wx
.BoxSizer(wx
.VERTICAL
)
343 self
._wholeWordCtrl
= wx
.CheckBox(self
, -1, _("Match whole word only"))
344 self
._wholeWordCtrl
.SetValue(config
.ReadInt(FIND_MATCHWHOLEWORD
, False))
345 self
._matchCaseCtrl
= wx
.CheckBox(self
, -1, _("Match case"))
346 self
._matchCaseCtrl
.SetValue(config
.ReadInt(FIND_MATCHCASE
, False))
347 self
._regExprCtrl
= wx
.CheckBox(self
, -1, _("Regular expression"))
348 self
._regExprCtrl
.SetValue(config
.ReadInt(FIND_MATCHREGEXPR
, False))
349 self
._wrapCtrl
= wx
.CheckBox(self
, -1, _("Wrap"))
350 self
._wrapCtrl
.SetValue(config
.ReadInt(FIND_MATCHWRAP
, False))
351 choiceSizer
.Add(self
._wholeWordCtrl
, 0, wx
.BOTTOM
, SPACE
)
352 choiceSizer
.Add(self
._matchCaseCtrl
, 0, wx
.BOTTOM
, SPACE
)
353 choiceSizer
.Add(self
._regExprCtrl
, 0, wx
.BOTTOM
, SPACE
)
354 choiceSizer
.Add(self
._wrapCtrl
, 0)
355 gridSizer
.Add(choiceSizer
, pos
=(1,0), span
=(2,1))
357 self
._radioBox
= wx
.RadioBox(self
, -1, _("Direction"), choices
= ["Up", "Down"])
358 self
._radioBox
.SetSelection(config
.ReadInt(FIND_MATCHUPDOWN
, 1))
359 gridSizer
.Add(self
._radioBox
, pos
=(1,1), span
=(2,1))
361 buttonSizer
= wx
.BoxSizer(wx
.VERTICAL
)
362 findBtn
= wx
.Button(self
, FindService
.FINDONE_ID
, _("Find Next"))
364 wx
.EVT_BUTTON(self
, FindService
.FINDONE_ID
, self
.OnActionEvent
)
365 cancelBtn
= wx
.Button(self
, wx
.ID_CANCEL
, _("Cancel"))
366 wx
.EVT_BUTTON(self
, wx
.ID_CANCEL
, self
.OnClose
)
367 buttonSizer
.Add(findBtn
, 0, wx
.BOTTOM
, HALF_SPACE
)
368 buttonSizer
.Add(cancelBtn
, 0)
369 gridSizer
.Add(buttonSizer
, pos
=(0,2), span
=(3,1))
371 borderSizer
.Add(gridSizer
, 0, wx
.ALL
, SPACE
)
373 self
.Bind(wx
.EVT_CLOSE
, self
.OnClose
)
375 self
.SetSizer(borderSizer
)
377 self
._findCtrl
.SetFocus()
379 def SaveConfig(self
):
380 """ Save find patterns and search flags to registry. """
381 findService
= wx
.GetApp().GetService(FindService
)
383 findService
.SaveFindConfig(self
._findCtrl
.GetValue(),
384 self
._wholeWordCtrl
.IsChecked(),
385 self
._matchCaseCtrl
.IsChecked(),
386 self
._regExprCtrl
.IsChecked(),
387 self
._wrapCtrl
.IsChecked(),
388 self
._radioBox
.GetSelection(),
397 def OnClose(self
, event
):
398 findService
= wx
.GetApp().GetService(FindService
)
400 findService
.OnFindClose(event
)
404 def OnActionEvent(self
, event
):
407 if wx
.GetApp().GetDocumentManager().GetFlags() & wx
.lib
.docview
.DOC_MDI
:
408 if wx
.GetApp().GetTopWindow().ProcessEvent(event
):
411 view
= wx
.GetApp().GetDocumentManager().GetLastActiveView()
412 if view
and view
.ProcessEvent(event
):
417 class FindReplaceDialog(FindDialog
):
418 """ Find/Replace Dialog with regular expression matching and wrap to top/bottom of file. """
420 def __init__(self
, parent
, id, title
, size
, findString
=None):
421 wx
.Dialog
.__init
__(self
, parent
, id, title
, size
=size
)
423 config
= wx
.ConfigBase_Get()
424 borderSizer
= wx
.BoxSizer(wx
.VERTICAL
)
425 gridSizer
= wx
.GridBagSizer(SPACE
, SPACE
)
427 gridSizer2
= wx
.GridBagSizer(SPACE
, SPACE
)
428 gridSizer2
.Add(wx
.StaticText(self
, -1, _("Find what:")), flag
=wx
.ALIGN_CENTER_VERTICAL
, pos
=(0,0))
430 findString
= config
.Read(FIND_MATCHPATTERN
, "")
431 self
._findCtrl
= wx
.TextCtrl(self
, -1, findString
, size
=(200,-1))
432 gridSizer2
.Add(self
._findCtrl
, pos
=(0,1))
433 gridSizer2
.Add(wx
.StaticText(self
, -1, _("Replace with:")), flag
=wx
.ALIGN_CENTER_VERTICAL
, pos
=(1,0))
434 self
._replaceCtrl
= wx
.TextCtrl(self
, -1, config
.Read(FIND_MATCHREPLACE
, ""), size
=(200,-1))
435 gridSizer2
.Add(self
._replaceCtrl
, pos
=(1,1))
436 gridSizer
.Add(gridSizer2
, pos
=(0,0), span
=(1,2))
437 choiceSizer
= wx
.BoxSizer(wx
.VERTICAL
)
438 self
._wholeWordCtrl
= wx
.CheckBox(self
, -1, _("Match whole word only"))
439 self
._wholeWordCtrl
.SetValue(config
.ReadInt(FIND_MATCHWHOLEWORD
, False))
440 self
._matchCaseCtrl
= wx
.CheckBox(self
, -1, _("Match case"))
441 self
._matchCaseCtrl
.SetValue(config
.ReadInt(FIND_MATCHCASE
, False))
442 self
._regExprCtrl
= wx
.CheckBox(self
, -1, _("Regular expression"))
443 self
._regExprCtrl
.SetValue(config
.ReadInt(FIND_MATCHREGEXPR
, False))
444 self
._wrapCtrl
= wx
.CheckBox(self
, -1, _("Wrap"))
445 self
._wrapCtrl
.SetValue(config
.ReadInt(FIND_MATCHWRAP
, False))
446 choiceSizer
.Add(self
._wholeWordCtrl
, 0, wx
.BOTTOM
, SPACE
)
447 choiceSizer
.Add(self
._matchCaseCtrl
, 0, wx
.BOTTOM
, SPACE
)
448 choiceSizer
.Add(self
._regExprCtrl
, 0, wx
.BOTTOM
, SPACE
)
449 choiceSizer
.Add(self
._wrapCtrl
, 0)
450 gridSizer
.Add(choiceSizer
, pos
=(1,0), span
=(2,1))
452 self
._radioBox
= wx
.RadioBox(self
, -1, _("Direction"), choices
= ["Up", "Down"])
453 self
._radioBox
.SetSelection(config
.ReadInt(FIND_MATCHUPDOWN
, 1))
454 gridSizer
.Add(self
._radioBox
, pos
=(1,1), span
=(2,1))
456 buttonSizer
= wx
.BoxSizer(wx
.VERTICAL
)
457 findBtn
= wx
.Button(self
, FindService
.FINDONE_ID
, _("Find Next"))
459 wx
.EVT_BUTTON(self
, FindService
.FINDONE_ID
, self
.OnActionEvent
)
460 cancelBtn
= wx
.Button(self
, wx
.ID_CANCEL
, _("Cancel"))
461 wx
.EVT_BUTTON(self
, wx
.ID_CANCEL
, self
.OnClose
)
462 replaceBtn
= wx
.Button(self
, FindService
.REPLACEONE_ID
, _("Replace"))
463 wx
.EVT_BUTTON(self
, FindService
.REPLACEONE_ID
, self
.OnActionEvent
)
464 replaceAllBtn
= wx
.Button(self
, FindService
.REPLACEALL_ID
, _("Replace All"))
465 wx
.EVT_BUTTON(self
, FindService
.REPLACEALL_ID
, self
.OnActionEvent
)
466 buttonSizer
.Add(findBtn
, 0, wx
.BOTTOM
, HALF_SPACE
)
467 buttonSizer
.Add(replaceBtn
, 0, wx
.BOTTOM
, HALF_SPACE
)
468 buttonSizer
.Add(replaceAllBtn
, 0, wx
.BOTTOM
, HALF_SPACE
)
469 buttonSizer
.Add(cancelBtn
, 0)
470 gridSizer
.Add(buttonSizer
, pos
=(0,2), span
=(3,1))
472 borderSizer
.Add(gridSizer
, 0, wx
.ALL
, SPACE
)
474 self
.Bind(wx
.EVT_CLOSE
, self
.OnClose
)
476 self
.SetSizer(borderSizer
)
478 self
._findCtrl
.SetFocus()
481 def SaveConfig(self
):
482 """ Save find/replace patterns and search flags to registry. """
483 findService
= wx
.GetApp().GetService(FindService
)
485 findService
.SaveFindConfig(self
._findCtrl
.GetValue(),
486 self
._wholeWordCtrl
.IsChecked(),
487 self
._matchCaseCtrl
.IsChecked(),
488 self
._regExprCtrl
.IsChecked(),
489 self
._wrapCtrl
.IsChecked(),
490 self
._radioBox
.GetSelection(),
491 self
._replaceCtrl
.GetValue()
495 #----------------------------------------------------------------------------
496 # Menu Bitmaps - generated by encode_bitmaps.py
497 #----------------------------------------------------------------------------
498 from wx
import ImageFromStream
, BitmapFromImage
504 '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\
505 \x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\
506 \x00\x00\x81IDAT8\x8d\xa5S\xc1\x16\xc0\x10\x0ckk\xff\xff\xc7d\x87\xad^U\r\
507 \x93S\xe5U$\n\xb3$:\xc1e\x17(\x19Z\xb3$\x9e\xf1DD\xe2\x15\x01x\xea\x93\xef\
508 \x04\x989\xea\x1b\xf2U\xc0\xda\xb4\xeb\x11\x1f:\xd8\xb5\xff8\x93\xd4\xa9\xae\
509 @/S\xaaUwJ3\x85\xc0\x81\xee\xeb.q\x17C\x81\xd5XU \x1a\x93\xc6\x18\x8d\x90\
510 \xe8}\x89\x00\x9a&\x9b_k\x94\x0c\xdf\xd78\xf8\x0b\x99Y\xb4\x08c\x9e\xfe\xc6\
511 \xe3\x087\xf9\xd0D\x180\xf1#\x8e\x00\x00\x00\x00IEND\xaeB`\x82'
515 return BitmapFromImage(getFindImage())
519 stream
= cStringIO
.StringIO(getFindData())
520 return ImageFromStream(stream
)