1 /******************************************************************************
3 * Copyright (C) 1997-2015 by Dimitri van Heesch.
5 * Permission to use, copy, modify, and distribute this software and its
6 * documentation under the terms of the GNU General Public License is hereby
7 * granted. No representations are made about the suitability of this software
8 * for any purpose. It is provided "as is" without express or implied warranty.
9 * See the GNU General Public License for more details.
11 * Documents produced by Doxygen are derivative works derived from the
12 * input used in their production; they are not affected by this license.
24 #include "memberdef.h"
25 #include "namespacedef.h"
28 DocSets::DocSets() : m_nodes(17), m_scopes(17)
34 m_nodes.setAutoDelete(TRUE);
43 void DocSets::initialize()
45 // -- get config options
46 QCString projectName = Config_getString(PROJECT_NAME);
47 if (projectName.isEmpty()) projectName="root";
48 QCString bundleId = Config_getString(DOCSET_BUNDLE_ID);
49 if (bundleId.isEmpty()) bundleId="org.doxygen.Project";
50 QCString feedName = Config_getString(DOCSET_FEEDNAME);
51 if (feedName.isEmpty()) feedName="FeedName";
52 QCString publisherId = Config_getString(DOCSET_PUBLISHER_ID);
53 if (publisherId.isEmpty()) publisherId="PublisherId";
54 QCString publisherName = Config_getString(DOCSET_PUBLISHER_NAME);
55 if (publisherName.isEmpty()) publisherName="PublisherName";
56 QCString projectNumber = Config_getString(PROJECT_NUMBER);
57 if (projectNumber.isEmpty()) projectNumber="ProjectNumber";
61 QCString mfName = Config_getString(HTML_OUTPUT) + "/Makefile";
62 QFile makefile(mfName);
63 if (!makefile.open(IO_WriteOnly))
65 err("Could not open file %s for writing\n",mfName.data());
68 FTextStream ts(&makefile);
70 ts << "DOCSET_NAME=" << bundleId << ".docset\n"
71 "DOCSET_CONTENTS=$(DOCSET_NAME)/Contents\n"
72 "DOCSET_RESOURCES=$(DOCSET_CONTENTS)/Resources\n"
73 "DOCSET_DOCUMENTS=$(DOCSET_RESOURCES)/Documents\n"
74 "DESTDIR=~/Library/Developer/Shared/Documentation/DocSets\n"
75 "XCODE_INSTALL=\"$(shell xcode-select -print-path)\"\n"
80 "\tmkdir -p $(DOCSET_DOCUMENTS)\n"
81 "\tcp Nodes.xml $(DOCSET_RESOURCES)\n"
82 "\tcp Tokens.xml $(DOCSET_RESOURCES)\n"
83 "\tcp Info.plist $(DOCSET_CONTENTS)\n"
84 "\ttar --exclude $(DOCSET_NAME) \\\n"
85 "\t --exclude Nodes.xml \\\n"
86 "\t --exclude Tokens.xml \\\n"
87 "\t --exclude Info.plist \\\n"
88 "\t --exclude Makefile -c -f - . \\\n"
89 "\t | (cd $(DOCSET_DOCUMENTS); tar xvf -)\n"
90 "\t$(XCODE_INSTALL)/usr/bin/docsetutil index $(DOCSET_NAME)\n"
91 "\trm -f $(DOCSET_DOCUMENTS)/Nodes.xml\n"
92 "\trm -f $(DOCSET_DOCUMENTS)/Info.plist\n"
93 "\trm -f $(DOCSET_DOCUMENTS)/Makefile\n"
94 "\trm -f $(DOCSET_RESOURCES)/Nodes.xml\n"
95 "\trm -f $(DOCSET_RESOURCES)/Tokens.xml\n"
98 "\trm -rf $(DOCSET_NAME)\n"
101 "\tmkdir -p $(DESTDIR)\n"
102 "\tcp -R $(DOCSET_NAME) $(DESTDIR)\n"
105 "\trm -rf $(DESTDIR)/$(DOCSET_NAME)\n"
110 // -- write Info.plist
112 QCString plName = Config_getString(HTML_OUTPUT) + "/Info.plist";
114 if (!plist.open(IO_WriteOnly))
116 err("Could not open file %s for writing\n",plName.data());
119 FTextStream ts(&plist);
121 ts << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
122 "<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\"\n"
123 "\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n"
124 "<plist version=\"1.0\">\n"
126 " <key>CFBundleName</key>\n"
127 " <string>" << projectName << "</string>\n"
128 " <key>CFBundleIdentifier</key>\n"
129 " <string>" << bundleId << "</string>\n"
130 " <key>CFBundleVersion</key>\n"
131 " <string>" << projectNumber << "</string>\n"
132 " <key>DocSetFeedName</key>\n"
133 " <string>" << feedName << "</string>\n"
134 " <key>DocSetPublisherIdentifier</key>\n"
135 " <string>" << publisherId << "</string>\n"
136 " <key>DocSetPublisherName</key>\n"
137 " <string>" << publisherName << "</string>\n"
139 " <key>DashDocSetFamily</key>\n"
140 " <string>doxy</string>\n"
141 " <key>DocSetPlatformFamily</key>\n"
142 " <string>doxygen</string>\n"
147 // -- start Nodes.xml
148 QCString notes = Config_getString(HTML_OUTPUT) + "/Nodes.xml";
149 m_nf = new QFile(notes);
150 if (!m_nf->open(IO_WriteOnly))
152 err("Could not open file %s for writing\n",notes.data());
155 //QCString indexName=Config_getBool(GENERATE_TREEVIEW)?"main":"index";
156 QCString indexName="index";
157 m_nts.setDevice(m_nf);
158 m_nts << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << endl;
159 m_nts << "<DocSetNodes version=\"1.0\">" << endl;
160 m_nts << " <TOC>" << endl;
161 m_nts << " <Node>" << endl;
162 m_nts << " <Name>Root</Name>" << endl;
163 m_nts << " <Path>" << indexName << Doxygen::htmlFileExtension << "</Path>" << endl;
164 m_nts << " <Subnodes>" << endl;
166 m_firstNode.resize(m_dc);
167 m_firstNode.at(0)=TRUE;
169 QCString tokens = Config_getString(HTML_OUTPUT) + "/Tokens.xml";
170 m_tf = new QFile(tokens);
171 if (!m_tf->open(IO_WriteOnly))
173 err("Could not open file %s for writing\n",tokens.data());
176 m_tts.setDevice(m_tf);
177 m_tts << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << endl;
178 m_tts << "<Tokens version=\"1.0\">" << endl;
181 void DocSets::finalize()
183 if (!m_firstNode.at(m_dc-1))
185 m_nts << indent() << " </Node>" << endl;
188 m_nts << " </Subnodes>" << endl;
189 m_nts << " </Node>" << endl;
190 m_nts << " </TOC>" << endl;
191 m_nts << "</DocSetNodes>" << endl;
196 m_tts << "</Tokens>" << endl;
202 QCString DocSets::indent()
205 result.fill(' ',(m_dc+2)*2);
209 void DocSets::incContentsDepth()
211 //printf("DocSets::incContentsDepth() m_dc=%d\n",m_dc);
213 m_nts << indent() << "<Subnodes>" << endl;
214 m_firstNode.resize(m_dc);
217 m_firstNode.at(m_dc-1)=TRUE;
221 void DocSets::decContentsDepth()
223 if (!m_firstNode.at(m_dc-1))
225 m_nts << indent() << " </Node>" << endl;
227 m_nts << indent() << "</Subnodes>" << endl;
229 //printf("DocSets::decContentsDepth() m_dc=%d\n",m_dc);
232 void DocSets::addContentsItem(bool isDir,
237 bool /* separateIndex */,
238 bool /* addToNavIndex */,
239 Definition * /*def*/)
242 //printf("DocSets::addContentsItem(%s) m_dc=%d\n",name,m_dc);
245 if (!m_firstNode.at(m_dc-1))
247 m_nts << indent() << " </Node>" << endl;
249 m_firstNode.at(m_dc-1)=FALSE;
250 m_nts << indent() << " <Node>" << endl;
251 m_nts << indent() << " <Name>" << convertToXML(name) << "</Name>" << endl;
252 if (file && file[0]=='^') // URL marker
254 m_nts << indent() << " <URL>" << convertToXML(&file[1])
257 else // relative file
259 m_nts << indent() << " <Path>";
260 if (file && file[0]=='!') // user specified file
262 m_nts << convertToXML(&file[1]);
264 else if (file) // doxygen generated file
266 m_nts << file << Doxygen::htmlFileExtension;
268 m_nts << "</Path>" << endl;
271 m_nts << indent() << " <Anchor>" << anchor << "</Anchor>" << endl;
277 void DocSets::addIndexItem(Definition *context,MemberDef *md,
278 const char *,const char *)
280 if (md==0 && context==0) return;
284 NamespaceDef *nd = 0;
288 fd = md->getFileDef();
289 cd = md->getClassDef();
290 nd = md->getNamespaceDef();
291 if (!md->isLinkable()) return; // internal symbol
298 // determine language
300 SrcLangExt langExt = SrcLangExt_Cpp;
303 langExt = md->getLanguage();
307 langExt = context->getLanguage();
312 case SrcLangExt_ObjC:
314 if (md && (md->isObjCMethod() || md->isObjCProperty()))
315 lang="occ"; // Objective C/C++
316 else if (fd && fd->name().right(2).lower()==".c")
318 else if (cd==0 && nd==0)
319 lang="c"; // Plain C symbol outside any class or namespace
324 case SrcLangExt_IDL: lang="idl"; break; // IDL
325 case SrcLangExt_CSharp: lang="csharp"; break; // C#
326 case SrcLangExt_PHP: lang="php"; break; // PHP4/5
327 case SrcLangExt_D: lang="d"; break; // D
328 case SrcLangExt_Java: lang="java"; break; // Java
329 case SrcLangExt_JS: lang="javascript"; break; // Javascript
330 case SrcLangExt_Python: lang="python"; break; // Python
331 case SrcLangExt_Fortran: lang="fortran"; break; // Fortran
332 case SrcLangExt_VHDL: lang="vhdl"; break; // VHDL
333 case SrcLangExt_XML: lang="xml"; break; // DBUS XML
334 case SrcLangExt_SQL: lang="sql"; break; // Sql
335 case SrcLangExt_Tcl: lang="tcl"; break; // Tcl
336 case SrcLangExt_Markdown:lang="markdown"; break; // Markdown
337 case SrcLangExt_Unknown: lang="unknown"; break; // should not happen!
344 if (md->getGroupDef())
345 context = md->getGroupDef();
346 else if (md->getFileDef())
347 context = md->getFileDef();
349 if (context==0) return; // should not happen
351 switch (md->memberType())
353 case MemberType_Define:
355 case MemberType_Function:
356 if (cd && (cd->compoundType()==ClassDef::Interface ||
357 cd->compoundType()==ClassDef::Class))
360 type="clm"; // class member
362 type="instm"; // instance member
364 else if (cd && cd->compoundType()==ClassDef::Protocol)
367 type="intfcm"; // interface class member
369 type="intfm"; // interface member
374 case MemberType_Variable:
376 case MemberType_Typedef:
378 case MemberType_Enumeration:
380 case MemberType_EnumValue:
381 type="econst"; break;
382 //case MemberDef::Prototype:
383 // type="prototype"; break;
384 case MemberType_Signal:
385 type="signal"; break;
386 case MemberType_Slot:
388 case MemberType_Friend:
390 case MemberType_DCOP:
392 case MemberType_Property:
393 if (cd && cd->compoundType()==ClassDef::Protocol)
394 type="intfp"; // interface property
396 type="instp"; // instance property
398 case MemberType_Event:
400 case MemberType_Interface:
402 case MemberType_Service:
405 cd = md->getClassDef();
406 nd = md->getNamespaceDef();
409 scope = cd->qualifiedName();
415 MemberDef *declMd = md->memberDeclaration();
416 if (declMd==0) declMd = md;
418 fd = md->getFileDef();
424 writeToken(m_tts,md,type,lang,scope,md->anchor(),decl);
426 else if (context && context->isLinkable())
428 if (fd==0 && context->definitionType()==Definition::TypeFile)
430 fd = (FileDef*)context;
432 if (cd==0 && context->definitionType()==Definition::TypeClass)
434 cd = (ClassDef*)context;
436 if (nd==0 && context->definitionType()==Definition::TypeNamespace)
438 nd = (NamespaceDef*)context;
446 scope = cd->qualifiedName();
447 if (cd->isTemplate())
451 else if (cd->compoundType()==ClassDef::Protocol)
454 if (scope.right(2)=="-p") scope=scope.left(scope.length()-2);
456 else if (cd->compoundType()==ClassDef::Interface)
460 else if (cd->compoundType()==ClassDef::Category)
468 IncludeInfo *ii = cd->includeInfo();
471 decl=ii->includeName;
479 if (m_scopes.find(context->getOutputFileBase())==0)
481 writeToken(m_tts,context,type,lang,scope,0,decl);
482 m_scopes.append(context->getOutputFileBase(),(void*)0x8);
487 void DocSets::writeToken(FTextStream &t,
489 const QCString &type,
490 const QCString &lang,
495 t << " <Token>" << endl;
496 t << " <TokenIdentifier>" << endl;
497 QCString name = d->name();
498 if (name.right(2)=="-p") name=name.left(name.length()-2);
499 t << " <Name>" << convertToXML(name) << "</Name>" << endl;
502 t << " <APILanguage>" << lang << "</APILanguage>" << endl;
506 t << " <Type>" << type << "</Type>" << endl;
510 t << " <Scope>" << convertToXML(scope) << "</Scope>" << endl;
512 t << " </TokenIdentifier>" << endl;
513 t << " <Path>" << d->getOutputFileBase()
514 << Doxygen::htmlFileExtension << "</Path>" << endl;
517 t << " <Anchor>" << anchor << "</Anchor>" << endl;
519 QCString tooltip = d->briefDescriptionAsTooltip();
520 if (!tooltip.isEmpty())
522 t << " <Abstract>" << convertToXML(tooltip) << "</Abstract>" << endl;
526 t << " <DeclaredIn>" << convertToXML(decl) << "</DeclaredIn>" << endl;
528 t << " </Token>" << endl;
531 void DocSets::addIndexFile(const char *name)