File indexing completed on 2024-12-08 04:20:22
0001 # -*- coding: utf-8 -*- 0002 # Copyright 2009-2010 Simon Edwards <simon@simonzone.com> 0003 # 0004 # This program is free software; you can redistribute it and/or modify 0005 # it under the terms of the GNU General Public License as published by 0006 # the Free Software Foundation; either version 2 of the License, or 0007 # (at your option) any later version. 0008 # 0009 # This program is distributed in the hope that it will be useful, 0010 # but WITHOUT ANY WARRANTY; without even the implied warranty of 0011 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0012 # GNU General Public License for more details. 0013 # 0014 # You should have received a copy of the GNU General Public License 0015 # along with this program; if not, write to the 0016 # Free Software Foundation, Inc., 0017 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 0018 0019 #from argvalidate import accepts,returns,one_of 0020 import types 0021 from .sealed import sealed 0022 import kbindinggenerator.cmake as cmake 0023 import kbindinggenerator.cpplexer as cpplexer 0024 import kbindinggenerator.cppparser as cppparser 0025 import kbindinggenerator.cppsymboldata as cppsymboldata 0026 import kbindinggenerator.sipparser as sipparser 0027 import kbindinggenerator.sipsymboldata as sipsymboldata 0028 import kbindinggenerator.cpptosiptransformer as cpptosiptransformer 0029 import kbindinggenerator.sipmerger as sipmerger 0030 import os 0031 import os.path 0032 import glob 0033 from .reducetxt import Reduce 0034 0035 0036 def cmp(a, b): 0037 return (a > b) - (a < b) 0038 0039 reducer = Reduce() 0040 0041 class ModuleGenerator(object): 0042 @sealed 0043 def __init__(self,module,cmakelists=[], cmakeVariables=None, headers=[],ignoreHeaders=[],noUpdateSip=[],outputDirectory=None, 0044 preprocessorValues=[],preprocessSubstitutionMacros=[],macros=[],bareMacros=[],exportMacros=None, 0045 ignoreBases=None,noCTSCC=[],sipImportDirs=[],sipImports=[],copyrightNotice=None, 0046 annotationRules=[],docsOutputDirectory=None,mainDocs=None,filenameMappingFunction=None, 0047 cppHeaderMappingFunction=None): 0048 0049 self._module = module 0050 self._cmakelists = [cmakelists] if (isinstance(cmakelists,str) or isinstance(cmakelists,unicode)) else cmakelists 0051 self._cmakeVariables = cmakeVariables if cmakeVariables is not None else {} 0052 self._headers = headers 0053 self._ignoreHeaders = set([ignoreHeaders] if isinstance(ignoreHeaders,str) else ignoreHeaders) 0054 self._noUpdateSip = noUpdateSip 0055 self._outputDirectory = outputDirectory 0056 0057 self._preprocessorValues = preprocessorValues 0058 self._preprocessSubstitutionMacros = preprocessSubstitutionMacros 0059 self._macros = macros 0060 self._bareMacros = bareMacros 0061 0062 self._filenameMappingFunction = filenameMappingFunction 0063 self._cppHeaderMappingFunction = cppHeaderMappingFunction 0064 0065 self._symbolData = cppsymboldata.SymbolData() 0066 self._cppParser = cppparser.CppParser() 0067 self._cppParser.preprocessorValues = self._preprocessorValues 0068 self._cppParser.bareMacros = self._bareMacros 0069 self._cppParser.macros = self._macros 0070 self._cppParser.preprocessorSubstitutionMacros = self._preprocessSubstitutionMacros 0071 0072 self._cppScopeList = [] 0073 0074 self._transformer = cpptosiptransformer.CppToSipTransformer() 0075 self._transformer.setExportMacros(exportMacros) 0076 self._transformer.setIgnoreBaseClasses(ignoreBases) 0077 self._transformer.setCopyrightNotice(copyrightNotice) 0078 self._noCTSCC = noCTSCC 0079 0080 self._copyrightNotice = copyrightNotice 0081 0082 self._sipImportDirs = sipImportDirs 0083 self._sipImports = sipImports 0084 0085 self._sipParser = sipparser.SipParser() 0086 self._sipSymbolData = sipsymboldata.SymbolData() 0087 0088 self._annotator = cpptosiptransformer.SipAnnotator() 0089 self._annotator.setMethodAnnotationRules(annotationRules) 0090 0091 self._docsOutputDirectory = docsOutputDirectory 0092 self._mainDocs = mainDocs 0093 0094 def run(self): 0095 print("Extracting header file list from CMake:") 0096 cppHeaderFilenameSet = self.extractCmakeListsHeaders() 0097 0098 extraHeaderSet = self.expandHeaders() 0099 cppHeaderFilenameSet.update(extraHeaderSet) 0100 0101 cppHeaderFilenameList = list(cppHeaderFilenameSet) 0102 cppHeaderFilenameList.sort() 0103 for filename in cppHeaderFilenameList: 0104 print(" Found %s" % (filename,)) 0105 0106 print("\nParsing Cpp headers:") 0107 headerScopeTuples = self._parseHeaders(cppHeaderFilenameList) 0108 0109 print("\nParsing imported Sip files:") 0110 self._parseImportedSip() 0111 0112 print("\nConverting header files into Sip files.") 0113 moduleSipScopes = self._convertCppToSip(headerScopeTuples) 0114 0115 print("\nExpanding class names:") 0116 for scope in moduleSipScopes: 0117 cpptosiptransformer.ExpandClassNames(self._sipSymbolData,scope) 0118 0119 print("\nAnnotating Sip files.") 0120 self._annotateSipScopes(moduleSipScopes) 0121 0122 _indexFilename = self._indexFilename() 0123 if os.path.exists(_indexFilename): 0124 print("\nParsing previous Sip files.") 0125 moduleSipScopes = self._updateScopes(moduleSipScopes) 0126 else: 0127 print("(%s not found. Skipping merge with previous sip files.)" % (_indexFilename,)) 0128 0129 print("\n") 0130 0131 print("Computing 'Convert To Sub Class Code'.") 0132 cpptosiptransformer.UpdateConvertToSubClassCodeDirectives(self._sipSymbolData,moduleSipScopes,self._noCTSCC) 0133 0134 #print("Sanity check.") 0135 #cpptosiptransformer.SanityCheckSip(self._sipSymbolData,moduleSipScopes) 0136 #return 0137 print("Writing Sip files.") 0138 if self._outputDirectory is not None: 0139 0140 if os.path.exists(self._outputDirectory) and not os.path.isdir(self._outputDirectory): 0141 print("Error: Output directory '%s' is not a directory.") 0142 else: 0143 if not os.path.exists(self._outputDirectory): 0144 os.mkdir(self._outputDirectory) 0145 self._writeScopes(moduleSipScopes) 0146 self._writeIndexSip(moduleSipScopes) 0147 else: 0148 print("Warning: Skipping writing because no output directory was specified.") 0149 0150 #for scope in moduleSipScopes: 0151 # print(scope.format()) 0152 print("Done.") 0153 0154 def extractCmakeListsHeaders(self): 0155 filenames = [] 0156 for cmakeFilename in self._cmakelists: 0157 dirName = os.path.dirname(cmakeFilename) 0158 for header in cmake.ExtractInstallFiles(cmakeFilename, variables=self._cmakeVariables): 0159 if os.path.basename(header) not in self._ignoreHeaders: 0160 filenames.append(os.path.join(dirName,header)) 0161 print(repr(set(filenames))) 0162 return set(filenames) 0163 0164 def expandHeaders(self): 0165 expanded_headers = set() 0166 for pattern in self._headers: 0167 for header in glob.iglob(pattern): 0168 expanded_headers.add(header) 0169 return expanded_headers 0170 0171 def _parseHeaders(self,cppHeaderFilenameList): 0172 headerScopeTuples = [] 0173 0174 for filename in cppHeaderFilenameList: 0175 print(" Parsing %s" % (filename,)) 0176 with open(filename) as fhandle: 0177 text = fhandle.read() 0178 0179 if self._cppHeaderMappingFunction is not None: 0180 basename = self._cppHeaderMappingFunction(self,filename) 0181 else: 0182 basename = os.path.basename(filename) 0183 0184 scope = self._cppParser.parse(self._symbolData, text, filename=filename, debugLevel=0) 0185 scope.setHeaderFilename(basename) 0186 headerScopeTuples.append( (basename,scope) ) 0187 #print(scope.format()) 0188 return headerScopeTuples 0189 0190 def _parseImportedSip(self): 0191 scopes = [] 0192 0193 for sipImport in self._sipImports: 0194 filename = self._findSipMod(sipImport) 0195 if filename is None: 0196 raise SystemExit 0197 print(" Parsing %s" % (filename,)) 0198 scopes.append(self._importSipFile(filename)) 0199 return scopes 0200 0201 def _findSipMod(self,sipModName): 0202 for sipImportDir in self._sipImportDirs: 0203 filename = os.path.join(sipImportDir,sipModName) 0204 if os.path.exists(filename): 0205 return filename 0206 else: 0207 print("Error: Unable to find sip import '%s'. (sipImportDirs=%s" % (sipModName,repr(self._sipImportDirs))) 0208 return None 0209 0210 def _importSipFile(self,sipFilename,noUpdateSip=[],module=None): 0211 with open(sipFilename) as fhandle: 0212 text = fhandle.read() 0213 0214 scope = self._sipParser.parse(self._sipSymbolData,text,filename=sipFilename,debugLevel=0) 0215 0216 # Figure out the Cpp header file name. 0217 def extractHeader(directives,directiveName): 0218 for directive in directives: 0219 if directive.name()==directiveName and directive.body() is not None: 0220 for line in directive.body().split('\n'): 0221 if line.startswith("#include <"): 0222 return line[10:-1] 0223 0224 directives = self._findAllInstance(scope,self._sipSymbolData.SipDirective) 0225 scope.setHeaderFilename(extractHeader(directives,"%TypeHeaderCode") \ 0226 or extractHeader(directives,"%ModuleHeaderCode") \ 0227 or sipFilename) 0228 0229 # Set the correct module name 0230 for item in scope: 0231 if isinstance(item,self._sipSymbolData.SipDirective): 0232 if item.name()=="Module": 0233 module = item.body().split(' ')[1] 0234 break 0235 scope.setModule(module) 0236 0237 # print(sipFilename + " -> " + scope.headerFilename()) 0238 0239 scopeList = [scope] 0240 0241 #print("********************************************") 0242 #print(scope.format()) 0243 0244 modDir = os.path.dirname(sipFilename) 0245 0246 for item in scope: 0247 if isinstance(item,self._sipSymbolData.SipDirective): 0248 if item.body().startswith("%Include"): 0249 sipIncludeFilename = item.body()[len("%Include")+1:] 0250 if sipIncludeFilename not in noUpdateSip: 0251 sipIncludeFullFilename = os.path.join(modDir,sipIncludeFilename) 0252 if os.path.exists(sipIncludeFullFilename): 0253 scopeList.extend(self._importSipFile(sipIncludeFullFilename,module=module)) 0254 else: 0255 print("Error: Unable to find sip import '%s'. (sipImportDirs=%s" % (sipIncludeFilename,repr(self._sipImportDirs))) 0256 0257 return scopeList 0258 0259 def _findAllInstance(self,scope,matchType): 0260 result = [] 0261 for item in scope: 0262 if isinstance(item,matchType): 0263 result.append(item) 0264 if isinstance(item,self._sipSymbolData.SipClass) or isinstance(item,self._sipSymbolData.Namespace): 0265 result.extend(self._findAllInstance(item,matchType)) 0266 return result 0267 0268 def _convertCppToSip(self,headerScopeTuples): 0269 sipScopes = [] 0270 for headerName,cppScope in headerScopeTuples: 0271 print(" Converting %s" % (headerName,)) 0272 sipscope = self._transformer.convert(cppScope,self._sipSymbolData) 0273 sipScopes.append(sipscope) 0274 return sipScopes 0275 0276 def _annotateSipScopes(self,moduleSipScopes): 0277 for scope in moduleSipScopes: 0278 self._annotator.applyRules(scope) 0279 0280 def _convertHeaderNameToSip(self,headerName): 0281 if self._filenameMappingFunction is not None: 0282 return self._filenameMappingFunction(self,headerName) 0283 0284 filename = os.path.basename(headerName) 0285 if filename.endswith(".h"): 0286 return filename[:-2]+".sip" 0287 return filename 0288 0289 def _writeScopes(self,moduleSipScopes): 0290 for scope in moduleSipScopes: 0291 fullPath = os.path.join(self._outputDirectory,self._convertHeaderNameToSip(scope.headerFilename())) 0292 with open(fullPath,'w') as fhandle: 0293 fhandle.write(scope.format()) 0294 0295 def _writeIndexSip(self,scopes): 0296 moduleName = self._module 0297 if '.' in self._module: 0298 moduleName = self._module[self._module.rfind('.')+1:] 0299 0300 indexFilename = self._indexFilename() 0301 with open(self._indexFilename(),'w') as fhandle: 0302 fhandle.write(self._indexSip( [s for s in scopes if s.headerFilename()!=indexFilename] )) 0303 0304 def _indexFilename(self): 0305 module = self._module 0306 if '.' in module: 0307 module = module.rpartition('.')[2] 0308 return os.path.join(self._outputDirectory,module) + "mod.sip" 0309 0310 def _updateScopes(self,updateSipScopes): 0311 previousSipScopes = self._importSipFile(self._indexFilename(),self._noUpdateSip) 0312 0313 # Match updateSipScopes 0314 updateSipMap = {} 0315 for scope in updateSipScopes: 0316 #print("header sip name: " + self._convertHeaderNameToSip(scope.headerFilename())) 0317 updateSipMap[self._convertHeaderNameToSip(scope.headerFilename())] = scope 0318 0319 for scope in previousSipScopes: 0320 filename = self._convertHeaderNameToSip(scope.headerFilename()) 0321 previousScope = updateSipMap.get(filename,None) 0322 if previousScope is not None: 0323 print(" Merging %s" % (filename,)) 0324 sipmerger.MergeSipScope(self._sipSymbolData,scope,updateSipMap[filename]) 0325 self._sipSymbolData.removeScope(updateSipMap[filename]) 0326 del updateSipMap[filename] 0327 else: 0328 print(" (Missing header file to match %s. Skipping merge.)" % (filename,) ) 0329 0330 for key in updateSipMap.keys(): 0331 print(" Adding new header "+key) 0332 previousSipScopes.append(updateSipMap[key]) 0333 0334 return previousSipScopes 0335 0336 def _indexSip(self,scopes): 0337 def key(x): return x.headerFilename() 0338 scopes.sort(key=key) 0339 0340 accu = [] 0341 0342 if self._copyrightNotice is not None: 0343 accu.append(self._copyrightNotice) 0344 0345 accu.append("\n%Module ") 0346 accu.append(self._module) 0347 accu.append("\n\n") 0348 0349 accu.append("%ModuleHeaderCode\n") 0350 accu.append("#pragma GCC visibility push(default)\n") 0351 accu.append("%End\n\n") 0352 0353 # %Import 0354 for sipImport in self._sipImports: 0355 accu.append("%Import ") 0356 accu.append(sipImport) 0357 accu.append("\n") 0358 accu.append("\n") 0359 0360 for sipFile in self._noUpdateSip: 0361 accu.append("%Include ") 0362 accu.append(sipFile) 0363 accu.append("\n") 0364 0365 for scope in scopes: 0366 accu.append("%Include ") 0367 accu.append(self._convertHeaderNameToSip(scope.headerFilename())) 0368 accu.append("\n") 0369 0370 return ''.join(accu) 0371 0372 def docs(self): 0373 print("Extracting header file list from CMake:") 0374 cppHeaderFilenameSet = self.extractCmakeListsHeaders() 0375 0376 extraHeaderSet = self.expandHeaders() 0377 cppHeaderFilenameSet.update(extraHeaderSet) 0378 0379 cppHeaderFilenameList = list(cppHeaderFilenameSet) 0380 cppHeaderFilenameList.sort() 0381 for filename in cppHeaderFilenameList: 0382 print(" Found %s" % (filename,)) 0383 0384 print("\nParsing Cpp headers:") 0385 headerScopeTuples = self._parseHeaders(cppHeaderFilenameList) 0386 cppScopes = [ x[1] for x in headerScopeTuples] 0387 0388 print("\nParsing imported Sip files:") 0389 self._parseImportedSip() 0390 0391 print("\nParsing module files:") 0392 previousSipScopes = self._importSipFile(self._indexFilename(),self._noUpdateSip) 0393 0394 print("\nWriting index page:") 0395 self.writeModuleIndexPage(previousSipScopes) 0396 0397 print("\nWriting class pages:") 0398 subclassMapping = BuildSubclassMap(previousSipScopes,self._sipSymbolData) 0399 #print(repr(subclassMapping)) 0400 0401 # Write out the 0402 def writeScopeDocs(scope): 0403 for item in scope: 0404 if isinstance(item,self._sipSymbolData.SipClass): 0405 self.writeClassDoc(item,subclassMapping) 0406 writeScopeDocs(item) 0407 elif isinstance(item,self._sipSymbolData.Namespace): 0408 writeScopeDocs(item) 0409 for scope in previousSipScopes: 0410 writeScopeDocs(scope) 0411 0412 print("\nWriting namespace pages:") 0413 self.writeNamespaces(previousSipScopes,cppScopes) 0414 return previousSipScopes 0415 0416 # @accepts(sipsymboldata.SymbolData.SipClass, dict) 0417 def writeClassDoc(self, sipClass, subclassMapping): 0418 classComment = "" 0419 cppClass = None 0420 try: 0421 cppClass = self._symbolData.lookupType(sipClass.fqName(),sipClass) 0422 0423 #print("\nHit " + sipClass.fqName()) 0424 #print("parent "+repr(cppClass.parentScope())) 0425 0426 parentScope = cppClass.parentScope() 0427 for item in parentScope: 0428 if isinstance(item,self._symbolData.Comment): 0429 classComment = item.value() 0430 #print("classComment:"+classComment) 0431 if item is cppClass: 0432 break 0433 0434 except KeyError: 0435 print("Unable to find Cpp class info for '" + sipClass.fqName() +" ' while writing class docs.") 0436 0437 self.writeClassPage(sipClass,subclassMapping,cppClass,classComment) 0438 0439 # @accepts(sipsymboldata.SymbolData.Entity) 0440 # @returns(str) 0441 def commentMapKey(self, item): 0442 if isinstance(item, (self._sipSymbolData.Constructor, self._symbolData.Constructor)): 0443 argNames = [(x.name() if x.name() is not None else "") for x in item.arguments()] 0444 key = item.name() + "|" + '|'.join(argNames) 0445 else: 0446 key = item.name() 0447 return key 0448 0449 # @accepts(sipsymboldata.SymbolData.CppClass) 0450 # @returns(dict) 0451 def buildCommentMap(self,cppClass): 0452 lastComment = None 0453 commentMap = {} 0454 0455 for item in cppClass: 0456 if isinstance(item,self._symbolData.Comment): 0457 lastComment = item.value() 0458 elif lastComment is not None: 0459 if isinstance(item, (self._symbolData.Function,self._symbolData.Enum) ): 0460 commentMap[self.commentMapKey(item)] = lastComment 0461 lastComment = None 0462 return commentMap 0463 0464 # @accepts(sipsymboldata.SymbolData.SipClass, dict, one_of(sipsymboldata.SymbolData.CppClass,types.NoneType), str) 0465 def writeClassPage(self,sipClass,subclassMapping,cppClass,classComment): 0466 def nameKey(a): return a.name() if a.name() is not None else "" 0467 enumList = [item for item in sipClass if isinstance(item,self._sipSymbolData.Enum) and not item.ignore()] 0468 enumList.sort(key=nameKey) 0469 0470 methodList = [item for item in sipClass if isinstance(item,self._sipSymbolData.Function) and not item.ignore()] 0471 methodList.sort(key=nameKey) 0472 constructorList = [item for item in sipClass if isinstance(item,self._sipSymbolData.Constructor) and not item.ignore()] 0473 constructorList.extend(methodList) 0474 methodList = constructorList 0475 0476 classList = [item for item in sipClass if isinstance(item,self._sipSymbolData.SipClass) and not item.ignore()] 0477 classList.sort(key=nameKey) 0478 0479 variableList = [item for item in sipClass if isinstance(item,self._sipSymbolData.Variable) and not item.ignore()] 0480 variableList.sort(key=nameKey) 0481 0482 commentMap = self.buildCommentMap(cppClass) if cppClass is not None else {} 0483 0484 #if cls in self.flagged: 0485 # flags = self.flagged [cls] 0486 #else: 0487 # flags = None 0488 0489 # create class page and add header 0490 className = sipClass.fqPythonName() # FIXME fqn required plus the python name. 0491 0492 page = open(os.path.join(self._docsOutputDirectory, "%s.html" % className), 'w') 0493 page.write(htmlHeader % {'title': className, 'path': '../'}) 0494 0495 if isSipClassAbstract(sipClass): 0496 abstract = """<dl class="abstract" compact><dt><b>Abstract class:</b></dt> 0497 <dd>This class can be used as a base class for new classes, but can not be instantiated directly.</dd></dl>""" 0498 else: 0499 abstract = '' 0500 # → arrow 0501 if len(sipClass.bases())!=0: 0502 bases = [] 0503 for base in sipClass.bases(): 0504 try: 0505 baseClass = self._sipSymbolData.lookupType(base,sipClass) 0506 except KeyError: 0507 baseClass = None 0508 if baseClass is not None: 0509 try: 0510 if isinstance(baseClass,self._sipSymbolData.Typedef): 0511 classHierarchy = self._sipSymbolData.lookupType(baseClass.argumentType(),baseClass).classHierarchy() 0512 else: 0513 classHierarchy = baseClass.classHierarchy() 0514 except KeyError: 0515 print("KeyError: Look up error on '"+baseClass.name()+"'") 0516 classHierarchy = [] 0517 0518 bases.append(' → '.join([self.formatType(x.fqPythonName(),sipClass) for x in classHierarchy])) 0519 0520 baseClasses = 'Inherits: '+ (','.join(bases)) + '<br />' 0521 else: 0522 baseClasses = '' 0523 0524 subClassSet = subclassMapping.get(sipClass,None) 0525 if subClassSet is not None: 0526 subClassList = list(subClassSet) 0527 subClassList.sort(key=nameKey) 0528 subClasses = 'Subclasses: ' + (', '.join ( [self.formatType(x.fqName(),sipClass) for x in subClassList] )) + '<br />' 0529 else: 0530 subClasses = '' 0531 0532 parentScope = sipClass.parentScope() 0533 if parentScope.name() is not None: 0534 namespace = "Namespace: " + self.linkType(parentScope.fqName(),None) + "<br />" 0535 else: 0536 namespace = "" 0537 0538 page.write (classHeader % 0539 {'classname': pyName(sipClass), 0540 'abstract': abstract, 0541 'modulename': self._module, 0542 'namespace': namespace, 0543 'baseclasses': baseClasses, 0544 'subclasses': subClasses, 0545 'description': self.formatDoxygen(classComment)} ) 0546 0547 page.write("""<table border="0" cellpadding="0" cellspacing="0">""") 0548 0549 # enums 0550 page.write(self.writeEnums(enumList)) 0551 0552 page.write(self.writeVariables(variableList)) 0553 0554 count = [0] 0555 def SignalFilter(obj): 0556 if obj.access() is self._sipSymbolData.ACCESS_SIGNALS: 0557 count[0] += 1 0558 return True 0559 else: 0560 return False 0561 s = self.writeMethodIndex(methodList, SignalFilter, "Signals", False) 0562 if count[0]!=0: 0563 page.write(s) 0564 0565 count = [0] 0566 def MethodFilter(obj): 0567 if (not obj.storage() == 'static') and not (obj.access() is self._sipSymbolData.ACCESS_SIGNALS): 0568 count[0] += 1 0569 return True 0570 else: 0571 return False 0572 s = self.writeMethodIndex(methodList, MethodFilter, "Methods") 0573 if count[0]!=0: 0574 page.write(s) 0575 0576 count = [0] 0577 def StaticFilter(obj): 0578 if obj.storage() == 'static' and not (obj.access() is self._sipSymbolData.ACCESS_SIGNALS): 0579 count[0] += 1 0580 return True 0581 else: 0582 return False 0583 s = self.writeMethodIndex(methodList, StaticFilter, "Static Methods", False) 0584 if count[0]!=0: 0585 page.write(s) 0586 0587 page.write("</table>\n") 0588 0589 0590 # signals 0591 self.writeMethodDetails(page, [x for x in methodList if SignalFilter(x)], commentMap, 0592 "Signal Documentation",True) 0593 0594 # methods 0595 self.writeMethodDetails(page, [x for x in methodList if MethodFilter(x)], commentMap) 0596 0597 # Static methods 0598 self.writeMethodDetails(page, [x for x in methodList if StaticFilter(x)], commentMap, 0599 "Static Method Documentation",True) 0600 0601 # variables 0602 self.writeVariableDetails(page, variableList, commentMap) 0603 0604 # enum detail 0605 self.writeEnumDetail(page, enumList, commentMap)#, flags) 0606 0607 # footer 0608 page.write(htmlFooter % {'path': '../'}) 0609 page.close() 0610 0611 # @accepts(list, types.FunctionType, str, useSelf=bool) 0612 # @returns(str) 0613 def writeMethodIndex(self, methodList, methodFilter, title, useSelf=True): 0614 result = [] 0615 result.append("""<tr><td colspan="2"><br><h2>""") 0616 result.append(title) 0617 result.append("""</h2></td></tr>\n""") 0618 0619 for obj in methodList: 0620 if not methodFilter(obj): 0621 continue 0622 0623 retList = [] 0624 if obj.return_(): 0625 retList.append(self.formatArgument(obj.return_(),obj)) 0626 0627 for arg in obj.arguments(): 0628 if 'Out' in arg.annotations(): 0629 if arg.name(): 0630 retList.append ('%s %s' % (self.formatType(arg.argumentType(),obj), arg.name())) 0631 else: 0632 retList.append (self.formatType(arg.argumentType(),obj)) 0633 0634 if retList: 0635 ret = ', '.join ( (item for item in retList if item!='') ) 0636 else: 0637 ret = '' 0638 0639 # param = '' 0640 # if 'pure' in obj.attributes.functionQualifier: 0641 # param += '<b style="color : #00aa00">pure virtual</b>' 0642 # if obj.ignore or obj.access == 'private': 0643 # param = '<i style="color : #aa0000">Not implemented</i>' 0644 # 0645 # if param != '': 0646 # print(obj.name + "~> "+param) 0647 0648 if isinstance(obj, self._sipSymbolData.Constructor): 0649 memname = "__init__" 0650 ret = "" 0651 else: 0652 memname = pyName(obj) 0653 memname = '<a class="el" href="#' + linkId(obj) + '">' + memname + '</a>' 0654 0655 result.append('<tr><td class="memItemLeft" nowrap align="right" valign="top">' + ret +' </td><td class="memItemRight" valign="bottom">' + memname + ' (') 0656 0657 comma = "" 0658 if useSelf: 0659 result.append('self') 0660 if len(obj.arguments())!=0: 0661 comma = ", " 0662 0663 i = 0 0664 for a in obj.arguments(): 0665 if 'In' in a.annotations() or not 'Out' in a.annotations(): 0666 paramtype = self.formatType(a.argumentType(),obj) 0667 paramname = a.name() 0668 if paramname is None: 0669 paramname = 'a%i' % i 0670 if a.defaultValue() is not None: 0671 paramname += "=" + a.defaultValue().replace ('::', '.') 0672 0673 result.append(comma + paramtype + " " + paramname) 0674 comma = ", " 0675 i += 1 0676 result.append(')</td></tr>\n') 0677 return "".join(result) 0678 0679 # @accepts(file, list, dict, title=str, functions=bool) 0680 def writeMethodDetails(self, page, methodList, commentMap, title="Method Documentation", functions=False): 0681 if not methodList: 0682 return 0683 0684 page.write('<hr><h2>' + title + '</h2>') 0685 for obj in methodList: 0686 comment = commentMap.setdefault(self.commentMapKey(obj),"") 0687 self.writeMethodDetail(page, obj, comment, function=functions) 0688 0689 # @accepts(file, one_of(sipsymboldata.SymbolData.Function,sipsymboldata.SymbolData.Constructor), str, function=bool) 0690 def writeMethodDetail(self, page, obj, comment, function=False): 0691 retList = [] 0692 if obj.return_(): 0693 retList.append(self.formatArgument(obj.return_(),obj)) 0694 0695 for arg in obj.arguments(): 0696 if 'Out' in arg.annotations(): 0697 if arg.name(): 0698 retList.append ('%s %s' % (self.formatArgument(arg,obj), arg.name())) 0699 else: 0700 retList.append (self.formatArgument(arg,obj)) 0701 0702 if retList: 0703 ret = ', '.join ( (item for item in retList if item!='') ) 0704 else: 0705 ret = '' 0706 0707 # param = '' 0708 # if obj.ignore or obj.access == 'private': 0709 # param = '<i style="color : #aa0000">Not implemented</i>' 0710 #i = 0 0711 #for arg in obj.arguments: 0712 # if not arg.name(): 0713 # arg.name = 'a%i' % i 0714 # i += 1 0715 0716 args = """<a class="anchor" name=\"""" + linkId(obj) + """"></a> 0717 <div class="memitem"> 0718 <div class="memproto"> 0719 <table class="memname">""" 0720 if isinstance(obj, self._sipSymbolData.Constructor): 0721 memname = "__init__" 0722 ret = "" 0723 else: 0724 memname = ret + " " + pyName(obj) 0725 0726 filteredArguments = [a for a in obj.arguments() if 'In' in a.annotations() or not 'Out' in a.annotations()] 0727 0728 if not filteredArguments: 0729 selfarg = '<em>self</em> ' if 'static' not in obj.qualifier() and not function else '' 0730 args += """<tr> 0731 <td class="memname">%s</td> 0732 <td>(</td> 0733 <td class="paramtype"> </td> 0734 <td class="paramname">%s)</td> 0735 <td width="100%%"> </td> 0736 </tr> 0737 """ % (memname,selfarg) 0738 0739 else: 0740 bracket = "(" 0741 if not function: 0742 args += """<tr> 0743 <td class="memname">%s</td> 0744 <td>%s</td> 0745 <td class="paramtype"> <em>self</em>, </td> 0746 <td class="paramname"></td> 0747 </tr>""" % (memname,bracket) 0748 memname = "" 0749 bracket = "" 0750 0751 i = 0 0752 for a in filteredArguments: 0753 paramtype = self.formatArgument(a,obj) 0754 paramname = a.name() 0755 if paramname is None: 0756 paramname = 'a%i' % i 0757 if a.defaultValue() is not None: 0758 paramname += "=" + a.defaultValue().replace ('::', '.') 0759 0760 comma = ", " if a is not filteredArguments[-1] else "" 0761 0762 args += """<tr> 0763 <td class="memname">%s</td> 0764 <td>%s</td> 0765 <td class="paramtype">%s </td> 0766 <td class="paramname"><em>%s</em>%s</td> 0767 </tr> 0768 """ % (memname,bracket,paramtype,paramname,comma) 0769 memname = "" 0770 bracket = "" 0771 i += 1 0772 args += """<tr> 0773 <td></td> 0774 <td>)</td> 0775 <td></td> 0776 <td></td> 0777 <td width="100%"> </td> 0778 </tr>""" 0779 args += """</table> 0780 </div> 0781 """ 0782 page.write(args) 0783 0784 page.write('<div class="memdoc">') 0785 if 'pure' in obj.qualifier(): 0786 page.write("""<dl compact><dt><b>Abstract method:</b></dt><dd>""") 0787 page.write("This method is abstract and can be overridden but not called directly.") 0788 page.write("""</dd></dl>""") 0789 0790 page.write(self.formatDoxygen(comment)) 0791 if obj.access() is self._sipSymbolData.ACCESS_SIGNALS: 0792 args = [arg.argumentType() for arg in obj.arguments()] 0793 page.write("""<dl compact><dt><b>Signal syntax:</b></dt><dd>""") 0794 page.write("""<code>QObject.connect(source, SIGNAL("%s(%s)"), target_slot)</code>""" % (pyName(obj), ', '.join (args))) 0795 page.write("""</dd></dl>""") 0796 0797 page.write('</div></div>') 0798 0799 # @accepts(list) 0800 # @returns(str) 0801 def writeEnums(self, enumList): #:, flags = None): 0802 if len(enumList)==0: 0803 return "" 0804 0805 result = [] 0806 result.append("""<tr><td colspan="2"><br><h2>Enumerations</h2></td></tr>\n""") 0807 0808 for obj in enumList: 0809 typeSafe = None 0810 if not obj.name(): 0811 objName = "<anonymous>" 0812 else: 0813 #if flags and obj.name() in flags: 0814 # typeSafe = flags [obj.name()] 0815 objName = obj.name() 0816 0817 result.append('<tr><td class="memItemLeft" nowrap align="right" valign="top"><a class="el" href="#' + linkId(obj) + '">' + objName +'</a> </td><td class="memItemRight" valign="bottom">{ ') 0818 0819 result.append(", ".join( [x.name() for x in obj] )) 0820 0821 if typeSafe: 0822 result.append(' }<br><i>Typesafe wrapper:</i> %s</td></tr>\n' % (typeSafe)) 0823 else: 0824 result.append(" }</td></tr>\n") 0825 0826 return "".join(result) 0827 0828 # @accepts(list) 0829 # @returns(str) 0830 def writeVariables(self, variableList): 0831 if not variableList: 0832 return "" 0833 result = [] 0834 result.append("""<tr><td colspan="2"><br><h2>""") 0835 result.append("Attributes") 0836 result.append("""</h2></td></tr>\n""") 0837 0838 for obj in variableList: 0839 result.append('<tr><td class="memItemLeft" nowrap align="right" valign="top">' + self.formatArgument(obj.argument(),obj) + ' </td><td class="memItemRight" valign="bottom"><a class="el" href="#var' + linkId(obj) + '">' + obj.name() +'</a></td></tr>') 0840 return "".join(result) 0841 0842 # @accepts(file,list,dict) 0843 def writeVariableDetails(self, page, variableList, commentMap): 0844 if not variableList: 0845 return 0846 0847 page.write('<hr><h2>Attribute Documentation</h2>') 0848 0849 for obj in variableList: 0850 page.write("""<a class="anchor" name="var""" + linkId(obj) + """"></a> 0851 <div class="memitem"> 0852 <div class="memproto"> 0853 <table class="memname"> 0854 <tr><td class="memname">""") 0855 page.write(self.formatArgument(obj.argument(),obj)) 0856 page.write(" ") 0857 page.write(pyName(obj)) 0858 page.write("""</td> 0859 </tr> 0860 </table> 0861 </div> 0862 <div class="memdoc">""") 0863 page.write(self.formatDoxygen(commentMap.setdefault(self.commentMapKey(obj),""))) 0864 page.write("""</div></div><p>""") 0865 0866 # @accepts(file,list,dict) 0867 def writeEnumDetail(self, page, enumList, commentMap): #flags = None): 0868 if not enumList: 0869 return 0870 0871 page.write('<hr><h2>Enumeration Documentation</h2>') 0872 0873 for obj in enumList: 0874 page.write("""<a class="anchor" name=\"""" + linkId(obj) + """"></a> 0875 <div class="memitem"> 0876 <div class="memproto"> 0877 <table class="memname"> 0878 <tr><td class="memname">""") 0879 typeSafe = None 0880 if not obj.name(): 0881 name = 'anonymous' 0882 else: 0883 #if flags and obj.name() in flags: 0884 # typeSafe = flags [obj.name()] 0885 name = obj.name() 0886 page.write(name) 0887 page.write("""</td> 0888 </tr> 0889 </table> 0890 </div> 0891 <div class="memdoc">""") 0892 page.write(self.formatDoxygen(commentMap.setdefault(self.commentMapKey(obj),""))) 0893 0894 if typeSafe: 0895 page.write("""<dl compact><dt><b>Note:</b></dt><dd>""") 0896 page.write("It is necessary to wrap members of this enumeration in a <code>" + typeSafe + "</code> instance when passing them to a method as group of flags. ") 0897 if len(obj.enumerators())>=2: 0898 page.write("For example: <code>" + typeSafe + "( " + obj[0].name() + " | " + obj[1].name() + ")</code>") 0899 page.write("""</dd></dl>""") 0900 0901 page.write("""<dl compact><dt><b>Enumerator: </b></dt><dd> 0902 <table border="0" cellspacing="2" cellpadding="0">""") 0903 0904 if obj.name() is not None: 0905 try: 0906 cppEnum = self._symbolData.lookupType(obj.name(),obj) 0907 print("Enum type is :" + repr(cppEnum)); 0908 obj = cppEnum 0909 except KeyError: 0910 print("Couldn't find enum:"+obj.name()) 0911 0912 for e in obj: 0913 if isinstance(e,self._symbolData.Enumerator): 0914 #docLine = self.formatDoxygen(e.doc).strip().replace('/', ' ') 0915 docLine = '' 0916 if e.value(): 0917 val = '= ' + str(e.value()) 0918 else: 0919 val = '' 0920 0921 page.write('<tr><td valign="top"><em>') 0922 page.write(e.name()) 0923 page.write('</em> ') 0924 page.write(val) 0925 page.write(docLine) 0926 page.write('</td><td>') 0927 page.write("""</table> 0928 </dl> 0929 </div></div><p>""") 0930 0931 # @accepts(list) 0932 def writeModuleIndexPage(self,sipScopes): 0933 #nsNames = self.namespaces.keys() 0934 #nsNames.sort() 0935 nsList = list(set( (item.name() for scope in sipScopes for item in scope if isinstance(item,self._sipSymbolData.Namespace) and not item.ignore()) )) 0936 nsList.append('global') 0937 nsList.sort() 0938 0939 if self._mainDocs: 0940 mainDocs = FetchDocs(self._mainDocs) 0941 else: 0942 mainDocs = '' 0943 0944 page = open(os.path.join(self._docsOutputDirectory, 'index.html'), 'w') 0945 page.write(htmlHeader % {'title': ('Module %s' % self._module), 'path': '../'}) 0946 page.write("<h1>%s Module</h1>\n" % self._module) 0947 page.write("<hr>") 0948 page.write(self.formatDoxygen(mainDocs)) 0949 0950 self.writeNSNamespacesIndex(page, nsList) 0951 0952 classList = [] 0953 for scope in sipScopes: 0954 classList.extend(self._findAllInstance(scope,self._sipSymbolData.SipClass)) 0955 #print(repr(classList)) 0956 classList = list( set (class_ for class_ in classList if not class_.ignore()) ) 0957 def nameKey(a): return a.name() 0958 classList.sort(key=nameKey) 0959 0960 self.writeNSClassIndex(page, classList) 0961 0962 page.write(htmlFooter % {'path': '../'}) 0963 page.close() 0964 0965 # @accepts(list,list) 0966 def writeNamespaces(self,sipScopes,cppScopes): 0967 # Figure out what namespace we have. 0968 namespaceCollector = {} # namespace FQN -> list of namespace objects 0969 for scope in sipScopes: 0970 for item in scope: 0971 if isinstance(item, self._sipSymbolData.Namespace): 0972 nsList = namespaceCollector.setdefault(item.fqName(),[]) 0973 nsList.append(item) 0974 0975 #print("nsList: " + repr(nsList)) 0976 0977 self.writeNamespacePage("global",sipScopes,cppScopes) 0978 0979 for fqName,ns in namespaceCollector.items(): 0980 self.writeNamespacePage(fqName,ns,cppScopes) 0981 0982 # @accepts(str,list,list) 0983 def writeNamespacePage(self,nsName,nsList,cppScopes): 0984 # print(repr(cppScopes)) 0985 # create namespace page and add header 0986 nspage = open(os.path.join(self._docsOutputDirectory, "%s.html" % nsName), 'w') 0987 nspage.write(htmlHeader % {'title': nsName, 'path': '../'}) 0988 0989 importcode = "from %s.%s import *" % (self._module,nsName) 0990 if nsName=='global': 0991 importcode = "from " + self._module + " import *" 0992 0993 description = "" 0994 if nsName!='global': 0995 for cppNS in self._symbolData.lookupNamespace(nsName): 0996 lastComment = None 0997 for item in cppNS.parentScope(): 0998 if isinstance(item,self._symbolData.Comment): 0999 lastComment = item.value() 1000 elif isinstance(item,self._symbolData.Namespace) and item.fqName()==nsName and lastComment is not None: 1001 description = lastComment 1002 lastComment = None 1003 1004 nspage.write(namespaceHeader % {'namespacename': nsName, 1005 'modulename': self._module, 1006 'import': importcode, 1007 'description': self.formatDoxygen(description)}) 1008 1009 def nameKey(a): return a.name() 1010 classList = [] 1011 for scope in nsList: 1012 classList.extend(self._findAllInstance(scope,self._sipSymbolData.SipClass)) 1013 classList.sort(key=nameKey) 1014 1015 # Class index (to other pages) 1016 self.writeNSClassIndex(nspage, classList) 1017 1018 # Intra-page index 1019 nspage.write("""<table border="0" cellpadding="0" cellspacing="0">""") 1020 1021 # enums 1022 enumList = [item for scope in nsList for item in scope 1023 if isinstance(item, self._sipSymbolData.Enum)] 1024 enumList.sort(key=nameKey) 1025 nspage.write(self.writeEnums(enumList)) 1026 1027 # Functions 1028 functionList = [item for scope in nsList for item in scope 1029 if isinstance(item, self._sipSymbolData.Function)] 1030 functionList.sort(key=nameKey) 1031 def all(x): return True 1032 if len(functionList)!=0: 1033 nspage.write(self.writeMethodIndex(functionList, all, "Functions", False)) 1034 1035 # Variables 1036 variableList = [item for scope in nsList for item in scope 1037 if isinstance(item, self._sipSymbolData.Variable)] 1038 variableList.sort(key=nameKey) 1039 nspage.write(self.writeVariables(variableList)) 1040 1041 nspage.write("</table>\n") 1042 1043 # Build the comment map. 1044 commentMap ={} 1045 scopes = self._symbolData.lookupNamespace(nsName) if nsName!='global' else cppScopes 1046 for cppNS in scopes: 1047 lastComment = None 1048 for item in cppNS: 1049 if isinstance(item,self._symbolData.Comment): 1050 lastComment = item.value() 1051 elif (isinstance(item,self._symbolData.Function) or isinstance(item,self._symbolData.Variable) 1052 or isinstance(item,self._symbolData.Enum)) and lastComment is not None: 1053 commentMap[self.commentMapKey(item)] = lastComment 1054 lastComment = None 1055 1056 # enum detail 1057 self.writeEnumDetail(nspage, enumList, commentMap) 1058 1059 # Functions. 1060 self.writeMethodDetails(nspage, functionList, commentMap, "Function Documentation", True) 1061 1062 # variables 1063 self.writeVariableDetails(nspage, variableList, commentMap) 1064 1065 # footer 1066 nspage.write (htmlFooter % {'path': '../'}) 1067 nspage.close () 1068 1069 # @accepts(file,list) 1070 def writeNSNamespacesIndex(self, page, namespaces): 1071 if not namespaces: 1072 return 1073 1074 page.write("<h2>Namespaces</h2>\n") 1075 1076 def format(obj): 1077 indexstring = obj 1078 if indexstring[0].upper()=='K': 1079 indexstring = indexstring[1:] 1080 name = obj 1081 if name=='global': 1082 name = '<i>' + name + '</i>' 1083 cellcontents = '<a class="el" href="%s.html">%s</a> ' % (obj,name) 1084 return (indexstring,cellcontents) 1085 1086 page.write(FormatTable(namespaces, format, key)) 1087 1088 # @accepts(file,list) 1089 def writeNSClassIndex(self, page, rawClassList): 1090 if not rawClassList: 1091 return 1092 1093 page.write ("<h2>Class Index</h2>\n") 1094 1095 def format(obj): 1096 if not obj.ignore(): 1097 classname = indexstring = obj.name() 1098 if indexstring[0].upper()=='K': 1099 indexstring = indexstring[1:] 1100 parentScope = obj.parentScope() 1101 scope = parentScope.fqPythonName() 1102 if not scope: 1103 cellcontents = '<a class="el" href="%s.html">%s</a> ' \ 1104 % (classname,classname) 1105 else: 1106 cellcontents = '<a class="el" href="%s.%s.html">%s</a> (<a class="el" href="%s.html">%s</a>) ' \ 1107 % (scope,classname,classname,scope,scope) 1108 1109 return (indexstring,cellcontents) 1110 else: 1111 return None 1112 1113 def key_obj(a): 1114 return a.name() 1115 page.write(FormatTable(rawClassList, format, key_obj)) 1116 1117 @staticmethod 1118 def WriteAllClasses(htmldst, nsNames, classNames): 1119 1120 # self.mainIndex = open(os.path.join(htmldst, 'index.txt'), 'r') 1121 # for line in self.mainIndex: 1122 # specifier, name = line.split (':') 1123 # name = name.strip () 1124 # if specifier == 'm': 1125 # module = name 1126 # elif specifier == 'n': 1127 # if name in ['global', 'Sonnet']: 1128 # nsNames.append ((module, name, '%s - %s' % (name, module))) 1129 # else: 1130 # nsNames.append ((module, name, name)) 1131 # elif specifier == 'c': 1132 # classNames.append ((module, name, name)) 1133 1134 def key(x): return x[1] 1135 nsNames.sort(key=key) 1136 classNames.sort(key=key) 1137 1138 page = open(os.path.join(htmldst, 'allclasses.html'), 'w') 1139 page.write(htmlHeader % {'title': 'PyKDE Namespace and Class Index', 'path': ''}) 1140 1141 # Namespaces 1142 page.write("<p>\n<h2>All Namespaces</h2>\n") 1143 1144 def extract_name(x): 1145 nameparts = x.split('.') 1146 indexstring = nameparts[-1].lower() 1147 if indexstring.startswith('k'): 1148 indexstring = indexstring[1:] 1149 return indexstring 1150 1151 def format(t): 1152 nameparts = t[1].split('.') 1153 indexstring = nameparts[-1].lower() 1154 if indexstring.startswith('k'): 1155 indexstring = indexstring[1:] 1156 1157 name = nameparts[-1] + ' (' + ('.'.join( [t[0]] + nameparts[:-1] )) + ')' 1158 1159 cellcontents = '<a href="' + t[0] + '/' + t[1] + '.html">' + name + '</a>' 1160 return (indexstring,cellcontents) 1161 def t_key(a): 1162 return key(extract_name(a[1])) 1163 page.write(FormatTable(nsNames, format, t_key, columns=2)) 1164 1165 # Classes 1166 page.write("<p>\n<h2>All Classes</h2>\n") 1167 page.write(FormatTable(classNames, format, t_key, columns=2)) 1168 1169 page.write(htmlFooter % {'path': ''}) 1170 page.close() 1171 1172 @staticmethod 1173 def WriteMainPage(htmldst): 1174 page = open(os.path.join(htmldst, 'modules.html'), 'w') 1175 page.write(htmlHeader % {'title': 'KDE 5 PyKDE API Reference', 'path': ''}) 1176 1177 page.write("""<p> 1178 <h2>KDE 5.0 PyKDE API Reference</h2> 1179 </p> 1180 <p> 1181 This is the reference to the KDE API as it appears to Python programs using PyKDE. This is just 1182 reference material, additional information about developing KDE applications using Python and the KDE API 1183 in general can be found on <a href="http://techbase.kde.org/">Techbase</a> and in the 1184 <a href="http://techbase.kde.org/Development/Languages/Python">Python section</a>. The reference for 1185 <a href="http://pyqt.sourceforge.net/Docs/PyQt5/class_reference.html">PyQt 5 is here</a>. 1186 </p> 1187 1188 <p> 1189 This documentation is automatically generated from the original C++ headers and embedded documentation. 1190 The classes, methods, functions, namespaces etc are described as they appear to Python code and 1191 also include addition type information about expected parameters and return types. Note that 1192 code fragments in the documentation have not been translated from C++ to Python. 1193 </p> 1194 """) 1195 1196 page.write(htmlFooter % {'path': ''}) 1197 1198 page.close() 1199 1200 # @accepts(sipsymboldata.SymbolData.Argument,sipsymboldata.SymbolData.Entity) 1201 # @returns(str) 1202 def formatArgument(self, arg, context): 1203 #print("argument: " + arg.argumentType()) 1204 return self.formatType(arg.argumentType(),context) 1205 1206 # formatType() 1207 # rObj - string, type name, may contain C++ '&' and '*' characters. 1208 # @accepts(str,sipsymboldata.SymbolData.Entity) 1209 # @returns(str) 1210 def formatType(self, ret, context): 1211 r = '' 1212 if not ret or ret == 'void': 1213 return '' 1214 1215 for i in range(len(ret)): 1216 if not ret[i] in ('*', '&'): 1217 r += ret[i] 1218 1219 if ret=="char": 1220 ret = "QString" 1221 1222 #if rObj.parentScope(): 1223 # r = '.'.join ([rObj.parentScope().fqName(), r]) 1224 r = self.linkType(r, context) 1225 return r 1226 1227 CppPythonTypeMapping = { 1228 'bool': 'bool', 1229 'int': 'int', 1230 'float': 'float', 1231 'long': 'long', 1232 'short': 'int', 1233 'qint32': 'int', 1234 'quint16': 'int', 1235 'qint64': 'long', 1236 'quint32': 'long', 1237 'uint': 'long', 1238 'qlonglong': 'long', 1239 'qulonglong': 'long', 1240 'double': 'float', 1241 'unsigned int': 'long', 1242 'unsigned long': 'long', 1243 'qreal': 'float', 1244 'unsigned short': 'int', 1245 'long long': 'long', 1246 'unsigned long long': 'long' 1247 } 1248 1249 def linkType(self, typeName, context): 1250 if typeName.startswith("const "): 1251 typeName = typeName[6:] 1252 while typeName.endswith('*') or typeName.endswith('&'): 1253 typeName = typeName[:-1] 1254 1255 if typeName == '...': 1256 return typeName 1257 1258 if typeName == 'char': 1259 typeName = 'QString' 1260 1261 # Handle QList<...> 1262 if typeName.startswith("QList<"): 1263 return '[' + self.linkType(typeName[6:-1],context) + ']' 1264 1265 if typeName.startswith("QFlags<"): 1266 return 'QFlags<' + self.linkType(typeName[7:-1],context) + '>' 1267 1268 if typeName.startswith("QHash<"): 1269 pivot = typeName.index(",") 1270 leftType = self.linkType(typeName[6:pivot],context) 1271 rightType = self.linkType(typeName[pivot+1:-1],context) 1272 return '{' + leftType + ':'+ rightType + '}' 1273 1274 if typeName.startswith("QMap<"): 1275 pivot = typeName.index(",") 1276 leftType = self.linkType(typeName[5:pivot],context) 1277 rightType = self.linkType(typeName[pivot+1:-1],context) 1278 return '{' + leftType + ':'+ rightType + '}' 1279 1280 if typeName.startswith("QPair<"): 1281 pivot = typeName.index(",") 1282 leftType = self.linkType(typeName[6:pivot],context) 1283 rightType = self.linkType(typeName[pivot+1:-1],context) 1284 return '(' + leftType + ','+ rightType + ')' 1285 1286 if typeName.startswith("Qt.") or typeName.startswith("Qt::"): 1287 return '<a href="http://www.riverbankcomputing.co.uk/static/Docs/PyQt4/html/qt.html">' + typeName + '</a>' 1288 1289 pyType = self.CppPythonTypeMapping.get(typeName) 1290 if pyType is not None: 1291 return pyType 1292 1293 fileName = typeName.replace('::','.') 1294 try: 1295 typeObject = self._sipSymbolData.lookupType(typeName.replace('.','::'),context) 1296 1297 if isinstance(typeObject,self._sipSymbolData.Typedef) and not (typeObject.argumentType() is not None and typeObject.argumentType().startswith('QFlags')) and typeObject.argumentType() is not None: 1298 return self.linkType(typeObject.argumentType(),context) 1299 1300 #print("typeObject: "+repr(typeObject)) 1301 #print("typeObject.topScope():"+repr(typeObject.topScope())) 1302 typeModule = typeObject.topScope().module() 1303 #print("typeObject.topScope().module(): " + repr(typeModule)) 1304 if typeModule.startswith("PyQt"): 1305 return '<a href="http://www.riverbankcomputing.co.uk/static/Docs/PyQt4/html/' + typeName.lower().replace('::','-') + '.html">' + typeObject.fqPythonName() + '</a>' 1306 elif typeModule.startswith("PyKDE4"): 1307 if isinstance(typeObject,self._sipSymbolData.Enum): 1308 parentScope = typeObject.parentScope() 1309 if isinstance(parentScope,self._sipSymbolData.TopLevelScope): 1310 parentPythonName = "global" 1311 else: 1312 parentPythonName = parentScope.fqPythonName() 1313 fileName = parentPythonName + ".html#" + linkId(typeObject) 1314 1315 elif isinstance(typeObject,self._sipSymbolData.Typedef): 1316 parentScope = typeObject.parentScope() 1317 if isinstance(parentScope,self._sipSymbolData.TopLevelScope): 1318 parentPythonName = "global" 1319 else: 1320 parentPythonName = parentScope.fqPythonName() 1321 fileName = parentPythonName + ".html" 1322 1323 else: 1324 fileName = typeObject.fqPythonName() + ".html" 1325 return '<a href="../' + typeModule[7:] + '/' + fileName + '">' + typeObject.fqPythonName() + '</a>' 1326 except KeyError: 1327 print("KeyError: Couldn't resolve '"+typeName+"'") 1328 1329 return typeName 1330 1331 # @accepts(str) 1332 # @returns(str) 1333 def stripComment(self, text): 1334 parts = text.split('\n') 1335 parts[0] = parts[0].strip() 1336 if parts[0]=='/**': 1337 parts[0] = None 1338 parts[-1] = parts[-1].strip() 1339 if parts[-1]=='**/' or parts[-1]=='*/': 1340 parts[-1] = None 1341 1342 # Transform for each line 1343 def clean(line): 1344 line = line.strip() 1345 if line.startswith('*'): 1346 return line[1:] 1347 else: 1348 return line 1349 return '\n'.join( (clean(line) for line in parts if line is not None) ) 1350 1351 # @accepts(str) 1352 # @returns(str) 1353 def formatDoxygen(self, text): 1354 if text: 1355 return reducer.do_txt(self.stripComment(text)) 1356 else: 1357 return '' 1358 1359 def AnnotationRule(methodTypeMatch,parameterTypeMatch,parameterNameMatch,annotations): 1360 return cpptosiptransformer.MethodAnnotationRule(methodTypeMatch,parameterTypeMatch,parameterNameMatch,annotations) 1361 1362 def PySlotRule(className=None,namespaceName=None,arg1Name=None,arg2Name=None): 1363 return cpptosiptransformer.PySlotRule(className,namespaceName,arg1Name,arg2Name) 1364 1365 1366 def pyName(obj): 1367 for anno in obj.annotations(): 1368 if anno.startswith("PyName"): 1369 return anno[7:] 1370 return obj.name() 1371 1372 def linkId(obj): 1373 if obj.name() is not None: 1374 return obj.name() 1375 else: 1376 return 'obj'+str(id(obj)) 1377 1378 def isSipClassAbstract(sipClass): 1379 for anno in sipClass.annotations(): 1380 if anno=="Abstract": 1381 return True 1382 return False 1383 1384 def BuildSubclassMap(scopeList,symbolData): 1385 mapping = {} 1386 def processScope(scope): 1387 for item in scope: 1388 if isinstance(item,symbolData.SipClass): 1389 class_ = item 1390 for baseName in class_.bases(): 1391 try: 1392 base = symbolData.lookupType(baseName,class_.parentScope()) 1393 if isinstance(base, symbolData.Typedef): 1394 print("Warning: %s Skipping typedef base '%s'." % (class_.sourceLocation(),baseName)) 1395 continue 1396 1397 subClassList = mapping.setdefault(base,set()) 1398 subClassList.add(class_) 1399 except KeyError: 1400 print("Warning: %s Unrecognized type '%s' found when building subclass map." % (class_.sourceLocation(),baseName)) 1401 elif isinstance(item,symbolData.Namespace): 1402 processScope(item) 1403 1404 for scope in scopeList: 1405 processScope(scope) 1406 return mapping 1407 1408 def FetchDocs(filename): 1409 lex = cpplexer.CppLexer() 1410 1411 with open(filename) as fhandle: 1412 data = fhandle.read() 1413 1414 lex.input(data) 1415 while True: 1416 tok = lex.token() 1417 if not tok: 1418 break # No more input 1419 if tok.type=='DOC': 1420 print(tok) 1421 return tok.value 1422 return "" 1423 1424 def key(a): 1425 if a.startswith('K'): 1426 a = a[1:] 1427 return a.lower() 1428 1429 def identity(x): 1430 return x 1431 1432 # (indexstring,cellcontents) = cellFunc(obj) 1433 def FormatTable(rawObjectList, cellFunc, keyFunc=identity, columns=3): 1434 if not rawObjectList: 1435 return 1436 1437 # Sort the class list with special treatment for the letter K. 1438 objectList = rawObjectList[:] 1439 objectList.sort(key=keyFunc) 1440 1441 result = [] 1442 1443 cells = [] 1444 letter = None 1445 for obj in objectList: 1446 tup = cellFunc(obj) 1447 if tup is None: 1448 continue 1449 indexstring, cellcontents = tup 1450 1451 newletter = indexstring[0].upper() 1452 if newletter!=letter: 1453 letter = newletter 1454 cells.append('<a name="letter_'+letter+'"> '+letter+' </a>') 1455 cells.append(cellcontents) 1456 1457 # Write it out. 1458 result.append("""<table width="95%" align="center" border="0" cellpadding="0" cellspacing="0"> 1459 <tbody>""") 1460 1461 def cell(i): return cells[i] if i<len(cells) else '' 1462 1463 section = int((len(cells)+columns-1)/columns) 1464 for i in range(section): 1465 result.append("<tr>") 1466 for j in range(columns): 1467 result.append("<td>" + cell(j*section + i) + "</td>") 1468 result.append("</tr>\n") 1469 result.append("</table>\n") 1470 1471 return "".join(result) 1472 1473 1474 # name 1475 htmlHeader = """<?xml version="1.0" encoding="UTF-8"?> 1476 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 1477 <html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"> 1478 1479 <head> 1480 <title>%(title)s</title> 1481 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 1482 <meta http-equiv="Content-Style-Type" content="text/css" /> 1483 <link rel="stylesheet" type="text/css" href="%(path)scommon/doxygen.css" /> 1484 <link rel="stylesheet" media="screen" type="text/css" title="KDE Colors" href="%(path)scommon/kde.css" /> 1485 </head> 1486 <body> 1487 <div id="container"> 1488 <div id="header"> 1489 <div id="header_top"> 1490 <div> 1491 <div> 1492 <img alt ="" src="%(path)scommon/top-kde.jpg"/> 1493 KDE 5.0 PyKDE API Reference 1494 </div> 1495 </div> 1496 </div> 1497 <div id="header_bottom"> 1498 <div id="location"> 1499 <ul> 1500 <li>KDE's Python API</li> 1501 </ul> 1502 </div> 1503 1504 <div id="menu"> 1505 <ul> 1506 <li><a href="%(path)smodules.html">Overview</a></li> 1507 <li><a href="http://techbase.kde.org/Development/Languages/Python">PyKDE Home</a></li> 1508 <li><a href="http://kde.org/family/">Sitemap</a></li> 1509 <li><a href="http://kde.org/contact/">Contact Us</a></li> 1510 </ul> 1511 </div> 1512 </div> 1513 </div> 1514 1515 <div id="body_wrapper"> 1516 <div id="body"> 1517 <div id="right"> 1518 <div class="content"> 1519 <div id="main"> 1520 <div class="clearer"> </div> 1521 """ 1522 # nothing 1523 htmlFooter = """ 1524 </div> 1525 </div> 1526 </div> 1527 1528 <div id="left"> 1529 1530 <div class="menu_box"> 1531 <div class="nav_list"> 1532 <ul> 1533 <li><a href="%(path)sallclasses.html">Full Index</a></li> 1534 </ul> 1535 </div> 1536 1537 <a name="cp-menu" /><div class="menutitle"><div> 1538 <h2 id="cp-menu-project">Modules</h2> 1539 </div></div> 1540 <div class="nav_list"> 1541 <ul>""" + ( 1542 """<li><a href="%(path)skarchive/index.html">karchive</a></li> 1543 <li><a href="%(path)skcoreaddons/index.html">kcoreaddons</a></li> 1544 <li><a href="%(path)skguiaddons/index.html">kguiaddons</a></li> 1545 <li><a href="%(path)skitemmodels/index.html">kitemmodels</a></li> 1546 <li><a href="%(path)skitemviews/index.html">kitemviews</a></li> 1547 <li><a href="%(path)skplotting/index.html">kplotting</a></li> 1548 <li><a href="%(path)skwidgetsaddons/index.html">kwidgetsaddons</a></li> 1549 <li><a href="%(path)ssolid/index.html">solid</a></li> 1550 <li><a href="%(path)ssonnet/index.html">sonnet</a></li> 1551 """ if True else 1552 """<li><a href="%(path)smarble/index.html">marble</a></li>""") + \ 1553 """ 1554 </ul></div></div> 1555 1556 </div> 1557 1558 </div> 1559 <div class="clearer"/> 1560 </div> 1561 1562 <div id="end_body"></div> 1563 </div> 1564 <div id="footer"><div id="footer_text"> 1565 This documentation is maintained by <a href="mailto:simon@simonzone.com">Simon Edwards</a>.<br /> 1566 KDE<sup>®</sup> and <a href="../images/kde_gear_black.png">the K Desktop Environment<sup>®</sup> logo</a> are registered trademarks of <a href="http://ev.kde.org/" title="Homepage of the KDE non-profit Organization">KDE e.V.</a> | 1567 <a href="http://www.kde.org/contact/impressum.php">Legal</a> 1568 </div></div> 1569 </body> 1570 </html> 1571 """ 1572 1573 #nsName, module, nsName, text 1574 namespaceHeader = """ 1575 <h1>%(namespacename)s Namespace Reference</h1> 1576 <code>%(import)s</code> 1577 <p> 1578 <h2>Detailed Description</h2> 1579 %(description)s 1580 """ 1581 1582 classListEntry = '<a href="%s.html">%s</a>' 1583 igclassListEntry = '<i style="color : #999999">%s</i>' 1584 1585 # classname, abstract, modulename, namespace, classname, baseclasses, description 1586 classHeader = """ 1587 <h1>%(classname)s Class Reference</h1> 1588 <code>from %(modulename)s import *</code> 1589 <p> 1590 %(baseclasses)s 1591 %(subclasses)s 1592 %(namespace)s 1593 <h2>Detailed Description</h2> 1594 %(abstract)s 1595 %(description)s 1596 """ 1597 1598 varEntry = '<tr><td width="60%%" valign="top"><b>%s</b> <i>%s</i></td><td width="40%%" align="left">%s</td></tr>\n'