325 lines
9.3 KiB
Python
325 lines
9.3 KiB
Python
import glob
|
|
import os
|
|
import pyclbr
|
|
|
|
import afxres
|
|
import commctrl
|
|
import pywin.framework.scriptutils
|
|
import regutil
|
|
import win32api
|
|
import win32con
|
|
import win32ui
|
|
from pywin.mfc import dialog
|
|
|
|
from . import hierlist
|
|
|
|
|
|
class HLIErrorItem(hierlist.HierListItem):
|
|
def __init__(self, text):
|
|
self.text = text
|
|
hierlist.HierListItem.__init__(self)
|
|
|
|
def GetText(self):
|
|
return self.text
|
|
|
|
|
|
class HLICLBRItem(hierlist.HierListItem):
|
|
def __init__(self, name, file, lineno, suffix=""):
|
|
# If the 'name' object itself has a .name, use it. Not sure
|
|
# how this happens, but seems pyclbr related.
|
|
# See PyWin32 bug 817035
|
|
self.name = getattr(name, "name", 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("The source of this object is unknown")
|
|
|
|
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 HLICLBRClass(HLICLBRItem):
|
|
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 = {}
|
|
HLICLBRItem.__init__(self, name, file, lineno, suffix)
|
|
|
|
def GetSubList(self):
|
|
ret = []
|
|
for c in self.super:
|
|
ret.append(HLICLBRClass(c, " (Parent class)"))
|
|
for meth, lineno in self.methods.items():
|
|
ret.append(HLICLBRMethod(meth, self.file, lineno, " (method)"))
|
|
return ret
|
|
|
|
def IsExpandable(self):
|
|
return len(self.methods) + len(self.super)
|
|
|
|
def GetBitmapColumn(self):
|
|
return 21
|
|
|
|
|
|
class HLICLBRFunction(HLICLBRClass):
|
|
def GetBitmapColumn(self):
|
|
return 22
|
|
|
|
|
|
class HLICLBRMethod(HLICLBRItem):
|
|
def GetBitmapColumn(self):
|
|
return 22
|
|
|
|
|
|
class HLIModuleItem(hierlist.HierListItem):
|
|
def __init__(self, path):
|
|
hierlist.HierListItem.__init__(self)
|
|
self.path = path
|
|
|
|
def GetText(self):
|
|
return os.path.split(self.path)[1] + " (module)"
|
|
|
|
def IsExpandable(self):
|
|
return 1
|
|
|
|
def TakeDefaultAction(self):
|
|
win32ui.GetApp().OpenDocumentFile(self.path)
|
|
|
|
def GetBitmapColumn(self):
|
|
col = 4 # Default
|
|
try:
|
|
if win32api.GetFileAttributes(self.path) & win32con.FILE_ATTRIBUTE_READONLY:
|
|
col = 5
|
|
except win32api.error:
|
|
pass
|
|
return col
|
|
|
|
def GetSubList(self):
|
|
mod, path = pywin.framework.scriptutils.GetPackageModuleName(self.path)
|
|
win32ui.SetStatusText("Building class list - please wait...", 1)
|
|
win32ui.DoWaitCursor(1)
|
|
try:
|
|
try:
|
|
reader = pyclbr.readmodule_ex # Post 1.5.2 interface.
|
|
extra_msg = " or functions"
|
|
except AttributeError:
|
|
reader = pyclbr.readmodule
|
|
extra_msg = ""
|
|
data = reader(mod, [path])
|
|
if data:
|
|
ret = []
|
|
for item in data.values():
|
|
if (
|
|
item.__class__ != pyclbr.Class
|
|
): # ie, it is a pyclbr Function instance (only introduced post 1.5.2)
|
|
ret.append(HLICLBRFunction(item, " (function)"))
|
|
else:
|
|
ret.append(HLICLBRClass(item, " (class)"))
|
|
ret.sort()
|
|
return ret
|
|
else:
|
|
return [HLIErrorItem("No Python classes%s in module." % (extra_msg,))]
|
|
finally:
|
|
win32ui.DoWaitCursor(0)
|
|
win32ui.SetStatusText(win32ui.LoadString(afxres.AFX_IDS_IDLEMESSAGE))
|
|
|
|
|
|
def MakePathSubList(path):
|
|
ret = []
|
|
for filename in glob.glob(os.path.join(path, "*")):
|
|
if os.path.isdir(filename) and os.path.isfile(
|
|
os.path.join(filename, "__init__.py")
|
|
):
|
|
ret.append(HLIDirectoryItem(filename, os.path.split(filename)[1]))
|
|
else:
|
|
if os.path.splitext(filename)[1].lower() in [".py", ".pyw"]:
|
|
ret.append(HLIModuleItem(filename))
|
|
return ret
|
|
|
|
|
|
class HLIDirectoryItem(hierlist.HierListItem):
|
|
def __init__(self, path, displayName=None, bSubDirs=0):
|
|
hierlist.HierListItem.__init__(self)
|
|
self.path = path
|
|
self.bSubDirs = bSubDirs
|
|
if displayName:
|
|
self.displayName = displayName
|
|
else:
|
|
self.displayName = path
|
|
|
|
def IsExpandable(self):
|
|
return 1
|
|
|
|
def GetText(self):
|
|
return self.displayName
|
|
|
|
def GetSubList(self):
|
|
ret = MakePathSubList(self.path)
|
|
if (
|
|
os.path.split(self.path)[1] == "win32com"
|
|
): # Complete and utter hack for win32com.
|
|
try:
|
|
path = win32api.GetFullPathName(
|
|
os.path.join(self.path, "..\\win32comext")
|
|
)
|
|
ret = ret + MakePathSubList(path)
|
|
except win32ui.error:
|
|
pass
|
|
return ret
|
|
|
|
|
|
class HLIProjectRoot(hierlist.HierListItem):
|
|
def __init__(self, projectName, displayName=None):
|
|
hierlist.HierListItem.__init__(self)
|
|
self.projectName = projectName
|
|
self.displayName = displayName or projectName
|
|
|
|
def GetText(self):
|
|
return self.displayName
|
|
|
|
def IsExpandable(self):
|
|
return 1
|
|
|
|
def GetSubList(self):
|
|
paths = regutil.GetRegisteredNamedPath(self.projectName)
|
|
pathList = paths.split(";")
|
|
if len(pathList) == 1: # Single dir - dont bother putting the dir in
|
|
ret = MakePathSubList(pathList[0])
|
|
else:
|
|
ret = list(map(HLIDirectoryItem, pathList))
|
|
return ret
|
|
|
|
|
|
class HLIRoot(hierlist.HierListItem):
|
|
def __init__(self):
|
|
hierlist.HierListItem.__init__(self)
|
|
|
|
def IsExpandable(self):
|
|
return 1
|
|
|
|
def GetSubList(self):
|
|
keyStr = regutil.BuildDefaultPythonKey() + "\\PythonPath"
|
|
hKey = win32api.RegOpenKey(regutil.GetRootKey(), keyStr)
|
|
try:
|
|
ret = []
|
|
ret.append(HLIProjectRoot("", "Standard Python Library")) # The core path.
|
|
index = 0
|
|
while 1:
|
|
try:
|
|
ret.append(HLIProjectRoot(win32api.RegEnumKey(hKey, index)))
|
|
index = index + 1
|
|
except win32api.error:
|
|
break
|
|
return ret
|
|
finally:
|
|
win32api.RegCloseKey(hKey)
|
|
|
|
|
|
class dynamic_browser(dialog.Dialog):
|
|
style = win32con.WS_OVERLAPPEDWINDOW | win32con.WS_VISIBLE
|
|
cs = (
|
|
win32con.WS_CHILD
|
|
| win32con.WS_VISIBLE
|
|
| commctrl.TVS_HASLINES
|
|
| commctrl.TVS_LINESATROOT
|
|
| commctrl.TVS_HASBUTTONS
|
|
)
|
|
|
|
dt = [
|
|
["Python Projects", (0, 0, 200, 200), style, None, (8, "MS Sans Serif")],
|
|
["SysTreeView32", None, win32ui.IDC_LIST1, (0, 0, 200, 200), cs],
|
|
]
|
|
|
|
def __init__(self, hli_root):
|
|
dialog.Dialog.__init__(self, self.dt)
|
|
self.hier_list = hierlist.HierListWithItems(hli_root, win32ui.IDB_BROWSER_HIER)
|
|
self.HookMessage(self.on_size, win32con.WM_SIZE)
|
|
|
|
def OnInitDialog(self):
|
|
self.hier_list.HierInit(self)
|
|
return dialog.Dialog.OnInitDialog(self)
|
|
|
|
def on_size(self, params):
|
|
lparam = params[3]
|
|
w = win32api.LOWORD(lparam)
|
|
h = win32api.HIWORD(lparam)
|
|
self.GetDlgItem(win32ui.IDC_LIST1).MoveWindow((0, 0, w, h))
|
|
|
|
|
|
def BrowseDialog():
|
|
root = HLIRoot()
|
|
if not root.IsExpandable():
|
|
raise TypeError(
|
|
"Browse() argument must have __dict__ attribute, or be a Browser supported type"
|
|
)
|
|
|
|
dlg = dynamic_browser(root)
|
|
dlg.CreateWindow()
|
|
|
|
|
|
def DockableBrowserCreator(parent):
|
|
root = HLIRoot()
|
|
hl = hierlist.HierListWithItems(root, win32ui.IDB_BROWSER_HIER)
|
|
|
|
style = (
|
|
win32con.WS_CHILD
|
|
| win32con.WS_VISIBLE
|
|
| win32con.WS_BORDER
|
|
| commctrl.TVS_HASLINES
|
|
| commctrl.TVS_LINESATROOT
|
|
| commctrl.TVS_HASBUTTONS
|
|
)
|
|
|
|
control = win32ui.CreateTreeCtrl()
|
|
control.CreateWindow(style, (0, 0, 150, 300), parent, win32ui.IDC_LIST1)
|
|
list = hl.HierInit(parent, control)
|
|
return control
|
|
|
|
|
|
def DockablePathBrowser():
|
|
import pywin.docking.DockingBar
|
|
|
|
bar = pywin.docking.DockingBar.DockingBar()
|
|
bar.CreateWindow(
|
|
win32ui.GetMainFrame(), DockableBrowserCreator, "Path Browser", 0x8E0A
|
|
)
|
|
bar.SetBarStyle(
|
|
bar.GetBarStyle()
|
|
| afxres.CBRS_TOOLTIPS
|
|
| afxres.CBRS_FLYBY
|
|
| afxres.CBRS_SIZE_DYNAMIC
|
|
)
|
|
bar.EnableDocking(afxres.CBRS_ALIGN_ANY)
|
|
win32ui.GetMainFrame().DockControlBar(bar)
|
|
|
|
|
|
# The "default" entry point
|
|
Browse = DockablePathBrowser
|