File size: 5,650 Bytes
d12bc25
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
# 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])