You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
ORPA-pyOpenRPA/Resources/WPy64-3720/python-3.7.2.amd64/Lib/site-packages/pythonwin/pywin/tools/hierlist.py

322 lines
11 KiB

# hierlist
#
# IMPORTANT - Please read before using.
# This module exposes an API for a Hierarchical Tree Control.
# Previously, a custom tree control was included in Pythonwin which
# has an API very similar to this.
# The current control used is the common "Tree Control". This module exists now
# to provide an API similar to the old control, but for the new Tree control.
# If you need to use the Tree Control, you may still find this API a reasonable
# choice. However, you should investigate using the tree control directly
# to provide maximum flexibility (but with extra work).
import sys
import win32ui
import win32con
import win32api
from win32api import RGB
from pywin.mfc import object, window, docview, dialog
import commctrl
# helper to get the text of an arbitary item
def GetItemText(item):
if type(item)==type(()) or type(item)==type([]):
use = item[0]
else:
use = item
if type(use)==type(''):
return use
else:
return repr(item)
class HierDialog(dialog.Dialog):
def __init__(self, title, hierList, bitmapID = win32ui.IDB_HIERFOLDERS, dlgID = win32ui.IDD_TREE, dll = None, childListBoxID = win32ui.IDC_LIST1):
dialog.Dialog.__init__(self, dlgID, dll ) # reuse this dialog.
self.hierList=hierList
self.dlgID = dlgID
self.title=title
# self.childListBoxID = childListBoxID
def OnInitDialog(self):
self.SetWindowText(self.title)
self.hierList.HierInit(self)
return dialog.Dialog.OnInitDialog(self)
class HierList(object.Object):
def __init__(self, root, bitmapID = win32ui.IDB_HIERFOLDERS, listBoxId = None, bitmapMask = None): # used to create object.
self.listControl = None
self.bitmapID = bitmapID
self.root = root
self.listBoxId = listBoxId
self.itemHandleMap = {}
self.filledItemHandlesMap = {}
self.bitmapMask = bitmapMask
def __getattr__(self, attr):
try:
return getattr(self.listControl, attr)
except AttributeError:
return object.Object.__getattr__(self, attr)
def ItemFromHandle(self, handle):
return self.itemHandleMap[handle]
def SetStyle(self, newStyle):
hwnd = self.listControl.GetSafeHwnd()
style = win32api.GetWindowLong(hwnd, win32con.GWL_STYLE);
win32api.SetWindowLong(hwnd, win32con.GWL_STYLE, (style | newStyle) )
def HierInit(self, parent, listControl = None ): # Used when window first exists.
# this also calls "Create" on the listbox.
# params - id of listbbox, ID of bitmap, size of bitmaps
if self.bitmapMask is None:
bitmapMask = RGB(0,0,255)
else:
bitmapMask = self.bitmapMask
self.imageList = win32ui.CreateImageList(self.bitmapID, 16, 0, bitmapMask)
if listControl is None:
if self.listBoxId is None: self.listBoxId = win32ui.IDC_LIST1
self.listControl = parent.GetDlgItem(self.listBoxId)
else:
self.listControl = listControl
lbid = listControl.GetDlgCtrlID()
assert self.listBoxId is None or self.listBoxId == lbid, "An invalid listbox control ID has been specified (specified as %s, but exists as %s)" % (self.listBoxId, lbid)
self.listBoxId = lbid
self.listControl.SetImageList(self.imageList, commctrl.LVSIL_NORMAL)
# self.list.AttachObject(self)
## ??? Need a better way to do this - either some way to detect if it's compiled with UNICODE
## defined, and/or a way to switch the constants based on UNICODE ???
if sys.version_info[0] < 3:
parent.HookNotify(self.OnTreeItemExpanding, commctrl.TVN_ITEMEXPANDINGA)
parent.HookNotify(self.OnTreeItemSelChanged, commctrl.TVN_SELCHANGEDA)
else:
parent.HookNotify(self.OnTreeItemExpanding, commctrl.TVN_ITEMEXPANDINGW)
parent.HookNotify(self.OnTreeItemSelChanged, commctrl.TVN_SELCHANGEDW)
parent.HookNotify(self.OnTreeItemDoubleClick, commctrl.NM_DBLCLK)
self.notify_parent = parent
if self.root:
self.AcceptRoot(self.root)
def DeleteAllItems(self):
self.listControl.DeleteAllItems()
self.root = None
self.itemHandleMap = {}
self.filledItemHandlesMap = {}
def HierTerm(self):
# Dont want notifies as we kill the list.
parent = self.notify_parent # GetParentFrame()
if sys.version_info[0] < 3:
parent.HookNotify(None, commctrl.TVN_ITEMEXPANDINGA)
parent.HookNotify(None, commctrl.TVN_SELCHANGEDA)
else:
parent.HookNotify(None, commctrl.TVN_ITEMEXPANDINGW)
parent.HookNotify(None, commctrl.TVN_SELCHANGEDW)
parent.HookNotify(None, commctrl.NM_DBLCLK)
self.DeleteAllItems()
self.listControl = None
self.notify_parent = None # Break a possible cycle
def OnTreeItemDoubleClick(self, info, extra):
(hwndFrom, idFrom, code) = info
if idFrom != self.listBoxId: return None
item = self.itemHandleMap[self.listControl.GetSelectedItem()]
self.TakeDefaultAction(item)
return 1
def OnTreeItemExpanding(self, info, extra):
(hwndFrom, idFrom, code) = info
if idFrom != self.listBoxId: return None
action, itemOld, itemNew, pt = extra
itemHandle = itemNew[0]
if itemHandle not in self.filledItemHandlesMap:
item = self.itemHandleMap[itemHandle]
self.AddSubList(itemHandle, self.GetSubList(item))
self.filledItemHandlesMap[itemHandle] = None
return 0
def OnTreeItemSelChanged(self, info, extra):
(hwndFrom, idFrom, code) = info
if idFrom != self.listBoxId: return None
action, itemOld, itemNew, pt = extra
itemHandle = itemNew[0]
item = self.itemHandleMap[itemHandle]
self.PerformItemSelected(item)
return 1
def AddSubList(self, parentHandle, subItems):
for item in subItems:
self.AddItem(parentHandle, item)
def AddItem(self, parentHandle, item, hInsertAfter = commctrl.TVI_LAST):
text = self.GetText(item)
if self.IsExpandable(item):
cItems = 1 # Trick it !!
else:
cItems = 0
bitmapCol = self.GetBitmapColumn(item)
bitmapSel = self.GetSelectedBitmapColumn(item)
if bitmapSel is None: bitmapSel = bitmapCol
## if type(text) is str:
## text = text.encode("mbcs")
hitem = self.listControl.InsertItem(parentHandle, hInsertAfter, (None, None, None, text, bitmapCol, bitmapSel, cItems, 0))
self.itemHandleMap[hitem] = item
return hitem
def _GetChildHandles(self, handle):
ret = []
try:
handle = self.listControl.GetChildItem(handle)
while 1:
ret.append(handle)
handle = self.listControl.GetNextItem(handle, commctrl.TVGN_NEXT)
except win32ui.error:
# out of children
pass
return ret
def ItemFromHandle(self, handle):
return self.itemHandleMap[handle]
def Refresh(self, hparent = None):
# Attempt to refresh the given item's sub-entries, but maintain the tree state
# (ie, the selected item, expanded items, etc)
if hparent is None: hparent = commctrl.TVI_ROOT
if hparent not in self.filledItemHandlesMap:
# This item has never been expanded, so no refresh can possibly be required.
return
root_item = self.itemHandleMap[hparent]
old_handles = self._GetChildHandles(hparent)
old_items = list(map( self.ItemFromHandle, old_handles ))
new_items = self.GetSubList(root_item)
# Now an inefficient technique for synching the items.
inew = 0
hAfter = commctrl.TVI_FIRST
for iold in range(len(old_items)):
inewlook = inew
matched = 0
while inewlook < len(new_items):
if old_items[iold] == new_items[inewlook]:
matched = 1
break
inewlook = inewlook + 1
if matched:
# Insert the new items.
# print "Inserting after", old_items[iold], old_handles[iold]
for i in range(inew, inewlook):
# print "Inserting index %d (%s)" % (i, new_items[i])
hAfter = self.AddItem(hparent, new_items[i], hAfter)
inew = inewlook + 1
# And recursively refresh iold
hold = old_handles[iold]
if hold in self.filledItemHandlesMap:
self.Refresh(hold)
else:
# Remove the deleted items.
# print "Deleting %d (%s)" % (iold, old_items[iold])
hdelete = old_handles[iold]
# First recurse and remove the children from the map.
for hchild in self._GetChildHandles(hdelete):
del self.itemHandleMap[hchild]
if hchild in self.filledItemHandlesMap:
del self.filledItemHandlesMap[hchild]
self.listControl.DeleteItem(hdelete)
hAfter = old_handles[iold]
# Fill any remaining new items:
for newItem in new_items[inew:]:
# print "Inserting new item", newItem
self.AddItem(hparent, newItem)
def AcceptRoot(self, root):
self.listControl.DeleteAllItems()
self.itemHandleMap = {commctrl.TVI_ROOT : root}
self.filledItemHandlesMap = {commctrl.TVI_ROOT : root}
subItems = self.GetSubList(root)
self.AddSubList(0, subItems)
def GetBitmapColumn(self, item):
if self.IsExpandable(item):
return 0
else:
return 4
def GetSelectedBitmapColumn(self, item):
return None # Use standard.
def GetSelectedBitmapColumn(self, item):
return 0
def CheckChangedChildren(self):
return self.listControl.CheckChangedChildren()
def GetText(self,item):
return GetItemText(item)
def PerformItemSelected(self, item):
try:
win32ui.SetStatusText('Selected ' + self.GetText(item))
except win32ui.error: # No status bar!
pass
def TakeDefaultAction(self, item):
win32ui.MessageBox('Got item ' + self.GetText(item))
##########################################################################
#
# Classes for use with seperate HierListItems.
#
#
class HierListWithItems(HierList):
def __init__(self, root, bitmapID = win32ui.IDB_HIERFOLDERS, listBoxID = None, bitmapMask = None): # used to create object.
HierList.__init__(self, root, bitmapID, listBoxID, bitmapMask )
def DelegateCall( self, fn):
return fn()
def GetBitmapColumn(self, item):
rc = self.DelegateCall(item.GetBitmapColumn)
if rc is None:
rc = HierList.GetBitmapColumn(self, item)
return rc
def GetSelectedBitmapColumn(self, item):
return self.DelegateCall(item.GetSelectedBitmapColumn)
def IsExpandable(self, item):
return self.DelegateCall( item.IsExpandable)
def GetText(self, item):
return self.DelegateCall( item.GetText )
def GetSubList(self, item):
return self.DelegateCall(item.GetSubList)
def PerformItemSelected(self, item):
func = getattr(item, "PerformItemSelected", None)
if func is None:
return HierList.PerformItemSelected( self, item )
else:
return self.DelegateCall(func)
def TakeDefaultAction(self, item):
func = getattr(item, "TakeDefaultAction", None)
if func is None:
return HierList.TakeDefaultAction( self, item )
else:
return self.DelegateCall(func)
# A hier list item - for use with a HierListWithItems
class HierListItem:
def __init__(self):
pass
def GetText(self):
pass
def GetSubList(self):
pass
def IsExpandable(self):
pass
def GetBitmapColumn(self):
return None # indicate he should do it.
def GetSelectedBitmapColumn(self):
return None # same as other
# for py3k/rich-comp sorting compatibility.
def __lt__(self, other):
# we want unrelated items to be sortable...
return id(self) < id(other)
# for py3k/rich-comp equality compatibility.
def __eq__(self, other):
return False