toolmenu.py 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. # toolmenu.py
  2. import win32ui
  3. import win32con
  4. import win32api
  5. from . import app
  6. import sys
  7. import string
  8. tools = {}
  9. idPos = 100
  10. # The default items should no tools menu exist in the INI file.
  11. defaultToolMenuItems = [
  12. ('Browser', 'win32ui.GetApp().OnViewBrowse(0,0)'),
  13. ('Browse PythonPath', 'from pywin.tools import browseProjects;browseProjects.Browse()'),
  14. ('Edit Python Path', 'from pywin.tools import regedit;regedit.EditRegistry()'),
  15. ('COM Makepy utility', 'from win32com.client import makepy;makepy.main()'),
  16. ('COM Browser', 'from win32com.client import combrowse;combrowse.main()'),
  17. ('Trace Collector Debugging tool', 'from pywin.tools import TraceCollector;TraceCollector.MakeOutputWindow()'),
  18. ]
  19. def LoadToolMenuItems():
  20. # Load from the registry.
  21. items = []
  22. lookNo = 1
  23. while 1:
  24. menu = win32ui.GetProfileVal("Tools Menu\\%s" % lookNo, "", "")
  25. if menu=="":
  26. break
  27. cmd = win32ui.GetProfileVal("Tools Menu\\%s" % lookNo, "Command", "")
  28. items.append((menu, cmd))
  29. lookNo = lookNo + 1
  30. if len(items)==0:
  31. items = defaultToolMenuItems
  32. return items
  33. def WriteToolMenuItems( items ):
  34. # Items is a list of (menu, command)
  35. # Delete the entire registry tree.
  36. try:
  37. mainKey = win32ui.GetAppRegistryKey()
  38. toolKey = win32api.RegOpenKey(mainKey, "Tools Menu")
  39. except win32ui.error:
  40. toolKey = None
  41. if toolKey is not None:
  42. while 1:
  43. try:
  44. subkey = win32api.RegEnumKey(toolKey, 0)
  45. except win32api.error:
  46. break
  47. win32api.RegDeleteKey(toolKey, subkey)
  48. # Keys are now removed - write the new ones.
  49. # But first check if we have the defaults - and if so, dont write anything!
  50. if items==defaultToolMenuItems:
  51. return
  52. itemNo = 1
  53. for menu, cmd in items:
  54. win32ui.WriteProfileVal("Tools Menu\\%s" % itemNo, "", menu)
  55. win32ui.WriteProfileVal("Tools Menu\\%s" % itemNo, "Command", cmd)
  56. itemNo = itemNo + 1
  57. def SetToolsMenu(menu, menuPos = None):
  58. global tools
  59. global idPos
  60. # todo - check the menu does not already exist.
  61. # Create the new menu
  62. toolsMenu = win32ui.CreatePopupMenu()
  63. # Load from the ini file.
  64. items = LoadToolMenuItems()
  65. for menuString, cmd in items:
  66. tools[idPos] = (menuString, cmd, menuString)
  67. toolsMenu.AppendMenu(win32con.MF_ENABLED|win32con.MF_STRING,idPos, menuString)
  68. win32ui.GetMainFrame().HookCommand(HandleToolCommand, idPos)
  69. idPos=idPos+1
  70. # Find the correct spot to insert the new tools menu.
  71. if menuPos is None:
  72. menuPos = menu.GetMenuItemCount()-2
  73. if menuPos<0: menuPos=0
  74. menu.InsertMenu(menuPos, win32con.MF_BYPOSITION|win32con.MF_ENABLED|win32con.MF_STRING|win32con.MF_POPUP, toolsMenu.GetHandle(), '&Tools')
  75. def HandleToolCommand(cmd, code):
  76. import traceback
  77. import re
  78. global tools
  79. (menuString, pyCmd, desc) = tools[cmd]
  80. win32ui.SetStatusText("Executing tool %s" % desc, 1)
  81. pyCmd = re.sub('\\\\n','\n', pyCmd)
  82. win32ui.DoWaitCursor(1)
  83. oldFlag = None
  84. try:
  85. oldFlag = sys.stdout.template.writeQueueing
  86. sys.stdout.template.writeQueueing = 0
  87. except (NameError, AttributeError):
  88. pass
  89. try:
  90. exec("%s\n" % pyCmd)
  91. worked=1
  92. except SystemExit:
  93. # The program raised a SystemExit - ignore it.
  94. worked = 1
  95. except:
  96. print("Failed to execute command:\n%s" % pyCmd)
  97. traceback.print_exc()
  98. worked=0
  99. if oldFlag is not None:
  100. sys.stdout.template.writeQueueing = oldFlag
  101. win32ui.DoWaitCursor(0)
  102. if worked:
  103. text = "Completed successfully."
  104. else:
  105. text = "Error executing %s." % desc
  106. win32ui.SetStatusText(text, 1)
  107. # The property page for maintaing the items on the Tools menu.
  108. import commctrl
  109. from pywin.mfc import dialog
  110. if win32ui.UNICODE:
  111. LVN_ENDLABELEDIT = commctrl.LVN_ENDLABELEDITW
  112. else:
  113. LVN_ENDLABELEDIT = commctrl.LVN_ENDLABELEDITA
  114. class ToolMenuPropPage(dialog.PropertyPage):
  115. def __init__(self):
  116. self.bImChangingEditControls = 0 # Am I programatically changing the controls?
  117. dialog.PropertyPage.__init__(self, win32ui.IDD_PP_TOOLMENU)
  118. def OnInitDialog(self):
  119. self.editMenuCommand = self.GetDlgItem(win32ui.IDC_EDIT2)
  120. self.butNew = self.GetDlgItem(win32ui.IDC_BUTTON3)
  121. # Now hook the change notification messages for the edit controls.
  122. self.HookCommand(self.OnCommandEditControls, win32ui.IDC_EDIT1)
  123. self.HookCommand(self.OnCommandEditControls, win32ui.IDC_EDIT2)
  124. self.HookNotify(self.OnNotifyListControl, commctrl.LVN_ITEMCHANGED)
  125. self.HookNotify(self.OnNotifyListControlEndLabelEdit, commctrl.LVN_ENDLABELEDIT)
  126. # Hook the button clicks.
  127. self.HookCommand(self.OnButtonNew, win32ui.IDC_BUTTON3) # New Item
  128. self.HookCommand(self.OnButtonDelete, win32ui.IDC_BUTTON4) # Delete item
  129. self.HookCommand(self.OnButtonMove, win32ui.IDC_BUTTON1) # Move up
  130. self.HookCommand(self.OnButtonMove, win32ui.IDC_BUTTON2) # Move down
  131. # Setup the columns in the list control
  132. lc = self.GetDlgItem(win32ui.IDC_LIST1)
  133. rect = lc.GetWindowRect()
  134. cx = rect[2] - rect[0]
  135. colSize = cx/2 - win32api.GetSystemMetrics(win32con.SM_CXBORDER) - 1
  136. item = commctrl.LVCFMT_LEFT, colSize, "Menu Text"
  137. lc.InsertColumn(0, item)
  138. item = commctrl.LVCFMT_LEFT, colSize, "Python Command"
  139. lc.InsertColumn(1, item)
  140. # Insert the existing tools menu
  141. itemNo = 0
  142. for desc, cmd in LoadToolMenuItems():
  143. lc.InsertItem(itemNo, desc)
  144. lc.SetItemText(itemNo, 1, cmd)
  145. itemNo = itemNo + 1
  146. self.listControl = lc
  147. return dialog.PropertyPage.OnInitDialog(self)
  148. def OnOK(self):
  149. # Write the menu back to the registry.
  150. items = []
  151. itemLook = 0
  152. while 1:
  153. try:
  154. text = self.listControl.GetItemText(itemLook, 0);
  155. if not text:
  156. break
  157. items.append( (text, self.listControl.GetItemText(itemLook, 1)) )
  158. except win32ui.error:
  159. # no more items!
  160. break
  161. itemLook = itemLook + 1
  162. WriteToolMenuItems( items )
  163. return self._obj_.OnOK()
  164. def OnCommandEditControls(self, id, cmd):
  165. # print "OnEditControls", id, cmd
  166. if cmd==win32con.EN_CHANGE and not self.bImChangingEditControls:
  167. itemNo = self.listControl.GetNextItem(-1, commctrl.LVNI_SELECTED)
  168. newText = self.editMenuCommand.GetWindowText()
  169. self.listControl.SetItemText(itemNo, 1, newText)
  170. return 0
  171. def OnNotifyListControlEndLabelEdit(self, id, cmd):
  172. newText = self.listControl.GetEditControl().GetWindowText()
  173. itemNo = self.listControl.GetNextItem(-1, commctrl.LVNI_SELECTED)
  174. self.listControl.SetItemText(itemNo, 0, newText)
  175. def OnNotifyListControl(self, id, cmd):
  176. # print id, cmd
  177. try:
  178. itemNo = self.listControl.GetNextItem(-1, commctrl.LVNI_SELECTED)
  179. except win32ui.error: # No selection!
  180. return
  181. self.bImChangingEditControls = 1
  182. try:
  183. item = self.listControl.GetItem(itemNo, 1)
  184. self.editMenuCommand.SetWindowText(item[4])
  185. finally:
  186. self.bImChangingEditControls = 0
  187. return 0 # we have handled this!
  188. def OnButtonNew(self, id, cmd):
  189. if cmd==win32con.BN_CLICKED:
  190. newIndex = self.listControl.GetItemCount()
  191. self.listControl.InsertItem(newIndex, "Click to edit the text")
  192. self.listControl.EnsureVisible(newIndex, 0)
  193. def OnButtonMove(self, id, cmd):
  194. if cmd==win32con.BN_CLICKED:
  195. try:
  196. itemNo = self.listControl.GetNextItem(-1, commctrl.LVNI_SELECTED)
  197. except win32ui.error:
  198. return
  199. menu = self.listControl.GetItemText(itemNo, 0)
  200. cmd = self.listControl.GetItemText(itemNo, 1)
  201. if id == win32ui.IDC_BUTTON1:
  202. # Move up
  203. if itemNo > 0:
  204. self.listControl.DeleteItem(itemNo)
  205. # reinsert it.
  206. self.listControl.InsertItem(itemNo-1, menu)
  207. self.listControl.SetItemText(itemNo-1, 1, cmd)
  208. else:
  209. # Move down.
  210. if itemNo < self.listControl.GetItemCount()-1:
  211. self.listControl.DeleteItem(itemNo)
  212. # reinsert it.
  213. self.listControl.InsertItem(itemNo+1, menu)
  214. self.listControl.SetItemText(itemNo+1, 1, cmd)
  215. def OnButtonDelete(self, id, cmd):
  216. if cmd==win32con.BN_CLICKED:
  217. try:
  218. itemNo = self.listControl.GetNextItem(-1, commctrl.LVNI_SELECTED)
  219. except win32ui.error: # No selection!
  220. return
  221. self.listControl.DeleteItem(itemNo)