|
1 /****************************************************************************** |
|
2 * |
|
3 * |
|
4 * |
|
5 * Copyright (C) 1997-2008 by Dimitri van Heesch. |
|
6 * |
|
7 * Permission to use, copy, modify, and distribute this software and its |
|
8 * documentation under the terms of the GNU General Public License is hereby |
|
9 * granted. No representations are made about the suitability of this software |
|
10 * for any purpose. It is provided "as is" without express or implied warranty. |
|
11 * See the GNU General Public License for more details. |
|
12 * |
|
13 * Documents produced by Doxygen are derivative works derived from the |
|
14 * input used in their production; they are not affected by this license. |
|
15 * |
|
16 * The code is this file is largely based on a contribution from |
|
17 * Harm van der Heijden <H.v.d.Heijden@phys.tue.nl> |
|
18 * Please send thanks to him and bug reports to me :-) |
|
19 */ |
|
20 |
|
21 #include <stdio.h> |
|
22 #include <stdlib.h> |
|
23 #include <qlist.h> |
|
24 #include <qdict.h> |
|
25 #include <qregexp.h> |
|
26 #include "qtextcodec.h" |
|
27 |
|
28 #include "htmlhelp.h" |
|
29 #include "config.h" |
|
30 #include "message.h" |
|
31 #include "doxygen.h" |
|
32 #include "language.h" |
|
33 #include "portable.h" |
|
34 |
|
35 //---------------------------------------------------------------------------- |
|
36 |
|
37 struct IndexField |
|
38 { |
|
39 QCString name; |
|
40 QCString url; |
|
41 QCString anchor; |
|
42 bool link; |
|
43 bool reversed; |
|
44 }; |
|
45 |
|
46 class IndexFieldList : public QList<IndexField> |
|
47 { |
|
48 public: |
|
49 int compareItems(GCI item1, GCI item2) |
|
50 { |
|
51 return stricmp(((IndexField *)item1)->name,((IndexField *)item2)->name); |
|
52 } |
|
53 ~IndexFieldList() {} |
|
54 }; |
|
55 |
|
56 class IndexFieldListIterator : public QListIterator<IndexField> |
|
57 { |
|
58 public: |
|
59 IndexFieldListIterator( const IndexFieldList &list) : |
|
60 QListIterator<IndexField>(list) {} |
|
61 }; |
|
62 |
|
63 class IndexFieldDict : public QDict<IndexField> |
|
64 { |
|
65 public: |
|
66 IndexFieldDict(int size) : QDict<IndexField>(size) {} |
|
67 ~IndexFieldDict() {} |
|
68 }; |
|
69 |
|
70 /*! A helper class for HtmlHelp that manages a two level index in |
|
71 * alphabetical order |
|
72 */ |
|
73 class HtmlHelpIndex |
|
74 { |
|
75 public: |
|
76 HtmlHelpIndex(); |
|
77 ~HtmlHelpIndex(); |
|
78 void addItem(const char *first,const char *second, |
|
79 const char *url, const char *anchor, |
|
80 bool hasLink,bool reversed); |
|
81 void writeFields(QTextStream &t); |
|
82 private: |
|
83 IndexFieldList *list; |
|
84 IndexFieldDict *dict; |
|
85 }; |
|
86 |
|
87 /*! Constructs a new HtmlHelp index */ |
|
88 HtmlHelpIndex::HtmlHelpIndex() |
|
89 { |
|
90 list = new IndexFieldList; |
|
91 dict = new IndexFieldDict(10007); |
|
92 list->setAutoDelete(TRUE); |
|
93 } |
|
94 |
|
95 /*! Destroys the HtmlHelp index */ |
|
96 HtmlHelpIndex::~HtmlHelpIndex() |
|
97 { |
|
98 delete list; |
|
99 delete dict; |
|
100 } |
|
101 |
|
102 /*! Stores an item in the index if it is not already present. |
|
103 * Items are stored in alphetical order, by sorting on the |
|
104 * concatenation of \a level1 and \a level2 (if present). |
|
105 * |
|
106 * \param level1 the string at level 1 in the index. |
|
107 * \param level2 the string at level 2 in the index (or 0 if not applicable). |
|
108 * \param url the url of the documentation (without .html extension). |
|
109 * \param anchor the anchor of the documentation within the page. |
|
110 * \param hasLink if true, the url (without anchor) can be used in the |
|
111 * level1 item, when writing the header of a list of level2 items. |
|
112 * \param reversed TRUE if level1 is the member name and level2 the compound |
|
113 * name. |
|
114 */ |
|
115 void HtmlHelpIndex::addItem(const char *level1,const char *level2, |
|
116 const char *url,const char *anchor,bool hasLink, |
|
117 bool reversed) |
|
118 { |
|
119 QCString key = level1; |
|
120 if (level2) key+= (QCString)"?" + level2; |
|
121 if (key.find(QRegExp("@[0-9]+"))!=-1) // skip anonymous stuff |
|
122 { |
|
123 return; |
|
124 } |
|
125 if (dict->find(key)==0) // new key |
|
126 { |
|
127 //printf(">>>>>>>>> HtmlHelpIndex::addItem(%s,%s,%s,%s)\n", |
|
128 // level1,level2,url,anchor); |
|
129 IndexField *f = new IndexField; |
|
130 f->name = key; |
|
131 f->url = url; |
|
132 f->anchor = anchor; |
|
133 f->link = hasLink; |
|
134 f->reversed = reversed; |
|
135 list->inSort(f); |
|
136 dict->insert(key,f); |
|
137 } |
|
138 } |
|
139 |
|
140 /*! Writes the sorted list of index items into a html like list. |
|
141 * |
|
142 * An list of calls with <code>name = level1,level2</code> as follows: |
|
143 * <pre> |
|
144 * a1,b1 |
|
145 * a1,b2 |
|
146 * a2,b1 |
|
147 * a2,b2 |
|
148 * a3 |
|
149 * a4,b1 |
|
150 * </pre> |
|
151 * |
|
152 * Will result in the following list: |
|
153 * |
|
154 * <pre> |
|
155 * a1 -> link to url if hasLink==TRUE |
|
156 * b1 -> link to url#anchor |
|
157 * b2 -> link to url#anchor |
|
158 * a2 -> link to url if hasLink==TRUE |
|
159 * b1 -> link to url#anchor |
|
160 * b2 -> link to url#anchor |
|
161 * a3 -> link to url if hasLink==TRUE |
|
162 * a4 -> link to url if hasLink==TRUE |
|
163 * b1 -> link to url#anchor |
|
164 * </pre> |
|
165 */ |
|
166 void HtmlHelpIndex::writeFields(QTextStream &t) |
|
167 { |
|
168 IndexFieldListIterator ifli(*list); |
|
169 IndexField *f; |
|
170 QCString lastLevel1; |
|
171 bool level2Started=FALSE; |
|
172 for (;(f=ifli.current());++ifli) |
|
173 { |
|
174 QCString level1,level2; |
|
175 int i; |
|
176 if ((i=f->name.find('?'))!=-1) |
|
177 { |
|
178 level1 = f->name.left(i); |
|
179 level2 = f->name.right(f->name.length()-i-1); |
|
180 } |
|
181 else |
|
182 { |
|
183 level1 = f->name.copy(); |
|
184 } |
|
185 |
|
186 if (level1!=lastLevel1) |
|
187 { // finish old list at level 2 |
|
188 if (level2Started) t << " </UL>" << endl; |
|
189 level2Started=FALSE; |
|
190 |
|
191 // <Antony> |
|
192 // Added this code so that an item with only one subitem is written |
|
193 // without any subitem. |
|
194 // For example: |
|
195 // a1, b1 -> will create only a1, not separate subitem for b1 |
|
196 // a2, b2 |
|
197 // a2, b3 |
|
198 QCString nextLevel1; |
|
199 IndexField* fnext = ++ifli; |
|
200 if (fnext) |
|
201 { |
|
202 nextLevel1 = fnext->name.left(fnext->name.find('?')); |
|
203 --ifli; |
|
204 } |
|
205 if (level1 != nextLevel1) |
|
206 { |
|
207 level2 = ""; |
|
208 } |
|
209 // </Antony> |
|
210 |
|
211 if (level2.isEmpty()) |
|
212 { |
|
213 t << " <LI><OBJECT type=\"text/sitemap\">"; |
|
214 t << "<param name=\"Local\" value=\"" << f->url << Doxygen::htmlFileExtension; |
|
215 if (!f->anchor.isEmpty() && f->reversed) t << "#" << f->anchor; |
|
216 t << "\">"; |
|
217 t << "<param name=\"Name\" value=\"" << level1 << "\">" |
|
218 "</OBJECT>\n"; |
|
219 } |
|
220 else |
|
221 { |
|
222 if (f->link) |
|
223 { |
|
224 t << " <LI><OBJECT type=\"text/sitemap\">"; |
|
225 t << "<param name=\"Local\" value=\"" << f->url << Doxygen::htmlFileExtension; |
|
226 if (!f->anchor.isEmpty() && f->reversed) t << "#" << f->anchor; |
|
227 t << "\">"; |
|
228 t << "<param name=\"Name\" value=\"" << level1 << "\">" |
|
229 "</OBJECT>\n"; |
|
230 } |
|
231 else |
|
232 { |
|
233 t << " <LI><OBJECT type=\"text/sitemap\">"; |
|
234 t << "<param name=\"See Also\" value=\"" << level1 << "\">"; |
|
235 t << "<param name=\"Name\" value=\"" << level1 << "\">" |
|
236 "</OBJECT>\n"; |
|
237 } |
|
238 } |
|
239 } |
|
240 if (!level2Started && !level2.isEmpty()) |
|
241 { // start new list at level 2 |
|
242 t << " <UL>" << endl; |
|
243 level2Started=TRUE; |
|
244 } |
|
245 else if (level2Started && level2.isEmpty()) |
|
246 { // end list at level 2 |
|
247 t << " </UL>" << endl; |
|
248 level2Started=FALSE; |
|
249 } |
|
250 if (level2Started) |
|
251 { |
|
252 t << " <LI><OBJECT type=\"text/sitemap\">"; |
|
253 t << "<param name=\"Local\" value=\"" << f->url << Doxygen::htmlFileExtension; |
|
254 if (!f->anchor.isEmpty()) t << "#" << f->anchor; |
|
255 t << "\">"; |
|
256 t << "<param name=\"Name\" value=\"" << level2 << "\">" |
|
257 "</OBJECT>\n"; |
|
258 } |
|
259 lastLevel1 = level1.copy(); |
|
260 } |
|
261 if (level2Started) t << " </UL>" << endl; |
|
262 } |
|
263 |
|
264 //---------------------------------------------------------------------------- |
|
265 |
|
266 HtmlHelp *HtmlHelp::theInstance = 0; |
|
267 |
|
268 /*! Constructs an html object. |
|
269 * The object has to be \link initialize() initialized\endlink before it can |
|
270 * be used. |
|
271 */ |
|
272 HtmlHelp::HtmlHelp() : indexFileDict(1009) |
|
273 { |
|
274 /* initial depth */ |
|
275 dc = 0; |
|
276 cf = kf = 0; |
|
277 index = new HtmlHelpIndex; |
|
278 m_fromUtf8 = (void *)(-1); |
|
279 } |
|
280 |
|
281 HtmlHelp::~HtmlHelp() |
|
282 { |
|
283 if (m_fromUtf8!=(void *)(-1)) portable_iconv_close(m_fromUtf8); |
|
284 } |
|
285 #if 0 |
|
286 /*! return a reference to the one and only instance of this class. |
|
287 */ |
|
288 HtmlHelp *HtmlHelp::getInstance() |
|
289 { |
|
290 if (theInstance==0) theInstance = new HtmlHelp; |
|
291 return theInstance; |
|
292 } |
|
293 #endif |
|
294 |
|
295 static QDict<QCString> s_languageDict; |
|
296 |
|
297 /*! This will create a contents file (index.hhc) and a index file (index.hhk) |
|
298 * and write the header of those files. |
|
299 * It also creates a project file (index.hhp) |
|
300 * \sa finalize() |
|
301 */ |
|
302 void HtmlHelp::initialize() |
|
303 { |
|
304 const char *str = Config_getString("CHM_INDEX_ENCODING"); |
|
305 if (!str) str = "CP1250"; // use safe and likely default |
|
306 m_fromUtf8 = portable_iconv_open(str,"UTF-8"); |
|
307 if (m_fromUtf8==(void *)(-1)) |
|
308 { |
|
309 err("Error: unsupported character conversion for CHM_INDEX_ENCODING: '%s'->'UTF-8'\n", str); |
|
310 exit(1); |
|
311 } |
|
312 |
|
313 /* open the contents file */ |
|
314 QCString fName = Config_getString("HTML_OUTPUT") + "/index.hhc"; |
|
315 cf = new QFile(fName); |
|
316 if (!cf->open(IO_WriteOnly)) |
|
317 { |
|
318 err("Could not open file %s for writing\n",fName.data()); |
|
319 exit(1); |
|
320 } |
|
321 /* Write the header of the contents file */ |
|
322 cts.setDevice(cf); |
|
323 cts.setEncoding(QTextStream::Latin1); |
|
324 cts << "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML//EN\">\n" |
|
325 "<HTML><HEAD></HEAD><BODY>\n" |
|
326 "<OBJECT type=\"text/site properties\">\n" |
|
327 "<param name=\"FrameName\" value=\"right\">\n" |
|
328 "</OBJECT>\n" |
|
329 "<UL>\n"; |
|
330 |
|
331 /* open the contents file */ |
|
332 fName = Config_getString("HTML_OUTPUT") + "/index.hhk"; |
|
333 kf = new QFile(fName); |
|
334 if (!kf->open(IO_WriteOnly)) |
|
335 { |
|
336 err("Could not open file %s for writing\n",fName.data()); |
|
337 exit(1); |
|
338 } |
|
339 /* Write the header of the contents file */ |
|
340 kts.setDevice(kf); |
|
341 kts.setEncoding(QTextStream::Latin1); |
|
342 kts << "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML//EN\">\n" |
|
343 "<HTML><HEAD></HEAD><BODY>\n" |
|
344 "<OBJECT type=\"text/site properties\">\n" |
|
345 "<param name=\"FrameName\" value=\"right\">\n" |
|
346 "</OBJECT>\n" |
|
347 "<UL>\n"; |
|
348 |
|
349 /* language codes for Html help |
|
350 0x405 Czech |
|
351 0x406 Danish |
|
352 0x413 Dutch |
|
353 0xC09 English (Australia) |
|
354 0x809 English (Britain) |
|
355 0x1009 English (Canada) |
|
356 0x1809 English (Ireland) |
|
357 0x1409 English (New Zealand) |
|
358 0x1C09 English (South Africa) |
|
359 0x409 English (United States) |
|
360 0x40B Finnish |
|
361 0x40C French |
|
362 0x407 German |
|
363 0x408 Greece |
|
364 0x40E Hungarian |
|
365 0x410 Italian |
|
366 0x814 Norwegian |
|
367 0x415 Polish |
|
368 0x816 Portuguese(Portugal) |
|
369 0x416 Portuguese(Brazil) |
|
370 0x419 Russian |
|
371 0x80A Spanish(Mexico) |
|
372 0xC0A Spanish(Modern Sort) |
|
373 0x40A Spanish(Traditional Sort) |
|
374 0x41D Swedish |
|
375 0x41F Turkey |
|
376 0x411 Japanese |
|
377 0x412 Korean |
|
378 0x804 Chinese (PRC) |
|
379 0x404 Chinese (Taiwan) |
|
380 |
|
381 New LCIDs: |
|
382 0x421 Indonesian |
|
383 0x41A Croatian |
|
384 0x418 Romanian |
|
385 0x424 Slovenian |
|
386 0x41B Slovak |
|
387 0x422 Ukrainian |
|
388 0x81A Serbian (Serbia, Latin) |
|
389 0x403 Catalan |
|
390 0x427 Lithuanian |
|
391 0x436 Afrikaans |
|
392 0x42A Vietnamese |
|
393 0x429 Persian (Iran) |
|
394 0xC01 Arabic (Egypt) - I don't know which version of arabic is used inside translator_ar.h , |
|
395 so I have chosen Egypt at random |
|
396 |
|
397 */ |
|
398 s_languageDict.setAutoDelete(TRUE); |
|
399 s_languageDict.clear(); |
|
400 s_languageDict.insert("czech", new QCString("0x405 Czech")); |
|
401 s_languageDict.insert("danish", new QCString("0x406 Danish")); |
|
402 s_languageDict.insert("dutch", new QCString("0x413 Dutch")); |
|
403 s_languageDict.insert("finnish", new QCString("0x40B Finnish")); |
|
404 s_languageDict.insert("french", new QCString("0x40C French")); |
|
405 s_languageDict.insert("german", new QCString("0x407 German")); |
|
406 s_languageDict.insert("greek", new QCString("0x408 Greece")); |
|
407 s_languageDict.insert("hungarian", new QCString("0x40E Hungarian")); |
|
408 s_languageDict.insert("italian", new QCString("0x410 Italian")); |
|
409 s_languageDict.insert("norwegian", new QCString("0x814 Norwegian")); |
|
410 s_languageDict.insert("polish", new QCString("0x415 Polish")); |
|
411 s_languageDict.insert("portuguese", new QCString("0x816 Portuguese(Portugal)")); |
|
412 s_languageDict.insert("brazil", new QCString("0x416 Portuguese(Brazil)")); |
|
413 s_languageDict.insert("russian", new QCString("0x419 Russian")); |
|
414 s_languageDict.insert("spanish", new QCString("0x40A Spanish(Traditional Sort)")); |
|
415 s_languageDict.insert("swedish", new QCString("0x41D Swedish")); |
|
416 s_languageDict.insert("turkish", new QCString("0x41F Turkey")); |
|
417 s_languageDict.insert("japanese", new QCString("0x411 Japanese")); |
|
418 s_languageDict.insert("japanese-en", new QCString("0x411 Japanese")); |
|
419 s_languageDict.insert("korean", new QCString("0x412 Korean")); |
|
420 s_languageDict.insert("korean-en", new QCString("0x412 Korean")); |
|
421 s_languageDict.insert("chinese", new QCString("0x804 Chinese (PRC)")); |
|
422 s_languageDict.insert("chinese-traditional", new QCString("0x404 Chinese (Taiwan)")); |
|
423 |
|
424 // new LCIDs |
|
425 s_languageDict.insert("indonesian", new QCString("0x412 Indonesian")); |
|
426 s_languageDict.insert("croatian", new QCString("0x41A Croatian")); |
|
427 s_languageDict.insert("romanian", new QCString("0x418 Romanian")); |
|
428 s_languageDict.insert("slovene", new QCString("0x424 Slovenian")); |
|
429 s_languageDict.insert("slovak", new QCString("0x41B Slovak")); |
|
430 s_languageDict.insert("ukrainian", new QCString("0x422 Ukrainian")); |
|
431 s_languageDict.insert("serbian", new QCString("0x81A Serbian (Serbia, Latin)")); |
|
432 s_languageDict.insert("catalan", new QCString("0x403 Catalan")); |
|
433 s_languageDict.insert("lithuanian", new QCString("0x427 Lithuanian")); |
|
434 s_languageDict.insert("afrikaans", new QCString("0x436 Afrikaans")); |
|
435 s_languageDict.insert("vietnamese", new QCString("0x42A Vietnamese")); |
|
436 s_languageDict.insert("persian", new QCString("0x429 Persian (Iran)")); |
|
437 s_languageDict.insert("arabic", new QCString("0xC01 Arabic (Egypt)")); |
|
438 } |
|
439 |
|
440 |
|
441 static QCString getLanguageString() |
|
442 { |
|
443 if (!theTranslator->idLanguage().isEmpty()) |
|
444 { |
|
445 QCString *s = s_languageDict[theTranslator->idLanguage()]; |
|
446 if (s) |
|
447 { |
|
448 return *s; |
|
449 } |
|
450 } |
|
451 // default language |
|
452 return "0x409 English (United States)"; |
|
453 } |
|
454 |
|
455 |
|
456 |
|
457 void HtmlHelp::createProjectFile() |
|
458 { |
|
459 /* Write the project file */ |
|
460 QCString fName = Config_getString("HTML_OUTPUT") + "/index.hhp"; |
|
461 QFile f(fName); |
|
462 if (f.open(IO_WriteOnly)) |
|
463 { |
|
464 QTextStream t(&f); |
|
465 #if QT_VERSION >= 200 |
|
466 t.setEncoding(QTextStream::Latin1); |
|
467 #endif |
|
468 |
|
469 |
|
470 |
|
471 QCString indexName="index"+Doxygen::htmlFileExtension; |
|
472 if (Config_getBool("GENERATE_TREEVIEW")) indexName="main"+Doxygen::htmlFileExtension; |
|
473 t << "[OPTIONS]\n"; |
|
474 if (!Config_getString("CHM_FILE").isEmpty()) |
|
475 { |
|
476 t << "Compiled file=" << Config_getString("CHM_FILE") << "\n"; |
|
477 } |
|
478 t << "Compatibility=1.1\n" |
|
479 "Full-text search=Yes\n" |
|
480 "Contents file=index.hhc\n" |
|
481 "Default Window=main\n" |
|
482 "Default topic=" << indexName << "\n" |
|
483 "Index file=index.hhk\n" |
|
484 "Language=" << getLanguageString() << endl; |
|
485 if (Config_getBool("BINARY_TOC")) t << "Binary TOC=YES\n"; |
|
486 if (Config_getBool("GENERATE_CHI")) t << "Create CHI file=YES\n"; |
|
487 t << "Title=" << recode(Config_getString("PROJECT_NAME")) << endl << endl; |
|
488 |
|
489 t << "[WINDOWS]" << endl; |
|
490 |
|
491 // NOTE: the 0x10387e number is a set of bits specifying the buttons |
|
492 // which should appear in the CHM viewer; that specific value |
|
493 // means "show all buttons including the font-size one"; |
|
494 // the font-size one is not normally settable by the HTML Help Workshop |
|
495 // utility but the way to set it is described here: |
|
496 // http://support.microsoft.com/?scid=kb%3Ben-us%3B240062&x=17&y=18 |
|
497 t << "main=\"" << recode(Config_getString("PROJECT_NAME")) << "\",\"index.hhc\"," |
|
498 "\"index.hhk\",\"" << indexName << "\",\"" << |
|
499 indexName << "\",,,,,0x23520,,0x10387e,,,,,,,,0" << endl << endl; |
|
500 |
|
501 t << "[FILES]" << endl; |
|
502 char *s = indexFiles.first(); |
|
503 while (s) |
|
504 { |
|
505 t << s << endl; |
|
506 s = indexFiles.next(); |
|
507 } |
|
508 t << "tabs.css" << endl; |
|
509 t << "tab_b.gif" << endl; |
|
510 t << "tab_l.gif" << endl; |
|
511 t << "tab_r.gif" << endl; |
|
512 if (Config_getBool("HTML_DYNAMIC_SECTIONS")) |
|
513 { |
|
514 t << "open.gif" << endl; |
|
515 t << "closed.gif" << endl; |
|
516 } |
|
517 f.close(); |
|
518 } |
|
519 else |
|
520 { |
|
521 err("Could not open file %s for writing\n",fName.data()); |
|
522 } |
|
523 } |
|
524 |
|
525 void HtmlHelp::addIndexFile(const char *s) |
|
526 { |
|
527 if (indexFileDict.find(s)==0) |
|
528 { |
|
529 indexFiles.append(s); |
|
530 indexFileDict.insert(s,(void *)0x8); |
|
531 } |
|
532 } |
|
533 |
|
534 /*! Finalizes the HTML help. This will finish and close the |
|
535 * contents file (index.hhc) and the index file (index.hhk). |
|
536 * \sa initialize() |
|
537 */ |
|
538 void HtmlHelp::finalize() |
|
539 { |
|
540 // end the contents file |
|
541 cts << "</UL>\n"; |
|
542 cts << "</BODY>\n"; |
|
543 cts << "</HTML>\n"; |
|
544 cts.unsetDevice(); |
|
545 cf->close(); |
|
546 delete cf; |
|
547 |
|
548 index->writeFields(kts); |
|
549 |
|
550 // end the index file |
|
551 kts << "</UL>\n"; |
|
552 kts << "</BODY>\n"; |
|
553 kts << "</HTML>\n"; |
|
554 kts.unsetDevice(); |
|
555 kf->close(); |
|
556 delete kf; |
|
557 |
|
558 createProjectFile(); |
|
559 s_languageDict.clear(); |
|
560 } |
|
561 |
|
562 /*! Increase the level of the contents hierarchy. |
|
563 * This will start a new unnumbered HTML list in contents file. |
|
564 * \sa decContentsDepth() |
|
565 */ |
|
566 void HtmlHelp::incContentsDepth() |
|
567 { |
|
568 int i; for (i=0;i<dc+1;i++) cts << " "; |
|
569 cts << "<UL>\n"; |
|
570 ++dc; |
|
571 } |
|
572 |
|
573 /*! Decrease the level of the contents hierarchy. |
|
574 * This will end the unnumber HTML list. |
|
575 * \sa incContentsDepth() |
|
576 */ |
|
577 void HtmlHelp::decContentsDepth() |
|
578 { |
|
579 int i; for (i=0;i<dc;i++) cts << " "; |
|
580 cts << "</UL>\n"; |
|
581 --dc; |
|
582 } |
|
583 |
|
584 QCString HtmlHelp::recode(const QCString &s) |
|
585 { |
|
586 int iSize = s.length(); |
|
587 int oSize = iSize*4+1; |
|
588 QCString output(oSize); |
|
589 size_t iLeft = iSize; |
|
590 size_t oLeft = oSize; |
|
591 const char *iPtr = s.data(); |
|
592 char *oPtr = output.data(); |
|
593 if (!portable_iconv(m_fromUtf8,&iPtr,&iLeft,&oPtr,&oLeft)) |
|
594 { |
|
595 oSize -= oLeft; |
|
596 output.resize(oSize+1); |
|
597 output.at(oSize)='\0'; |
|
598 return output; |
|
599 } |
|
600 else |
|
601 { |
|
602 return s; |
|
603 } |
|
604 } |
|
605 |
|
606 /*! Add an list item to the contents file. |
|
607 * \param isDir boolean indicating if this is a dir or file entry |
|
608 * \param name the name of the item. |
|
609 * \param ref the URL of to the item. |
|
610 * \param file the file in which the item is defined. |
|
611 * \param anchor the anchor of the item. |
|
612 */ |
|
613 void HtmlHelp::addContentsItem(bool isDir, |
|
614 const char *name, |
|
615 const char * /*ref*/, |
|
616 const char *file, |
|
617 const char *anchor) |
|
618 { |
|
619 // If we're using a binary toc then folders cannot have links. |
|
620 if(Config_getBool("BINARY_TOC") && isDir) |
|
621 { |
|
622 file = 0; |
|
623 anchor = 0; |
|
624 } |
|
625 int i; for (i=0;i<dc;i++) cts << " "; |
|
626 cts << "<LI><OBJECT type=\"text/sitemap\">"; |
|
627 cts << "<param name=\"Name\" value=\"" << recode(name) << "\">"; |
|
628 if (file) // made file optional param - KPW |
|
629 { |
|
630 cts << "<param name=\"Local\" value=\"" << file << Doxygen::htmlFileExtension; |
|
631 if (anchor) cts << "#" << anchor; |
|
632 cts << "\">"; |
|
633 } |
|
634 cts << "<param name=\"ImageNumber\" value=\""; |
|
635 if (isDir) // added - KPW |
|
636 { |
|
637 cts << (int)BOOK_CLOSED ; |
|
638 } |
|
639 else |
|
640 { |
|
641 cts << (int)TEXT; |
|
642 } |
|
643 cts << "\">"; |
|
644 cts << "</OBJECT>\n"; |
|
645 } |
|
646 |
|
647 |
|
648 void HtmlHelp::addIndexItem(Definition *context,MemberDef *md, |
|
649 const char *anc,const char *word) |
|
650 { |
|
651 if (md) |
|
652 { |
|
653 static bool separateMemberPages = Config_getBool("SEPARATE_MEMBER_PAGES"); |
|
654 if (context==0) // global member |
|
655 { |
|
656 if (md->getGroupDef()) |
|
657 context = md->getGroupDef(); |
|
658 else if (md->getFileDef()) |
|
659 context = md->getFileDef(); |
|
660 } |
|
661 if (context==0) return; // should not happen |
|
662 |
|
663 QCString cfname = md->getOutputFileBase(); |
|
664 QCString cfiname = context->getOutputFileBase(); |
|
665 QCString level1 = context->name(); |
|
666 QCString level2 = md->name(); |
|
667 QCString contRef = separateMemberPages ? cfname : cfiname; |
|
668 QCString memRef = cfname; |
|
669 QCString anchor = anc; |
|
670 index->addItem(level1,level2,contRef,anchor,TRUE,FALSE); |
|
671 index->addItem(level2,level1,memRef,anchor,TRUE,TRUE); |
|
672 } |
|
673 else if (context) |
|
674 { |
|
675 QCString level1 = word ? QCString(word) : context->name(); |
|
676 index->addItem(level1,0,context->getOutputFileBase(),anc,TRUE,FALSE); |
|
677 } |
|
678 } |
|
679 |