# ModuleBrowser.py - A view that provides a module browser for an editor document.
import pywin.mfc.docview
import win32ui
import win32con
import commctrl
import win32api
from pywin.tools import hierlist,browser
import pywin.framework.scriptutils
import afxres
import pyclbr
class HierListCLBRModule(hierlist.HierListItem):
def __init__(self, modName, clbrdata):
self.modName = modName
self.clbrdata = clbrdata
def GetText(self):
return self.modName
def GetSubList(self):
ret = []
for item in self.clbrdata.itervalues():
if item.__class__ != pyclbr.Class: # ie, it is a pyclbr Function instance (only introduced post 1.5.2)
ret.append(HierListCLBRFunction( item ) )
else:
ret.append(HierListCLBRClass( item) )
ret.sort()
return ret
def IsExpandable(self):
return 1
class HierListCLBRItem(hierlist.HierListItem):
def __init__(self, name, file, lineno, suffix = ""):
self.name = str(name)
self.file = file
self.lineno = lineno
self.suffix = suffix
def __lt__(self, other):
return self.name < other.name
def __eq__(self, other):
return self.name == other.name
def GetText(self):
return self.name + self.suffix
def TakeDefaultAction(self):
if self.file:
pywin.framework.scriptutils.JumpToDocument(self.file, self.lineno, bScrollToTop = 1)
else:
win32ui.SetStatusText("Can not locate the source code for this object.")
def PerformItemSelected(self):
if self.file is None:
msg = "%s - source can not be located." % (self.name, )
else:
msg = "%s defined at line %d of %s" % (self.name, self.lineno, self.file)
win32ui.SetStatusText(msg)
class HierListCLBRClass(HierListCLBRItem):
def __init__(self, clbrclass, suffix = ""):
try:
name = clbrclass.name
file = clbrclass.file
lineno = clbrclass.lineno
self.super = clbrclass.super
self.methods = clbrclass.methods
except AttributeError:
name = clbrclass
file = lineno = None
self.super = []; self.methods = {}
HierListCLBRItem.__init__(self, name, file, lineno, suffix)
def GetSubList(self):
r1 = []
for c in self.super:
r1.append(HierListCLBRClass(c, " (Parent class)"))
r1.sort()
r2=[]
for meth, lineno in self.methods.iteritems():
r2.append(HierListCLBRMethod(meth, self.file, lineno))
r2.sort()
return r1+r2
def IsExpandable(self):
return len(self.methods) + len(self.super)
def GetBitmapColumn(self):
return 21
class HierListCLBRFunction(HierListCLBRItem):
def __init__(self, clbrfunc, suffix = ""):
name = clbrfunc.name
file = clbrfunc.file
lineno = clbrfunc.lineno
HierListCLBRItem.__init__(self, name, file, lineno, suffix)
def GetBitmapColumn(self):
return 22
class HierListCLBRMethod(HierListCLBRItem):
def GetBitmapColumn(self):
return 22
class HierListCLBRErrorItem(hierlist.HierListItem):
def __init__(self, text):
self.text = text
def GetText(self):
return self.text
def GetSubList(self):
return [HierListCLBRErrorItem(self.text)]
def IsExpandable(self):
return 0
class HierListCLBRErrorRoot(HierListCLBRErrorItem):
def IsExpandable(self):
return 1
class BrowserView(pywin.mfc.docview.TreeView):
def OnInitialUpdate(self):
self.list = None
rc = self._obj_.OnInitialUpdate()
self.HookMessage(self.OnSize, win32con.WM_SIZE)
self.bDirty = 0
self.destroying = 0
return rc
def DestroyBrowser(self):
self.DestroyList()
def OnActivateView(self, activate, av, dv):
# print "AV", self.bDirty, activate
if activate:
self.CheckRefreshList()
return self._obj_.OnActivateView(activate, av, dv)
def _MakeRoot(self):
path = self.GetDocument().GetPathName()
if not path:
return HierListCLBRErrorRoot("Error: Can not browse a file until it is saved")
else:
mod, path = pywin.framework.scriptutils.GetPackageModuleName(path)
if self.bDirty:
what = "Refreshing"
# Hack for pyclbr being too smart
try:
del pyclbr._modules[mod]
except (KeyError, AttributeError):
pass
else:
what = "Building"
win32ui.SetStatusText("%s class list - please wait..." % (what,), 1)
win32ui.DoWaitCursor(1)
try:
reader = pyclbr.readmodule_ex # new version post 1.5.2
except AttributeError:
reader = pyclbr.readmodule
try:
data = reader(mod, [path])
if data:
return HierListCLBRModule(mod, data)
else:
return HierListCLBRErrorRoot("No Python classes in module.")
finally:
win32ui.DoWaitCursor(0)
win32ui.SetStatusText(win32ui.LoadString(afxres.AFX_IDS_IDLEMESSAGE))
def DestroyList(self):
self.destroying = 1
list = getattr(self, "list", None) # If the document was not successfully opened, we may not have a list.
self.list = None
if list is not None:
list.HierTerm()
self.destroying = 0
def CheckMadeList(self):
if self.list is not None or self.destroying: return
self.rootitem = root = self._MakeRoot()
self.list = list = hierlist.HierListWithItems( root, win32ui.IDB_BROWSER_HIER)
list.HierInit(self.GetParentFrame(), self)
list.SetStyle(commctrl.TVS_HASLINES | commctrl.TVS_LINESATROOT | commctrl.TVS_HASBUTTONS)
def CheckRefreshList(self):
if self.bDirty:
if self.list is None:
self.CheckMadeList()
else:
new_root = self._MakeRoot()
if self.rootitem.__class__==new_root.__class__==HierListCLBRModule:
self.rootitem.modName = new_root.modName
self.rootitem.clbrdata = new_root.clbrdata
self.list.Refresh()
else:
self.list.AcceptRoot(self._MakeRoot())
self.bDirty = 0
def OnSize(self, params):
lparam = params[3]
w = win32api.LOWORD(lparam)
h = win32api.HIWORD(lparam)
if w != 0:
self.CheckMadeList()
elif w == 0:
self.DestroyList()
return 1
def _UpdateUIForState(self):
self.bDirty = 1
|