]> git.saurik.com Git - wxWidgets.git/blob - wxPython/samples/ide/activegrid/tool/FindInDirService.py
Add code to remove the selection (if any) in wxTextCtrl::WriteText for multi-line...
[wxWidgets.git] / wxPython / samples / ide / activegrid / tool / FindInDirService.py
1 #----------------------------------------------------------------------------
2 # Name: IDEFindService.py
3 # Purpose: Find Service for pydocview
4 #
5 # Author: Morgan Hua
6 #
7 # Created: 8/15/03
8 # CVS-ID: $Id$
9 # Copyright: (c) 2004-2005 ActiveGrid, Inc.
10 # License: wxWindows License
11 #----------------------------------------------------------------------------
12
13 import wx
14 import wx.lib.docview
15 import os
16 from os.path import join
17 import re
18 import ProjectEditor
19 import MessageService
20 import FindService
21 import OutlineService
22 _ = wx.GetTranslation
23
24
25 #----------------------------------------------------------------------------
26 # Constants
27 #----------------------------------------------------------------------------
28 FILENAME_MARKER = _("Found in file: ")
29 PROJECT_MARKER = _("Searching project: ")
30 FIND_MATCHDIR = "FindMatchDir"
31 FIND_MATCHDIRSUBFOLDERS = "FindMatchDirSubfolders"
32
33 SPACE = 10
34 HALF_SPACE = 5
35
36
37 class FindInDirService(FindService.FindService):
38
39 #----------------------------------------------------------------------------
40 # Constants
41 #----------------------------------------------------------------------------
42 FINDALL_ID = wx.NewId() # for bringing up Find All dialog box
43 FINDDIR_ID = wx.NewId() # for bringing up Find Dir dialog box
44
45
46 def InstallControls(self, frame, menuBar = None, toolBar = None, statusBar = None, document = None):
47 FindService.FindService.InstallControls(self, frame, menuBar, toolBar, statusBar, document)
48
49 editMenu = menuBar.GetMenu(menuBar.FindMenu(_("&Edit")))
50 wx.EVT_MENU(frame, FindInDirService.FINDALL_ID, self.ProcessEvent)
51 wx.EVT_UPDATE_UI(frame, FindInDirService.FINDALL_ID, self.ProcessUpdateUIEvent)
52 editMenu.Append(FindInDirService.FINDALL_ID, _("Find in Project...\tCtrl+Shift+F"), _("Searches for the specified text in all the files in the project"))
53 wx.EVT_MENU(frame, FindInDirService.FINDDIR_ID, self.ProcessEvent)
54 wx.EVT_UPDATE_UI(frame, FindInDirService.FINDDIR_ID, self.ProcessUpdateUIEvent)
55 editMenu.Append(FindInDirService.FINDDIR_ID, _("Find in Directory..."), _("Searches for the specified text in all the files in the directory"))
56
57
58 def ProcessEvent(self, event):
59 id = event.GetId()
60 if id == FindInDirService.FINDALL_ID:
61 view = wx.GetApp().GetDocumentManager().GetCurrentView()
62 if hasattr(view, "GetCtrl") and view.GetCtrl() and hasattr(view.GetCtrl(), "GetSelectedText"):
63 self.ShowFindAllDialog(view.GetCtrl().GetSelectedText())
64 else:
65 self.ShowFindAllDialog()
66 return True
67 elif id == FindInDirService.FINDDIR_ID:
68 view = wx.GetApp().GetDocumentManager().GetCurrentView()
69 if hasattr(view, "GetCtrl") and view.GetCtrl() and hasattr(view.GetCtrl(), "GetSelectedText"):
70 self.ShowFindDirDialog(view.GetCtrl().GetSelectedText())
71 else:
72 self.ShowFindDirDialog()
73 return True
74 else:
75 return FindService.FindService.ProcessEvent(self, event)
76
77
78 def ProcessUpdateUIEvent(self, event):
79 id = event.GetId()
80 if id == FindInDirService.FINDALL_ID:
81 projectService = wx.GetApp().GetService(ProjectEditor.ProjectService)
82 if projectService.GetFilesFromCurrentProject():
83 event.Enable(True)
84 else:
85 event.Enable(False)
86 return True
87 elif id == FindInDirService.FINDDIR_ID:
88 event.Enable(True)
89 else:
90 return FindService.FindService.ProcessUpdateUIEvent(self, event)
91
92
93 def ShowFindDirDialog(self, findString=None):
94 config = wx.ConfigBase_Get()
95
96 frame = wx.Dialog(wx.GetApp().GetTopWindow(), -1, _("Find in Directory"), size= (320,200))
97 borderSizer = wx.BoxSizer(wx.HORIZONTAL)
98
99 contentSizer = wx.BoxSizer(wx.VERTICAL)
100 lineSizer = wx.BoxSizer(wx.HORIZONTAL)
101 lineSizer.Add(wx.StaticText(frame, -1, _("Directory:")), 0, wx.ALIGN_CENTER | wx.RIGHT, HALF_SPACE)
102 dirCtrl = wx.TextCtrl(frame, -1, config.Read(FIND_MATCHDIR, ""), size=(200,-1))
103 dirCtrl.SetToolTipString(dirCtrl.GetValue())
104 lineSizer.Add(dirCtrl, 0, wx.LEFT, HALF_SPACE)
105 findDirButton = wx.Button(frame, -1, _("Browse..."))
106 lineSizer.Add(findDirButton, 0, wx.LEFT, HALF_SPACE)
107 contentSizer.Add(lineSizer, 0, wx.BOTTOM, SPACE)
108
109 def OnBrowseButton(event):
110 dlg = wx.DirDialog(frame, _("Choose a directory:"), style=wx.DD_DEFAULT_STYLE)
111 dir = dirCtrl.GetValue()
112 if len(dir):
113 dlg.SetPath(dir)
114 dlg.CenterOnParent()
115 if dlg.ShowModal() == wx.ID_OK:
116 dirCtrl.SetValue(dlg.GetPath())
117 dirCtrl.SetToolTipString(dirCtrl.GetValue())
118 dirCtrl.SetInsertionPointEnd()
119 dlg.Destroy()
120 wx.EVT_BUTTON(findDirButton, -1, OnBrowseButton)
121
122 subfolderCtrl = wx.CheckBox(frame, -1, _("Search in subdirectories"))
123 subfolderCtrl.SetValue(config.ReadInt(FIND_MATCHDIRSUBFOLDERS, True))
124 contentSizer.Add(subfolderCtrl, 0, wx.BOTTOM, SPACE)
125
126 lineSizer = wx.BoxSizer(wx.VERTICAL) # let the line expand horizontally without vertical expansion
127 lineSizer.Add(wx.StaticLine(frame, -1, size = (10,-1)), 0, flag=wx.EXPAND)
128 contentSizer.Add(lineSizer, flag=wx.EXPAND|wx.ALIGN_CENTER_VERTICAL|wx.BOTTOM, border=HALF_SPACE)
129
130 if wx.Platform == "__WXMAC__":
131 contentSizer.Add((-1, 10), 0, wx.EXPAND)
132
133 lineSizer = wx.BoxSizer(wx.HORIZONTAL)
134 lineSizer.Add(wx.StaticText(frame, -1, _("Find what:")), 0, wx.ALIGN_CENTER | wx.RIGHT, HALF_SPACE)
135 if not findString:
136 findString = config.Read(FindService.FIND_MATCHPATTERN, "")
137 findCtrl = wx.TextCtrl(frame, -1, findString, size=(200,-1))
138 findCtrl.SetFocus()
139 findCtrl.SetSelection(0,-1)
140 lineSizer.Add(findCtrl, 0, wx.LEFT, HALF_SPACE)
141 contentSizer.Add(lineSizer, 0, wx.BOTTOM, SPACE)
142 wholeWordCtrl = wx.CheckBox(frame, -1, _("Match whole word only"))
143 wholeWordCtrl.SetValue(config.ReadInt(FindService.FIND_MATCHWHOLEWORD, False))
144 matchCaseCtrl = wx.CheckBox(frame, -1, _("Match case"))
145 matchCaseCtrl.SetValue(config.ReadInt(FindService.FIND_MATCHCASE, False))
146 regExprCtrl = wx.CheckBox(frame, -1, _("Regular expression"))
147 regExprCtrl.SetValue(config.ReadInt(FindService.FIND_MATCHREGEXPR, False))
148 contentSizer.Add(wholeWordCtrl, 0, wx.BOTTOM, SPACE)
149 contentSizer.Add(matchCaseCtrl, 0, wx.BOTTOM, SPACE)
150 contentSizer.Add(regExprCtrl, 0, wx.BOTTOM, SPACE)
151 borderSizer.Add(contentSizer, 0, wx.TOP | wx.BOTTOM | wx.LEFT, SPACE)
152
153 buttonSizer = wx.BoxSizer(wx.VERTICAL)
154 findBtn = wx.Button(frame, wx.ID_OK, _("Find"))
155 findBtn.SetDefault()
156 BTM_SPACE = HALF_SPACE
157 if wx.Platform == "__WXMAC__":
158 BTM_SPACE = SPACE
159 buttonSizer.Add(findBtn, 0, wx.BOTTOM, BTM_SPACE)
160 buttonSizer.Add(wx.Button(frame, wx.ID_CANCEL), 0)
161 borderSizer.Add(buttonSizer, 0, wx.ALL, SPACE)
162
163 frame.SetSizer(borderSizer)
164 frame.Fit()
165
166 frame.CenterOnParent()
167 status = frame.ShowModal()
168
169 passedCheck = False
170 while status == wx.ID_OK and not passedCheck:
171 if not os.path.exists(dirCtrl.GetValue()):
172 dlg = wx.MessageDialog(frame,
173 _("'%s' does not exist.") % dirCtrl.GetValue(),
174 _("Find in Directory"),
175 wx.OK | wx.ICON_EXCLAMATION
176 )
177 dlg.CenterOnParent()
178 dlg.ShowModal()
179 dlg.Destroy()
180
181 status = frame.ShowModal()
182 elif len(findCtrl.GetValue()) == 0:
183 dlg = wx.MessageDialog(frame,
184 _("'Find what:' cannot be empty."),
185 _("Find in Directory"),
186 wx.OK | wx.ICON_EXCLAMATION
187 )
188 dlg.CenterOnParent()
189 dlg.ShowModal()
190 dlg.Destroy()
191
192 status = frame.ShowModal()
193 else:
194 passedCheck = True
195
196
197 # save user choice state for this and other Find Dialog Boxes
198 dirString = dirCtrl.GetValue()
199 searchSubfolders = subfolderCtrl.IsChecked()
200 self.SaveFindDirConfig(dirString, searchSubfolders)
201
202 findString = findCtrl.GetValue()
203 matchCase = matchCaseCtrl.IsChecked()
204 wholeWord = wholeWordCtrl.IsChecked()
205 regExpr = regExprCtrl.IsChecked()
206 self.SaveFindConfig(findString, wholeWord, matchCase, regExpr)
207
208 frame.Destroy()
209 if status == wx.ID_OK:
210 messageService = wx.GetApp().GetService(MessageService.MessageService)
211 messageService.ShowWindow()
212
213 view = messageService.GetView()
214 if view:
215 wx.GetApp().GetTopWindow().SetCursor(wx.StockCursor(wx.CURSOR_WAIT))
216 view.ClearLines()
217 view.SetCallback(self.OnJumpToFoundLine)
218
219 view.AddLines(_("Searching for '%s' in '%s'\n\n") % (findString, dirString))
220
221 if os.path.isfile(dirString):
222 try:
223 docFile = file(dirString, 'r')
224 lineNum = 1
225 needToDisplayFilename = True
226 line = docFile.readline()
227 while line:
228 count, foundStart, foundEnd, newText = self.DoFind(findString, None, line, 0, 0, True, matchCase, wholeWord, regExpr)
229 if count != -1:
230 if needToDisplayFilename:
231 view.AddLines(FILENAME_MARKER + dirString + "\n")
232 needToDisplayFilename = False
233 line = repr(lineNum).zfill(4) + ":" + line
234 view.AddLines(line)
235 line = docFile.readline()
236 lineNum += 1
237 if not needToDisplayFilename:
238 view.AddLines("\n")
239 except IOError, (code, message):
240 print _("Warning, unable to read file: '%s'. %s") % (dirString, message)
241 else:
242 # do search in files on disk
243 for root, dirs, files in os.walk(dirString):
244 if not searchSubfolders and root != dirString:
245 break
246
247 for name in files:
248 filename = os.path.join(root, name)
249 try:
250 docFile = file(filename, 'r')
251 except IOError, (code, message):
252 print _("Warning, unable to read file: '%s'. %s") % (filename, message)
253 continue
254
255 lineNum = 1
256 needToDisplayFilename = True
257 line = docFile.readline()
258 while line:
259 count, foundStart, foundEnd, newText = self.DoFind(findString, None, line, 0, 0, True, matchCase, wholeWord, regExpr)
260 if count != -1:
261 if needToDisplayFilename:
262 view.AddLines(FILENAME_MARKER + filename + "\n")
263 needToDisplayFilename = False
264 line = repr(lineNum).zfill(4) + ":" + line
265 view.AddLines(line)
266 line = docFile.readline()
267 lineNum += 1
268 if not needToDisplayFilename:
269 view.AddLines("\n")
270
271 view.AddLines(_("Search completed."))
272 wx.GetApp().GetTopWindow().SetCursor(wx.StockCursor(wx.CURSOR_DEFAULT))
273
274 return True
275 else:
276 return False
277
278
279 def SaveFindDirConfig(self, dirString, searchSubfolders):
280 """ Save search dir patterns and flags to registry.
281
282 dirString = search directory
283 searchSubfolders = Search subfolders
284 """
285 config = wx.ConfigBase_Get()
286 config.Write(FIND_MATCHDIR, dirString)
287 config.WriteInt(FIND_MATCHDIRSUBFOLDERS, searchSubfolders)
288
289
290 def ShowFindAllDialog(self, findString=None):
291 config = wx.ConfigBase_Get()
292
293 frame = wx.Dialog(wx.GetApp().GetTopWindow(), -1, _("Find in Project"), size= (320,200))
294 borderSizer = wx.BoxSizer(wx.HORIZONTAL)
295
296 contentSizer = wx.BoxSizer(wx.VERTICAL)
297 lineSizer = wx.BoxSizer(wx.HORIZONTAL)
298 lineSizer.Add(wx.StaticText(frame, -1, _("Find what:")), 0, wx.ALIGN_CENTER | wx.RIGHT, HALF_SPACE)
299 if not findString:
300 findString = config.Read(FindService.FIND_MATCHPATTERN, "")
301 findCtrl = wx.TextCtrl(frame, -1, findString, size=(200,-1))
302 lineSizer.Add(findCtrl, 0, wx.LEFT, HALF_SPACE)
303 contentSizer.Add(lineSizer, 0, wx.BOTTOM, SPACE)
304 wholeWordCtrl = wx.CheckBox(frame, -1, _("Match whole word only"))
305 wholeWordCtrl.SetValue(config.ReadInt(FindService.FIND_MATCHWHOLEWORD, False))
306 matchCaseCtrl = wx.CheckBox(frame, -1, _("Match case"))
307 matchCaseCtrl.SetValue(config.ReadInt(FindService.FIND_MATCHCASE, False))
308 regExprCtrl = wx.CheckBox(frame, -1, _("Regular expression"))
309 regExprCtrl.SetValue(config.ReadInt(FindService.FIND_MATCHREGEXPR, False))
310 contentSizer.Add(wholeWordCtrl, 0, wx.BOTTOM, SPACE)
311 contentSizer.Add(matchCaseCtrl, 0, wx.BOTTOM, SPACE)
312 contentSizer.Add(regExprCtrl, 0, wx.BOTTOM, SPACE)
313 borderSizer.Add(contentSizer, 0, wx.TOP | wx.BOTTOM | wx.LEFT, SPACE)
314
315 buttonSizer = wx.BoxSizer(wx.VERTICAL)
316 findBtn = wx.Button(frame, wx.ID_OK, _("Find"))
317 findBtn.SetDefault()
318 BTM_SPACE = HALF_SPACE
319 if wx.Platform == "__WXMAC__":
320 BTM_SPACE = SPACE
321 buttonSizer.Add(findBtn, 0, wx.BOTTOM, BTM_SPACE)
322 buttonSizer.Add(wx.Button(frame, wx.ID_CANCEL), 0)
323 borderSizer.Add(buttonSizer, 0, wx.ALL, SPACE)
324
325 frame.SetSizer(borderSizer)
326 frame.Fit()
327
328 frame.CenterOnParent()
329 status = frame.ShowModal()
330
331 # save user choice state for this and other Find Dialog Boxes
332 findString = findCtrl.GetValue()
333 matchCase = matchCaseCtrl.IsChecked()
334 wholeWord = wholeWordCtrl.IsChecked()
335 regExpr = regExprCtrl.IsChecked()
336 self.SaveFindConfig(findString, wholeWord, matchCase, regExpr)
337
338 frame.Destroy()
339 if status == wx.ID_OK:
340 messageService = wx.GetApp().GetService(MessageService.MessageService)
341 messageService.ShowWindow()
342
343 view = messageService.GetView()
344 if view:
345 view.ClearLines()
346 view.SetCallback(self.OnJumpToFoundLine)
347
348 projectService = wx.GetApp().GetService(ProjectEditor.ProjectService)
349 projectFilenames = projectService.GetFilesFromCurrentProject()
350
351 projView = projectService.GetView()
352 if projView:
353 projName = wx.lib.docview.FileNameFromPath(projView.GetDocument().GetFilename())
354 view.AddLines(PROJECT_MARKER + projName + "\n\n")
355
356 # do search in open files first, open files may have been modified and different from disk because it hasn't been saved
357 openDocs = wx.GetApp().GetDocumentManager().GetDocuments()
358 openDocsInProject = filter(lambda openDoc: openDoc.GetFilename() in projectFilenames, openDocs)
359 for openDoc in openDocsInProject:
360 if isinstance(openDoc, ProjectEditor.ProjectDocument): # don't search project model
361 continue
362
363 openDocView = openDoc.GetFirstView()
364 # some views don't have a in memory text object to search through such as the PM and the DM
365 # even if they do have a non-text searchable object, how do we display it in the message window?
366 if not hasattr(openDocView, "GetValue"):
367 continue
368 text = openDocView.GetValue()
369
370 lineNum = 1
371 needToDisplayFilename = True
372 start = 0
373 end = 0
374 count = 0
375 while count != -1:
376 count, foundStart, foundEnd, newText = self.DoFind(findString, None, text, start, end, True, matchCase, wholeWord, regExpr)
377 if count != -1:
378 if needToDisplayFilename:
379 view.AddLines(FILENAME_MARKER + openDoc.GetFilename() + "\n")
380 needToDisplayFilename = False
381
382 lineNum = openDocView.LineFromPosition(foundStart)
383 line = repr(lineNum).zfill(4) + ":" + openDocView.GetLine(lineNum)
384 view.AddLines(line)
385
386 start = text.find("\n", foundStart)
387 if start == -1:
388 break
389 end = start
390 if not needToDisplayFilename:
391 view.AddLines("\n")
392 openDocNames = map(lambda openDoc: openDoc.GetFilename(), openDocs)
393
394 # do search in closed files, skipping the open ones we already searched
395 filenames = filter(lambda filename: filename not in openDocNames, projectFilenames)
396 for filename in filenames:
397 try:
398 docFile = file(filename, 'r')
399 except IOError, (code, message):
400 print _("Warning, unable to read file: '%s'. %s") % (filename, message)
401 continue
402
403 lineNum = 1
404 needToDisplayFilename = True
405 line = docFile.readline()
406 while line:
407 count, foundStart, foundEnd, newText = self.DoFind(findString, None, line, 0, 0, True, matchCase, wholeWord, regExpr)
408 if count != -1:
409 if needToDisplayFilename:
410 view.AddLines(FILENAME_MARKER + filename + "\n")
411 needToDisplayFilename = False
412 line = repr(lineNum).zfill(4) + ":" + line
413 view.AddLines(line)
414 line = docFile.readline()
415 lineNum += 1
416 if not needToDisplayFilename:
417 view.AddLines("\n")
418
419 view.AddLines(_("Search for '%s' completed.") % findString)
420
421 return True
422 else:
423 return False
424
425
426 def OnJumpToFoundLine(self, event):
427 messageService = wx.GetApp().GetService(MessageService.MessageService)
428 lineText, pos = messageService.GetView().GetCurrLine()
429 if lineText == "\n" or lineText.find(FILENAME_MARKER) != -1 or lineText.find(PROJECT_MARKER) != -1:
430 return
431 lineEnd = lineText.find(":")
432 if lineEnd == -1:
433 return
434 else:
435 lineNum = int(lineText[0:lineEnd])
436
437 text = messageService.GetView().GetText()
438 curPos = messageService.GetView().GetCurrentPos()
439
440 startPos = text.rfind(FILENAME_MARKER, 0, curPos)
441 endPos = text.find("\n", startPos)
442 filename = text[startPos + len(FILENAME_MARKER):endPos]
443
444 foundView = None
445 openDocs = wx.GetApp().GetDocumentManager().GetDocuments()
446 for openDoc in openDocs:
447 if openDoc.GetFilename() == filename:
448 foundView = openDoc.GetFirstView()
449 break
450
451 if not foundView:
452 doc = wx.GetApp().GetDocumentManager().CreateDocument(filename, wx.lib.docview.DOC_SILENT|wx.lib.docview.DOC_OPEN_ONCE)
453 if doc:
454 foundView = doc.GetFirstView()
455
456 if foundView:
457 foundView.GetFrame().SetFocus()
458 foundView.Activate()
459 if hasattr(foundView, "GotoLine"):
460 foundView.GotoLine(lineNum)
461 startPos = foundView.PositionFromLine(lineNum)
462 # wxBug: Need to select in reverse order, (end, start) to put cursor at head of line so positioning is correct
463 # Also, if we use the correct positioning order (start, end), somehow, when we open a edit window for the first
464 # time, we don't see the selection, it is scrolled off screen
465 foundView.SetSelection(startPos - 1 + len(lineText[lineEnd:].rstrip("\n")), startPos)
466 wx.GetApp().GetService(OutlineService.OutlineService).LoadOutline(foundView, position=startPos)
467
468