doxygen-1.7.0-modify_footer
[platform/upstream/doxygen.git] / src / qhp.cpp
1 /*
2  * Copyright (C) 2008 by Sebastian Pipping.
3  * Copyright (C) 2008 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  * Sebastian Pipping <sebastian@pipping.org>
15  */
16
17 #include "qhp.h"
18 #include "qhpxmlwriter.h"
19 #include "message.h"
20 #include "config.h"
21 #include "memberdef.h"
22 #include "groupdef.h"
23 #include "doxygen.h"
24 #include "filedef.h"
25
26 #include <qstringlist.h>
27 #include <string.h>
28
29 static QCString makeFileName(const char * withoutExtension)
30 {
31   QCString result=withoutExtension;
32   if (!result.isEmpty())
33   {
34     if (result.at(0)=='!') // relative URL -> strip marker
35     {
36       result=result.mid(1);
37     }
38     else // add specified HTML extension
39     {
40       result+=Doxygen::htmlFileExtension;
41     }
42   }
43   return result;
44 }
45
46 static QCString makeRef(const char * withoutExtension, const char * anchor)
47 {
48   //printf("QHP::makeRef(%s,%s)\n",withoutExtension,anchor);
49   if (!withoutExtension) return QCString(); 
50   QCString result = makeFileName(withoutExtension);
51   if (!anchor) return result;
52   return result+"#"+anchor;
53 }
54
55 Qhp::Qhp() : m_prevSectionLevel(0), m_sectionLevel(0)
56 {
57   m_doc.setIndentLevel(0);
58   m_toc.setIndentLevel(2);
59   m_index.setIndentLevel(2);
60   m_files.setIndentLevel(2);
61 }
62
63 Qhp::~Qhp()
64 {
65   clearPrevSection();
66 }
67
68 void Qhp::initialize()
69 {
70   /*
71   <QtHelpProject version="1.0">
72     <namespace>mycompany.com.myapplication.1_0</namespace>
73     <virtualFolder>doc</virtualFolder>
74     <customFilter name="My Application 1.0">
75       <filterAttribute>myapp</filterAttribute>
76       <filterAttribute>1.0</filterAttribute>
77     </customFilter>
78     <filterSection>
79       <filterAttribute>myapp</filterAttribute>
80       <filterAttribute>1.0</filterAttribute>
81   ..
82   */
83   QCString nameSpace       = Config_getString("QHP_NAMESPACE");
84   QCString virtualFolder   = Config_getString("QHP_VIRTUAL_FOLDER");
85
86   const char * rootAttributes[] =
87   { "version", "1.0", 0 };
88
89   m_doc.open("QtHelpProject", rootAttributes);
90   m_doc.openCloseContent("namespace", nameSpace);
91   m_doc.openCloseContent("virtualFolder", virtualFolder);
92
93   // Add custom filter
94   QCString filterName = Config_getString("QHP_CUST_FILTER_NAME");
95   if (!filterName.isEmpty())
96   {
97     const char * tagAttributes[] = 
98     { "name", filterName, 0 };
99     m_doc.open("customFilter", tagAttributes);
100
101     QStringList customFilterAttributes = QStringList::split(QChar(' '), Config_getString("QHP_CUST_FILTER_ATTRS"));
102     for (int i = 0; i < (int)customFilterAttributes.count(); i++)
103     {
104       m_doc.openCloseContent("filterAttribute", customFilterAttributes[i].utf8());
105     }
106     m_doc.close("customFilter");
107   }
108
109   m_doc.open("filterSection");
110
111   // Add section attributes
112   QStringList sectionFilterAttributes = QStringList::split(QChar(' '),
113       Config_getString("QHP_SECT_FILTER_ATTRS"));
114   if (!sectionFilterAttributes.contains(QString("doxygen")))
115   {
116     sectionFilterAttributes << "doxygen";
117   }
118   for (int i = 0; i < (int)sectionFilterAttributes.count(); i++)
119   {
120     m_doc.openCloseContent("filterAttribute", sectionFilterAttributes[i].utf8());
121   }
122
123   m_toc.open("toc");
124
125   // Add extra root node
126   QCString fullProjectname = getFullProjectName();
127   const char * const attributes[] =
128   { "title", fullProjectname,
129     "ref",   QCString("index")+Doxygen::htmlFileExtension,
130     NULL
131   };
132   m_toc.open("section", attributes);
133   m_prevSectionTitle = getFullProjectName();
134   m_prevSectionLevel = 1;
135   m_sectionLevel = 1;
136
137   m_index.open("keywords");
138   m_files.open("files");
139 }
140
141 void Qhp::finalize()
142 {
143   // Finish TOC
144   handlePrevSection();
145   for (int i = m_prevSectionLevel; i > 0; i--)
146   {
147     m_toc.close("section");
148   }
149   m_toc.close("toc");
150   m_doc.insert(m_toc);
151
152   // Finish index
153   m_index.close("keywords");
154   m_doc.insert(m_index);
155
156   // Finish files
157   m_files.close("files");
158   m_doc.insert(m_files);
159
160   m_doc.close("filterSection");
161   m_doc.close("QtHelpProject");
162
163   QCString fileName = Config_getString("HTML_OUTPUT") + "/" + getQhpFileName();
164   QFile file(fileName);
165   if (!file.open(IO_WriteOnly))
166   {
167     err("Could not open file %s for writing\n", fileName.data());
168     exit(1);
169   }
170   m_doc.dumpTo(file);
171 }
172
173 void Qhp::incContentsDepth()
174 {
175   m_sectionLevel++;
176   //printf("Qhp::incContentsDepth() %d->%d\n",m_sectionLevel-1,m_sectionLevel);
177 }
178
179 void Qhp::decContentsDepth()
180 {
181   //printf("Qhp::decContentsDepth() %d->%d\n",m_sectionLevel,m_sectionLevel-1);
182   if (m_sectionLevel <= 0)
183   {
184     return;
185   }
186   m_sectionLevel--;
187 }
188
189 void Qhp::addContentsItem(bool /*isDir*/, const char * name, 
190                           const char * /*ref*/, const char * file, 
191                           const char * /*anchor*/,bool /* separateIndex */,
192                           bool /* addToNavIndex */,
193                           Definition * /*def*/)
194 {
195   //printf("Qhp::addContentsItem(%s) %d\n",name,m_sectionLevel);
196   // Backup difference before modification
197
198   QCString f = file;
199   if (!f.isEmpty() && f.at(0)=='^') return; // absolute URL not supported
200
201   int diff = m_prevSectionLevel - m_sectionLevel;
202
203   handlePrevSection();
204   setPrevSection(name, f, m_sectionLevel);
205
206   // Close sections as needed
207   for (; diff > 0; diff--)
208   {
209     m_toc.close("section");
210   }
211 }
212
213 void Qhp::addIndexItem(Definition *context,MemberDef *md,
214                        const char *word)
215 {
216   (void)word;
217   //printf("addIndexItem(%s %s %s\n",
218   //       context?context->name().data():"<none>",
219   //       md?md->name().data():"<none>",
220   //       word);
221
222   if (md) // member
223   {
224     static bool separateMemberPages = Config_getBool("SEPARATE_MEMBER_PAGES");
225     if (context==0) // global member
226     {
227       if (md->getGroupDef())
228         context = md->getGroupDef();
229       else if (md->getFileDef())
230         context = md->getFileDef();
231     }
232     if (context==0) return; // should not happen
233     QCString cfname  = md->getOutputFileBase();
234     QCString cfiname = context->getOutputFileBase();
235     QCString level1  = context->name();
236     QCString level2  = word ? QCString(word) : md->name();
237     QCString contRef = separateMemberPages ? cfname : cfiname;
238     QCString anchor  = md->anchor();
239
240     QCString ref;
241
242     // <keyword name="foo" id="MyApplication::foo" ref="doc.html#foo"/>
243     ref = makeRef(contRef, anchor);
244     QCString id = level1+"::"+level2;
245     const char * attributes[] =
246     {
247       "name", level2,
248       "id",   id,
249       "ref",  ref,
250       0
251     };
252     m_index.openClose("keyword", attributes);
253   }
254   else if (context) // container
255   {
256     // <keyword name="Foo" id="Foo" ref="doc.html"/>
257     QCString contRef = context->getOutputFileBase();
258     QCString level1  = word ? QCString(word) : context->name();
259     QCString ref = makeFileName(contRef);
260     const char * attributes[] =
261     {
262       "name", level1,
263       "id",   level1,
264       "ref",  ref,
265       0
266     };
267     m_index.openClose("keyword", attributes);
268   }
269 }
270
271 void Qhp::addIndexFile(const char * name)
272 {
273   addFile(name);
274 }
275
276 QCString Qhp::getQhpFileName()
277 {
278   return "index.qhp";
279 }
280
281 QCString Qhp::getFullProjectName()
282 {
283   QCString projectName = Config_getString("PROJECT_NAME");
284   QCString versionText = Config_getString("PROJECT_NUMBER");
285   if (projectName.isEmpty()) projectName="Root";
286   return projectName + (versionText.isEmpty()
287       ? QCString("")
288       : QCString(" ") + versionText);
289 }
290
291 void Qhp::handlePrevSection()
292 {
293   /*
294   <toc>
295     <section title="My Application Manual" ref="index.html">
296       <section title="Chapter 1" ref="doc.html#chapter1"/>
297       <section title="Chapter 2" ref="doc.html#chapter2"/>
298       <section title="Chapter 3" ref="doc.html#chapter3"/>
299     </section>
300   </toc>
301   */
302
303   if (m_prevSectionTitle.isNull())
304   {
305     m_prevSectionTitle=" "; // should not happen...
306   }
307
308   // We skip "Main Page" as our extra root is pointing to that
309   if (!((m_prevSectionLevel==1) && (m_prevSectionTitle==getFullProjectName())))
310   {
311     QCString finalRef = makeFileName(m_prevSectionRef);
312
313     const char * const attributes[] =
314     { "title", m_prevSectionTitle,
315       "ref",   finalRef,
316       NULL
317     };
318
319     if (m_prevSectionLevel < m_sectionLevel)
320     {
321       // Section with children
322       m_toc.open("section", attributes);
323     }
324     else
325     {
326       // Section without children
327       m_toc.openClose("section", attributes);
328     }
329   }
330
331   clearPrevSection();
332 }
333
334 void Qhp::setPrevSection(const char * title, const char * ref, int level)
335 {
336   m_prevSectionTitle = title;
337   m_prevSectionRef   = ref;
338   m_prevSectionLevel = level;
339 }
340
341 void Qhp::clearPrevSection()
342 {
343   m_prevSectionTitle.resize(0);
344   m_prevSectionRef.resize(0);
345 }
346
347 void Qhp::addFile(const char * fileName)
348 {
349   m_files.openCloseContent("file", fileName);
350 }
351
352 void Qhp::addImageFile(const char *fileName)
353 {
354   addFile(fileName);
355 }
356
357 void Qhp::addStyleSheetFile(const char *fileName)
358 {
359   addFile(fileName);
360 }
361