My Project
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
qhp.cpp
Go to the documentation of this file.
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 #include <qfile.h>
29 
30 static QCString makeFileName(const char * withoutExtension)
31 {
32  QCString result=withoutExtension;
33  if (!result.isEmpty())
34  {
35  if (result.at(0)=='!') // relative URL -> strip marker
36  {
37  result=result.mid(1);
38  }
39  else // add specified HTML extension
40  {
42  }
43  }
44  return result;
45 }
46 
47 static QCString makeRef(const char * withoutExtension, const char * anchor)
48 {
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;
54 }
55 
56 Qhp::Qhp() : m_prevSectionLevel(0), m_sectionLevel(0), m_skipMainPageSection(FALSE)
57 {
62 }
63 
65 {
67 }
68 
70 {
71  /*
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>
78  </customFilter>
79  <filterSection>
80  <filterAttribute>myapp</filterAttribute>
81  <filterAttribute>1.0</filterAttribute>
82  ..
83  */
84  QCString nameSpace = Config_getString(QHP_NAMESPACE);
85  QCString virtualFolder = Config_getString(QHP_VIRTUAL_FOLDER);
86 
87  m_doc.declaration("1.0", "UTF-8");
88 
89  const char * rootAttributes[] =
90  { "version", "1.0", 0 };
91 
92  m_doc.open("QtHelpProject", rootAttributes);
93  m_doc.openCloseContent("namespace", nameSpace);
94  m_doc.openCloseContent("virtualFolder", virtualFolder);
95 
96  // Add custom filter
97  QCString filterName = Config_getString(QHP_CUST_FILTER_NAME);
98  if (!filterName.isEmpty())
99  {
100  const char * tagAttributes[] =
101  { "name", filterName, 0 };
102  m_doc.open("customFilter", tagAttributes);
103 
104  QStringList customFilterAttributes = QStringList::split(QChar(' '), Config_getString(QHP_CUST_FILTER_ATTRS));
105  for (int i = 0; i < (int)customFilterAttributes.count(); i++)
106  {
107  m_doc.openCloseContent("filterAttribute", customFilterAttributes[i].utf8());
108  }
109  m_doc.close("customFilter");
110  }
111 
112  m_doc.open("filterSection");
113 
114  // Add section attributes
115  QStringList sectionFilterAttributes = QStringList::split(QChar(' '),
116  Config_getString(QHP_SECT_FILTER_ATTRS));
117  if (!sectionFilterAttributes.contains(QString("doxygen")))
118  {
119  sectionFilterAttributes << "doxygen";
120  }
121  for (int i = 0; i < (int)sectionFilterAttributes.count(); i++)
122  {
123  m_doc.openCloseContent("filterAttribute", sectionFilterAttributes[i].utf8());
124  }
125 
126  m_toc.open("toc");
127 
128  // Add extra root node
129  QCString fullProjectname = getFullProjectName();
130  QCString indexFile = "index"+Doxygen::htmlFileExtension;
131  const char * const attributes[] =
132  { "title", fullProjectname,
133  "ref", indexFile,
134  NULL
135  };
136  m_toc.open("section", attributes);
138  m_prevSectionLevel = 1;
139  m_sectionLevel = 1;
140 
141  m_index.open("keywords");
142  m_files.open("files");
143 }
144 
146 {
147  // Finish TOC
149  for (int i = m_prevSectionLevel; i > 0; i--)
150  {
151  m_toc.close("section");
152  }
153  m_toc.close("toc");
154  m_doc.insert(m_toc);
155 
156  // Finish index
157  m_index.close("keywords");
159 
160  // Finish files
161  m_files.close("files");
163 
164  m_doc.close("filterSection");
165  m_doc.close("QtHelpProject");
166 
167  QCString fileName = Config_getString(HTML_OUTPUT) + "/" + getQhpFileName();
168  QFile file(fileName);
169  if (!file.open(IO_WriteOnly))
170  {
171  err("Could not open file %s for writing\n", fileName.data());
172  exit(1);
173  }
174  m_doc.dumpTo(file);
175 }
176 
178 {
179  m_sectionLevel++;
180 }
181 
183 {
185  {
186  m_skipMainPageSection=FALSE;
187  return;
188  }
189  m_sectionLevel--;
190 }
191 
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*/)
197 {
198  //printf("Qhp::addContentsItem(%s) %d\n",name,m_sectionLevel);
199  // Backup difference before modification
200 
201  QCString f = file;
202  if (!f.isEmpty() && f.at(0)=='^') return; // absolute URL not supported
203 
204  int diff = m_prevSectionLevel - m_sectionLevel;
205 
207  setPrevSection(name, f, anchor, m_sectionLevel);
208 
209  // Close sections as needed
210  //printf("Qhp::addContentsItem() closing %d sections\n",diff);
211  for (; diff > 0; diff--)
212  {
213  m_toc.close("section");
214  }
215 }
216 
218  const char *sectionAnchor,const char *word)
219 {
220  (void)word;
221  //printf("addIndexItem(%s %s %s\n",
222  // context?context->name().data():"<none>",
223  // md?md->name().data():"<none>",
224  // word);
225 
226  if (md) // member
227  {
228  static bool separateMemberPages = Config_getBool(SEPARATE_MEMBER_PAGES);
229  if (context==0) // global member
230  {
231  if (md->getGroupDef())
232  context = md->getGroupDef();
233  else if (md->getFileDef())
234  context = md->getFileDef();
235  }
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();
243 
244  QCString ref;
245 
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[] =
250  {
251  "name", level2,
252  "id", id,
253  "ref", ref,
254  0
255  };
256  m_index.openClose("keyword", attributes);
257  }
258  else if (context) // container
259  {
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[] =
265  {
266  "name", level1,
267  "id", level1,
268  "ref", ref,
269  0
270  };
271  m_index.openClose("keyword", attributes);
272  }
273 }
274 
275 void Qhp::addIndexFile(const char * name)
276 {
277  addFile(name);
278 }
279 
281 {
282  return "index.qhp";
283 }
284 
286 {
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()
291  ? QCString("")
292  : QCString(" ") + versionText);
293 }
294 
296 {
297  /*
298  <toc>
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"/>
303  </section>
304  </toc>
305  */
306 
307  if (m_prevSectionTitle.isNull())
308  {
309  m_prevSectionTitle=" "; // should not happen...
310  }
311 
312  // We skip "Main Page" as our extra root is pointing to that
314  {
315  QCString finalRef = makeRef(m_prevSectionBaseName, m_prevSectionAnchor);
316 
317  const char * const attributes[] =
318  { "title", m_prevSectionTitle,
319  "ref", finalRef,
320  NULL
321  };
322 
324  {
325  // Section with children
326  m_toc.open("section", attributes);
327  }
328  else
329  {
330  // Section without children
331  m_toc.openClose("section", attributes);
332  }
333  }
334  else
335  {
337  }
338 
340 }
341 
342 void Qhp::setPrevSection(const char * title, const char * basename, const char * anchor, int level)
343 {
344  m_prevSectionTitle = title;
345  m_prevSectionBaseName = basename;
346  m_prevSectionAnchor = anchor;
347  m_prevSectionLevel = level;
348 }
349 
351 {
352  m_prevSectionTitle.resize(0);
353  m_prevSectionBaseName.resize(0);
354  m_prevSectionAnchor.resize(0);
355 }
356 
357 void Qhp::addFile(const char * fileName)
358 {
359  m_files.openCloseContent("file", fileName);
360 }
361 
362 void Qhp::addImageFile(const char *fileName)
363 {
364  addFile(fileName);
365 }
366 
367 void Qhp::addStyleSheetFile(const char *fileName)
368 {
369  addFile(fileName);
370 }
371