|
1 # -*- coding: utf-8 -*- |
|
2 |
|
3 # Copyright (c) 2009 Detlev Offenbach <detlev@die-offenbachs.de> |
|
4 # |
|
5 |
|
6 """ |
|
7 Module implementing the QtHelp generator for the builtin documentation generator. |
|
8 """ |
|
9 |
|
10 import sys |
|
11 import os |
|
12 import shutil |
|
13 import codecs |
|
14 import subprocess |
|
15 |
|
16 from Utilities import joinext, relpath, html_encode |
|
17 |
|
18 HelpCollection = r"""<?xml version="1.0" encoding="utf-8" ?> |
|
19 <QHelpCollectionProject version="1.0"> |
|
20 <docFiles> |
|
21 <register> |
|
22 <file>%(helpfile)s</file> |
|
23 </register> |
|
24 </docFiles> |
|
25 </QHelpCollectionProject> |
|
26 """ |
|
27 |
|
28 HelpProject = r"""<?xml version="1.0" encoding="UTF-8"?> |
|
29 <QtHelpProject version="1.0"> |
|
30 <namespace>%(namespace)s</namespace> |
|
31 <virtualFolder>%(folder)s</virtualFolder> |
|
32 <customFilter name="%(filter_name)s"> |
|
33 %(filter_attributes)s |
|
34 </customFilter> |
|
35 <filterSection> |
|
36 %(filter_attributes)s |
|
37 <toc> |
|
38 %(sections)s |
|
39 </toc> |
|
40 <keywords> |
|
41 %(keywords)s |
|
42 </keywords> |
|
43 <files> |
|
44 %(files)s |
|
45 </files> |
|
46 </filterSection> |
|
47 </QtHelpProject> |
|
48 """ |
|
49 |
|
50 HelpProjectFile = 'source.qhp' |
|
51 HelpHelpFile = 'source.qch' |
|
52 HelpCollectionProjectFile = 'source.qhcp' |
|
53 HelpCollectionFile = 'collection.qhc' |
|
54 |
|
55 class QtHelpGenerator(object): |
|
56 """ |
|
57 Class implementing the QtHelp generator for the builtin documentation generator. |
|
58 """ |
|
59 def __init__(self, htmlDir, |
|
60 outputDir, namespace, virtualFolder, filterName, filterAttributes, |
|
61 title, createCollection): |
|
62 """ |
|
63 Constructor |
|
64 |
|
65 @param htmlDir directory containing the HTML files (string) |
|
66 @param outputDir output directory for the files (string) |
|
67 @param namespace namespace to be used (string) |
|
68 @param virtualFolder virtual folder to be used (string) |
|
69 @param filterName name of the custom filter (string) |
|
70 @param filterAttributes ':' separated list of filter attributes (string) |
|
71 @param title title to be used for the generated help (string) |
|
72 @param createCollection flag indicating the generation of the collection |
|
73 files (boolean) |
|
74 """ |
|
75 self.htmlDir = htmlDir |
|
76 self.outputDir = outputDir |
|
77 self.namespace = namespace |
|
78 self.virtualFolder = virtualFolder |
|
79 self.filterName = filterName |
|
80 self.filterAttributes = filterAttributes and filterAttributes.split(':') or [] |
|
81 self.relPath = relpath(self.htmlDir, self.outputDir) |
|
82 self.title = title |
|
83 self.createCollection = createCollection |
|
84 |
|
85 self.packages = { |
|
86 "00index" : { |
|
87 "subpackages" : {}, |
|
88 "modules" : {} |
|
89 } |
|
90 } |
|
91 self.remembered = False |
|
92 self.keywords = [] |
|
93 |
|
94 def remember(self, file, moduleDocument, basename=""): |
|
95 """ |
|
96 Public method to remember a documentation file. |
|
97 |
|
98 @param file The filename to be remembered. (string) |
|
99 @param moduleDocument The ModuleDocument object containing the |
|
100 information for the file. |
|
101 @param basename The basename of the file hierarchy to be documented. |
|
102 The basename is stripped off the filename if it starts with |
|
103 the basename. |
|
104 """ |
|
105 self.remembered = True |
|
106 if basename: |
|
107 file = file.replace(basename, "") |
|
108 |
|
109 if "__init__" in file: |
|
110 dir = os.path.dirname(file) |
|
111 udir = os.path.dirname(dir) |
|
112 base = os.path.basename(dir) |
|
113 if udir: |
|
114 upackage = udir.replace(os.sep, ".") |
|
115 try: |
|
116 elt = self.packages[upackage] |
|
117 except KeyError: |
|
118 elt = self.packages["00index"] |
|
119 else: |
|
120 elt = self.packages["00index"] |
|
121 package = dir.replace(os.sep, ".") |
|
122 elt["subpackages"][package] = moduleDocument.name() |
|
123 |
|
124 self.packages[package] = { |
|
125 "subpackages" : {}, |
|
126 "modules" : {} |
|
127 } |
|
128 |
|
129 kwEntry = ("%s (Package)" % package.split('.')[-1], |
|
130 joinext("index-%s" % package, ".html")) |
|
131 if kwEntry not in self.keywords: |
|
132 self.keywords.append(kwEntry) |
|
133 |
|
134 if moduleDocument.isEmpty(): |
|
135 return |
|
136 |
|
137 package = os.path.dirname(file).replace(os.sep, ".") |
|
138 try: |
|
139 elt = self.packages[package] |
|
140 except KeyError: |
|
141 elt = self.packages["00index"] |
|
142 elt["modules"][moduleDocument.name()] = moduleDocument.name() |
|
143 |
|
144 if "__init__" not in file: |
|
145 kwEntry = ("%s (Module)" % moduleDocument.name().split('.')[-1], |
|
146 joinext(moduleDocument.name(), ".html")) |
|
147 if kwEntry not in self.keywords: |
|
148 self.keywords.append(kwEntry) |
|
149 for kw in moduleDocument.getQtHelpKeywords(): |
|
150 kwEntry = (kw[0], "%s%s" % (joinext(moduleDocument.name(), ".html"), kw[1])) |
|
151 if kwEntry not in self.keywords: |
|
152 self.keywords.append(kwEntry) |
|
153 |
|
154 def __generateSections(self, package, level): |
|
155 """ |
|
156 Private method to generate the sections part. |
|
157 |
|
158 @param package name of the package to process (string) |
|
159 @param level indentation level (integer) |
|
160 @return sections part (string) |
|
161 """ |
|
162 indent = level * ' ' |
|
163 indent1 = indent + ' ' |
|
164 s = indent + '<section title="%s" ref="%s">\n' % \ |
|
165 (package == "00index" and self.title or package, |
|
166 package == "00index" and \ |
|
167 joinext("index", ".html") or \ |
|
168 joinext("index-%s" % package, ".html")) |
|
169 for subpack in sorted(self.packages[package]["subpackages"]): |
|
170 s += self.__generateSections(subpack, level + 1) |
|
171 for mod in sorted(self.packages[package]["modules"]): |
|
172 s += indent1 + '<section title="%s" ref="%s" />\n' % \ |
|
173 (mod, joinext(mod, ".html")) |
|
174 s += indent + '</section>\n' |
|
175 return s |
|
176 |
|
177 def __generateKeywords(self): |
|
178 """ |
|
179 Private method to generate the keywords section. |
|
180 |
|
181 @return keywords section (string) |
|
182 """ |
|
183 indent = level * ' ' |
|
184 return "\n".join([]) |
|
185 |
|
186 def generateFiles(self, basename = ""): |
|
187 """ |
|
188 Public method to generate all index files. |
|
189 |
|
190 @param basename The basename of the file hierarchy to be documented. |
|
191 The basename is stripped off the filename if it starts with |
|
192 the basename. |
|
193 """ |
|
194 if not self.remembered: |
|
195 sys.stderr.write("No QtHelp to generate.\n") |
|
196 return |
|
197 |
|
198 if basename: |
|
199 basename = basename.replace(os.sep, ".") |
|
200 if not basename.endswith("."): |
|
201 basename = "%s." % basename |
|
202 |
|
203 sections = self.__generateSections("00index", 3) |
|
204 filesList = sorted([e for e in os.listdir(self.htmlDir) if e.endswith('.html')]) |
|
205 files = "\n".join([" <file>%s</file>" % f for f in filesList]) |
|
206 filterAttribs = "\n".join([" <filterAttribute>%s</filterAttribute>" % a \ |
|
207 for a in self.filterAttributes]) |
|
208 keywords = "\n".join( |
|
209 [' <keyword name="%s" id="%s" ref="%s" />' % \ |
|
210 (html_encode(kw[0]), html_encode(kw[0]), html_encode(kw[1])) \ |
|
211 for kw in self.keywords]) |
|
212 |
|
213 helpAttribs = { |
|
214 "namespace" : self.namespace, |
|
215 "folder" : self.virtualFolder, |
|
216 "filter_name" : self.filterName, |
|
217 "filter_attributes" : filterAttribs, |
|
218 "sections" : sections, |
|
219 "keywords" : keywords, |
|
220 "files" : files, |
|
221 } |
|
222 |
|
223 f = codecs.open(os.path.join(self.outputDir, HelpProjectFile), 'w', 'utf-8') |
|
224 f.write(HelpProject % helpAttribs) |
|
225 f.close() |
|
226 |
|
227 if self.createCollection and \ |
|
228 not os.path.exists(os.path.join(self.outputDir, HelpCollectionProjectFile)): |
|
229 collectionAttribs = { |
|
230 "helpfile" : HelpHelpFile, |
|
231 } |
|
232 |
|
233 f = codecs.open(os.path.join(self.outputDir, HelpCollectionProjectFile), |
|
234 'w', 'utf-8') |
|
235 f.write(HelpCollection % collectionAttribs) |
|
236 f.close() |
|
237 |
|
238 sys.stdout.write("QtHelp files written.\n") |
|
239 sys.stdout.write("Generating QtHelp documentation...\n") |
|
240 sys.stdout.flush() |
|
241 sys.stderr.flush() |
|
242 |
|
243 cwd = os.getcwd() |
|
244 # generate the compressed files |
|
245 shutil.copy(os.path.join(self.outputDir, HelpProjectFile), self.htmlDir) |
|
246 os.chdir(self.htmlDir) |
|
247 subprocess.call(["qhelpgenerator", "source.qhp", |
|
248 "-o", os.path.join(self.outputDir, HelpHelpFile)]) |
|
249 os.remove(HelpProjectFile) |
|
250 |
|
251 if self.createCollection: |
|
252 sys.stdout.write("Generating QtHelp collection...\n") |
|
253 sys.stdout.flush() |
|
254 sys.stderr.flush() |
|
255 os.chdir(self.outputDir) |
|
256 subprocess.call(["qcollectiongenerator", "source.qhcp", "-o", "collection.qhc"]) |
|
257 |
|
258 os.chdir(cwd) |