-#----------------------------------------------------------------------------
-# Name: IDEFindService.py
-# Purpose: Find Service for pydocview
-#
-# Author: Morgan Hua
-#
-# Created: 8/15/03
-# CVS-ID: $Id$
-# Copyright: (c) 2004-2005 ActiveGrid, Inc.
-# License: wxWindows License
-#----------------------------------------------------------------------------
-
-import wx
-import wx.lib.docview
-import os
-from os.path import join
-import re
-import ProjectEditor
-import MessageService
-import FindService
-import OutlineService
-_ = wx.GetTranslation
-
-
-#----------------------------------------------------------------------------
-# Constants
-#----------------------------------------------------------------------------
-FILENAME_MARKER = _("Found in file: ")
-PROJECT_MARKER = _("Searching project: ")
-FIND_MATCHDIR = "FindMatchDir"
-FIND_MATCHDIRSUBFOLDERS = "FindMatchDirSubfolders"
-
-SPACE = 10
-HALF_SPACE = 5
-
-
-class IDEFindService(FindService.FindService):
-
- #----------------------------------------------------------------------------
- # Constants
- #----------------------------------------------------------------------------
- FINDALL_ID = wx.NewId() # for bringing up Find All dialog box
- FINDDIR_ID = wx.NewId() # for bringing up Find Dir dialog box
-
-
- def InstallControls(self, frame, menuBar = None, toolBar = None, statusBar = None, document = None):
- FindService.FindService.InstallControls(self, frame, menuBar, toolBar, statusBar, document)
-
- editMenu = menuBar.GetMenu(menuBar.FindMenu(_("&Edit")))
- wx.EVT_MENU(frame, IDEFindService.FINDALL_ID, self.ProcessEvent)
- wx.EVT_UPDATE_UI(frame, IDEFindService.FINDALL_ID, self.ProcessUpdateUIEvent)
- editMenu.Append(IDEFindService.FINDALL_ID, _("Find in Project...\tCtrl+Shift+F"), _("Searches for the specified text in all the files in the project"))
- wx.EVT_MENU(frame, IDEFindService.FINDDIR_ID, self.ProcessEvent)
- wx.EVT_UPDATE_UI(frame, IDEFindService.FINDDIR_ID, self.ProcessUpdateUIEvent)
- editMenu.Append(IDEFindService.FINDDIR_ID, _("Find in Directory..."), _("Searches for the specified text in all the files in the directory"))
-
-
- def ProcessEvent(self, event):
- id = event.GetId()
- if id == IDEFindService.FINDALL_ID:
- self.ShowFindAllDialog()
- return True
- elif id == IDEFindService.FINDDIR_ID:
- self.ShowFindDirDialog()
- return True
- else:
- return FindService.FindService.ProcessEvent(self, event)
-
-
- def ProcessUpdateUIEvent(self, event):
- id = event.GetId()
- if id == IDEFindService.FINDALL_ID:
- projectService = wx.GetApp().GetService(ProjectEditor.ProjectService)
- view = projectService.GetView()
- if view and view.GetDocument() and view.GetDocument().GetFiles():
- event.Enable(True)
- else:
- event.Enable(False)
- return True
- elif id == IDEFindService.FINDDIR_ID:
- event.Enable(True)
- else:
- return FindService.FindService.ProcessUpdateUIEvent(self, event)
-
-
- def ShowFindDirDialog(self):
- config = wx.ConfigBase_Get()
-
- frame = wx.Dialog(None, -1, _("Find in Directory"), size= (320,200))
- borderSizer = wx.BoxSizer(wx.HORIZONTAL)
-
- contentSizer = wx.BoxSizer(wx.VERTICAL)
- lineSizer = wx.BoxSizer(wx.HORIZONTAL)
- lineSizer.Add(wx.StaticText(frame, -1, _("Directory:")), 0, wx.ALIGN_CENTER | wx.RIGHT, HALF_SPACE)
- dirCtrl = wx.TextCtrl(frame, -1, config.Read(FIND_MATCHDIR, ""), size=(200,-1))
- dirCtrl.SetToolTipString(dirCtrl.GetValue())
- lineSizer.Add(dirCtrl, 0, wx.LEFT, HALF_SPACE)
- findDirButton = wx.Button(frame, -1, "Browse...")
- lineSizer.Add(findDirButton, 0, wx.LEFT, HALF_SPACE)
- contentSizer.Add(lineSizer, 0, wx.BOTTOM, SPACE)
-
- def OnBrowseButton(event):
- dlg = wx.DirDialog(frame, _("Choose a directory:"), style=wx.DD_DEFAULT_STYLE)
- dir = dirCtrl.GetValue()
- if len(dir):
- dlg.SetPath(dir)
- if dlg.ShowModal() == wx.ID_OK:
- dirCtrl.SetValue(dlg.GetPath())
- dirCtrl.SetToolTipString(dirCtrl.GetValue())
- dirCtrl.SetInsertionPointEnd()
-
- dlg.Destroy()
- wx.EVT_BUTTON(findDirButton, -1, OnBrowseButton)
-
- subfolderCtrl = wx.CheckBox(frame, -1, _("Search in subfolders"))
- subfolderCtrl.SetValue(config.ReadInt(FIND_MATCHDIRSUBFOLDERS, True))
- contentSizer.Add(subfolderCtrl, 0, wx.BOTTOM, SPACE)
-
- lineSizer = wx.BoxSizer(wx.VERTICAL) # let the line expand horizontally without vertical expansion
- lineSizer.Add(wx.StaticLine(frame, -1, size = (10,-1)), 0, flag=wx.EXPAND)
- contentSizer.Add(lineSizer, flag=wx.EXPAND|wx.ALIGN_CENTER_VERTICAL|wx.BOTTOM, border=HALF_SPACE)
-
- lineSizer = wx.BoxSizer(wx.HORIZONTAL)
- lineSizer.Add(wx.StaticText(frame, -1, _("Find what:")), 0, wx.ALIGN_CENTER | wx.RIGHT, HALF_SPACE)
- findCtrl = wx.TextCtrl(frame, -1, config.Read(FindService.FIND_MATCHPATTERN, ""), size=(200,-1))
- lineSizer.Add(findCtrl, 0, wx.LEFT, HALF_SPACE)
- contentSizer.Add(lineSizer, 0, wx.BOTTOM, SPACE)
- wholeWordCtrl = wx.CheckBox(frame, -1, _("Match whole word only"))
- wholeWordCtrl.SetValue(config.ReadInt(FindService.FIND_MATCHWHOLEWORD, False))
- matchCaseCtrl = wx.CheckBox(frame, -1, _("Match case"))
- matchCaseCtrl.SetValue(config.ReadInt(FindService.FIND_MATCHCASE, False))
- regExprCtrl = wx.CheckBox(frame, -1, _("Regular expression"))
- regExprCtrl.SetValue(config.ReadInt(FindService.FIND_MATCHREGEXPR, False))
- contentSizer.Add(wholeWordCtrl, 0, wx.BOTTOM, SPACE)
- contentSizer.Add(matchCaseCtrl, 0, wx.BOTTOM, SPACE)
- contentSizer.Add(regExprCtrl, 0, wx.BOTTOM, SPACE)
- borderSizer.Add(contentSizer, 0, wx.TOP | wx.BOTTOM | wx.LEFT, SPACE)
-
- buttonSizer = wx.BoxSizer(wx.VERTICAL)
- findBtn = wx.Button(frame, wx.ID_OK, _("Find"))
- findBtn.SetDefault()
- buttonSizer.Add(findBtn, 0, wx.BOTTOM, HALF_SPACE)
- buttonSizer.Add(wx.Button(frame, wx.ID_CANCEL, _("Cancel")), 0)
- borderSizer.Add(buttonSizer, 0, wx.ALL, SPACE)
-
- frame.SetSizer(borderSizer)
- frame.Fit()
-
- status = frame.ShowModal()
-
- # save user choice state for this and other Find Dialog Boxes
- dirString = dirCtrl.GetValue()
- searchSubfolders = subfolderCtrl.IsChecked()
- self.SaveFindDirConfig(dirString, searchSubfolders)
-
- findString = findCtrl.GetValue()
- matchCase = matchCaseCtrl.IsChecked()
- wholeWord = wholeWordCtrl.IsChecked()
- regExpr = regExprCtrl.IsChecked()
- self.SaveFindConfig(findString, wholeWord, matchCase, regExpr)
-
- while not os.path.exists(dirString):
- dlg = wx.MessageDialog(frame,
- _("'%s' does not exist.") % dirString,
- _("Find in Directory"),
- wx.OK | wx.ICON_EXCLAMATION
- )
- dlg.ShowModal()
- dlg.Destroy()
-
- status = frame.ShowModal()
-
- # save user choice state for this and other Find Dialog Boxes
- dirString = dirCtrl.GetValue()
- searchSubfolders = subfolderCtrl.IsChecked()
- self.SaveFindDirConfig(dirString, searchSubfolders)
-
- findString = findCtrl.GetValue()
- matchCase = matchCaseCtrl.IsChecked()
- wholeWord = wholeWordCtrl.IsChecked()
- regExpr = regExprCtrl.IsChecked()
- self.SaveFindConfig(findString, wholeWord, matchCase, regExpr)
-
- if status == wx.ID_CANCEL:
- break
-
-
- if status == wx.ID_OK:
- frame.Destroy()
-
- messageService = wx.GetApp().GetService(MessageService.MessageService)
- messageService.ShowWindow()
-
- view = messageService.GetView()
- if view:
- wx.GetApp().GetTopWindow().SetCursor(wx.StockCursor(wx.CURSOR_WAIT))
- view.ClearLines()
- view.SetCallback(self.OnJumpToFoundLine)
-
- view.AddLines(_("Searching for '%s' in '%s'\n\n") % (findString, dirString))
-
- if os.path.isfile(dirString):
- try:
- docFile = file(dirString, 'r')
- lineNum = 1
- needToDisplayFilename = True
- line = docFile.readline()
- while line:
- count, foundStart, foundEnd, newText = self.DoFind(findString, None, line, 0, 0, True, matchCase, wholeWord, regExpr)
- if count != -1:
- if needToDisplayFilename:
- view.AddLines(FILENAME_MARKER + dirString + "\n")
- needToDisplayFilename = False
- line = repr(lineNum).zfill(4) + ":" + line
- view.AddLines(line)
- line = docFile.readline()
- lineNum += 1
- if not needToDisplayFilename:
- view.AddLines("\n")
- except IOError, (code, message):
- print _("Warning, unable to read file: '%s'. %s") % (dirString, message)
- else:
- # do search in files on disk
- for root, dirs, files in os.walk(dirString):
- if not searchSubfolders and root != dirString:
- break
-
- for name in files:
- filename = os.path.join(root, name)
- try:
- docFile = file(filename, 'r')
- except IOError, (code, message):
- print _("Warning, unable to read file: '%s'. %s") % (filename, message)
- continue
-
- lineNum = 1
- needToDisplayFilename = True
- line = docFile.readline()
- while line:
- count, foundStart, foundEnd, newText = self.DoFind(findString, None, line, 0, 0, True, matchCase, wholeWord, regExpr)
- if count != -1:
- if needToDisplayFilename:
- view.AddLines(FILENAME_MARKER + filename + "\n")
- needToDisplayFilename = False
- line = repr(lineNum).zfill(4) + ":" + line
- view.AddLines(line)
- line = docFile.readline()
- lineNum += 1
- if not needToDisplayFilename:
- view.AddLines("\n")
-
- view.AddLines(_("Search completed."))
- wx.GetApp().GetTopWindow().SetCursor(wx.StockCursor(wx.CURSOR_DEFAULT))
-
- return True
- else:
- frame.Destroy()
- return False
-
-
- def SaveFindDirConfig(self, dirString, searchSubfolders):
- """ Save search dir patterns and flags to registry.
-
- dirString = search directory
- searchSubfolders = Search subfolders
- """
- config = wx.ConfigBase_Get()
- config.Write(FIND_MATCHDIR, dirString)
- config.WriteInt(FIND_MATCHDIRSUBFOLDERS, searchSubfolders)
-
-
- def ShowFindAllDialog(self):
- config = wx.ConfigBase_Get()
-
- frame = wx.Dialog(None, -1, _("Find in Project"), size= (320,200))
- borderSizer = wx.BoxSizer(wx.HORIZONTAL)
-
- contentSizer = wx.BoxSizer(wx.VERTICAL)
- lineSizer = wx.BoxSizer(wx.HORIZONTAL)
- lineSizer.Add(wx.StaticText(frame, -1, _("Find what:")), 0, wx.ALIGN_CENTER | wx.RIGHT, HALF_SPACE)
- findCtrl = wx.TextCtrl(frame, -1, config.Read(FindService.FIND_MATCHPATTERN, ""), size=(200,-1))
- lineSizer.Add(findCtrl, 0, wx.LEFT, HALF_SPACE)
- contentSizer.Add(lineSizer, 0, wx.BOTTOM, SPACE)
- wholeWordCtrl = wx.CheckBox(frame, -1, _("Match whole word only"))
- wholeWordCtrl.SetValue(config.ReadInt(FindService.FIND_MATCHWHOLEWORD, False))
- matchCaseCtrl = wx.CheckBox(frame, -1, _("Match case"))
- matchCaseCtrl.SetValue(config.ReadInt(FindService.FIND_MATCHCASE, False))
- regExprCtrl = wx.CheckBox(frame, -1, _("Regular expression"))
- regExprCtrl.SetValue(config.ReadInt(FindService.FIND_MATCHREGEXPR, False))
- contentSizer.Add(wholeWordCtrl, 0, wx.BOTTOM, SPACE)
- contentSizer.Add(matchCaseCtrl, 0, wx.BOTTOM, SPACE)
- contentSizer.Add(regExprCtrl, 0, wx.BOTTOM, SPACE)
- borderSizer.Add(contentSizer, 0, wx.TOP | wx.BOTTOM | wx.LEFT, SPACE)
-
- buttonSizer = wx.BoxSizer(wx.VERTICAL)
- findBtn = wx.Button(frame, wx.ID_OK, _("Find"))
- findBtn.SetDefault()
- buttonSizer.Add(findBtn, 0, wx.BOTTOM, HALF_SPACE)
- buttonSizer.Add(wx.Button(frame, wx.ID_CANCEL, _("Cancel")), 0)
- borderSizer.Add(buttonSizer, 0, wx.ALL, SPACE)
-
- frame.SetSizer(borderSizer)
- frame.Fit()
-
- status = frame.ShowModal()
-
- # save user choice state for this and other Find Dialog Boxes
- findString = findCtrl.GetValue()
- matchCase = matchCaseCtrl.IsChecked()
- wholeWord = wholeWordCtrl.IsChecked()
- regExpr = regExprCtrl.IsChecked()
- self.SaveFindConfig(findString, wholeWord, matchCase, regExpr)
-
- if status == wx.ID_OK:
- frame.Destroy()
-
- messageService = wx.GetApp().GetService(MessageService.MessageService)
- messageService.ShowWindow()
-
- view = messageService.GetView()
- if view:
- view.ClearLines()
- view.SetCallback(self.OnJumpToFoundLine)
-
- projectService = wx.GetApp().GetService(ProjectEditor.ProjectService)
- projectFilenames = projectService.GetFilesFromCurrentProject()
-
- projView = projectService.GetView()
- if projView:
- projName = wx.lib.docview.FileNameFromPath(projView.GetDocument().GetFilename())
- view.AddLines(PROJECT_MARKER + projName + "\n\n")
-
- # do search in open files first, open files may have been modified and different from disk because it hasn't been saved
- openDocs = wx.GetApp().GetDocumentManager().GetDocuments()
- openDocsInProject = filter(lambda openDoc: openDoc.GetFilename() in projectFilenames, openDocs)
- for openDoc in openDocsInProject:
- if isinstance(openDoc, ProjectEditor.ProjectDocument): # don't search project model
- continue
-
- openDocView = openDoc.GetFirstView()
- # some views don't have a in memory text object to search through such as the PM and the DM
- # even if they do have a non-text searchable object, how do we display it in the message window?
- if not hasattr(openDocView, "GetValue"):
- continue
- text = openDocView.GetValue()
-
- lineNum = 1
- needToDisplayFilename = True
- start = 0
- end = 0
- count = 0
- while count != -1:
- count, foundStart, foundEnd, newText = self.DoFind(findString, None, text, start, end, True, matchCase, wholeWord, regExpr)
- if count != -1:
- if needToDisplayFilename:
- view.AddLines(FILENAME_MARKER + openDoc.GetFilename() + "\n")
- needToDisplayFilename = False
-
- lineNum = openDocView.LineFromPosition(foundStart)
- line = repr(lineNum).zfill(4) + ":" + openDocView.GetLine(lineNum)
- view.AddLines(line)
-
- start = text.find("\n", foundStart)
- if start == -1:
- break
- end = start
- if not needToDisplayFilename:
- view.AddLines("\n")
- openDocNames = map(lambda openDoc: openDoc.GetFilename(), openDocs)
-
- # do search in closed files, skipping the open ones we already searched
- filenames = filter(lambda filename: filename not in openDocNames, projectFilenames)
- for filename in filenames:
- try:
- docFile = file(filename, 'r')
- except IOError, (code, message):
- print _("Warning, unable to read file: '%s'. %s") % (filename, message)
- continue
-
- lineNum = 1
- needToDisplayFilename = True
- line = docFile.readline()
- while line:
- count, foundStart, foundEnd, newText = self.DoFind(findString, None, line, 0, 0, True, matchCase, wholeWord, regExpr)
- if count != -1:
- if needToDisplayFilename:
- view.AddLines(FILENAME_MARKER + filename + "\n")
- needToDisplayFilename = False
- line = repr(lineNum).zfill(4) + ":" + line
- view.AddLines(line)
- line = docFile.readline()
- lineNum += 1
- if not needToDisplayFilename:
- view.AddLines("\n")
-
- view.AddLines(_("Search for '%s' completed.") % findString)
-
- return True
- else:
- frame.Destroy()
- return False
-
-
- def OnJumpToFoundLine(self, event):
- messageService = wx.GetApp().GetService(MessageService.MessageService)
- lineText, pos = messageService.GetView().GetCurrLine()
- if lineText == "\n" or lineText.find(FILENAME_MARKER) != -1 or lineText.find(PROJECT_MARKER) != -1:
- return
- lineEnd = lineText.find(":")
- if lineEnd == -1:
- return
- else:
- lineNum = int(lineText[0:lineEnd])
-
- text = messageService.GetView().GetText()
- curPos = messageService.GetView().GetCurrentPos()
-
- startPos = text.rfind(FILENAME_MARKER, 0, curPos)
- endPos = text.find("\n", startPos)
- filename = text[startPos + len(FILENAME_MARKER):endPos]
-
- foundView = None
- openDocs = wx.GetApp().GetDocumentManager().GetDocuments()
- for openDoc in openDocs:
- if openDoc.GetFilename() == filename:
- foundView = openDoc.GetFirstView()
- break
-
- if not foundView:
- doc = wx.GetApp().GetDocumentManager().CreateDocument(filename, wx.lib.docview.DOC_SILENT)
- foundView = doc.GetFirstView()
-
- if foundView:
- foundView.GetFrame().SetFocus()
- foundView.Activate()
- if hasattr(foundView, "GotoLine"):
- foundView.GotoLine(lineNum)
- startPos = foundView.PositionFromLine(lineNum)
- # wxBug: Need to select in reverse order, (end, start) to put cursor at head of line so positioning is correct
- # Also, if we use the correct positioning order (start, end), somehow, when we open a edit window for the first
- # time, we don't see the selection, it is scrolled off screen
- foundView.SetSelection(startPos - 1 + len(lineText[lineEnd:].rstrip("\n")), startPos)
- wx.GetApp().GetService(OutlineService.OutlineService).LoadOutline(foundView, position=startPos)
-
-