2 * Copyright (C) 2008 by Sebastian Pipping.
3 * Copyright (C) 2008 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.
14 * Sebastian Pipping <sebastian@pipping.org>
18 #include "qhpxmlwriter.h"
21 #include "memberdef.h"
26 #include <qstringlist.h>
30 static QCString makeFileName(const char * withoutExtension)
32 QCString result=withoutExtension;
33 if (!result.isEmpty())
35 if (result.at(0)=='!') // relative URL -> strip marker
39 else // add specified HTML extension
41 result+=Doxygen::htmlFileExtension;
47 static QCString makeRef(const char * withoutExtension, const char * anchor)
49 //printf("QHP::makeRef(%s,%s)\n",withoutExtension,anchor);
50 if (!withoutExtension) return QCString();
51 QCString result = makeFileName(withoutExtension);
52 if (!anchor) return result;
53 return result+"#"+anchor;
56 Qhp::Qhp() : m_prevSectionLevel(0), m_sectionLevel(0), m_skipMainPageSection(FALSE)
58 m_doc.setIndentLevel(0);
59 m_toc.setIndentLevel(2);
60 m_index.setIndentLevel(2);
61 m_files.setIndentLevel(2);
69 void Qhp::initialize()
72 <QtHelpProject version="1.0">
73 <namespace>mycompany.com.myapplication.1_0</namespace>
74 <virtualFolder>doc</virtualFolder>
75 <customFilter name="My Application 1.0">
76 <filterAttribute>myapp</filterAttribute>
77 <filterAttribute>1.0</filterAttribute>
80 <filterAttribute>myapp</filterAttribute>
81 <filterAttribute>1.0</filterAttribute>
84 QCString nameSpace = Config_getString(QHP_NAMESPACE);
85 QCString virtualFolder = Config_getString(QHP_VIRTUAL_FOLDER);
87 m_doc.declaration("1.0", "UTF-8");
89 const char * rootAttributes[] =
90 { "version", "1.0", 0 };
92 m_doc.open("QtHelpProject", rootAttributes);
93 m_doc.openCloseContent("namespace", nameSpace);
94 m_doc.openCloseContent("virtualFolder", virtualFolder);
97 QCString filterName = Config_getString(QHP_CUST_FILTER_NAME);
98 if (!filterName.isEmpty())
100 const char * tagAttributes[] =
101 { "name", filterName, 0 };
102 m_doc.open("customFilter", tagAttributes);
104 QStringList customFilterAttributes = QStringList::split(QChar(' '), Config_getString(QHP_CUST_FILTER_ATTRS));
105 for (int i = 0; i < (int)customFilterAttributes.count(); i++)
107 m_doc.openCloseContent("filterAttribute", customFilterAttributes[i].utf8());
109 m_doc.close("customFilter");
112 m_doc.open("filterSection");
114 // Add section attributes
115 QStringList sectionFilterAttributes = QStringList::split(QChar(' '),
116 Config_getString(QHP_SECT_FILTER_ATTRS));
117 if (!sectionFilterAttributes.contains(QString("doxygen")))
119 sectionFilterAttributes << "doxygen";
121 for (int i = 0; i < (int)sectionFilterAttributes.count(); i++)
123 m_doc.openCloseContent("filterAttribute", sectionFilterAttributes[i].utf8());
128 // Add extra root node
129 QCString fullProjectname = getFullProjectName();
130 QCString indexFile = "index"+Doxygen::htmlFileExtension;
131 const char * const attributes[] =
132 { "title", fullProjectname,
136 m_toc.open("section", attributes);
137 m_prevSectionTitle = getFullProjectName();
138 m_prevSectionLevel = 1;
141 m_index.open("keywords");
142 m_files.open("files");
149 for (int i = m_prevSectionLevel; i > 0; i--)
151 m_toc.close("section");
157 m_index.close("keywords");
158 m_doc.insert(m_index);
161 m_files.close("files");
162 m_doc.insert(m_files);
164 m_doc.close("filterSection");
165 m_doc.close("QtHelpProject");
167 QCString fileName = Config_getString(HTML_OUTPUT) + "/" + getQhpFileName();
168 QFile file(fileName);
169 if (!file.open(IO_WriteOnly))
171 err("Could not open file %s for writing\n", fileName.data());
177 void Qhp::incContentsDepth()
182 void Qhp::decContentsDepth()
184 if (m_sectionLevel<=0 || (m_sectionLevel==1 && m_skipMainPageSection))
186 m_skipMainPageSection=FALSE;
192 void Qhp::addContentsItem(bool /*isDir*/, const char * name,
193 const char * /*ref*/, const char * file,
194 const char *anchor, bool /* separateIndex */,
195 bool /* addToNavIndex */,
196 Definition * /*def*/)
198 //printf("Qhp::addContentsItem(%s) %d\n",name,m_sectionLevel);
199 // Backup difference before modification
202 if (!f.isEmpty() && f.at(0)=='^') return; // absolute URL not supported
204 int diff = m_prevSectionLevel - m_sectionLevel;
207 setPrevSection(name, f, anchor, m_sectionLevel);
209 // Close sections as needed
210 //printf("Qhp::addContentsItem() closing %d sections\n",diff);
211 for (; diff > 0; diff--)
213 m_toc.close("section");
217 void Qhp::addIndexItem(Definition *context,MemberDef *md,
218 const char *sectionAnchor,const char *word)
221 //printf("addIndexItem(%s %s %s\n",
222 // context?context->name().data():"<none>",
223 // md?md->name().data():"<none>",
228 static bool separateMemberPages = Config_getBool(SEPARATE_MEMBER_PAGES);
229 if (context==0) // global member
231 if (md->getGroupDef())
232 context = md->getGroupDef();
233 else if (md->getFileDef())
234 context = md->getFileDef();
236 if (context==0) return; // should not happen
237 QCString cfname = md->getOutputFileBase();
238 QCString cfiname = context->getOutputFileBase();
239 QCString level1 = context->name();
240 QCString level2 = word ? QCString(word) : md->name();
241 QCString contRef = separateMemberPages ? cfname : cfiname;
242 QCString anchor = sectionAnchor ? QCString(sectionAnchor) : md->anchor();
246 // <keyword name="foo" id="MyApplication::foo" ref="doc.html#foo"/>
247 ref = makeRef(contRef, anchor);
248 QCString id = level1+"::"+level2;
249 const char * attributes[] =
256 m_index.openClose("keyword", attributes);
258 else if (context) // container
260 // <keyword name="Foo" id="Foo" ref="doc.html#Foo"/>
261 QCString contRef = context->getOutputFileBase();
262 QCString level1 = word ? QCString(word) : context->name();
263 QCString ref = makeRef(contRef,sectionAnchor);
264 const char * attributes[] =
271 m_index.openClose("keyword", attributes);
275 void Qhp::addIndexFile(const char * name)
280 QCString Qhp::getQhpFileName()
285 QCString Qhp::getFullProjectName()
287 QCString projectName = Config_getString(PROJECT_NAME);
288 QCString versionText = Config_getString(PROJECT_NUMBER);
289 if (projectName.isEmpty()) projectName="Root";
290 return projectName + (versionText.isEmpty()
292 : QCString(" ") + versionText);
295 void Qhp::handlePrevSection()
299 <section title="My Application Manual" ref="index.html">
300 <section title="Chapter 1" ref="doc.html#chapter1"/>
301 <section title="Chapter 2" ref="doc.html#chapter2"/>
302 <section title="Chapter 3" ref="doc.html#chapter3"/>
307 if (m_prevSectionTitle.isNull())
309 m_prevSectionTitle=" "; // should not happen...
312 // We skip "Main Page" as our extra root is pointing to that
313 if (!((m_prevSectionLevel==1) && (m_prevSectionTitle==getFullProjectName())))
315 QCString finalRef = makeRef(m_prevSectionBaseName, m_prevSectionAnchor);
317 const char * const attributes[] =
318 { "title", m_prevSectionTitle,
323 if (m_prevSectionLevel < m_sectionLevel)
325 // Section with children
326 m_toc.open("section", attributes);
330 // Section without children
331 m_toc.openClose("section", attributes);
336 m_skipMainPageSection=TRUE;
342 void Qhp::setPrevSection(const char * title, const char * basename, const char * anchor, int level)
344 m_prevSectionTitle = title;
345 m_prevSectionBaseName = basename;
346 m_prevSectionAnchor = anchor;
347 m_prevSectionLevel = level;
350 void Qhp::clearPrevSection()
352 m_prevSectionTitle.resize(0);
353 m_prevSectionBaseName.resize(0);
354 m_prevSectionAnchor.resize(0);
357 void Qhp::addFile(const char * fileName)
359 m_files.openCloseContent("file", fileName);
362 void Qhp::addImageFile(const char *fileName)
367 void Qhp::addStyleSheetFile(const char *fileName)