# toolmenu.py import sys import win32api import win32con import win32ui from . import app 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(modal=False)", ), ( "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 re import traceback 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)