174 lines
5.5 KiB
Python
174 lines
5.5 KiB
Python
|
# help.py - help utilities for PythonWin.
|
||
|
import os
|
||
|
|
||
|
import regutil
|
||
|
import win32api
|
||
|
import win32con
|
||
|
import win32ui
|
||
|
|
||
|
htmlhelp_handle = None
|
||
|
|
||
|
html_help_command_translators = {
|
||
|
win32con.HELP_CONTENTS: 1, # HH_DISPLAY_TOC
|
||
|
win32con.HELP_CONTEXT: 15, # HH_HELP_CONTEXT
|
||
|
win32con.HELP_FINDER: 1, # HH_DISPLAY_TOC
|
||
|
}
|
||
|
|
||
|
|
||
|
def FinalizeHelp():
|
||
|
global htmlhelp_handle
|
||
|
if htmlhelp_handle is not None:
|
||
|
import win32help
|
||
|
|
||
|
try:
|
||
|
# frame = win32ui.GetMainFrame().GetSafeHwnd()
|
||
|
frame = 0
|
||
|
win32help.HtmlHelp(frame, None, win32help.HH_UNINITIALIZE, htmlhelp_handle)
|
||
|
except win32help.error:
|
||
|
print("Failed to finalize htmlhelp!")
|
||
|
htmlhelp_handle = None
|
||
|
|
||
|
|
||
|
def OpenHelpFile(fileName, helpCmd=None, helpArg=None):
|
||
|
"Open a help file, given a full path"
|
||
|
# default help arg.
|
||
|
win32ui.DoWaitCursor(1)
|
||
|
try:
|
||
|
if helpCmd is None:
|
||
|
helpCmd = win32con.HELP_CONTENTS
|
||
|
ext = os.path.splitext(fileName)[1].lower()
|
||
|
if ext == ".hlp":
|
||
|
win32api.WinHelp(
|
||
|
win32ui.GetMainFrame().GetSafeHwnd(), fileName, helpCmd, helpArg
|
||
|
)
|
||
|
# XXX - using the htmlhelp API wreaks havoc with keyboard shortcuts
|
||
|
# so we disable it, forcing ShellExecute, which works fine (but
|
||
|
# doesn't close the help file when Pythonwin is closed.
|
||
|
# Tom Heller also points out http://www.microsoft.com/mind/0499/faq/faq0499.asp,
|
||
|
# which may or may not be related.
|
||
|
elif 0 and ext == ".chm":
|
||
|
import win32help
|
||
|
|
||
|
global htmlhelp_handle
|
||
|
helpCmd = html_help_command_translators.get(helpCmd, helpCmd)
|
||
|
# frame = win32ui.GetMainFrame().GetSafeHwnd()
|
||
|
frame = 0 # Dont want it overlapping ours!
|
||
|
if htmlhelp_handle is None:
|
||
|
htmlhelp_hwnd, htmlhelp_handle = win32help.HtmlHelp(
|
||
|
frame, None, win32help.HH_INITIALIZE
|
||
|
)
|
||
|
win32help.HtmlHelp(frame, fileName, helpCmd, helpArg)
|
||
|
else:
|
||
|
# Hope that the extension is registered, and we know what to do!
|
||
|
win32api.ShellExecute(0, "open", fileName, None, "", win32con.SW_SHOW)
|
||
|
return fileName
|
||
|
finally:
|
||
|
win32ui.DoWaitCursor(-1)
|
||
|
|
||
|
|
||
|
def ListAllHelpFiles():
|
||
|
ret = []
|
||
|
ret = _ListAllHelpFilesInRoot(win32con.HKEY_LOCAL_MACHINE)
|
||
|
# Ensure we don't get dups.
|
||
|
for item in _ListAllHelpFilesInRoot(win32con.HKEY_CURRENT_USER):
|
||
|
if item not in ret:
|
||
|
ret.append(item)
|
||
|
return ret
|
||
|
|
||
|
|
||
|
def _ListAllHelpFilesInRoot(root):
|
||
|
"""Returns a list of (helpDesc, helpFname) for all registered help files"""
|
||
|
import regutil
|
||
|
|
||
|
retList = []
|
||
|
try:
|
||
|
key = win32api.RegOpenKey(
|
||
|
root, regutil.BuildDefaultPythonKey() + "\\Help", 0, win32con.KEY_READ
|
||
|
)
|
||
|
except win32api.error as exc:
|
||
|
import winerror
|
||
|
|
||
|
if exc.winerror != winerror.ERROR_FILE_NOT_FOUND:
|
||
|
raise
|
||
|
return retList
|
||
|
try:
|
||
|
keyNo = 0
|
||
|
while 1:
|
||
|
try:
|
||
|
helpDesc = win32api.RegEnumKey(key, keyNo)
|
||
|
helpFile = win32api.RegQueryValue(key, helpDesc)
|
||
|
retList.append((helpDesc, helpFile))
|
||
|
keyNo = keyNo + 1
|
||
|
except win32api.error as exc:
|
||
|
import winerror
|
||
|
|
||
|
if exc.winerror != winerror.ERROR_NO_MORE_ITEMS:
|
||
|
raise
|
||
|
break
|
||
|
finally:
|
||
|
win32api.RegCloseKey(key)
|
||
|
return retList
|
||
|
|
||
|
|
||
|
def SelectAndRunHelpFile():
|
||
|
from pywin.dialogs import list
|
||
|
|
||
|
helpFiles = ListAllHelpFiles()
|
||
|
if len(helpFiles) == 1:
|
||
|
# only 1 help file registered - probably ours - no point asking
|
||
|
index = 0
|
||
|
else:
|
||
|
index = list.SelectFromLists("Select Help file", helpFiles, ["Title"])
|
||
|
if index is not None:
|
||
|
OpenHelpFile(helpFiles[index][1])
|
||
|
|
||
|
|
||
|
helpIDMap = None
|
||
|
|
||
|
|
||
|
def SetHelpMenuOtherHelp(mainMenu):
|
||
|
"""Modifies the main Help Menu to handle all registered help files.
|
||
|
mainMenu -- The main menu to modify - usually from docTemplate.GetSharedMenu()
|
||
|
"""
|
||
|
|
||
|
# Load all help files from the registry.
|
||
|
global helpIDMap
|
||
|
if helpIDMap is None:
|
||
|
helpIDMap = {}
|
||
|
cmdID = win32ui.ID_HELP_OTHER
|
||
|
excludeList = ["Main Python Documentation", "Pythonwin Reference"]
|
||
|
firstList = ListAllHelpFiles()
|
||
|
# We actually want to not only exclude these entries, but
|
||
|
# their help file names (as many entries may share the same name)
|
||
|
excludeFnames = []
|
||
|
for desc, fname in firstList:
|
||
|
if desc in excludeList:
|
||
|
excludeFnames.append(fname)
|
||
|
|
||
|
helpDescs = []
|
||
|
for desc, fname in firstList:
|
||
|
if fname not in excludeFnames:
|
||
|
helpIDMap[cmdID] = (desc, fname)
|
||
|
win32ui.GetMainFrame().HookCommand(HandleHelpOtherCommand, cmdID)
|
||
|
cmdID = cmdID + 1
|
||
|
|
||
|
helpMenu = mainMenu.GetSubMenu(
|
||
|
mainMenu.GetMenuItemCount() - 1
|
||
|
) # Help menu always last.
|
||
|
otherHelpMenuPos = 2 # cant search for ID, as sub-menu has no ID.
|
||
|
otherMenu = helpMenu.GetSubMenu(otherHelpMenuPos)
|
||
|
while otherMenu.GetMenuItemCount():
|
||
|
otherMenu.DeleteMenu(0, win32con.MF_BYPOSITION)
|
||
|
|
||
|
if helpIDMap:
|
||
|
for id, (desc, fname) in helpIDMap.items():
|
||
|
otherMenu.AppendMenu(win32con.MF_ENABLED | win32con.MF_STRING, id, desc)
|
||
|
else:
|
||
|
helpMenu.EnableMenuItem(
|
||
|
otherHelpMenuPos, win32con.MF_BYPOSITION | win32con.MF_GRAYED
|
||
|
)
|
||
|
|
||
|
|
||
|
def HandleHelpOtherCommand(cmd, code):
|
||
|
OpenHelpFile(helpIDMap[cmd][1])
|