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