256 lines
7.7 KiB
Python
256 lines
7.7 KiB
Python
# toolmenu.py
|
|
|
|
import win32ui
|
|
import win32con
|
|
import win32api
|
|
from . import app
|
|
import sys
|
|
import string
|
|
|
|
tools = {}
|
|
idPos = 100
|
|
|
|
# The default items should no tools menu exist in the INI file.
|
|
defaultToolMenuItems = [
|
|
('Browser', 'win32ui.GetApp().OnViewBrowse(0,0)'),
|
|
('Browse PythonPath', 'from pywin.tools import browseProjects;browseProjects.Browse()'),
|
|
('Edit Python Path', 'from pywin.tools import regedit;regedit.EditRegistry()'),
|
|
('COM Makepy utility', 'from win32com.client import makepy;makepy.main()'),
|
|
('COM Browser', 'from win32com.client import combrowse;combrowse.main()'),
|
|
('Trace Collector Debugging tool', 'from pywin.tools import TraceCollector;TraceCollector.MakeOutputWindow()'),
|
|
]
|
|
|
|
def LoadToolMenuItems():
|
|
# Load from the registry.
|
|
items = []
|
|
lookNo = 1
|
|
while 1:
|
|
menu = win32ui.GetProfileVal("Tools Menu\\%s" % lookNo, "", "")
|
|
if menu=="":
|
|
break
|
|
cmd = win32ui.GetProfileVal("Tools Menu\\%s" % lookNo, "Command", "")
|
|
items.append((menu, cmd))
|
|
lookNo = lookNo + 1
|
|
|
|
if len(items)==0:
|
|
items = defaultToolMenuItems
|
|
return items
|
|
|
|
def WriteToolMenuItems( items ):
|
|
# Items is a list of (menu, command)
|
|
# Delete the entire registry tree.
|
|
try:
|
|
mainKey = win32ui.GetAppRegistryKey()
|
|
toolKey = win32api.RegOpenKey(mainKey, "Tools Menu")
|
|
except win32ui.error:
|
|
toolKey = None
|
|
if toolKey is not None:
|
|
while 1:
|
|
try:
|
|
subkey = win32api.RegEnumKey(toolKey, 0)
|
|
except win32api.error:
|
|
break
|
|
win32api.RegDeleteKey(toolKey, subkey)
|
|
# Keys are now removed - write the new ones.
|
|
# But first check if we have the defaults - and if so, dont write anything!
|
|
if items==defaultToolMenuItems:
|
|
return
|
|
itemNo = 1
|
|
for menu, cmd in items:
|
|
win32ui.WriteProfileVal("Tools Menu\\%s" % itemNo, "", menu)
|
|
win32ui.WriteProfileVal("Tools Menu\\%s" % itemNo, "Command", cmd)
|
|
itemNo = itemNo + 1
|
|
|
|
def SetToolsMenu(menu, menuPos = None):
|
|
global tools
|
|
global idPos
|
|
|
|
# todo - check the menu does not already exist.
|
|
# Create the new menu
|
|
toolsMenu = win32ui.CreatePopupMenu()
|
|
|
|
# Load from the ini file.
|
|
items = LoadToolMenuItems()
|
|
for menuString, cmd in items:
|
|
tools[idPos] = (menuString, cmd, menuString)
|
|
toolsMenu.AppendMenu(win32con.MF_ENABLED|win32con.MF_STRING,idPos, menuString)
|
|
win32ui.GetMainFrame().HookCommand(HandleToolCommand, idPos)
|
|
idPos=idPos+1
|
|
|
|
# Find the correct spot to insert the new tools menu.
|
|
if menuPos is None:
|
|
menuPos = menu.GetMenuItemCount()-2
|
|
if menuPos<0: menuPos=0
|
|
|
|
menu.InsertMenu(menuPos, win32con.MF_BYPOSITION|win32con.MF_ENABLED|win32con.MF_STRING|win32con.MF_POPUP, toolsMenu.GetHandle(), '&Tools')
|
|
|
|
def HandleToolCommand(cmd, code):
|
|
import traceback
|
|
import re
|
|
global tools
|
|
(menuString, pyCmd, desc) = tools[cmd]
|
|
win32ui.SetStatusText("Executing tool %s" % desc, 1)
|
|
pyCmd = re.sub('\\\\n','\n', pyCmd)
|
|
win32ui.DoWaitCursor(1)
|
|
oldFlag = None
|
|
try:
|
|
oldFlag = sys.stdout.template.writeQueueing
|
|
sys.stdout.template.writeQueueing = 0
|
|
except (NameError, AttributeError):
|
|
pass
|
|
|
|
try:
|
|
exec("%s\n" % pyCmd)
|
|
worked=1
|
|
except SystemExit:
|
|
# The program raised a SystemExit - ignore it.
|
|
worked = 1
|
|
except:
|
|
print("Failed to execute command:\n%s" % pyCmd)
|
|
traceback.print_exc()
|
|
worked=0
|
|
if oldFlag is not None:
|
|
sys.stdout.template.writeQueueing = oldFlag
|
|
win32ui.DoWaitCursor(0)
|
|
if worked:
|
|
text = "Completed successfully."
|
|
else:
|
|
text = "Error executing %s." % desc
|
|
win32ui.SetStatusText(text, 1)
|
|
|
|
# The property page for maintaing the items on the Tools menu.
|
|
import commctrl
|
|
from pywin.mfc import dialog
|
|
|
|
if win32ui.UNICODE:
|
|
LVN_ENDLABELEDIT = commctrl.LVN_ENDLABELEDITW
|
|
else:
|
|
LVN_ENDLABELEDIT = commctrl.LVN_ENDLABELEDITA
|
|
|
|
class ToolMenuPropPage(dialog.PropertyPage):
|
|
def __init__(self):
|
|
self.bImChangingEditControls = 0 # Am I programatically changing the controls?
|
|
dialog.PropertyPage.__init__(self, win32ui.IDD_PP_TOOLMENU)
|
|
|
|
def OnInitDialog(self):
|
|
self.editMenuCommand = self.GetDlgItem(win32ui.IDC_EDIT2)
|
|
self.butNew = self.GetDlgItem(win32ui.IDC_BUTTON3)
|
|
|
|
# Now hook the change notification messages for the edit controls.
|
|
self.HookCommand(self.OnCommandEditControls, win32ui.IDC_EDIT1)
|
|
self.HookCommand(self.OnCommandEditControls, win32ui.IDC_EDIT2)
|
|
|
|
self.HookNotify(self.OnNotifyListControl, commctrl.LVN_ITEMCHANGED)
|
|
self.HookNotify(self.OnNotifyListControlEndLabelEdit, commctrl.LVN_ENDLABELEDIT)
|
|
|
|
# Hook the button clicks.
|
|
self.HookCommand(self.OnButtonNew, win32ui.IDC_BUTTON3) # New Item
|
|
self.HookCommand(self.OnButtonDelete, win32ui.IDC_BUTTON4) # Delete item
|
|
self.HookCommand(self.OnButtonMove, win32ui.IDC_BUTTON1) # Move up
|
|
self.HookCommand(self.OnButtonMove, win32ui.IDC_BUTTON2) # Move down
|
|
|
|
# Setup the columns in the list control
|
|
lc = self.GetDlgItem(win32ui.IDC_LIST1)
|
|
rect = lc.GetWindowRect()
|
|
cx = rect[2] - rect[0]
|
|
colSize = cx/2 - win32api.GetSystemMetrics(win32con.SM_CXBORDER) - 1
|
|
|
|
item = commctrl.LVCFMT_LEFT, colSize, "Menu Text"
|
|
lc.InsertColumn(0, item)
|
|
|
|
item = commctrl.LVCFMT_LEFT, colSize, "Python Command"
|
|
lc.InsertColumn(1, item)
|
|
|
|
# Insert the existing tools menu
|
|
itemNo = 0
|
|
for desc, cmd in LoadToolMenuItems():
|
|
lc.InsertItem(itemNo, desc)
|
|
lc.SetItemText(itemNo, 1, cmd)
|
|
itemNo = itemNo + 1
|
|
|
|
self.listControl = lc
|
|
return dialog.PropertyPage.OnInitDialog(self)
|
|
|
|
def OnOK(self):
|
|
# Write the menu back to the registry.
|
|
items = []
|
|
itemLook = 0
|
|
while 1:
|
|
try:
|
|
text = self.listControl.GetItemText(itemLook, 0);
|
|
if not text:
|
|
break
|
|
items.append( (text, self.listControl.GetItemText(itemLook, 1)) )
|
|
except win32ui.error:
|
|
# no more items!
|
|
break
|
|
itemLook = itemLook + 1
|
|
WriteToolMenuItems( items )
|
|
return self._obj_.OnOK()
|
|
|
|
def OnCommandEditControls(self, id, cmd):
|
|
# print "OnEditControls", id, cmd
|
|
if cmd==win32con.EN_CHANGE and not self.bImChangingEditControls:
|
|
itemNo = self.listControl.GetNextItem(-1, commctrl.LVNI_SELECTED)
|
|
newText = self.editMenuCommand.GetWindowText()
|
|
self.listControl.SetItemText(itemNo, 1, newText)
|
|
|
|
return 0
|
|
|
|
def OnNotifyListControlEndLabelEdit(self, id, cmd):
|
|
newText = self.listControl.GetEditControl().GetWindowText()
|
|
itemNo = self.listControl.GetNextItem(-1, commctrl.LVNI_SELECTED)
|
|
self.listControl.SetItemText(itemNo, 0, newText)
|
|
|
|
def OnNotifyListControl(self, id, cmd):
|
|
# print id, cmd
|
|
try:
|
|
itemNo = self.listControl.GetNextItem(-1, commctrl.LVNI_SELECTED)
|
|
except win32ui.error: # No selection!
|
|
return
|
|
|
|
self.bImChangingEditControls = 1
|
|
try:
|
|
item = self.listControl.GetItem(itemNo, 1)
|
|
self.editMenuCommand.SetWindowText(item[4])
|
|
finally:
|
|
self.bImChangingEditControls = 0
|
|
|
|
return 0 # we have handled this!
|
|
|
|
def OnButtonNew(self, id, cmd):
|
|
if cmd==win32con.BN_CLICKED:
|
|
newIndex = self.listControl.GetItemCount()
|
|
self.listControl.InsertItem(newIndex, "Click to edit the text")
|
|
self.listControl.EnsureVisible(newIndex, 0)
|
|
|
|
def OnButtonMove(self, id, cmd):
|
|
if cmd==win32con.BN_CLICKED:
|
|
try:
|
|
itemNo = self.listControl.GetNextItem(-1, commctrl.LVNI_SELECTED)
|
|
except win32ui.error:
|
|
return
|
|
menu = self.listControl.GetItemText(itemNo, 0)
|
|
cmd = self.listControl.GetItemText(itemNo, 1)
|
|
if id == win32ui.IDC_BUTTON1:
|
|
# Move up
|
|
if itemNo > 0:
|
|
self.listControl.DeleteItem(itemNo)
|
|
# reinsert it.
|
|
self.listControl.InsertItem(itemNo-1, menu)
|
|
self.listControl.SetItemText(itemNo-1, 1, cmd)
|
|
else:
|
|
# Move down.
|
|
if itemNo < self.listControl.GetItemCount()-1:
|
|
self.listControl.DeleteItem(itemNo)
|
|
# reinsert it.
|
|
self.listControl.InsertItem(itemNo+1, menu)
|
|
self.listControl.SetItemText(itemNo+1, 1, cmd)
|
|
|
|
def OnButtonDelete(self, id, cmd):
|
|
if cmd==win32con.BN_CLICKED:
|
|
try:
|
|
itemNo = self.listControl.GetNextItem(-1, commctrl.LVNI_SELECTED)
|
|
except win32ui.error: # No selection!
|
|
return
|
|
self.listControl.DeleteItem(itemNo)
|