2024-10-02 22:15:59 +04:00

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