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