|
1 /****************************************************************************** |
|
2 * |
|
3 * Copyright (C) 1997-2008 by Dimitri van Heesch. |
|
4 * |
|
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. |
|
10 * |
|
11 * Documents produced by Doxygen are derivative works derived from the |
|
12 * input used in their production; they are not affected by this license. |
|
13 * |
|
14 */ |
|
15 |
|
16 #include "docsets.h" |
|
17 #include "config.h" |
|
18 #include "message.h" |
|
19 #include "doxygen.h" |
|
20 #include <qfile.h> |
|
21 |
|
22 |
|
23 DocSets::DocSets() : m_nodes(17), m_scopes(17) |
|
24 { |
|
25 m_nf = 0; |
|
26 m_tf = 0; |
|
27 m_dc = 0; |
|
28 m_id = 0; |
|
29 m_nodes.setAutoDelete(TRUE); |
|
30 } |
|
31 |
|
32 DocSets::~DocSets() |
|
33 { |
|
34 delete m_nf; |
|
35 delete m_tf; |
|
36 } |
|
37 |
|
38 void DocSets::initialize() |
|
39 { |
|
40 // -- get config options |
|
41 QCString projectName = Config_getString("PROJECT_NAME"); |
|
42 if (projectName.isEmpty()) projectName="root"; |
|
43 QCString bundleId = Config_getString("DOCSET_BUNDLE_ID"); |
|
44 if (bundleId.isEmpty()) bundleId="org.doxygen.Project"; |
|
45 QCString feedName = Config_getString("DOCSET_FEEDNAME"); |
|
46 if (feedName.isEmpty()) feedName="FeedName"; |
|
47 |
|
48 // -- write Makefile |
|
49 { |
|
50 QCString mfName = Config_getString("HTML_OUTPUT") + "/Makefile"; |
|
51 QFile makefile(mfName); |
|
52 if (!makefile.open(IO_WriteOnly)) |
|
53 { |
|
54 err("Could not open file %s for writing\n",mfName.data()); |
|
55 exit(1); |
|
56 } |
|
57 QTextStream ts(&makefile); |
|
58 ts.setEncoding(QTextStream::UnicodeUTF8); |
|
59 |
|
60 ts << "DOCSET_NAME=" << bundleId << ".docset\n" |
|
61 "DOCSET_CONTENTS=$(DOCSET_NAME)/Contents\n" |
|
62 "DOCSET_RESOURCES=$(DOCSET_CONTENTS)/Resources\n" |
|
63 "DOCSET_DOCUMENTS=$(DOCSET_RESOURCES)/Documents\n" |
|
64 "DESTDIR=~/Library/Developer/Shared/Documentation/DocSets\n" |
|
65 "XCODE_INSTALL=$(shell xcode-select -print-path)\n" |
|
66 "\n" |
|
67 "all: docset\n" |
|
68 "\n" |
|
69 "docset:\n" |
|
70 "\tmkdir -p $(DOCSET_DOCUMENTS)\n" |
|
71 "\tcp Nodes.xml $(DOCSET_RESOURCES)\n" |
|
72 "\tcp Tokens.xml $(DOCSET_RESOURCES)\n" |
|
73 "\tcp Info.plist $(DOCSET_CONTENTS)\n" |
|
74 "\ttar --exclude $(DOCSET_NAME) \\\n" |
|
75 "\t --exclude Nodes.xml \\\n" |
|
76 "\t --exclude Tokens.xml \\\n" |
|
77 "\t --exclude Info.plist \\\n" |
|
78 "\t --exclude Makefile -c -f - . \\\n" |
|
79 "\t | (cd $(DOCSET_DOCUMENTS); tar xvf -)\n" |
|
80 "\t$(XCODE_INSTALL)/usr/bin/docsetutil index $(DOCSET_NAME)\n" |
|
81 "\trm -f $(DOCSET_DOCUMENTS)/Nodes.xml\n" |
|
82 "\trm -f $(DOCSET_DOCUMENTS)/Info.plist\n" |
|
83 "\trm -f $(DOCSET_DOCUMENTS)/Makefile\n" |
|
84 "\trm -f $(DOCSET_RESOURCES)/Nodes.xml\n" |
|
85 "\trm -f $(DOCSET_RESOURCES)/Tokens.xml\n" |
|
86 "\n" |
|
87 "install: docset\n" |
|
88 "\tmkdir -p $(DESTDIR)\n" |
|
89 "\tcp -R $(DOCSET_NAME) $(DESTDIR)\n" |
|
90 "\n" |
|
91 "uninstall:\n" |
|
92 "\trm -rf $(DESTDIR)/$(DOCSET_NAME)\n" |
|
93 "\n" |
|
94 "always:\n"; |
|
95 } |
|
96 |
|
97 // -- write Info.plist |
|
98 { |
|
99 QCString plName = Config_getString("HTML_OUTPUT") + "/Info.plist"; |
|
100 QFile plist(plName); |
|
101 if (!plist.open(IO_WriteOnly)) |
|
102 { |
|
103 err("Could not open file %s for writing\n",plName.data()); |
|
104 exit(1); |
|
105 } |
|
106 QTextStream ts(&plist); |
|
107 ts.setEncoding(QTextStream::UnicodeUTF8); |
|
108 |
|
109 ts << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" |
|
110 "<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\"\n" |
|
111 "\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n" |
|
112 "<plist version=\"1.0\">\n" |
|
113 "<dict>\n" |
|
114 " <key>CFBundleName</key>\n" |
|
115 " <string>" << projectName << "</string>\n" |
|
116 " <key>CFBundleIdentifier</key>\n" |
|
117 " <string>" << bundleId << ".docset</string>\n" |
|
118 " <key>DocSetFeedName</key>\n" |
|
119 " <string>" << feedName << "</string>\n" |
|
120 "</dict>\n" |
|
121 "</plist>\n"; |
|
122 } |
|
123 |
|
124 // -- start Nodes.xml |
|
125 QCString notes = Config_getString("HTML_OUTPUT") + "/Nodes.xml"; |
|
126 m_nf = new QFile(notes); |
|
127 if (!m_nf->open(IO_WriteOnly)) |
|
128 { |
|
129 err("Could not open file %s for writing\n",notes.data()); |
|
130 exit(1); |
|
131 } |
|
132 QCString indexName=Config_getBool("GENERATE_TREEVIEW")?"main":"index"; |
|
133 m_nts.setDevice(m_nf); |
|
134 m_nts.setEncoding(QTextStream::UnicodeUTF8); |
|
135 m_nts << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << endl; |
|
136 m_nts << "<DocSetNodes version=\"1.0\">" << endl; |
|
137 m_nts << " <TOC>" << endl; |
|
138 m_nts << " <Node>" << endl; |
|
139 m_nts << " <Name>Root</Name>" << endl; |
|
140 m_nts << " <Path>" << indexName << Doxygen::htmlFileExtension << "</Path>" << endl; |
|
141 m_nts << " <Subnodes>" << endl; |
|
142 m_dc = 1; |
|
143 m_firstNode.resize(m_dc); |
|
144 m_firstNode.at(0)=TRUE; |
|
145 |
|
146 QCString tokens = Config_getString("HTML_OUTPUT") + "/Tokens.xml"; |
|
147 m_tf = new QFile(tokens); |
|
148 if (!m_tf->open(IO_WriteOnly)) |
|
149 { |
|
150 err("Could not open file %s for writing\n",tokens.data()); |
|
151 exit(1); |
|
152 } |
|
153 m_tts.setDevice(m_tf); |
|
154 m_tts.setEncoding(QTextStream::UnicodeUTF8); |
|
155 m_tts << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << endl; |
|
156 m_tts << "<Tokens version=\"1.0\">" << endl; |
|
157 } |
|
158 |
|
159 void DocSets::finalize() |
|
160 { |
|
161 m_nts << indent() << " </Node>" << endl; |
|
162 m_dc--; |
|
163 m_nts << " </Subnodes>" << endl; |
|
164 m_nts << " </Node>" << endl; |
|
165 m_nts << " </TOC>" << endl; |
|
166 m_nts << "</DocSetNodes>" << endl; |
|
167 m_nf->close(); |
|
168 delete m_nf; |
|
169 m_nf=0; |
|
170 |
|
171 m_tts << "</Tokens>" << endl; |
|
172 m_tf->close(); |
|
173 delete m_tf; |
|
174 m_tf=0; |
|
175 } |
|
176 |
|
177 QCString DocSets::indent() |
|
178 { |
|
179 QCString result; |
|
180 result.fill(' ',(m_dc+2)*2); |
|
181 return result; |
|
182 } |
|
183 |
|
184 void DocSets::incContentsDepth() |
|
185 { |
|
186 ++m_dc; |
|
187 m_nts << indent() << "<Subnodes>" << endl; |
|
188 m_firstNode.resize(m_dc); |
|
189 if (m_dc>0) |
|
190 { |
|
191 m_firstNode.at(m_dc-1)=TRUE; |
|
192 } |
|
193 } |
|
194 |
|
195 void DocSets::decContentsDepth() |
|
196 { |
|
197 if (!m_firstNode.at(m_dc-1)) |
|
198 { |
|
199 m_nts << indent() << " </Node>" << endl; |
|
200 } |
|
201 m_nts << indent() << "</Subnodes>" << endl; |
|
202 --m_dc; |
|
203 } |
|
204 |
|
205 void DocSets::addContentsItem(bool isDir, |
|
206 const char *name, |
|
207 const char *ref, |
|
208 const char *file, |
|
209 const char *anchor) |
|
210 { |
|
211 (void)isDir; |
|
212 if (file && ref==0) |
|
213 { |
|
214 if (!m_firstNode.at(m_dc-1)) |
|
215 { |
|
216 m_nts << indent() << " </Node>" << endl; |
|
217 } |
|
218 m_firstNode.at(m_dc-1)=FALSE; |
|
219 m_nts << indent() << " <Node>" << endl; |
|
220 m_nts << indent() << " <Name>" << convertToXML(name) << "</Name>" << endl; |
|
221 m_nts << indent() << " <Path>" << file << Doxygen::htmlFileExtension; |
|
222 if (anchor) |
|
223 { |
|
224 m_nts << "#" << anchor; |
|
225 } |
|
226 m_nts << "</Path>" << endl; |
|
227 } |
|
228 } |
|
229 |
|
230 void DocSets::addIndexItem(Definition *context,MemberDef *md, |
|
231 const char *anchor,const char *word) |
|
232 { |
|
233 (void)anchor; |
|
234 (void)word; |
|
235 if (md==0 || context==0) return; // TODO: also index non members... |
|
236 |
|
237 FileDef *fd = 0; |
|
238 ClassDef *cd = 0; |
|
239 NamespaceDef *nd = 0; |
|
240 |
|
241 if (md) |
|
242 { |
|
243 fd = md->getFileDef(); |
|
244 cd = md->getClassDef(); |
|
245 nd = md->getNamespaceDef(); |
|
246 if (!md->isLinkable()) return; // internal symbol |
|
247 } |
|
248 |
|
249 QCString scope; |
|
250 QCString type; |
|
251 QCString decl; |
|
252 |
|
253 // determine language |
|
254 QCString lang; |
|
255 SrcLangExt langExt = SrcLangExt_Cpp; |
|
256 if (fd) langExt = getLanguageFromFileName(fd->name()); |
|
257 switch (langExt) |
|
258 { |
|
259 case SrcLangExt_Cpp: |
|
260 case SrcLangExt_ObjC: |
|
261 { |
|
262 if (md && (md->isObjCMethod() || md->isObjCProperty())) |
|
263 lang="occ"; // Objective C/C++ |
|
264 else if (fd && fd->name().right(2).lower()==".c") |
|
265 lang="c"; // Plain C |
|
266 else if (cd==0 && nd==0) |
|
267 lang="c"; // Plain C symbol outside any class or namespace |
|
268 else |
|
269 lang="cpp"; // C++ |
|
270 } |
|
271 break; |
|
272 case SrcLangExt_IDL: lang="idl"; break; // IDL |
|
273 case SrcLangExt_CSharp: lang="csharp"; break; // C# |
|
274 case SrcLangExt_PHP: lang="php"; break; // PHP4/5 |
|
275 case SrcLangExt_D: lang="d"; break; // D |
|
276 case SrcLangExt_Java: lang="java"; break; // Java |
|
277 case SrcLangExt_JS: lang="javascript"; break; // Javascript |
|
278 case SrcLangExt_Python: lang="python"; break; // Python |
|
279 case SrcLangExt_F90: lang="fortran"; break; // Fortran |
|
280 case SrcLangExt_VHDL: lang="vhdl"; break; // VHDL |
|
281 case SrcLangExt_XML: lang="xml"; break; // DBUS XML |
|
282 } |
|
283 |
|
284 if (md) |
|
285 { |
|
286 if (!md->isLinkable()) return; // internal symbol |
|
287 if (context==0) |
|
288 { |
|
289 if (md->getGroupDef()) |
|
290 context = md->getGroupDef(); |
|
291 else if (md->getFileDef()) |
|
292 context = md->getFileDef(); |
|
293 if (context==0) return; // should not happen |
|
294 |
|
295 switch (md->memberType()) |
|
296 { |
|
297 case MemberDef::Define: |
|
298 type="macro"; break; |
|
299 case MemberDef::Function: |
|
300 if (cd && (cd->compoundType()==ClassDef::Interface || |
|
301 cd->compoundType()==ClassDef::Class)) |
|
302 { |
|
303 if (md->isStatic()) |
|
304 type="clm"; // class member |
|
305 else |
|
306 type="instm"; // instance member |
|
307 } |
|
308 else if (cd && cd->compoundType()==ClassDef::Protocol) |
|
309 { |
|
310 if (md->isStatic()) |
|
311 type="intfcm"; // interface class member |
|
312 else |
|
313 type="intfm"; // interface member |
|
314 } |
|
315 else |
|
316 type="func"; |
|
317 break; |
|
318 case MemberDef::Variable: |
|
319 type="data"; break; |
|
320 case MemberDef::Typedef: |
|
321 type="tdef"; break; |
|
322 case MemberDef::Enumeration: |
|
323 type="enum"; break; |
|
324 case MemberDef::EnumValue: |
|
325 type="econst"; break; |
|
326 //case MemberDef::Prototype: |
|
327 // type="prototype"; break; |
|
328 case MemberDef::Signal: |
|
329 type="signal"; break; |
|
330 case MemberDef::Slot: |
|
331 type="slot"; break; |
|
332 case MemberDef::Friend: |
|
333 type="ffunc"; break; |
|
334 case MemberDef::DCOP: |
|
335 type="dcop"; break; |
|
336 case MemberDef::Property: |
|
337 if (cd && cd->compoundType()==ClassDef::Protocol) |
|
338 type="intfp"; // interface property |
|
339 else |
|
340 type="instp"; // instance property |
|
341 break; |
|
342 case MemberDef::Event: |
|
343 type="event"; break; |
|
344 } |
|
345 writeToken(m_tts,md,type,lang,scope,md->anchor()); |
|
346 } |
|
347 } |
|
348 else if (context && context->isLinkable()) |
|
349 { |
|
350 if (fd==0 && context->definitionType()==Definition::TypeFile) |
|
351 { |
|
352 fd = (FileDef*)context; |
|
353 } |
|
354 if (cd==0 && context->definitionType()==Definition::TypeClass) |
|
355 { |
|
356 cd = (ClassDef*)context; |
|
357 } |
|
358 if (nd==0 && context->definitionType()==Definition::TypeNamespace) |
|
359 { |
|
360 nd = (NamespaceDef*)context; |
|
361 } |
|
362 if (fd) |
|
363 { |
|
364 type="file"; |
|
365 } |
|
366 else if (cd) |
|
367 { |
|
368 scope = cd->qualifiedName(); |
|
369 if (cd->isTemplate()) |
|
370 { |
|
371 type="tmplt"; |
|
372 } |
|
373 else if (cd->compoundType()==ClassDef::Protocol) |
|
374 { |
|
375 type="intf"; |
|
376 if (scope.right(2)=="-p") scope=scope.left(scope.length()-2); |
|
377 } |
|
378 else if (cd->compoundType()==ClassDef::Interface) |
|
379 { |
|
380 type="cl"; |
|
381 } |
|
382 else if (cd->compoundType()==ClassDef::Category) |
|
383 { |
|
384 type="cat"; |
|
385 } |
|
386 else |
|
387 { |
|
388 type = "cl"; |
|
389 } |
|
390 IncludeInfo *ii = cd->includeInfo(); |
|
391 if (ii) |
|
392 { |
|
393 decl=ii->includeName; |
|
394 if (decl.isEmpty()) |
|
395 { |
|
396 decl=ii->local; |
|
397 } |
|
398 } |
|
399 } |
|
400 else if (nd) |
|
401 { |
|
402 scope = nd->name(); |
|
403 type = "ns"; |
|
404 } |
|
405 if (m_scopes.find(context->getOutputFileBase())==0) |
|
406 { |
|
407 writeToken(m_tts,context,type,lang,0,0,decl); |
|
408 m_scopes.append(context->getOutputFileBase(),(void*)0x8); |
|
409 } |
|
410 } |
|
411 } |
|
412 |
|
413 void DocSets::writeToken(QTextStream &t, |
|
414 const Definition *d, |
|
415 const QCString &type, |
|
416 const QCString &lang, |
|
417 const char *scope, |
|
418 const char *anchor, |
|
419 const char *decl) |
|
420 { |
|
421 t << " <Token>" << endl; |
|
422 t << " <TokenIdentifier>" << endl; |
|
423 QString name = d->name(); |
|
424 if (name.right(2)=="-p") name=name.left(name.length()-2); |
|
425 t << " <Name>" << convertToXML(name) << "</Name>" << endl; |
|
426 if (!lang.isEmpty()) |
|
427 { |
|
428 t << " <APILanguage>" << lang << "</APILanguage>" << endl; |
|
429 } |
|
430 if (!type.isEmpty()) |
|
431 { |
|
432 t << " <Type>" << type << "</Type>" << endl; |
|
433 } |
|
434 if (scope) |
|
435 { |
|
436 t << " <Scope>" << convertToXML(scope) << "</Scope>" << endl; |
|
437 } |
|
438 t << " </TokenIdentifier>" << endl; |
|
439 t << " <Path>" << d->getOutputFileBase() |
|
440 << Doxygen::htmlFileExtension << "</Path>" << endl; |
|
441 if (anchor) |
|
442 { |
|
443 t << " <Anchor>" << anchor << "</Anchor>" << endl; |
|
444 } |
|
445 QCString tooltip = d->briefDescriptionAsTooltip(); |
|
446 if (!tooltip.isEmpty()) |
|
447 { |
|
448 t << " <Abstract>" << convertToXML(tooltip) << "</Abstract>" << endl; |
|
449 } |
|
450 if (decl) |
|
451 { |
|
452 t << " <DeclaredIn>" << convertToXML(decl) << "</DeclaredIn>" << endl; |
|
453 } |
|
454 t << " </Token>" << endl; |
|
455 } |
|
456 |
|
457 void DocSets::addIndexFile(const char *name) |
|
458 { |
|
459 (void)name; |
|
460 } |
|
461 |