]> git.saurik.com Git - wxWidgets.git/blob - wxPython/samples/pydocview/FindService.py
fixed wxVsnprintf() to write as much as it can if the output buffer is too short
[wxWidgets.git] / wxPython / samples / pydocview / FindService.py
1 #----------------------------------------------------------------------------
2 # Name: FindService.py
3 # Purpose: Find Service for pydocview
4 #
5 # Author: Peter Yared, Morgan Hua
6 #
7 # Created: 8/15/03
8 # CVS-ID: $Id$
9 # Copyright: (c) 2003-2005 ActiveGrid, Inc.
10 # License: wxWindows License
11 #----------------------------------------------------------------------------
12
13 import wx
14 import wx.lib.docview
15 import wx.lib.pydocview
16 import re
17 _ = wx.GetTranslation
18
19
20 #----------------------------------------------------------------------------
21 # Constants
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"
30
31 FIND_SYNTAXERROR = -2
32
33 SPACE = 10
34 HALF_SPACE = 5
35
36
37 #----------------------------------------------------------------------------
38 # Classes
39 #----------------------------------------------------------------------------
40
41 class FindService(wx.lib.pydocview.DocService):
42
43 #----------------------------------------------------------------------------
44 # Constants
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
54
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
58
59
60 def __init__(self):
61 self._replaceDialog = None
62 self._findDialog = None
63 self._findReplaceData = wx.FindReplaceData()
64 self._findReplaceData.SetFlags(wx.FR_DOWN)
65
66
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)
86
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)
90 toolBar.Realize()
91
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)
96
97
98 def ProcessUpdateUIEvent(self, event):
99 id = event.GetId()
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):
105 event.Enable(False)
106 return True
107 else:
108 return False
109
110
111 def ShowFindReplaceDialog(self, findString="", replace = False):
112 """ Display find/replace dialog box.
113
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.
116 """
117 if replace:
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
122
123 self._replaceDialog = FindReplaceDialog(self.GetDocumentManager().FindSuitableParent(), -1, _("Replace"), size=(320,200), findString=findString)
124 self._replaceDialog.CenterOnParent()
125 self._replaceDialog.Show(True)
126 else:
127 if self._replaceDialog != None:
128 # No reason to have both find and replace dialogs up at the same time
129 self._replaceDialog.DoClose()
130 self._replaceDialog = None
131
132 self._findDialog = FindDialog(self.GetDocumentManager().FindSuitableParent(), -1, _("Find"), size=(320,200), findString=findString)
133 self._findDialog.CenterOnParent()
134 self._findDialog.Show(True)
135
136
137
138 def OnFindClose(self, event):
139 """ Cleanup handles when find/replace dialog is closed """
140 if self._findDialog != None:
141 self._findDialog = None
142 elif self._replaceDialog != None:
143 self._replaceDialog = None
144
145
146 def GetCurrentDialog(self):
147 """ return handle to either the find or replace dialog """
148 if self._findDialog != None:
149 return self._findDialog
150 return self._replaceDialog
151
152
153 def GetLineNumber(self, parent):
154 """ Display Goto Line Number dialog box """
155 line = -1
156 dialog = wx.TextEntryDialog(parent, _("Enter line number to go to:"), _("Go to Line"))
157 dialog.CenterOnParent()
158 if dialog.ShowModal() == wx.ID_OK:
159 try:
160 line = int(dialog.GetValue())
161 if line > 65535:
162 line = 65535
163 except:
164 pass
165 dialog.Destroy()
166 # This one is ugly: wx.GetNumberFromUser("", _("Enter line number to go to:"), _("Go to Line"), 1, min = 1, max = 65535, parent = parent)
167 return line
168
169
170 def DoFind(self, findString, replaceString, text, startLoc, endLoc, down, matchCase, wholeWord, regExpr = False, replace = False, replaceAll = False, wrap = False):
171 """ Do the actual work of the find/replace.
172
173 Returns the tuple (count, start, end, newText).
174 count = number of string replacements
175 start = start position of found string
176 end = end position of found string
177 newText = new replaced text
178 """
179 flags = 0
180 if regExpr:
181 pattern = findString
182 else:
183 pattern = re.escape(findString) # Treat the strings as a literal string
184 if not matchCase:
185 flags = re.IGNORECASE
186 if wholeWord:
187 pattern = r"\b%s\b" % pattern
188
189 try:
190 reg = re.compile(pattern, flags)
191 except:
192 # syntax error of some sort
193 import sys
194 msgTitle = wx.GetApp().GetAppName()
195 if not msgTitle:
196 msgTitle = _("Regular Expression Search")
197 wx.MessageBox(_("Invalid regular expression \"%s\". %s") % (pattern, sys.exc_value),
198 msgTitle,
199 wx.OK | wx.ICON_EXCLAMATION,
200 self.GetView())
201 return FIND_SYNTAXERROR, None, None, None
202
203 if replaceAll:
204 newText, count = reg.subn(replaceString, text)
205 if count == 0:
206 return -1, None, None, None
207 else:
208 return count, None, None, newText
209
210 start = -1
211 if down:
212 match = reg.search(text, endLoc)
213 if match == None:
214 if wrap: # try again, but this time from top of file
215 match = reg.search(text, 0)
216 if match == None:
217 return -1, None, None, None
218 else:
219 return -1, None, None, None
220 start = match.start()
221 end = match.end()
222 else:
223 match = reg.search(text)
224 if match == None:
225 return -1, None, None, None
226 found = None
227 i, j = match.span()
228 while i < startLoc and j <= startLoc:
229 found = match
230 if i == j:
231 j = j + 1
232 match = reg.search(text, j)
233 if match == None:
234 break
235 i, j = match.span()
236 if found == None:
237 if wrap: # try again, but this time from bottom of file
238 match = reg.search(text, startLoc)
239 if match == None:
240 return -1, None, None, None
241 found = None
242 i, j = match.span()
243 end = len(text)
244 while i < end and j <= end:
245 found = match
246 if i == j:
247 j = j + 1
248 match = reg.search(text, j)
249 if match == None:
250 break
251 i, j = match.span()
252 if found == None:
253 return -1, None, None, None
254 else:
255 return -1, None, None, None
256 start = found.start()
257 end = found.end()
258
259 if replace and start != -1:
260 newText, count = reg.subn(replaceString, text, 1)
261 return count, start, end, newText
262
263 return 0, start, end, None
264
265
266 def SaveFindConfig(self, findString, wholeWord, matchCase, regExpr = None, wrap = None, upDown = None, replaceString = None):
267 """ Save find/replace patterns and search flags to registry.
268
269 findString = search pattern
270 wholeWord = match whole word only
271 matchCase = match case
272 regExpr = use regular expressions in search pattern
273 wrap = return to top/bottom of file on search
274 upDown = search up or down from current cursor position
275 replaceString = replace string
276 """
277 config = wx.ConfigBase_Get()
278
279 config.Write(FIND_MATCHPATTERN, findString)
280 config.WriteInt(FIND_MATCHCASE, matchCase)
281 config.WriteInt(FIND_MATCHWHOLEWORD, wholeWord)
282 if replaceString != None:
283 config.Write(FIND_MATCHREPLACE, replaceString)
284 if regExpr != None:
285 config.WriteInt(FIND_MATCHREGEXPR, regExpr)
286 if wrap != None:
287 config.WriteInt(FIND_MATCHWRAP, wrap)
288 if upDown != None:
289 config.WriteInt(FIND_MATCHUPDOWN, upDown)
290
291
292 def GetFindString(self):
293 """ Load the search pattern from registry """
294 return wx.ConfigBase_Get().Read(FIND_MATCHPATTERN, "")
295
296
297 def GetReplaceString(self):
298 """ Load the replace pattern from registry """
299 return wx.ConfigBase_Get().Read(FIND_MATCHREPLACE, "")
300
301
302 def GetFlags(self):
303 """ Load search parameters from registry """
304 config = wx.ConfigBase_Get()
305
306 flags = 0
307 if config.ReadInt(FIND_MATCHWHOLEWORD, False):
308 flags = flags | wx.FR_WHOLEWORD
309 if config.ReadInt(FIND_MATCHCASE, False):
310 flags = flags | wx.FR_MATCHCASE
311 if config.ReadInt(FIND_MATCHUPDOWN, False):
312 flags = flags | wx.FR_DOWN
313 if config.ReadInt(FIND_MATCHREGEXPR, False):
314 flags = flags | FindService.FR_REGEXP
315 if config.ReadInt(FIND_MATCHWRAP, False):
316 flags = flags | FindService.FR_WRAP
317 return flags
318
319
320 class FindDialog(wx.Dialog):
321 """ Find Dialog with regular expression matching and wrap to top/bottom of file. """
322
323 def __init__(self, parent, id, title, size, findString=None):
324 wx.Dialog.__init__(self, parent, id, title, size=size)
325
326 config = wx.ConfigBase_Get()
327 borderSizer = wx.BoxSizer(wx.VERTICAL)
328 gridSizer = wx.GridBagSizer(SPACE, SPACE)
329
330 lineSizer = wx.BoxSizer(wx.HORIZONTAL)
331 lineSizer.Add(wx.StaticText(self, -1, _("Find what:")), 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT, SPACE)
332 if not findString:
333 findString = config.Read(FIND_MATCHPATTERN, "")
334 self._findCtrl = wx.TextCtrl(self, -1, findString, size=(200,-1))
335 lineSizer.Add(self._findCtrl, 0)
336 gridSizer.Add(lineSizer, pos=(0,0), span=(1,2))
337 choiceSizer = wx.BoxSizer(wx.VERTICAL)
338 self._wholeWordCtrl = wx.CheckBox(self, -1, _("Match whole word only"))
339 self._wholeWordCtrl.SetValue(config.ReadInt(FIND_MATCHWHOLEWORD, False))
340 self._matchCaseCtrl = wx.CheckBox(self, -1, _("Match case"))
341 self._matchCaseCtrl.SetValue(config.ReadInt(FIND_MATCHCASE, False))
342 self._regExprCtrl = wx.CheckBox(self, -1, _("Regular expression"))
343 self._regExprCtrl.SetValue(config.ReadInt(FIND_MATCHREGEXPR, False))
344 self._wrapCtrl = wx.CheckBox(self, -1, _("Wrap"))
345 self._wrapCtrl.SetValue(config.ReadInt(FIND_MATCHWRAP, False))
346 choiceSizer.Add(self._wholeWordCtrl, 0, wx.BOTTOM, SPACE)
347 choiceSizer.Add(self._matchCaseCtrl, 0, wx.BOTTOM, SPACE)
348 choiceSizer.Add(self._regExprCtrl, 0, wx.BOTTOM, SPACE)
349 choiceSizer.Add(self._wrapCtrl, 0)
350 gridSizer.Add(choiceSizer, pos=(1,0), span=(2,1))
351
352 self._radioBox = wx.RadioBox(self, -1, _("Direction"), choices = ["Up", "Down"])
353 self._radioBox.SetSelection(config.ReadInt(FIND_MATCHUPDOWN, 1))
354 gridSizer.Add(self._radioBox, pos=(1,1), span=(2,1))
355
356 buttonSizer = wx.BoxSizer(wx.VERTICAL)
357 findBtn = wx.Button(self, FindService.FINDONE_ID, _("Find Next"))
358 findBtn.SetDefault()
359 wx.EVT_BUTTON(self, FindService.FINDONE_ID, self.OnActionEvent)
360 cancelBtn = wx.Button(self, wx.ID_CANCEL)
361 wx.EVT_BUTTON(self, wx.ID_CANCEL, self.OnClose)
362 BTM_SPACE = HALF_SPACE
363 if wx.Platform == "__WXMAC__":
364 BTM_SPACE = SPACE
365 buttonSizer.Add(findBtn, 0, wx.BOTTOM, BTM_SPACE)
366 buttonSizer.Add(cancelBtn, 0)
367 gridSizer.Add(buttonSizer, pos=(0,2), span=(3,1))
368
369 borderSizer.Add(gridSizer, 0, wx.ALL, SPACE)
370
371 self.Bind(wx.EVT_CLOSE, self.OnClose)
372
373 self.SetSizer(borderSizer)
374 self.Fit()
375 self._findCtrl.SetFocus()
376
377 def SaveConfig(self):
378 """ Save find patterns and search flags to registry. """
379 findService = wx.GetApp().GetService(FindService)
380 if findService:
381 findService.SaveFindConfig(self._findCtrl.GetValue(),
382 self._wholeWordCtrl.IsChecked(),
383 self._matchCaseCtrl.IsChecked(),
384 self._regExprCtrl.IsChecked(),
385 self._wrapCtrl.IsChecked(),
386 self._radioBox.GetSelection(),
387 )
388
389
390 def DoClose(self):
391 self.SaveConfig()
392 self.Destroy()
393
394
395 def OnClose(self, event):
396 findService = wx.GetApp().GetService(FindService)
397 if findService:
398 findService.OnFindClose(event)
399 self.DoClose()
400
401
402 def OnActionEvent(self, event):
403 self.SaveConfig()
404
405 if wx.GetApp().GetDocumentManager().GetFlags() & wx.lib.docview.DOC_MDI:
406 if wx.GetApp().GetTopWindow().ProcessEvent(event):
407 return True
408 else:
409 view = wx.GetApp().GetDocumentManager().GetLastActiveView()
410 if view and view.ProcessEvent(event):
411 return True
412 return False
413
414
415 class FindReplaceDialog(FindDialog):
416 """ Find/Replace Dialog with regular expression matching and wrap to top/bottom of file. """
417
418 def __init__(self, parent, id, title, size, findString=None):
419 wx.Dialog.__init__(self, parent, id, title, size=size)
420
421 config = wx.ConfigBase_Get()
422 borderSizer = wx.BoxSizer(wx.VERTICAL)
423 gridSizer = wx.GridBagSizer(SPACE, SPACE)
424
425 gridSizer2 = wx.GridBagSizer(SPACE, SPACE)
426 gridSizer2.Add(wx.StaticText(self, -1, _("Find what:")), flag=wx.ALIGN_CENTER_VERTICAL, pos=(0,0))
427 if not findString:
428 findString = config.Read(FIND_MATCHPATTERN, "")
429 self._findCtrl = wx.TextCtrl(self, -1, findString, size=(200,-1))
430 gridSizer2.Add(self._findCtrl, pos=(0,1))
431 gridSizer2.Add(wx.StaticText(self, -1, _("Replace with:")), flag=wx.ALIGN_CENTER_VERTICAL, pos=(1,0))
432 self._replaceCtrl = wx.TextCtrl(self, -1, config.Read(FIND_MATCHREPLACE, ""), size=(200,-1))
433 gridSizer2.Add(self._replaceCtrl, pos=(1,1))
434 gridSizer.Add(gridSizer2, pos=(0,0), span=(1,2))
435 choiceSizer = wx.BoxSizer(wx.VERTICAL)
436 self._wholeWordCtrl = wx.CheckBox(self, -1, _("Match whole word only"))
437 self._wholeWordCtrl.SetValue(config.ReadInt(FIND_MATCHWHOLEWORD, False))
438 self._matchCaseCtrl = wx.CheckBox(self, -1, _("Match case"))
439 self._matchCaseCtrl.SetValue(config.ReadInt(FIND_MATCHCASE, False))
440 self._regExprCtrl = wx.CheckBox(self, -1, _("Regular expression"))
441 self._regExprCtrl.SetValue(config.ReadInt(FIND_MATCHREGEXPR, False))
442 self._wrapCtrl = wx.CheckBox(self, -1, _("Wrap"))
443 self._wrapCtrl.SetValue(config.ReadInt(FIND_MATCHWRAP, False))
444 choiceSizer.Add(self._wholeWordCtrl, 0, wx.BOTTOM, SPACE)
445 choiceSizer.Add(self._matchCaseCtrl, 0, wx.BOTTOM, SPACE)
446 choiceSizer.Add(self._regExprCtrl, 0, wx.BOTTOM, SPACE)
447 choiceSizer.Add(self._wrapCtrl, 0)
448 gridSizer.Add(choiceSizer, pos=(1,0), span=(2,1))
449
450 self._radioBox = wx.RadioBox(self, -1, _("Direction"), choices = ["Up", "Down"])
451 self._radioBox.SetSelection(config.ReadInt(FIND_MATCHUPDOWN, 1))
452 gridSizer.Add(self._radioBox, pos=(1,1), span=(2,1))
453
454 buttonSizer = wx.BoxSizer(wx.VERTICAL)
455 findBtn = wx.Button(self, FindService.FINDONE_ID, _("Find Next"))
456 findBtn.SetDefault()
457 wx.EVT_BUTTON(self, FindService.FINDONE_ID, self.OnActionEvent)
458 cancelBtn = wx.Button(self, wx.ID_CANCEL)
459 wx.EVT_BUTTON(self, wx.ID_CANCEL, self.OnClose)
460 replaceBtn = wx.Button(self, FindService.REPLACEONE_ID, _("Replace"))
461 wx.EVT_BUTTON(self, FindService.REPLACEONE_ID, self.OnActionEvent)
462 replaceAllBtn = wx.Button(self, FindService.REPLACEALL_ID, _("Replace All"))
463 wx.EVT_BUTTON(self, FindService.REPLACEALL_ID, self.OnActionEvent)
464
465 BTM_SPACE = HALF_SPACE
466 if wx.Platform == "__WXMAC__":
467 BTM_SPACE = SPACE
468
469 buttonSizer.Add(findBtn, 0, wx.BOTTOM, BTM_SPACE)
470 buttonSizer.Add(replaceBtn, 0, wx.BOTTOM, BTM_SPACE)
471 buttonSizer.Add(replaceAllBtn, 0, wx.BOTTOM, BTM_SPACE)
472 buttonSizer.Add(cancelBtn, 0)
473 gridSizer.Add(buttonSizer, pos=(0,2), span=(3,1))
474
475 borderSizer.Add(gridSizer, 0, wx.ALL, SPACE)
476
477 self.Bind(wx.EVT_CLOSE, self.OnClose)
478
479 self.SetSizer(borderSizer)
480 self.Fit()
481 self._findCtrl.SetFocus()
482
483
484 def SaveConfig(self):
485 """ Save find/replace patterns and search flags to registry. """
486 findService = wx.GetApp().GetService(FindService)
487 if findService:
488 findService.SaveFindConfig(self._findCtrl.GetValue(),
489 self._wholeWordCtrl.IsChecked(),
490 self._matchCaseCtrl.IsChecked(),
491 self._regExprCtrl.IsChecked(),
492 self._wrapCtrl.IsChecked(),
493 self._radioBox.GetSelection(),
494 self._replaceCtrl.GetValue()
495 )
496
497
498 #----------------------------------------------------------------------------
499 # Menu Bitmaps - generated by encode_bitmaps.py
500 #----------------------------------------------------------------------------
501 from wx import ImageFromStream, BitmapFromImage
502 import cStringIO
503
504
505 def getFindData():
506 return \
507 '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\
508 \x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\
509 \x00\x01\xb1IDAT8\x8d\xa5\x93=o\xd3P\x14\x86\x1f\xa7\x11\x95<\xdc\xc6\xecN+5\
510 [\x86B\x99\xacLQ2Zr[\x89\xa1\xfd\x0b%\x95\x90\x00\xf1\x03\x80\x01\x98\x80\
511 \x19G\xac\x0cm\xff@Y\xd9:\xd9Ck\x94\xd6\xddb\x94\x9b\x98\xc8\xd2e1C\xe5\x8b\
512 \xdd\x14\x96\xbe\xdb=\x1f\xefy\xef\xf90\x8c\xda\x12wA\xbd\xfc\x18\xfa\x9fs\
513 \x80\xf9|\x0e\xc0\x93\xc1\x81\x01\xf0\xe6\xf5\xab\x1c`:\x9d\x02\xf0\xf6\xdd{\
514 \xa3\xc8\xa9\xddd\xec\xf5z\xb4Z\xeb\x00\x1c\x1f\x1d\xe6\x85\xdd\xf3<\x06\x83\
515 \xc1\x82\xbd\xa2 \x0cCL\xd3d<\x1e\x13\xc71\xb6m\x030\x1a\x8d\x08\x82\x00\x80\
516 \xb3\xb3s:\x9d\x8e\xce\xa9(h6\x9b8\x8e\x83m\xdb4\x1a\r\x82 \xe0\xc5\xf3g\xb9\
517 eY\xb4\xdbm\x1c\xc7Y\xe8\x81&\xf8\xf4\xf1C\xde\xedv+\xce\x97Owx\xfc\xe8k\xc5\
518 \xb6\xb7\xb7\x8b\xef\x0foW \x84\xe0\xea\xea\x02\xa5\x94n\x18\x80\x94\x92\xd9\
519 l\x02@\x96e\x95>\xd4nVO\xd3\xb9\x0e\xba\r\xa6i\xd2\xef\xf7\xf0\xfd!\xc7G\x87\
520 y\xed:)\xd5\x01J\xfd\xd6c\xfc~\x9a\xfc\x93\xe8\xf2\xf2\x02(Ma6\x9b \x84@)\
521 \xa5\t}\xff\x0b\xd0\'I~R\x14\xca\xb2L\xfb\x97\x97\xef-\xeeA!_J\x89\xeb\xba\
522 \xb8\xae\xab\xbf\x06\x7f\x97\xacP[\x87\xeb9\x0b!H\x92\ta\x18"\xa5\xd4U\xbd\
523 \xadm\xe3\xe1\x83\x8d<\x8a~\x90\xa6\xbf\x88\xe3\x18)\xa5&\xa9\x03X\x96E\xab\
524 \xb5\x8em7\xf5\xc2\x94\xb1\xba\xba\xc6\xe6\xe6\x06++\xf7\x89\xa2\xa8\xe2\xd3\
525 =89\xf9Va.\x14\x14\xd8\xdf?X VJa\x14\xd7X\xde\xef2\xbc\xadm\xe3\x7f~\xe3\xae\
526 \xe7\xfc\x07\x84;\xc5\x82\xa1m&\x95\x00\x00\x00\x00IEND\xaeB`\x82'
527
528
529 def getFindBitmap():
530 return BitmapFromImage(getFindImage())
531
532
533 def getFindImage():
534 stream = cStringIO.StringIO(getFindData())
535 return ImageFromStream(stream)
536