1 /******************************************************************************
2  *
3  *
4  *
5  * Copyright (C) 1997-2015 by Parker Waechter & Dimitri van Heesch.
6  *
7  * Style sheet additions by Alexander Bartolich
8  *
9  * Permission to use, copy, modify, and distribute this software and its
10  * documentation under the terms of the GNU General Public License is hereby
11  * granted. No representations are made about the suitability of this software
12  * for any purpose. It is provided "as is" without express or implied warranty.
13  * See the GNU General Public License for more details.
14  *
15  * Documents produced by Doxygen are derivative works derived from the
16  * input used in their production; they are not affected by this license.
17  *
18  */
19 
20 #include <chrono>
21 #include <ctime>
22 #include <stdlib.h>
23 
24 #include "rtfgen.h"
25 #include "config.h"
26 #include "message.h"
27 #include "doxygen.h"
28 #include "util.h"
29 #include "diagram.h"
30 #include "language.h"
31 #include "dot.h"
32 #include "dotcallgraph.h"
33 #include "dotclassgraph.h"
34 #include "dotdirdeps.h"
35 #include "dotincldepgraph.h"
36 #include "version.h"
37 #include "pagedef.h"
38 #include "rtfstyle.h"
39 #include "rtfdocvisitor.h"
40 #include "docparser.h"
41 #include "dirdef.h"
42 #include "vhdldocgen.h"
43 #include "portable.h"
44 #include "groupdef.h"
45 #include "classlist.h"
46 #include "filename.h"
47 #include "namespacedef.h"
48 #include "dir.h"
49 #include "utf8.h"
50 #include "debug.h"
51 
52 
53 //#define DBG_RTF(x) x;
54 #define DBG_RTF(x)
55 
dateToRTFDateString()56 static QCString dateToRTFDateString()
57 {
58   auto now = std::chrono::system_clock::now();
59   auto time = std::chrono::system_clock::to_time_t(now);
60   auto tm = *localtime(&time);
61 
62   QCString result;
63   result.sprintf("\\yr%d\\mo%d\\dy%d\\hr%d\\min%d\\sec%d",
64       tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday,
65       tm.tm_hour, tm.tm_min, tm.tm_sec);
66   return result;
67 }
68 
RTFGenerator()69 RTFGenerator::RTFGenerator() : OutputGenerator(Config_getString(RTF_OUTPUT))
70 {
71 }
72 
RTFGenerator(const RTFGenerator & og)73 RTFGenerator::RTFGenerator(const RTFGenerator &og) : OutputGenerator(og)
74 {
75 }
76 
operator =(const RTFGenerator & og)77 RTFGenerator &RTFGenerator::operator=(const RTFGenerator &og)
78 {
79   OutputGenerator::operator=(og);
80   return *this;
81 }
82 
clone() const83 std::unique_ptr<OutputGenerator> RTFGenerator::clone() const
84 {
85   return std::make_unique<RTFGenerator>(*this);
86 }
87 
~RTFGenerator()88 RTFGenerator::~RTFGenerator()
89 {
90 }
91 
setRelativePath(const QCString & path)92 void RTFGenerator::setRelativePath(const QCString &path)
93 {
94   m_relPath = path;
95 }
96 
setSourceFileName(const QCString & name)97 void RTFGenerator::setSourceFileName(const QCString &name)
98 {
99   m_sourceFileName = name;
100 }
101 
writeStyleSheetFile(TextStream & t)102 void RTFGenerator::writeStyleSheetFile(TextStream &t)
103 {
104   t << "# Generated by doxygen " << getDoxygenVersion() << "\n\n";
105   t << "# This file describes styles used for generating RTF output.\n";
106   t << "# All text after a hash (#) is considered a comment and will be ignored.\n";
107   t << "# Remove a hash to activate a line.\n\n";
108 
109   int i;
110   for ( i=0 ; rtf_Style_Default[i].reference!=0 ; i++ )
111   {
112     t << "# " << rtf_Style_Default[i].name << " = "
113               << rtf_Style_Default[i].reference
114               << rtf_Style_Default[i].definition << "\n";
115   }
116 }
117 
writeExtensionsFile(TextStream & t)118 void RTFGenerator::writeExtensionsFile(TextStream &t)
119 {
120   t << "# Generated by doxygen " << getDoxygenVersion() << "\n\n";
121   t << "# This file describes extensions used for generating RTF output.\n";
122   t << "# All text after a hash (#) is considered a comment and will be ignored.\n";
123   t << "# Remove a hash to activate a line.\n\n";
124 
125   t << "# Overrides the project title.\n";
126 
127   t << "#Title           = \n\n";
128 
129   t << "# Name of the company that produced this document.\n";
130   t << "#Company         = \n\n";
131 
132   t << "# Filename of a company or project logo.\n";
133   t << "#LogoFilename    = \n\n";
134 
135   t << "# Author of the document.\n";
136   t << "#Author          = \n\n";
137 
138   t << "# Type of document (e.g. Design Specification, User Manual, etc.).\n";
139   t << "#DocumentType    = \n\n";
140 
141   t << "# Document tracking number.\n";
142   t << "#DocumentId      = \n\n";
143 
144   t << "# Name of the author's manager.\n";
145   t << "# This field is not displayed in the document itself, but it is \n";
146   t << "# available in the information block of the rtf file.  In Microsoft \n";
147   t << "# Word, it is available under File:Properties.\n";
148   t << "#Manager         = \n\n";
149 
150   t << "# Subject of the document.\n";
151   t << "# This field is not displayed in the document itself, but it is \n";
152   t << "# available in the information block of the rtf file.  In Microsoft \n";
153   t << "# Word, it is available under File:Properties.\n";
154   t << "#Subject         = \n\n";
155 
156   t << "# Comments regarding the document.\n";
157   t << "# This field is not displayed in the document itself, but it is \n";
158   t << "# available in the information block of the rtf file.  In Microsoft \n";
159   t << "# Word, it is available under File:Properties.\n";
160   t << "#Comments        = \n\n";
161 
162   t << "# Keywords associated with the document.\n";
163   t << "# This field is not displayed in the document itself, but it is \n";
164   t << "# available in the information block of the rtf file.  In Microsoft \n";
165   t << "# Word, it is available under File:Properties.\n";
166   t << "#Keywords        = \n\n";
167 }
168 
169 
init()170 void RTFGenerator::init()
171 {
172   QCString dir=Config_getString(RTF_OUTPUT);
173   Dir d(dir.str());
174   if (!d.exists() && !d.mkdir(dir.str()))
175   {
176     term("Could not create output directory %s\n",qPrint(dir));
177   }
178 
179   // first duplicate strings of rtf_Style_Default
180   const struct Rtf_Style_Default* def = rtf_Style_Default;
181   while (def->reference)
182   {
183     if (def->definition == 0)
184     {
185       err("Internal: rtf_Style_Default[%s] has no definition.\n", def->name);
186     }
187     else
188     {
189       rtf_Style.insert(std::make_pair(def->name, StyleData(def->reference, def->definition)));
190     }
191     def++;
192   }
193 
194   // overwrite some (or all) definitions from file
195   QCString rtfStyleSheetFile = Config_getString(RTF_STYLESHEET_FILE);
196   if (!rtfStyleSheetFile.isEmpty())
197   {
198     loadStylesheet(rtfStyleSheetFile, rtf_Style);
199   }
200 
201   // If user has defined an extension file, load its contents.
202   QCString rtfExtensionsFile = Config_getString(RTF_EXTENSIONS_FILE);
203   if (!rtfExtensionsFile.isEmpty())
204   {
205     loadExtensions(rtfExtensionsFile);
206   }
207 
208   createSubDirs(d);
209 }
210 
cleanup()211 void RTFGenerator::cleanup()
212 {
213   QCString dname = Config_getString(RTF_OUTPUT);
214   Dir d(dname.str());
215   clearSubDirs(d);
216 }
217 
makeIndexName(const QCString & s,int i)218 static QCString makeIndexName(const QCString &s,int i)
219 {
220   QCString result=s;
221   result+=(char)(i+'0');
222   return result;
223 }
224 
beginRTFDocument()225 void RTFGenerator::beginRTFDocument()
226 {
227   /* all the included RTF files should begin with the
228    * same header
229    */
230   m_t << "{\\rtf1\\ansi\\ansicpg" << theTranslator->trRTFansicp();
231   m_t << "\\uc1 \\deff0\\deflang1033\\deflangfe1033\n";
232 
233   DBG_RTF(m_t << "{\\comment Beginning font list}\n")
234   m_t << "{\\fonttbl ";
235   m_t << "{\\f0\\froman\\fcharset" << theTranslator->trRTFCharSet();
236   m_t << "\\fprq2{\\*\\panose 02020603050405020304}Times New Roman;}\n";
237   m_t << "{\\f1\\fswiss\\fcharset" << theTranslator->trRTFCharSet();
238   m_t << "\\fprq2{\\*\\panose 020b0604020202020204}Arial;}\n";
239   m_t << "{\\f2\\fmodern\\fcharset" << theTranslator->trRTFCharSet();
240   m_t << "\\fprq1{\\*\\panose 02070309020205020404}Courier New;}\n";
241   m_t << "{\\f3\\froman\\fcharset2\\fprq2{\\*\\panose 05050102010706020507}Symbol;}\n";
242   m_t << "}\n";
243   DBG_RTF(m_t << "{\\comment begin colors}\n")
244   m_t << "{\\colortbl;";
245   m_t << "\\red0\\green0\\blue0;";
246   m_t << "\\red0\\green0\\blue255;";
247   m_t << "\\red0\\green255\\blue255;";
248   m_t << "\\red0\\green255\\blue0;";
249   m_t << "\\red255\\green0\\blue255;";
250   m_t << "\\red255\\green0\\blue0;";
251   m_t << "\\red255\\green255\\blue0;";
252   m_t << "\\red255\\green255\\blue255;";
253   m_t << "\\red0\\green0\\blue128;";
254   m_t << "\\red0\\green128\\blue128;";
255   m_t << "\\red0\\green128\\blue0;";
256   m_t << "\\red128\\green0\\blue128;";
257   m_t << "\\red128\\green0\\blue0;";
258   m_t << "\\red128\\green128\\blue0;";
259   m_t << "\\red128\\green128\\blue128;";
260   m_t << "\\red192\\green192\\blue192;";
261 
262   // code highlighting colors. Note order is important see also RTFGenerator::startFontClass
263   m_t << "\\red0\\green128\\blue0;";   // keyword = index 17
264   m_t << "\\red96\\green64\\blue32;";  // keywordtype
265   m_t << "\\rede0\\green128\\blue0;";  // keywordflow
266   m_t << "\\red128\\green0\\blue0;";   // comment
267   m_t << "\\red128\\green96\\blue32;"; // preprocessor
268   m_t << "\\red0\\green32\\blue128;";  // stringliteral
269   m_t << "\\red0\\green128\\blue128;"; // charliteral
270   m_t << "\\red255\\green0\\blue255;"; // vhdldigit
271   m_t << "\\red0\\green0\\blue0;";     // vhdlchar
272   m_t << "\\red112\\green0\\blue112;"; // vhdlkeyword
273   m_t << "\\red255\\green0\\blue0;";   // vhdllogic
274 
275   m_t << "}\n";
276 
277   DBG_RTF(m_t << "{\\comment Beginning style list}\n")
278   m_t << "{\\stylesheet\n";
279   m_t << "{\\widctlpar\\adjustright \\fs20\\cgrid \\snext0 Normal;}\n";
280 
281   // set the paper dimensions according to PAPER_TYPE
282   static auto paperType = Config_getEnum(PAPER_TYPE);
283   m_t << "{";
284   switch (paperType)
285   {
286     // width & height values are inches * 1440
287     case PAPER_TYPE_t::a4:        m_t << "\\paperw11900\\paperh16840"; break;
288     case PAPER_TYPE_t::letter:    m_t << "\\paperw12240\\paperh15840"; break;
289     case PAPER_TYPE_t::legal:     m_t << "\\paperw12240\\paperh20160"; break;
290     case PAPER_TYPE_t::executive: m_t << "\\paperw10440\\paperh15120"; break;
291   }
292   m_t << "\\margl1800\\margr1800\\margt1440\\margb1440\\gutter0\\ltrsect}\n";
293 
294   // sort styles ascending by \s-number via an intermediate QArray
295   unsigned maxIndex = 0;
296   for (const auto &kv : rtf_Style)
297   {
298     uint index = kv.second.index();
299     if (index > maxIndex) maxIndex = index;
300   }
301   std::vector<const StyleData*> array(maxIndex + 1, 0);
302   ASSERT(maxIndex < array.size());
303 
304   for (const auto &kv : rtf_Style)
305   {
306     uint index = kv.second.index();
307     if (array[index] != 0)
308     {
309       msg("Style '%s' redefines \\s%d.\n", kv.first.c_str(), index);
310     }
311     array[index] = &kv.second;
312   }
313 
314   // write array elements
315   size_t size = array.size();
316   for(size_t i = 0; i < size; i++)
317   {
318     const StyleData *pStyle = array[i];
319     if (pStyle)
320     {
321       m_t << "{" << pStyle->reference() << pStyle->definition() << ";}\n";
322     }
323   }
324 
325   m_t << "}\n";
326   // this comment is needed for postprocessing!
327   m_t << "{\\comment begin body}\n";
328 
329 }
330 
beginRTFChapter()331 void RTFGenerator::beginRTFChapter()
332 {
333   m_t << "\n";
334   DBG_RTF(m_t << "{\\comment BeginRTFChapter}\n")
335   m_t << rtf_Style_Reset;
336 
337   // if we are compact, no extra page breaks...
338   if (Config_getBool(COMPACT_RTF))
339   {
340     //      m_t << "\\sect\\sectd\\sbknone\n";
341     m_t << "\\sect\\sbknone\n";
342     rtfwriteRuler_thick();
343   }
344   else
345     m_t << "\\sect\\sbkpage\n";
346   //m_t << "\\sect\\sectd\\sbkpage\n";
347 
348   m_t << rtf_Style["Heading1"].reference() << "\n";
349 }
350 
beginRTFSection()351 void RTFGenerator::beginRTFSection()
352 {
353   m_t << "\n";
354   DBG_RTF(m_t << "{\\comment BeginRTFSection}\n")
355   m_t << rtf_Style_Reset;
356 
357   // if we are compact, no extra page breaks...
358   if (Config_getBool(COMPACT_RTF))
359   {
360     m_t << "\\sect\\sbknone\n";
361     rtfwriteRuler_emboss();
362   }
363   else
364   {
365     m_t << "\\sect\\sbkpage\n";
366   }
367 
368   m_t << rtf_Style["Heading2"].reference() << "\n";
369 }
370 
startFile(const QCString & name,const QCString &,const QCString &,int)371 void RTFGenerator::startFile(const QCString &name,const QCString &,const QCString &,int)
372 {
373   //setEncoding(QCString().sprintf("CP%s",theTranslator->trRTFansicp()));
374   QCString fileName=name;
375   m_relPath = relativePathToRoot(fileName);
376 
377   if (fileName.right(4)!=".rtf" ) fileName+=".rtf";
378   startPlainFile(fileName);
379   setRelativePath(m_relPath);
380   setSourceFileName(stripPath(fileName));
381   beginRTFDocument();
382 }
383 
endFile()384 void RTFGenerator::endFile()
385 {
386   DBG_RTF(m_t << "{\\comment endFile}\n")
387   m_t << "}";
388 
389   endPlainFile();
390   setSourceFileName("");
391 }
392 
startProjectNumber()393 void RTFGenerator::startProjectNumber()
394 {
395   DBG_RTF(m_t << "{\\comment startProjectNumber }\n")
396   m_t << " ";
397 }
398 
endProjectNumber()399 void RTFGenerator::endProjectNumber()
400 {
401   DBG_RTF(m_t << "{\\comment endProjectNumber }\n")
402 }
403 
startIndexSection(IndexSections is)404 void RTFGenerator::startIndexSection(IndexSections is)
405 {
406   //QCString paperName;
407 
408   //m_indentLevel = 0;
409 
410   switch (is)
411   {
412     case isTitlePageStart:
413       // basic RTFstart
414       // get readyfor author etc
415 
416       m_t << "{\\info \n";
417       m_t << "{\\title {\\comment ";
418       break;
419     case isTitlePageAuthor:
420       m_t << "}\n";
421       if (!rtf_subject.isEmpty())      m_t << "{\\subject "  << rtf_subject      << "}\n";
422       if (!rtf_comments.isEmpty())     m_t << "{\\comment "  << rtf_comments     << "}\n";
423       if (!rtf_company.isEmpty())      m_t << "{\\company "  << rtf_company      << "}\n";
424       if (!rtf_author.isEmpty())       m_t << "{\\author "   << rtf_author       << "}\n";
425       if (!rtf_manager.isEmpty())      m_t << "{\\manager "  << rtf_manager      << "}\n";
426       if (!rtf_documentType.isEmpty()) m_t << "{\\category " << rtf_documentType << "}\n";
427       if (!rtf_keywords.isEmpty())     m_t << "{\\keywords " << rtf_keywords     << "}\n";
428       m_t << "{\\comment ";
429       break;
430     case isMainPage:
431       //Introduction
432       beginRTFChapter();
433       break;
434     //case isPackageIndex:
435     //  //Package Index
436     //  beginRTFChapter();
437     //  break;
438     case isModuleIndex:
439       //Module Index
440       beginRTFChapter();
441       break;
442     case isDirIndex:
443       //Directory Index
444       beginRTFChapter();
445       break;
446     case isNamespaceIndex:
447       //Namespace Index
448       beginRTFChapter();
449       break;
450     case isConceptIndex:
451       //Concept Index
452       beginRTFChapter();
453       break;
454     case isClassHierarchyIndex:
455       //Hierarchical Index
456       DBG_RTF(m_t << "{\\comment start classhierarchy}\n")
457       beginRTFChapter();
458       break;
459     case isCompoundIndex:
460       //Annotated Compound Index
461       beginRTFChapter();
462       break;
463     case isFileIndex:
464       //Annotated File Index
465       beginRTFChapter();
466       break;
467     case isPageIndex:
468       //Related Page Index
469       beginRTFChapter();
470       break;
471     case isModuleDocumentation:
472       {
473         //Module Documentation
474         for (const auto &gd : *Doxygen::groupLinkedMap)
475         {
476           if (!gd->isReference())
477           {
478             beginRTFChapter();
479             break;
480           }
481         }
482       }
483       break;
484     case isDirDocumentation:
485       {
486         //Directory Documentation
487         for (const auto &dd : *Doxygen::dirLinkedMap)
488         {
489           if (dd->isLinkableInProject())
490           {
491             beginRTFChapter();
492             break;
493           }
494         }
495       }
496       break;
497     case isNamespaceDocumentation:
498       {
499         // Namespace Documentation
500         for (const auto &nd : *Doxygen::namespaceLinkedMap)
501         {
502           if (nd->isLinkableInProject())
503           {
504             beginRTFChapter();
505             break;
506           }
507         }
508       }
509       break;
510     case isConceptDocumentation:
511       {
512         // Concept Documentation
513         for (const auto &cd : *Doxygen::conceptLinkedMap)
514         {
515           if (cd->isLinkableInProject())
516           {
517             beginRTFChapter();
518             break;
519           }
520         }
521       }
522       break;
523     case isClassDocumentation:
524       {
525         //Compound Documentation
526         for (const auto &cd : *Doxygen::classLinkedMap)
527         {
528           if (cd->isLinkableInProject() &&
529               cd->templateMaster()==0 &&
530              !cd->isEmbeddedInOuterScope() &&
531              !cd->isAlias()
532              )
533           {
534             beginRTFChapter();
535             break;
536           }
537         }
538       }
539       break;
540     case isFileDocumentation:
541       {
542         //File Documentation
543         bool isFirst=TRUE;
544         for (const auto &fn : *Doxygen::inputNameLinkedMap)
545         {
546           for (const auto &fd : *fn)
547           {
548             if (fd->isLinkableInProject() || fd->generateSourceFile())
549             {
550               if (isFirst)
551               {
552                 beginRTFChapter();
553                 isFirst=FALSE;
554                 break;
555               }
556             }
557           }
558           if (!isFirst)
559           {
560             break;
561           }
562         }
563       }
564       break;
565     case isExampleDocumentation:
566       {
567         //Example Documentation
568         beginRTFChapter();
569       }
570       break;
571     case isPageDocumentation:
572       {
573         //Page Documentation
574         beginRTFChapter();
575       }
576       break;
577     case isPageDocumentation2:
578       {
579         m_t << "{\\tc \\v ";
580       }
581       break;
582     case isEndIndex:
583       break;
584   }
585 }
586 
endIndexSection(IndexSections is)587 void RTFGenerator::endIndexSection(IndexSections is)
588 {
589   bool fortranOpt = Config_getBool(OPTIMIZE_FOR_FORTRAN);
590   bool vhdlOpt    = Config_getBool(OPTIMIZE_OUTPUT_VHDL);
591   QCString projectName = Config_getString(PROJECT_NAME);
592 
593   switch (is)
594   {
595     case isTitlePageStart:
596       if (!rtf_title.isEmpty())
597         // User has overridden document title in extensions file
598         m_t << "}" << rtf_title;
599       else
600         m_t << "}" << projectName;
601       break;
602     case isTitlePageAuthor:
603       {
604         m_t << " doxygen" << getDoxygenVersion() << ".}\n";
605         m_t << "{\\creatim " << dateToRTFDateString() << "}\n}";
606         DBG_RTF(m_t << "{\\comment end of infoblock}\n");
607         // setup for this section
608         m_t << rtf_Style_Reset <<"\n";
609         m_t << "\\sectd\\pgnlcrm\n";
610         m_t << "{\\footer "<<rtf_Style["Footer"].reference() << "{\\chpgn}}\n";
611         // the title entry
612         DBG_RTF(m_t << "{\\comment begin title page}\n")
613 
614 
615         m_t << rtf_Style_Reset << rtf_Style["SubTitle"].reference() << "\n"; // set to title style
616 
617         m_t << "\\vertalc\\qc\\par\\par\\par\\par\\par\\par\\par\n";
618         if (!rtf_logoFilename.isEmpty())
619         {
620           m_t << "{\\field\\flddirty {\\*\\fldinst INCLUDEPICTURE \"" << rtf_logoFilename;
621           m_t << "\" \\\\d \\\\*MERGEFORMAT} {\\fldrslt IMAGE }}\\par\\par\n";
622         }
623         if (!rtf_company.isEmpty())
624         {
625           m_t << rtf_company << "\\par\\par\n";
626         }
627 
628         m_t << rtf_Style_Reset << rtf_Style["Title"].reference() << "\n"; // set to title style
629         if (!rtf_title.isEmpty())
630         {
631           // User has overridden document title in extensions file
632           m_t << "{\\field\\fldedit {\\*\\fldinst TITLE \\\\*MERGEFORMAT}{\\fldrslt " << rtf_title << "}}\\par\n";
633         }
634         else
635         {
636           std::unique_ptr<IDocParser> parser { createDocParser() };
637           std::unique_ptr<DocText>    root   { validatingParseText(*parser.get(), projectName) };
638           m_t << "{\\field\\fldedit {\\*\\fldinst TITLE \\\\*MERGEFORMAT}{\\fldrslt ";
639           writeDoc(root.get(),0,0,0);
640           m_t << "}}\\par\n";
641         }
642 
643         m_t << rtf_Style_Reset << rtf_Style["SubTitle"].reference() << "\n"; // set to title style
644         m_t << "\\par\n";
645         if (!rtf_documentType.isEmpty())
646         {
647           m_t << rtf_documentType << "\\par\n";
648         }
649         if (!rtf_documentId.isEmpty())
650         {
651           m_t << rtf_documentId << "\\par\n";
652         }
653         m_t << "\\par\\par\\par\\par\\par\\par\\par\\par\\par\\par\\par\\par\n";
654 
655         m_t << rtf_Style_Reset << rtf_Style["SubTitle"].reference() << "\n"; // set to subtitle style
656         if (!rtf_author.isEmpty())
657         {
658           m_t << "{\\field\\fldedit {\\*\\fldinst AUTHOR \\\\*MERGEFORMAT}{\\fldrslt "<< rtf_author << " }}\\par\n";
659         }
660         else
661         {
662           m_t << "{\\field\\fldedit {\\*\\fldinst AUTHOR \\\\*MERGEFORMAT}{\\fldrslt AUTHOR}}\\par\n";
663         }
664 
665         m_t << theTranslator->trVersion() << " " << Config_getString(PROJECT_NUMBER) << "\\par";
666         m_t << "{\\field\\fldedit {\\*\\fldinst CREATEDATE \\\\*MERGEFORMAT}"
667           "{\\fldrslt "<< dateToString(FALSE) << " }}\\par\n";
668         m_t << "\\page\\page";
669         DBG_RTF(m_t << "{\\comment End title page}\n")
670 
671         // table of contents section
672         DBG_RTF(m_t << "{\\comment Table of contents}\n")
673         m_t << "\\vertalt\n";
674         m_t << rtf_Style_Reset << "\n";
675         m_t << rtf_Style["Heading1"].reference();
676         m_t << theTranslator->trRTFTableOfContents() << "\\par\n";
677         m_t << rtf_Style_Reset << "\\par\n";
678         m_t << "{\\field\\fldedit {\\*\\fldinst TOC \\\\f \\\\*MERGEFORMAT}{\\fldrslt Table of contents}}\\par\n";
679         m_t << rtf_Style_Reset << "\n";
680       }
681       break;
682     case isMainPage:
683       m_t << "\\par " << rtf_Style_Reset << "\n";
684       if (!mainPageHasTitle())
685       {
686         m_t << "{\\tc \\v " << theTranslator->trMainPage() << "}\n";
687       }
688       else
689       {
690         m_t << "{\\tc \\v " << substitute(Doxygen::mainPage->title(),"%","") << "}\n";
691       }
692       m_t << "{\\field\\fldedit{\\*\\fldinst INCLUDETEXT \"";
693       //if (Config_getBool(GENERATE_TREEVIEW)) m_t << "main"; else m_t << "index";
694       m_t << "index";
695       m_t << ".rtf\" \\\\*MERGEFORMAT}{\\fldrslt includedstuff}}\n";
696       break;
697     //case isPackageIndex:
698     //  m_t << "\\par " << rtf_Style_Reset << "\n";
699     //  m_t << "{\\tc \\v " << theTranslator->trPackageList() << "}\n";
700     //  m_t << "{\\field\\fldedit{\\*\\fldinst INCLUDETEXT \"packages.rtf\" \\\\*MERGEFORMAT}{\\fldrslt includedstuff}}\n";
701     //  break;
702     case isModuleIndex:
703       m_t << "\\par " << rtf_Style_Reset << "\n";
704       m_t << "{\\tc \\v " << theTranslator->trModuleIndex() << "}\n";
705       m_t << "{\\field\\fldedit{\\*\\fldinst INCLUDETEXT \"modules.rtf\" \\\\*MERGEFORMAT}{\\fldrslt includedstuff}}\n";
706       break;
707     case isDirIndex:
708       m_t << "\\par " << rtf_Style_Reset << "\n";
709       m_t << "{\\tc \\v " << theTranslator->trDirIndex() << "}\n";
710       m_t << "{\\field\\fldedit{\\*\\fldinst INCLUDETEXT \"dirs.rtf\" \\\\*MERGEFORMAT}{\\fldrslt includedstuff}}\n";
711       break;
712     case isNamespaceIndex:
713       m_t << "\\par " << rtf_Style_Reset << "\n";
714       if (fortranOpt)
715       {
716           m_t << "{\\tc \\v " << theTranslator->trModulesIndex() << "}\n";
717       }
718       else
719       {
720           m_t << "{\\tc \\v " << theTranslator->trNamespaceIndex() << "}\n";
721       }
722 
723       m_t << "{\\field\\fldedit{\\*\\fldinst INCLUDETEXT \"namespaces.rtf\" \\\\*MERGEFORMAT}{\\fldrslt includedstuff}}\n";
724       break;
725     case isConceptIndex:
726       m_t << "\\par " << rtf_Style_Reset << "\n";
727       m_t << "{\\tc \\v " << theTranslator->trConceptIndex() << "}\n";
728       m_t << "{\\field\\fldedit{\\*\\fldinst INCLUDETEXT \"concepts.rtf\" \\\\*MERGEFORMAT}{\\fldrslt includedstuff}}\n";
729       break;
730     case isClassHierarchyIndex:
731       m_t << "\\par " << rtf_Style_Reset << "\n";
732       m_t << "{\\tc \\v " << theTranslator->trHierarchicalIndex() << "}\n";
733       m_t << "{\\field\\fldedit{\\*\\fldinst INCLUDETEXT \"hierarchy.rtf\" \\\\*MERGEFORMAT}{\\fldrslt includedstuff}}\n";
734       break;
735     case isCompoundIndex:
736       m_t << "\\par " << rtf_Style_Reset << "\n";
737       if (fortranOpt)
738       {
739         m_t << "{\\tc \\v " << theTranslator->trCompoundIndexFortran() << "}\n";
740       }
741       else if (vhdlOpt)
742       {
743         m_t << "{\\tc \\v " << theTranslator->trDesignUnitIndex() << "}\n";
744       }
745       else
746       {
747         m_t << "{\\tc \\v " << theTranslator->trCompoundIndex() << "}\n";
748       }
749       m_t << "{\\field\\fldedit{\\*\\fldinst INCLUDETEXT \"annotated.rtf\" \\\\*MERGEFORMAT}{\\fldrslt includedstuff}}\n";
750       break;
751     case isFileIndex:
752       m_t << "\\par " << rtf_Style_Reset << "\n";
753       m_t << "{\\tc \\v " << theTranslator->trFileIndex() << "}\n";
754       m_t << "{\\field\\fldedit{\\*\\fldinst INCLUDETEXT \"files.rtf\" \\\\*MERGEFORMAT}{\\fldrslt includedstuff}}\n";
755       break;
756     case isPageIndex:
757       m_t << "\\par " << rtf_Style_Reset << "\n";
758       m_t << "{\\tc \\v " << theTranslator->trPageIndex() << "}\n";
759       m_t << "{\\field\\fldedit{\\*\\fldinst INCLUDETEXT \"pages.rtf\" \\\\*MERGEFORMAT}{\\fldrslt includedstuff}}\n";
760       break;
761     case isModuleDocumentation:
762       {
763         bool first=true;
764         m_t << "{\\tc \\v " << theTranslator->trModuleDocumentation() << "}\n";
765         for (const auto &gd : *Doxygen::groupLinkedMap)
766         {
767           if (!gd->isReference())
768           {
769             m_t << "\\par " << rtf_Style_Reset << "\n";
770             if (!first)
771             {
772               beginRTFSection();
773             }
774             first=false;
775             m_t << "{\\field\\fldedit{\\*\\fldinst INCLUDETEXT \"";
776             m_t << gd->getOutputFileBase();
777             m_t << ".rtf\" \\\\*MERGEFORMAT}{\\fldrslt includedstuff}}\n";
778           }
779         }
780       }
781       break;
782     case isDirDocumentation:
783       {
784         bool first=true;
785         m_t << "{\\tc \\v " << theTranslator->trDirDocumentation() << "}\n";
786         for (const auto &dd : *Doxygen::dirLinkedMap)
787         {
788           if (dd->isLinkableInProject())
789           {
790             m_t << "\\par " << rtf_Style_Reset << "\n";
791             if (!first)
792             {
793               beginRTFSection();
794             }
795             first=false;
796             m_t << "{\\field\\fldedit{\\*\\fldinst INCLUDETEXT \"";
797             m_t << dd->getOutputFileBase();
798             m_t << ".rtf\" \\\\*MERGEFORMAT}{\\fldrslt includedstuff}}\n";
799           }
800         }
801       }
802       break;
803     case isNamespaceDocumentation:
804       {
805         bool first=true;
806         for (const auto &nd : *Doxygen::namespaceLinkedMap)
807         {
808           if (nd->isLinkableInProject() && !nd->isAlias())
809           {
810             m_t << "\\par " << rtf_Style_Reset << "\n";
811             if (!first)
812             {
813               beginRTFSection();
814             }
815             first=false;
816             m_t << "{\\field\\fldedit{\\*\\fldinst INCLUDETEXT \"";
817             m_t << nd->getOutputFileBase();
818             m_t << ".rtf\" \\\\*MERGEFORMAT}{\\fldrslt includedstuff}}\n";
819           }
820         }
821       }
822       break;
823     case isConceptDocumentation:
824       {
825         bool first=true;
826         for (const auto &cd : *Doxygen::conceptLinkedMap)
827         {
828           if (cd->isLinkableInProject() && !cd->isAlias())
829           {
830             m_t << "\\par " << rtf_Style_Reset << "\n";
831             if (!first)
832             {
833               beginRTFSection();
834             }
835             first=false;
836             m_t << "{\\field\\fldedit{\\*\\fldinst INCLUDETEXT \"";
837             m_t << cd->getOutputFileBase();
838             m_t << ".rtf\" \\\\*MERGEFORMAT}{\\fldrslt includedstuff}}\n";
839           }
840         }
841       }
842       break;
843     case isClassDocumentation:
844       {
845         bool first=true;
846         if (fortranOpt)
847         {
848           m_t << "{\\tc \\v " << theTranslator->trTypeDocumentation() << "}\n";
849         }
850         else
851         {
852           m_t << "{\\tc \\v " << theTranslator->trClassDocumentation() << "}\n";
853         }
854         for (const auto &cd : *Doxygen::classLinkedMap)
855         {
856           if (cd->isLinkableInProject() &&
857               cd->templateMaster()==0 &&
858              !cd->isEmbeddedInOuterScope() &&
859              !cd->isAlias()
860              )
861           {
862             m_t << "\\par " << rtf_Style_Reset << "\n";
863             if (!first)
864             {
865               beginRTFSection();
866             }
867             first=false;
868             m_t << "{\\field\\fldedit{\\*\\fldinst INCLUDETEXT \"";
869             m_t << cd->getOutputFileBase();
870             m_t << ".rtf\" \\\\*MERGEFORMAT}{\\fldrslt includedstuff}}\n";
871           }
872         }
873       }
874       break;
875     case isFileDocumentation:
876       {
877         bool isFirst=TRUE;
878 
879         m_t << "{\\tc \\v " << theTranslator->trFileDocumentation() << "}\n";
880         for (const auto &fn : *Doxygen::inputNameLinkedMap)
881         {
882           for (const auto &fd : *fn)
883           {
884             if (fd->isLinkableInProject())
885             {
886               m_t << "\\par " << rtf_Style_Reset << "\n";
887               if (!isFirst)
888               {
889                 beginRTFSection();
890               }
891               isFirst=FALSE;
892               m_t << "{\\field\\fldedit{\\*\\fldinst INCLUDETEXT \"";
893               m_t << fd->getOutputFileBase();
894               m_t << ".rtf\" \\\\*MERGEFORMAT}{\\fldrslt includedstuff}}\n";
895             }
896             if (fd->generateSourceFile())
897             {
898               m_t << "\\par " << rtf_Style_Reset << "\n";
899               if (!isFirst)
900               {
901                 beginRTFSection();
902               }
903               isFirst=FALSE;
904               m_t << "{\\field\\fldedit{\\*\\fldinst INCLUDETEXT \"";
905               m_t << fd->getSourceFileBase();
906               m_t << ".rtf\" \\\\*MERGEFORMAT}{\\fldrslt includedstuff}}\n";
907             }
908           }
909         }
910       }
911       break;
912     case isExampleDocumentation:
913       {
914         //m_t << "}\n";
915         bool isFirst=true;
916         m_t << "{\\tc \\v " << theTranslator->trExampleDocumentation() << "}\n";
917         for (const auto &pd : *Doxygen::exampleLinkedMap)
918         {
919           m_t << "\\par " << rtf_Style_Reset << "\n";
920           if (!isFirst)
921           {
922             beginRTFSection();
923           }
924           isFirst=false;
925           m_t << "{\\field\\fldedit{\\*\\fldinst INCLUDETEXT \"";
926           m_t << pd->getOutputFileBase();
927           m_t << ".rtf\" \\\\*MERGEFORMAT}{\\fldrslt includedstuff}}\n";
928         }
929       }
930       break;
931     case isPageDocumentation:
932       {
933 //#error "fix me in the same way as the latex index..."
934         //m_t << "{\\tc \\v " << theTranslator->trPageDocumentation() << "}\n";
935         //m_t << "}\n";
936         //bool first=TRUE;
937         //for (const auto *pd : Doxygen::pageLinkedMap)
938         //{
939         //  if (!pd->getGroupDef() && !pd->isReference())
940         //  {
941         //    if (first) m_t << "\\par " << rtf_Style_Reset << "\n";
942         //    m_t << "{\\field\\fldedit{\\*\\fldinst INCLUDETEXT \"";
943         //    m_t << pd->getOutputFileBase();
944         //    m_t << ".rtf\" \\\\*MERGEFORMAT}{\\fldrslt includedstuff}}\n";
945         //    first=FALSE;
946         //  }
947         //}
948       }
949       break;
950     case isPageDocumentation2:
951       {
952         m_t << "}";
953         m_t << "\\par " << rtf_Style_Reset << "\n";
954       }
955       break;
956     case isEndIndex:
957       beginRTFChapter();
958       m_t << rtf_Style["Heading1"].reference();
959       m_t << theTranslator->trRTFGeneralIndex() << "\\par \n";
960       m_t << rtf_Style_Reset << "\n";
961       m_t << "{\\tc \\v " << theTranslator->trRTFGeneralIndex() << "}\n";
962       m_t << "{\\field\\fldedit {\\*\\fldinst INDEX \\\\c2 \\\\*MERGEFORMAT}{\\fldrslt INDEX}}\n";
963 
964       break;
965    }
966 }
967 
writePageLink(const QCString & name,bool first)968 void RTFGenerator::writePageLink(const QCString &name,bool first)
969 {
970    if (first) m_t << "\\par " << rtf_Style_Reset << "\n";
971    m_t << "{\\field\\fldedit{\\*\\fldinst INCLUDETEXT \"";
972    m_t << name;
973    m_t << ".rtf\" \\\\*MERGEFORMAT}{\\fldrslt includedstuff}}\n";
974 }
975 
lastIndexPage()976 void RTFGenerator::lastIndexPage()
977 {
978   DBG_RTF(m_t << "{\\comment Beginning Body of RTF Document}\n")
979   // end page and setup for rest of document
980   m_t << "\\sect \\sbkpage \\pgndec \\pgnrestart\n";
981   m_t << "\\sect \\sectd \\sbknone\n";
982 
983   // set new footer with arabic numbers
984   m_t << "{\\footer "<< rtf_Style["Footer"].reference() << "{\\chpgn}}\n";
985 
986 }
987 
writeStyleInfo(int)988 void RTFGenerator::writeStyleInfo(int)
989 {
990 }
991 
lineBreak(const QCString &)992 void RTFGenerator::lineBreak(const QCString &)
993 {
994   DBG_RTF(m_t << "{\\comment (lineBreak)}"    << "\n")
995   m_t << "\\par\n";
996   m_omitParagraph = TRUE;
997 }
998 
writeString(const QCString & text)999 void RTFGenerator::writeString(const QCString &text)
1000 {
1001   m_t << text;
1002 }
1003 
startIndexList()1004 void RTFGenerator::startIndexList()
1005 {
1006   DBG_RTF(m_t << "{\\comment (startIndexList)}\n")
1007   m_t << "{\n";
1008   m_t << "\\par\n";
1009   incIndentLevel();
1010   m_t << rtf_Style_Reset << rtf_LCList_DepthStyle() << "\n";
1011   m_omitParagraph = TRUE;
1012 }
1013 
endIndexList()1014 void RTFGenerator::endIndexList()
1015 {
1016   DBG_RTF(m_t << "{\\comment (endIndexList)}\n")
1017   if (!m_omitParagraph)
1018   {
1019     m_t << "\\par";
1020     m_omitParagraph = TRUE;
1021   }
1022   m_t << "}";
1023   decIndentLevel();
1024 }
1025 
1026 /*! start bullet list */
startItemList()1027 void RTFGenerator::startItemList()
1028 {
1029   newParagraph();
1030   incIndentLevel();
1031   int level = indentLevel();
1032   DBG_RTF(m_t << "{\\comment (startItemList level=" << level << ") }\n")
1033   m_t << "{";
1034   m_listItemInfo[level].number = 1;
1035   m_listItemInfo[level].isEnum = false;
1036   m_listItemInfo[level].type   = '1';
1037 }
1038 
1039 /*! end bullet list */
endItemList()1040 void RTFGenerator::endItemList()
1041 {
1042   newParagraph();
1043   DBG_RTF(m_t << "{\\comment (endItemList level=" << indentLevel() << ")}\n")
1044   m_t << "}";
1045   decIndentLevel();
1046   m_omitParagraph = TRUE;
1047 }
1048 
1049 /*! write bullet or enum item */
startItemListItem()1050 void RTFGenerator::startItemListItem()
1051 {
1052   DBG_RTF(m_t << "{\\comment (startItemListItem)}\n")
1053   newParagraph();
1054   m_t << rtf_Style_Reset;
1055   int level = indentLevel();
1056   if (m_listItemInfo[level].isEnum)
1057   {
1058     m_t << rtf_EList_DepthStyle() << "\n";
1059     m_t << m_listItemInfo[level].number << ".\\tab ";
1060     m_listItemInfo[level].number++;
1061   }
1062   else
1063   {
1064     m_t << rtf_BList_DepthStyle() << "\n";
1065   }
1066   m_omitParagraph = TRUE;
1067 }
1068 
endItemListItem()1069 void RTFGenerator::endItemListItem()
1070 {
1071   DBG_RTF(m_t << "{\\comment (endItemListItem)}\n")
1072 }
1073 
startIndexItem(const QCString &,const QCString &)1074 void RTFGenerator::startIndexItem(const QCString &,const QCString &)
1075 {
1076   DBG_RTF(m_t << "{\\comment (startIndexItem)}\n")
1077 
1078   if (!m_omitParagraph)
1079   {
1080     m_t << "\\par\n";
1081     m_omitParagraph = TRUE;
1082   }
1083 }
1084 
endIndexItem(const QCString & ref,const QCString & fn)1085 void RTFGenerator::endIndexItem(const QCString &ref,const QCString &fn)
1086 {
1087   DBG_RTF(m_t << "{\\comment (endIndexItem)}\n")
1088   if (ref.isEmpty() && !fn.isEmpty())
1089   {
1090     m_t << "\\tab ";
1091     writeRTFReference(fn);
1092     m_t << "\n";
1093   }
1094   else
1095   {
1096     m_t << "\n";
1097   }
1098   m_omitParagraph = TRUE;
1099 }
1100 
startHtmlLink(const QCString & url)1101 void RTFGenerator::startHtmlLink(const QCString &url)
1102 {
1103 
1104   if (Config_getBool(RTF_HYPERLINKS))
1105   {
1106     m_t << "{\\field {\\*\\fldinst { HYPERLINK \"";
1107     m_t << url;
1108     m_t << "\" }{}";
1109     m_t << "}{\\fldrslt {\\cs37\\ul\\cf2 ";
1110   }
1111   else
1112   {
1113     startTypewriter();
1114   }
1115 }
1116 
endHtmlLink()1117 void RTFGenerator::endHtmlLink()
1118 {
1119   if (Config_getBool(RTF_HYPERLINKS))
1120   {
1121     m_t << "}}}\n";
1122   }
1123   else
1124   {
1125     endTypewriter();
1126   }
1127 }
1128 
writeStartAnnoItem(const QCString &,const QCString & f,const QCString & path,const QCString & name)1129 void RTFGenerator::writeStartAnnoItem(const QCString &,const QCString &f,
1130     const QCString &path,const QCString &name)
1131 {
1132   DBG_RTF(m_t << "{\\comment (writeStartAnnoItem)}\n")
1133   m_t << "{\\b ";
1134   if (!path.isEmpty()) docify(path);
1135   if (!f.isEmpty() && Config_getBool(RTF_HYPERLINKS))
1136   {
1137     m_t << "{\\field {\\*\\fldinst { HYPERLINK  \\\\l \"";
1138     m_t << rtfFormatBmkStr(stripPath(f));
1139     m_t << "\" }{}";
1140     m_t << "}{\\fldrslt {\\cs37\\ul\\cf2 ";
1141 
1142     docify(name);
1143 
1144     m_t << "}}}\n";
1145   }
1146   else
1147   {
1148     docify(name);
1149   }
1150   m_t << "} ";
1151 }
1152 
writeEndAnnoItem(const QCString & name)1153 void RTFGenerator::writeEndAnnoItem(const QCString &name)
1154 {
1155   DBG_RTF(m_t << "{\\comment (writeEndAnnoItem)}\n")
1156   if (!name.isEmpty())
1157   {
1158     m_t << "\\tab ";
1159     writeRTFReference(name);
1160     m_t << "\n";
1161   }
1162   else
1163   {
1164     m_t << "\n";
1165   }
1166   newParagraph();
1167 }
1168 
startIndexKey()1169 void RTFGenerator::startIndexKey()
1170 {
1171   DBG_RTF(m_t << "{\\comment (startIndexKey)}\n")
1172   m_t << "{\\b ";
1173 }
1174 
endIndexKey()1175 void RTFGenerator::endIndexKey()
1176 {
1177   DBG_RTF(m_t << "{\\comment (endIndexKey)}\n")
1178 }
1179 
startIndexValue(bool hasBrief)1180 void RTFGenerator::startIndexValue(bool hasBrief)
1181 {
1182   DBG_RTF(m_t << "{\\comment (startIndexValue)}\n")
1183   m_t << " ";
1184   if (hasBrief) m_t << "(";
1185 }
1186 
endIndexValue(const QCString & name,bool hasBrief)1187 void RTFGenerator::endIndexValue(const QCString &name,bool hasBrief)
1188 {
1189   DBG_RTF(m_t << "{\\comment (endIndexValue)}\n")
1190   if (hasBrief) m_t << ")";
1191   m_t << "} ";
1192   if (!name.isEmpty())
1193   {
1194     m_t << "\\tab ";
1195     writeRTFReference(name);
1196     m_t << "\n";
1197   }
1198   else
1199   {
1200     m_t << "\n";
1201   }
1202   m_omitParagraph=FALSE;
1203   newParagraph();
1204 }
1205 
startSubsection()1206 void RTFGenerator::startSubsection()
1207 {
1208   //beginRTFSubSection();
1209   m_t << "\n";
1210   DBG_RTF(m_t << "{\\comment Begin SubSection}\n")
1211   m_t << rtf_Style_Reset;
1212   m_t << rtf_Style["Heading3"].reference() << "\n";
1213 }
1214 
endSubsection()1215 void RTFGenerator::endSubsection()
1216 {
1217   newParagraph();
1218   m_t << rtf_Style_Reset << "\n";
1219 }
1220 
startSubsubsection()1221 void RTFGenerator::startSubsubsection()
1222 {
1223   //beginRTFSubSubSection();
1224   m_t << "\n";
1225   DBG_RTF(m_t << "{\\comment Begin SubSubSection}\n")
1226   m_t << "{\n";
1227   m_t << rtf_Style_Reset << rtf_Style["Heading4"].reference() << "\n";
1228 }
1229 
endSubsubsection()1230 void RTFGenerator::endSubsubsection()
1231 {
1232   newParagraph();
1233   m_t << "}\n";
1234 }
1235 
startTextLink(const QCString & f,const QCString & anchor)1236 void RTFGenerator::startTextLink(const QCString &f,const QCString &anchor)
1237 {
1238   if (Config_getBool(RTF_HYPERLINKS))
1239   {
1240     QCString ref;
1241     if (!f.isEmpty())
1242     {
1243       ref+=stripPath(f);
1244     }
1245     if (!anchor.isEmpty())
1246     {
1247       ref+='_';
1248       ref+=anchor;
1249     }
1250 
1251     m_t << "{\\field {\\*\\fldinst { HYPERLINK  \\\\l \"";
1252     m_t << rtfFormatBmkStr(ref);
1253     m_t << "\" }{}";
1254     m_t << "}{\\fldrslt {\\cs37\\ul\\cf2 ";
1255   }
1256 }
1257 
endTextLink()1258 void RTFGenerator::endTextLink()
1259 {
1260   if (Config_getBool(RTF_HYPERLINKS))
1261   {
1262     m_t << "}}}\n";
1263   }
1264 }
1265 
writeObjectLink(const QCString & ref,const QCString & f,const QCString & anchor,const QCString & text)1266 void RTFGenerator::writeObjectLink(const QCString &ref, const QCString &f,
1267     const QCString &anchor, const QCString &text)
1268 {
1269   if (ref.isEmpty() && Config_getBool(RTF_HYPERLINKS))
1270   {
1271     QCString refName;
1272     if (!f.isEmpty())
1273     {
1274       refName+=stripPath(f);
1275     }
1276     if (!anchor.isEmpty())
1277     {
1278       refName+='_';
1279       refName+=anchor;
1280     }
1281 
1282     m_t << "{\\field {\\*\\fldinst { HYPERLINK  \\\\l \"";
1283     m_t << rtfFormatBmkStr(refName);
1284     m_t << "\" }{}";
1285     m_t << "}{\\fldrslt {\\cs37\\ul\\cf2 ";
1286 
1287     docify(text);
1288 
1289     m_t << "}}}\n";
1290   }
1291   else
1292   {
1293     startBold();
1294     docify(text);
1295     endBold();
1296   }
1297 }
1298 
startPageRef()1299 void RTFGenerator::startPageRef()
1300 {
1301   m_t << " (";
1302   startEmphasis();
1303 }
1304 
endPageRef(const QCString & clname,const QCString & anchor)1305 void RTFGenerator::endPageRef(const QCString &clname, const QCString &anchor)
1306 {
1307   QCString ref;
1308   if (!clname.isEmpty())
1309   {
1310     ref+=clname;
1311   }
1312   if (!anchor.isEmpty())
1313   {
1314     ref+='_';
1315     ref+=anchor;
1316   }
1317   writeRTFReference(ref);
1318   endEmphasis();
1319   m_t << ")";
1320 }
1321 
writeCodeLink(CodeSymbolType,const QCString & ref,const QCString & f,const QCString & anchor,const QCString & name,const QCString &)1322 void RTFGenerator::writeCodeLink(CodeSymbolType,
1323                                  const QCString &ref,const QCString &f,
1324                                  const QCString &anchor,const QCString &name,
1325                                  const QCString &)
1326 {
1327   if (ref.isEmpty() && Config_getBool(RTF_HYPERLINKS))
1328   {
1329     QCString refName;
1330     if (!f.isEmpty())
1331     {
1332       refName+=stripPath(f);
1333     }
1334     if (!anchor.isEmpty())
1335     {
1336       refName+='_';
1337       refName+=anchor;
1338     }
1339 
1340     m_t << "{\\field {\\*\\fldinst { HYPERLINK  \\\\l \"";
1341     m_t << rtfFormatBmkStr(refName);
1342     m_t << "\" }{}";
1343     m_t << "}{\\fldrslt {\\cs37\\ul\\cf2 ";
1344 
1345     codify(name);
1346 
1347     m_t << "}}}\n";
1348   }
1349   else
1350   {
1351     codify(name);
1352   }
1353 }
1354 
startTitleHead(const QCString &)1355 void RTFGenerator::startTitleHead(const QCString &)
1356 {
1357   DBG_RTF(m_t << "{\\comment startTitleHead}\n")
1358 
1359   //    beginRTFSection();
1360   m_t << rtf_Style_Reset << rtf_Style["Heading2"].reference() << "\n";
1361 }
1362 
endTitleHead(const QCString & fileName,const QCString & name)1363 void RTFGenerator::endTitleHead(const QCString &fileName,const QCString &name)
1364 {
1365   DBG_RTF(m_t << "{\\comment endTitleHead}\n")
1366   m_t << "\\par " << rtf_Style_Reset << "\n";
1367   if (!name.isEmpty())
1368   {
1369     // make table of contents entry
1370     m_t << "{\\tc\\tcl2 \\v ";
1371     docify(name);
1372     m_t << "}\n";
1373 
1374     // make an index entry
1375     addIndexItem(name,QCString());
1376   }
1377   if (!fileName.isEmpty())
1378   {
1379     writeAnchor(fileName,QCString());
1380   }
1381 }
1382 
startTitle()1383 void RTFGenerator::startTitle()
1384 {
1385   DBG_RTF(m_t << "{\\comment startTitle}\n")
1386   if (Config_getBool(COMPACT_RTF))
1387     beginRTFSection();
1388   else
1389     beginRTFChapter();
1390 }
1391 
startGroupHeader(int extraIndent)1392 void RTFGenerator::startGroupHeader(int extraIndent)
1393 {
1394   DBG_RTF(m_t << "{\\comment startGroupHeader}\n")
1395   //newParagraph();
1396   m_t << rtf_Style_Reset;
1397   if (extraIndent==2)
1398   {
1399     m_t << rtf_Style["Heading5"].reference();
1400   }
1401   else if (extraIndent==1)
1402   {
1403     m_t << rtf_Style["Heading4"].reference();
1404   }
1405   else // extraIndent==0
1406   {
1407     m_t << rtf_Style["Heading3"].reference();
1408   }
1409   m_t << "\n";
1410 }
1411 
endGroupHeader(int)1412 void RTFGenerator::endGroupHeader(int)
1413 {
1414   DBG_RTF(m_t << "{\\comment endGroupHeader}\n")
1415   m_t << "\\par\n";
1416   m_t << rtf_Style_Reset << "\n";
1417 }
1418 
startMemberDoc(const QCString & clname,const QCString & memname,const QCString &,const QCString &,int,int,bool showInline)1419 void RTFGenerator::startMemberDoc(const QCString &clname,
1420     const QCString &memname,
1421     const QCString &,
1422     const QCString &,
1423     int,
1424     int,
1425     bool showInline)
1426 {
1427   DBG_RTF(m_t << "{\\comment startMemberDoc}\n")
1428   if (!memname.isEmpty() && memname[0]!='@')
1429   {
1430     addIndexItem(memname,clname);
1431     addIndexItem(clname,memname);
1432   }
1433   m_t << rtf_Style_Reset << rtf_Style[showInline ? "Heading5" : "Heading4"].reference();
1434   //styleStack.push(rtf_Style_Heading4);
1435   m_t << "{\n";
1436   //printf("RTFGenerator::startMemberDoc() '%s'\n",rtf_Style["Heading4"].reference());
1437   startBold();
1438   m_t << "\n";
1439 }
1440 
endMemberDoc(bool)1441 void RTFGenerator::endMemberDoc(bool)
1442 {
1443   DBG_RTF(m_t << "{\\comment endMemberDoc}\n")
1444   //const QCString &style = styleStack.pop();
1445   //printf("RTFGenerator::endMemberDoc() '%s'\n",style);
1446   //ASSERT(style==rtf_Style["Heading4"].reference());
1447   endBold();
1448   m_t << "}\n";
1449   newParagraph();
1450 }
1451 
startDoxyAnchor(const QCString &,const QCString &,const QCString &,const QCString &,const QCString &)1452 void RTFGenerator::startDoxyAnchor(const QCString &,const QCString &,
1453                                    const QCString &,const QCString &,
1454                                    const QCString &
1455                                   )
1456 {
1457   DBG_RTF(m_t << "{\\comment startDoxyAnchor}\n")
1458 }
1459 
endDoxyAnchor(const QCString & fName,const QCString & anchor)1460 void RTFGenerator::endDoxyAnchor(const QCString &fName,const QCString &anchor)
1461 {
1462   QCString ref;
1463   if (!fName.isEmpty())
1464   {
1465     ref+=stripPath(fName);
1466   }
1467   if (!anchor.isEmpty())
1468   {
1469     ref+='_';
1470     ref+=anchor;
1471   }
1472 
1473   DBG_RTF(m_t << "{\\comment endDoxyAnchor}\n")
1474   m_t << "{\\bkmkstart ";
1475   m_t << rtfFormatBmkStr(ref);
1476   m_t << "}\n";
1477   m_t << "{\\bkmkend ";
1478   m_t << rtfFormatBmkStr(ref);
1479   m_t << "}\n";
1480 }
1481 
addIndexItem(const QCString & s1,const QCString & s2)1482 void RTFGenerator::addIndexItem(const QCString &s1,const QCString &s2)
1483 {
1484   if (!s1.isEmpty())
1485   {
1486     m_t << "{\\xe \\v ";
1487     docify(s1);
1488     if (!s2.isEmpty())
1489     {
1490       m_t << "\\:";
1491       docify(s2);
1492     }
1493     m_t << "}\n";
1494   }
1495 }
1496 
startIndent()1497 void RTFGenerator::startIndent()
1498 {
1499   incIndentLevel();
1500   DBG_RTF(m_t << "{\\comment (startIndent) }\n")
1501   m_t << "{\n";
1502   m_t << rtf_Style_Reset << rtf_CList_DepthStyle() << "\n";
1503 }
1504 
endIndent()1505 void RTFGenerator::endIndent()
1506 {
1507   m_t << "}\n";
1508   decIndentLevel();
1509 }
1510 
1511 
startDescription()1512 void RTFGenerator::startDescription()
1513 {
1514   DBG_RTF(m_t << "{\\comment (startDescription)}"    << "\n")
1515   m_t << "{\n";
1516   m_t << rtf_Style_Reset << rtf_DList_DepthStyle();
1517 }
1518 
endDescription()1519 void RTFGenerator::endDescription()
1520 {
1521   DBG_RTF(m_t << "{\\comment (endDescription)}"    << "\n")
1522   newParagraph();
1523   m_t << "}";
1524 }
1525 
startDescItem()1526 void RTFGenerator::startDescItem()
1527 {
1528   newParagraph();
1529   DBG_RTF(m_t << "{\\comment (startDescItem)}\n")
1530   m_t << "{\\b ";
1531 }
1532 
endDescItem()1533 void RTFGenerator::endDescItem()
1534 {
1535   DBG_RTF(m_t << "{\\comment (endDescItem)}\n")
1536   m_t << "}\n";
1537   newParagraph();
1538 }
1539 
startMemberDescription(const QCString &,const QCString &,bool)1540 void RTFGenerator::startMemberDescription(const QCString &,const QCString &,bool)
1541 {
1542   DBG_RTF(m_t << "{\\comment (startMemberDescription)}\n")
1543   m_t << "{\n";
1544   incIndentLevel();
1545   m_t << rtf_Style_Reset << rtf_CList_DepthStyle();
1546   startEmphasis();
1547 }
1548 
endMemberDescription()1549 void RTFGenerator::endMemberDescription()
1550 {
1551   DBG_RTF(m_t << "{\\comment (endMemberDescription)}\n")
1552   endEmphasis();
1553   //newParagraph();
1554   decIndentLevel();
1555   m_t << "\\par";
1556   m_t << "}\n";
1557   m_omitParagraph = TRUE;
1558 }
1559 
startDescList(SectionTypes)1560 void RTFGenerator::startDescList(SectionTypes)
1561 {
1562   DBG_RTF(m_t << "{\\comment (startDescList)}\n")
1563   m_t << "{"; // ends at endDescList
1564   m_t << "{"; // ends at endDescTitle
1565   startBold();
1566   newParagraph();
1567 }
1568 
startDescForItem()1569 void RTFGenerator::startDescForItem()
1570 {
1571   DBG_RTF(m_t << "{\\comment (startDescForItem) }\n")
1572 }
1573 
endDescForItem()1574 void RTFGenerator::endDescForItem()
1575 {
1576   DBG_RTF(m_t << "{\\comment (endDescForItem) }\n")
1577 }
1578 
startSection(const QCString &,const QCString & title,SectionType type)1579 void RTFGenerator::startSection(const QCString &,const QCString &title,SectionType type)
1580 {
1581   DBG_RTF(m_t << "{\\comment (startSection)}\n")
1582   m_t << "{";
1583   m_t << rtf_Style_Reset;
1584   int num=4;
1585   switch(type)
1586   {
1587     case SectionType::Page:          num=2; break;
1588     case SectionType::Section:       num=3; break;
1589     case SectionType::Subsection:    num=4; break;
1590     case SectionType::Subsubsection: num=4; break;
1591     case SectionType::Paragraph:     num=4; break;
1592     default: ASSERT(0); break;
1593   }
1594   QCString heading;
1595   heading.sprintf("Heading%d",num);
1596   // set style
1597   m_t << rtf_Style[heading.str()].reference();
1598   // make table of contents entry
1599   m_t << "{\\tc\\tcl" << num << " \\v ";
1600   docify(title);
1601   m_t << "}\n";
1602 }
1603 
endSection(const QCString & lab,SectionType)1604 void RTFGenerator::endSection(const QCString &lab,SectionType)
1605 {
1606   DBG_RTF(m_t << "{\\comment (endSection)}\n")
1607   // make bookmark
1608   m_omitParagraph=FALSE;
1609   newParagraph();
1610   writeAnchor(QCString(),lab);
1611   m_t << "}";
1612 }
1613 
docify(const QCString & str)1614 void RTFGenerator::docify(const QCString &str)
1615 {
1616   if (!str.isEmpty())
1617   {
1618     const unsigned char *p=(const unsigned char *)str.data();
1619     unsigned char c;
1620     //unsigned char pc='\0';
1621     while (*p)
1622     {
1623       //static bool MultiByte = FALSE;
1624       c=*p++;
1625 
1626       switch (c)
1627       {
1628         case '{':  m_t << "\\{";            break;
1629         case '}':  m_t << "\\}";            break;
1630         case '\\': m_t << "\\\\";           break;
1631         default:
1632           {
1633             // see if we can insert an hyphenation hint
1634             //if (isupper(c) && islower(pc) && !insideTabbing) m_t << "\\-";
1635             m_t << (char)c;
1636           }
1637       }
1638       //pc = c;
1639       m_omitParagraph = FALSE;
1640     }
1641   }
1642 }
1643 
codify(const QCString & str)1644 void RTFGenerator::codify(const QCString &str)
1645 {
1646   // note that RTF does not have a "verbatim", so "\n" means
1647   // nothing... add a "newParagraph()";
1648   //static char spaces[]="        ";
1649   if (!str.isEmpty())
1650   {
1651     const unsigned char *p=(const unsigned char *)str.data();
1652     unsigned char c;
1653     int spacesToNextTabStop;
1654 
1655     while (*p)
1656     {
1657       //static bool MultiByte = FALSE;
1658 
1659       c=*p++;
1660 
1661       switch(c)
1662       {
1663         case '\t':  spacesToNextTabStop = Config_getInt(TAB_SIZE) - (m_col%Config_getInt(TAB_SIZE));
1664                     m_t << Doxygen::spaces.left(spacesToNextTabStop);
1665                     m_col+=spacesToNextTabStop;
1666                     break;
1667         case '\n':  newParagraph();
1668                     m_t << '\n'; m_col=0;
1669                     break;
1670         case '{':   m_t << "\\{"; m_col++;          break;
1671         case '}':   m_t << "\\}"; m_col++;          break;
1672         case '\\':  m_t << "\\\\"; m_col++;         break;
1673         default:    p=(const unsigned char *)writeUTF8Char(m_t,(const char *)p-1); m_col++; break;
1674       }
1675     }
1676   }
1677 }
1678 
writeChar(char c)1679 void RTFGenerator::writeChar(char c)
1680 {
1681   char cs[2];
1682   cs[0]=c;
1683   cs[1]=0;
1684   docify(cs);
1685 }
1686 
startClassDiagram()1687 void RTFGenerator::startClassDiagram()
1688 {
1689   DBG_RTF(m_t << "{\\comment startClassDiagram }\n")
1690 }
1691 
endClassDiagram(const ClassDiagram & d,const QCString & fileName,const QCString &)1692 void RTFGenerator::endClassDiagram(const ClassDiagram &d,
1693     const QCString &fileName,const QCString &)
1694 {
1695   newParagraph();
1696 
1697   // create a png file
1698   d.writeImage(m_t,dir(),m_relPath,fileName,FALSE);
1699 
1700   // display the file
1701   m_t << "{\n";
1702   m_t << rtf_Style_Reset << "\n";
1703   m_t << "\\par\\pard \\qc {\\field\\flddirty {\\*\\fldinst INCLUDEPICTURE \"";
1704   m_t << fileName << ".png\"";
1705   m_t << " \\\\d \\\\*MERGEFORMAT}{\\fldrslt IMAGE}}\\par\n";
1706   m_t << "}\n";
1707 }
1708 
startMemberItem(const QCString &,int,const QCString &)1709 void RTFGenerator::startMemberItem(const QCString &,int,const QCString &)
1710 {
1711   DBG_RTF(m_t << "{\\comment startMemberItem }\n")
1712   m_t << rtf_Style_Reset << rtf_BList_DepthStyle() << "\n"; // set style to appropriate depth
1713 }
1714 
endMemberItem()1715 void RTFGenerator::endMemberItem()
1716 {
1717   DBG_RTF(m_t << "{\\comment endMemberItem }\n")
1718   newParagraph();
1719 }
1720 
writeAnchor(const QCString & fileName,const QCString & name)1721 void RTFGenerator::writeAnchor(const QCString &fileName,const QCString &name)
1722 {
1723   QCString anchor;
1724   if (!fileName.isEmpty())
1725   {
1726     anchor+=stripPath(fileName);
1727   }
1728   if (!fileName.isEmpty() && !name.isEmpty())
1729   {
1730     anchor+='_';
1731   }
1732   if (!name.isEmpty())
1733   {
1734     anchor+=name;
1735   }
1736   //printf("writeAnchor(%s->%s)\n",qPrint(anchor),qPrint(rtfFormatBmkStr(anchor)));
1737 
1738   DBG_RTF(m_t << "{\\comment writeAnchor (" << anchor << ")}\n")
1739   m_t << "{\\bkmkstart " << rtfFormatBmkStr(anchor) << "}\n";
1740   m_t << "{\\bkmkend " << rtfFormatBmkStr(anchor) << "}\n";
1741 }
1742 
writeRTFReference(const QCString & label)1743 void RTFGenerator::writeRTFReference(const QCString &label)
1744 {
1745   m_t << "{\\field\\fldedit {\\*\\fldinst PAGEREF ";
1746   m_t << rtfFormatBmkStr(stripPath(label));
1747   m_t << " \\\\*MERGEFORMAT}{\\fldrslt pagenum}}";
1748 }
1749 
startCodeFragment(const QCString &)1750 void RTFGenerator::startCodeFragment(const QCString &)
1751 {
1752   DBG_RTF(m_t << "{\\comment (startCodeFragment) }\n")
1753   m_t << "{\n";
1754   m_t << rtf_Style_Reset << rtf_Code_DepthStyle();
1755 }
1756 
endCodeFragment(const QCString &)1757 void RTFGenerator::endCodeFragment(const QCString &)
1758 {
1759   endCodeLine();
1760 
1761   DBG_RTF(m_t << "{\\comment (endCodeFragment) }\n")
1762   m_t << "}\n";
1763   m_omitParagraph = TRUE;
1764 }
1765 
writeNonBreakableSpace(int)1766 void RTFGenerator::writeNonBreakableSpace(int)
1767 {
1768   m_t << "\\~ ";
1769 }
1770 
1771 
startMemberList()1772 void RTFGenerator::startMemberList()
1773 {
1774   m_t << "\n";
1775   DBG_RTF(m_t << "{\\comment (startMemberList) }\n")
1776   m_t << "{\n";
1777 #ifdef DELETEDCODE
1778   if (!insideTabbing)
1779     m_t << "\\begin{CompactItemize}\n";
1780 #endif
1781 }
1782 
endMemberList()1783 void RTFGenerator::endMemberList()
1784 {
1785   DBG_RTF(m_t << "{\\comment (endMemberList) }\n")
1786   m_t << "}\n";
1787 #ifdef DELETEDCODE
1788   if (!insideTabbing)
1789     m_t << "\\end{CompactItemize}\n";
1790 #endif
1791 }
1792 
startDescTable(const QCString & title)1793 void RTFGenerator::startDescTable(const QCString &title)
1794 {
1795   DBG_RTF(m_t << "{\\comment (startDescTable) }\n")
1796   m_t << "{\\par\n";
1797   m_t << "{" << rtf_Style["Heading5"].reference() << "\n";
1798   docify(title);
1799   m_t << ":\\par}\n";
1800   m_t << rtf_Style_Reset << rtf_DList_DepthStyle();
1801   m_t << "\\trowd \\trgaph108\\trleft426\\tblind426"
1802        "\\trbrdrt\\brdrs\\brdrw10\\brdrcf15 "
1803        "\\trbrdrl\\brdrs\\brdrw10\\brdrcf15 "
1804        "\\trbrdrb\\brdrs\\brdrw10\\brdrcf15 "
1805        "\\trbrdrr\\brdrs\\brdrw10\\brdrcf15 "
1806        "\\trbrdrh\\brdrs\\brdrw10\\brdrcf15 "
1807        "\\trbrdrv\\brdrs\\brdrw10\\brdrcf15 \n";
1808   int i,columnPos[2] = { 25, 100 };
1809   for (i=0;i<2;i++)
1810   {
1811     m_t << "\\clvertalt\\clbrdrt\\brdrs\\brdrw10\\brdrcf15 "
1812          "\\clbrdrl\\brdrs\\brdrw10\\brdrcf15 "
1813          "\\clbrdrb\\brdrs\\brdrw10\\brdrcf15 "
1814          "\\clbrdrr \\brdrs\\brdrw10\\brdrcf15 "
1815          "\\cltxlrtb "
1816          "\\cellx" << (rtf_pageWidth*columnPos[i]/100) << "\n";
1817   }
1818   m_t << "\\pard \\widctlpar\\intbl\\adjustright\n";
1819 }
1820 
endDescTable()1821 void RTFGenerator::endDescTable()
1822 {
1823   DBG_RTF(m_t << "{\\comment (endDescTable)}\n")
1824   m_t << "}\n";
1825 }
1826 
startDescTableRow()1827 void RTFGenerator::startDescTableRow()
1828 {
1829 }
1830 
endDescTableRow()1831 void RTFGenerator::endDescTableRow()
1832 {
1833 }
1834 
startDescTableTitle()1835 void RTFGenerator::startDescTableTitle()
1836 {
1837   DBG_RTF(m_t << "{\\comment (startDescTableTitle) }\n")
1838   m_t << "{\\qr ";
1839 }
1840 
endDescTableTitle()1841 void RTFGenerator::endDescTableTitle()
1842 {
1843   DBG_RTF(m_t << "{\\comment (endDescTableTitle) }\n")
1844   m_t << "\\cell }";
1845 }
1846 
startDescTableData()1847 void RTFGenerator::startDescTableData()
1848 {
1849   DBG_RTF(m_t << "{\\comment (startDescTableData) }\n")
1850   m_t << "{";
1851 }
1852 
endDescTableData()1853 void RTFGenerator::endDescTableData()
1854 {
1855   DBG_RTF(m_t << "{\\comment (endDescTableData) }\n")
1856   m_t << "\\cell }{\\row }\n";
1857 }
1858 
1859 // a style for list formatted as a "bulleted list"
1860 
indentLevel() const1861 int RTFGenerator::indentLevel() const
1862 {
1863   return std::min(m_indentLevel,maxIndentLevels-1);
1864 }
1865 
incIndentLevel()1866 void RTFGenerator::incIndentLevel()
1867 {
1868   m_indentLevel++;
1869   if (m_indentLevel>=maxIndentLevels)
1870   {
1871     err("Maximum indent level (%d) exceeded while generating RTF output!\n",maxIndentLevels);
1872   }
1873 }
1874 
decIndentLevel()1875 void RTFGenerator::decIndentLevel()
1876 {
1877   m_indentLevel--;
1878   if (m_indentLevel<0)
1879   {
1880     err("Negative indent level while generating RTF output!\n");
1881     m_indentLevel=0;
1882   }
1883 }
1884 
1885 // a style for list formatted with "list continue" style
rtf_CList_DepthStyle()1886 QCString RTFGenerator::rtf_CList_DepthStyle()
1887 {
1888   QCString n=makeIndexName("ListContinue",indentLevel());
1889   return rtf_Style[n.str()].reference();
1890 }
1891 
1892 // a style for list formatted as a "latext style" table of contents
rtf_LCList_DepthStyle()1893 QCString RTFGenerator::rtf_LCList_DepthStyle()
1894 {
1895   QCString n=makeIndexName("LatexTOC",indentLevel());
1896   return rtf_Style[n.str()].reference();
1897 }
1898 
1899 // a style for list formatted as a "bullet" style
rtf_BList_DepthStyle()1900 QCString RTFGenerator::rtf_BList_DepthStyle()
1901 {
1902   QCString n=makeIndexName("ListBullet",indentLevel());
1903   return rtf_Style[n.str()].reference();
1904 }
1905 
1906 // a style for list formatted as a "enumeration" style
rtf_EList_DepthStyle()1907 QCString RTFGenerator::rtf_EList_DepthStyle()
1908 {
1909   QCString n=makeIndexName("ListEnum",indentLevel());
1910   return rtf_Style[n.str()].reference();
1911 }
1912 
rtf_DList_DepthStyle()1913 QCString RTFGenerator::rtf_DList_DepthStyle()
1914 {
1915   QCString n=makeIndexName("DescContinue",indentLevel());
1916   return rtf_Style[n.str()].reference();
1917 }
1918 
rtf_Code_DepthStyle()1919 QCString RTFGenerator::rtf_Code_DepthStyle()
1920 {
1921   QCString n=makeIndexName("CodeExample",indentLevel());
1922   return rtf_Style[n.str()].reference();
1923 }
1924 
startTextBlock(bool dense)1925 void RTFGenerator::startTextBlock(bool dense)
1926 {
1927   DBG_RTF(m_t << "{\\comment startTextBlock}\n")
1928   m_t << "{\n";
1929   m_t << rtf_Style_Reset;
1930   if (dense) // no spacing between "paragraphs"
1931   {
1932     m_t << rtf_Style["DenseText"].reference();
1933   }
1934   else // some spacing
1935   {
1936     m_t << rtf_Style["BodyText"].reference();
1937   }
1938 }
1939 
endTextBlock(bool)1940 void RTFGenerator::endTextBlock(bool /*paraBreak*/)
1941 {
1942   newParagraph();
1943   DBG_RTF(m_t << "{\\comment endTextBlock}\n")
1944   m_t << "}\n";
1945   //m_omitParagraph = TRUE;
1946 }
1947 
newParagraph()1948 void RTFGenerator::newParagraph()
1949 {
1950   if (!m_omitParagraph)
1951   {
1952     DBG_RTF(m_t << "{\\comment (newParagraph)}\n")
1953     m_t << "\\par\n";
1954   }
1955   m_omitParagraph = FALSE;
1956 }
1957 
startParagraph(const QCString & txt)1958 void RTFGenerator::startParagraph(const QCString &txt)
1959 {
1960   DBG_RTF(m_t << "{\\comment startParagraph}\n")
1961   newParagraph();
1962   m_t << "{\n";
1963   if (QCString(txt) == "reference") m_t << "\\ql\n";
1964 }
1965 
endParagraph()1966 void RTFGenerator::endParagraph()
1967 {
1968   DBG_RTF(m_t << "{\\comment endParagraph}\n")
1969   m_t << "}\\par\n";
1970   m_omitParagraph = TRUE;
1971 }
1972 
startMemberSubtitle()1973 void RTFGenerator::startMemberSubtitle()
1974 {
1975   DBG_RTF(m_t << "{\\comment startMemberSubtitle}\n")
1976   m_t << "{\n";
1977   m_t << rtf_Style_Reset << rtf_CList_DepthStyle() << "\n";
1978 }
1979 
endMemberSubtitle()1980 void RTFGenerator::endMemberSubtitle()
1981 {
1982   DBG_RTF(m_t << "{\\comment endMemberSubtitle}\n")
1983   newParagraph();
1984   m_t << "}\n";
1985 }
1986 
isLeadBytes(int c)1987 bool isLeadBytes(int c)
1988 {
1989   bool result;
1990 
1991   QCString codePage = theTranslator->trRTFansicp();
1992 
1993   if (codePage == "932")       // cp932 (Japanese Shift-JIS)
1994   {
1995     result = (0x81<=c && c<=0x9f) || (0xe0<=c && c<=0xfc);
1996   }
1997   else if (codePage == "936")  // cp936 (Simplified Chinese GBK)
1998   {
1999     result = 0x81<=c && c<=0xFE;
2000   }
2001   else if (codePage == "949")  // cp949 (Korean)
2002   {
2003     result = 0x81<=c && c<=0xFE;
2004   }
2005   else if (codePage == "950")  // cp950 (Traditional Chinese Big5)
2006   {
2007     result = 0x81<=c && c<=0xFE;
2008   }
2009   else                         // for SBCS Codepages (cp1252,1251 etc...)
2010   {
2011     result = false;
2012   }
2013 
2014   return result;
2015 }
2016 
2017 
2018 // note: function is not reentrant!
encodeForOutput(TextStream & t,const QCString & s)2019 static void encodeForOutput(TextStream &t,const QCString &s)
2020 {
2021   if (s==0) return;
2022   QCString encoding;
2023   bool converted=FALSE;
2024   int l = (int)s.length();
2025   static std::vector<char> enc;
2026   if (l*4>(int)enc.size()) enc.resize(l*4); // worst case
2027   encoding.sprintf("CP%s",qPrint(theTranslator->trRTFansicp()));
2028   if (!encoding.isEmpty())
2029   {
2030     // convert from UTF-8 back to the output encoding
2031     void *cd = portable_iconv_open(encoding.data(),"UTF-8");
2032     if (cd!=(void *)(-1))
2033     {
2034       size_t iLeft=l;
2035       size_t oLeft=enc.size();
2036       const char *inputPtr = s.data();
2037       char *outputPtr = &enc[0];
2038       if (!portable_iconv(cd, &inputPtr, &iLeft, &outputPtr, &oLeft))
2039       {
2040         enc.resize(enc.size()-(unsigned int)oLeft);
2041         converted=TRUE;
2042       }
2043       portable_iconv_close(cd);
2044     }
2045   }
2046   if (!converted) // if we did not convert anything, copy as is.
2047   {
2048     memcpy(enc.data(),s.data(),l);
2049     enc.resize(l);
2050   }
2051   uint i;
2052   bool multiByte = FALSE;
2053 
2054   for (i=0;i<enc.size();i++)
2055   {
2056     uchar c = (uchar)enc.at(i);
2057 
2058     if (c>=0x80 || multiByte)
2059     {
2060       char esc[10];
2061       sprintf(esc,"\\'%X",c);        // escape sequence for SBCS and DBCS(1st&2nd bytes).
2062       t << esc;
2063 
2064       if (!multiByte)
2065       {
2066         multiByte = isLeadBytes(c);  // It may be DBCS Codepages.
2067       }
2068       else
2069       {
2070         multiByte = FALSE;           // end of Double Bytes Character.
2071       }
2072     }
2073     else
2074     {
2075       t << (char)c;
2076     }
2077   }
2078 }
2079 
2080 /**
2081  * VERY brittle routine inline RTF's included by other RTF's.
2082  * it is recursive and ugly.
2083  */
preProcessFile(Dir & d,const QCString & infName,TextStream & t,bool bIncludeHeader=TRUE)2084 static bool preProcessFile(Dir &d,const QCString &infName, TextStream &t, bool bIncludeHeader=TRUE)
2085 {
2086   static bool rtfDebug = Debug::isFlagSet(Debug::Rtf);
2087   std::ifstream f(infName.str(),std::ifstream::in);
2088   if (!f.is_open())
2089   {
2090     err("problems opening rtf file '%s' for reading\n",infName.data());
2091     return false;
2092   }
2093 
2094   const int maxLineLength = 10240;
2095   static QCString lineBuf(maxLineLength);
2096 
2097   // scan until find end of header
2098   // this is EXTREEEEEEEMLY brittle.  It works on OUR rtf
2099   // files because the first line before the body
2100   // ALWAYS contains "{\comment begin body}"
2101   std::string line;
2102   while (getline(f,line))
2103   {
2104     line+='\n';
2105     if (line.find("\\comment begin body")!=std::string::npos) break;
2106     if (bIncludeHeader) encodeForOutput(t,line.c_str());
2107   }
2108 
2109   std::string prevLine;
2110   bool first=true;
2111   while (getline(f,line))
2112   {
2113     line+='\n';
2114     size_t pos;
2115     if ((pos=prevLine.find("INCLUDETEXT \""))!=std::string::npos)
2116     {
2117       size_t startNamePos  = prevLine.find('"',pos)+1;
2118       size_t endNamePos    = prevLine.find('"',startNamePos);
2119       std::string fileName = prevLine.substr(startNamePos,endNamePos-startNamePos);
2120       DBG_RTF(m_t << "{\\comment begin include " << fileName << "}\n")
2121       if (!preProcessFile(d,fileName.c_str(),t,FALSE)) return FALSE;
2122       DBG_RTF(m_t << "{\\comment end include " << fileName << "}\n")
2123     }
2124     else if (!first) // no INCLUDETEXT on this line
2125     {
2126       encodeForOutput(t,prevLine.c_str());
2127     }
2128     prevLine = line;
2129     first=false;
2130   }
2131   if (!bIncludeHeader) // skip final '}' in case we don't include headers
2132   {
2133     size_t pos = line.rfind('}');
2134     if (pos==std::string::npos)
2135     {
2136       err("Strange, the last char was not a '}'\n");
2137       pos = line.length();
2138     }
2139     encodeForOutput(t,line.substr(0,pos).c_str());
2140   }
2141   else
2142   {
2143     encodeForOutput(t,line.c_str());
2144   }
2145   f.close();
2146   // remove temporary file
2147   if (!rtfDebug) d.remove(infName.str());
2148   return TRUE;
2149 }
2150 
startDotGraph()2151 void RTFGenerator::startDotGraph()
2152 {
2153   DBG_RTF(m_t << "{\\comment (startDotGraph)}\n")
2154 }
2155 
endDotGraph(DotClassGraph & g)2156 void RTFGenerator::endDotGraph(DotClassGraph &g)
2157 {
2158   newParagraph();
2159 
2160   QCString fn =
2161     g.writeGraph(m_t,GOF_BITMAP,EOF_Rtf,dir(),fileName(),m_relPath,TRUE,FALSE);
2162 
2163   // display the file
2164   m_t << "{\n";
2165   m_t << rtf_Style_Reset << "\n";
2166   m_t << "\\par\\pard \\qc {\\field\\flddirty {\\*\\fldinst INCLUDEPICTURE \"";
2167   QCString imgExt = getDotImageExtension();
2168   m_t << fn << "." << imgExt;
2169   m_t << "\" \\\\d \\\\*MERGEFORMAT}{\\fldrslt IMAGE}}\\par\n";
2170   m_t << "}\n";
2171   newParagraph();
2172   DBG_RTF(m_t << "{\\comment (endDotGraph)}\n")
2173 }
2174 
startInclDepGraph()2175 void RTFGenerator::startInclDepGraph()
2176 {
2177   DBG_RTF(m_t << "{\\comment (startInclDepGraph)}\n")
2178 }
2179 
endInclDepGraph(DotInclDepGraph & g)2180 void RTFGenerator::endInclDepGraph(DotInclDepGraph &g)
2181 {
2182   newParagraph();
2183 
2184   QCString fn = g.writeGraph(m_t,GOF_BITMAP,EOF_Rtf,dir(),fileName(),m_relPath,FALSE);
2185 
2186   // display the file
2187   m_t << "{\n";
2188   m_t << rtf_Style_Reset << "\n";
2189   m_t << "\\par\\pard \\qc {\\field\\flddirty {\\*\\fldinst INCLUDEPICTURE \"";
2190   QCString imgExt = getDotImageExtension();
2191   m_t << fn << "." << imgExt;
2192   m_t << "\" \\\\d \\\\*MERGEFORMAT}{\\fldrslt IMAGE}}\\par\n";
2193   m_t << "}\n";
2194   DBG_RTF(m_t << "{\\comment (endInclDepGraph)}\n")
2195 }
2196 
startGroupCollaboration()2197 void RTFGenerator::startGroupCollaboration()
2198 {
2199 }
2200 
endGroupCollaboration(DotGroupCollaboration &)2201 void RTFGenerator::endGroupCollaboration(DotGroupCollaboration &)
2202 {
2203 }
2204 
startCallGraph()2205 void RTFGenerator::startCallGraph()
2206 {
2207   DBG_RTF(m_t << "{\\comment (startCallGraph)}\n")
2208 }
2209 
endCallGraph(DotCallGraph & g)2210 void RTFGenerator::endCallGraph(DotCallGraph &g)
2211 {
2212   newParagraph();
2213 
2214   QCString fn = g.writeGraph(m_t,GOF_BITMAP,EOF_Rtf,dir(),fileName(),m_relPath,FALSE);
2215 
2216   // display the file
2217   m_t << "{\n";
2218   m_t << rtf_Style_Reset << "\n";
2219   m_t << "\\par\\pard \\qc {\\field\\flddirty {\\*\\fldinst INCLUDEPICTURE \"";
2220   QCString imgExt = getDotImageExtension();
2221   m_t << fn << "." << imgExt;
2222   m_t << "\" \\\\d \\\\*MERGEFORMAT}{\\fldrslt IMAGE}}\\par\n";
2223   m_t << "}\n";
2224   DBG_RTF(m_t << "{\\comment (endCallGraph)}\n")
2225 }
2226 
startDirDepGraph()2227 void RTFGenerator::startDirDepGraph()
2228 {
2229   DBG_RTF(m_t << "{\\comment (startDirDepGraph)}\n")
2230 }
2231 
endDirDepGraph(DotDirDeps & g)2232 void RTFGenerator::endDirDepGraph(DotDirDeps &g)
2233 {
2234   newParagraph();
2235 
2236   QCString fn = g.writeGraph(m_t,GOF_BITMAP,EOF_Rtf,dir(),fileName(),m_relPath,FALSE);
2237 
2238   // display the file
2239   m_t << "{\n";
2240   m_t << rtf_Style_Reset << "\n";
2241   m_t << "\\par\\pard \\qc {\\field\\flddirty {\\*\\fldinst INCLUDEPICTURE \"";
2242   QCString imgExt = getDotImageExtension();
2243   m_t << fn << "." << imgExt;
2244   m_t << "\" \\\\d \\\\*MERGEFORMAT}{\\fldrslt IMAGE}}\\par\n";
2245   m_t << "}\n";
2246   DBG_RTF(m_t << "{\\comment (endDirDepGraph)}\n")
2247 }
2248 
2249 /** Tests the integrity of the result by counting brackets.
2250  *
2251  */
testRTFOutput(const QCString & name)2252 void testRTFOutput(const QCString &name)
2253 {
2254   int bcount=0;
2255   int line=1;
2256   int c;
2257   std::ifstream f(name.data(),std::ifstream::in);
2258   if (f.is_open())
2259   {
2260     while ((c=f.get())!=-1)
2261     {
2262       if (c=='\\') // escape char
2263       {
2264         c=f.get();
2265         if (c==-1) break;
2266       }
2267       else if (c=='{') // open bracket
2268       {
2269         bcount++;
2270       }
2271       else if (c=='}') // close bracket
2272       {
2273         bcount--;
2274         if (bcount<0)
2275         {
2276           goto err;
2277           break;
2278         }
2279       }
2280       else if (c=='\n') // newline
2281       {
2282         line++;
2283       }
2284     }
2285   }
2286   if (bcount==0) return; // file is OK.
2287 err:
2288   err("RTF integrity test failed at line %d of %s due to a bracket mismatch.\n"
2289       "       Please try to create a small code example that produces this error \n"
2290       "       and send that to doxygen@gmail.com.\n",line,qPrint(name));
2291 }
2292 
2293 /**
2294  * This is an API to a VERY brittle RTF preprocessor that combines nested
2295  * RTF files.  This version replaces the infile with the new file
2296  */
preProcessFileInplace(const QCString & path,const QCString & name)2297 bool RTFGenerator::preProcessFileInplace(const QCString &path,const QCString &name)
2298 {
2299   static bool rtfDebug = Debug::isFlagSet(Debug::Rtf);
2300   Dir d(path.str());
2301   // store the original directory
2302   if (!d.exists())
2303   {
2304     err("Output dir %s does not exist!\n",qPrint(path));
2305     return FALSE;
2306   }
2307   std::string oldDir = Dir::currentDirPath();
2308 
2309   // go to the html output directory (i.e. path)
2310   Dir::setCurrent(d.absPath());
2311   Dir thisDir;
2312 
2313   QCString combinedName = path+"/combined.rtf";
2314   QCString mainRTFName  = path+"/"+name;
2315 
2316   std::ofstream f(combinedName.str(),std::ofstream::out | std::ofstream::binary);
2317   if (!f.is_open())
2318   {
2319     err("Failed to open %s for writing!\n",combinedName.data());
2320     Dir::setCurrent(oldDir);
2321     return FALSE;
2322   }
2323   TextStream outt(&f);
2324 
2325   if (!preProcessFile(thisDir,mainRTFName,outt))
2326   {
2327     // it failed, remove the temp file
2328     outt.flush();
2329     f.close();
2330     if (!rtfDebug) thisDir.remove(combinedName.str());
2331     Dir::setCurrent(oldDir);
2332     return FALSE;
2333   }
2334 
2335   // everything worked, move the files
2336   outt.flush();
2337   f.close();
2338   if (!rtfDebug)
2339   {
2340     thisDir.remove(mainRTFName.str());
2341   }
2342   else
2343   {
2344     thisDir.rename(mainRTFName.str(),mainRTFName.str() + ".org");
2345   }
2346   thisDir.rename(combinedName.str(),mainRTFName.str());
2347 
2348   testRTFOutput(mainRTFName);
2349 
2350   Dir::setCurrent(oldDir);
2351   return TRUE;
2352 }
2353 
startMemberGroupHeader(bool hasHeader)2354 void RTFGenerator::startMemberGroupHeader(bool hasHeader)
2355 {
2356   DBG_RTF(m_t << "{\\comment startMemberGroupHeader}\n")
2357   m_t << "{\n";
2358   if (hasHeader) incIndentLevel();
2359   m_t << rtf_Style_Reset << rtf_Style["GroupHeader"].reference();
2360 }
2361 
endMemberGroupHeader()2362 void RTFGenerator::endMemberGroupHeader()
2363 {
2364   DBG_RTF(m_t << "{\\comment endMemberGroupHeader}\n")
2365   newParagraph();
2366   m_t << rtf_Style_Reset << rtf_CList_DepthStyle();
2367 }
2368 
startMemberGroupDocs()2369 void RTFGenerator::startMemberGroupDocs()
2370 {
2371   DBG_RTF(m_t << "{\\comment startMemberGroupDocs}\n")
2372   startEmphasis();
2373 }
2374 
endMemberGroupDocs()2375 void RTFGenerator::endMemberGroupDocs()
2376 {
2377   DBG_RTF(m_t << "{\\comment endMemberGroupDocs}\n")
2378   endEmphasis();
2379   newParagraph();
2380 }
2381 
startMemberGroup()2382 void RTFGenerator::startMemberGroup()
2383 {
2384   DBG_RTF(m_t << "{\\comment startMemberGroup}\n")
2385   m_t << rtf_Style_Reset << rtf_BList_DepthStyle() << "\n";
2386 }
2387 
endMemberGroup(bool hasHeader)2388 void RTFGenerator::endMemberGroup(bool hasHeader)
2389 {
2390   DBG_RTF(m_t << "{\\comment endMemberGroup}\n")
2391   if (hasHeader) decIndentLevel();
2392   m_t << "}";
2393 }
2394 
startExamples()2395 void RTFGenerator::startExamples()
2396 {
2397   DBG_RTF(m_t << "{\\comment (startExamples)}\n")
2398   m_t << "{"; // ends at endDescList
2399   m_t << "{"; // ends at endDescTitle
2400   startBold();
2401   newParagraph();
2402   docify(theTranslator->trExamples());
2403   endBold();
2404   m_t << "}";
2405   newParagraph();
2406   incIndentLevel();
2407   m_t << rtf_Style_Reset << rtf_DList_DepthStyle();
2408 }
2409 
endExamples()2410 void RTFGenerator::endExamples()
2411 {
2412   DBG_RTF(m_t << "{\\comment (endExamples)}\n")
2413   m_omitParagraph = FALSE;
2414   newParagraph();
2415   decIndentLevel();
2416   m_omitParagraph = TRUE;
2417   m_t << "}";
2418 }
2419 
startParamList(ParamListTypes,const QCString & title)2420 void RTFGenerator::startParamList(ParamListTypes,const QCString &title)
2421 {
2422   DBG_RTF(m_t << "{\\comment (startParamList)}\n")
2423   m_t << "{"; // ends at endParamList
2424   m_t << "{"; // ends at endDescTitle
2425   startBold();
2426   newParagraph();
2427   docify(title);
2428   endBold();
2429   m_t << "}";
2430   newParagraph();
2431   incIndentLevel();
2432   m_t << rtf_Style_Reset << rtf_DList_DepthStyle();
2433 }
2434 
endParamList()2435 void RTFGenerator::endParamList()
2436 {
2437   DBG_RTF(m_t << "{\\comment (endParamList)}\n")
2438   newParagraph();
2439   decIndentLevel();
2440   m_omitParagraph = TRUE;
2441   m_t << "}";
2442 }
2443 
startParameterType(bool first,const QCString & key)2444 void RTFGenerator::startParameterType(bool first,const QCString &key)
2445 {
2446   DBG_RTF(m_t << "{\\comment (startParameterType)}\n")
2447   if (!first && !key.isEmpty())
2448   {
2449     m_t << " " << key << " ";
2450   }
2451 }
2452 
endParameterType()2453 void RTFGenerator::endParameterType()
2454 {
2455   DBG_RTF(m_t << "{\\comment (endParameterType)}\n")
2456   m_t << " ";
2457 }
2458 
exceptionEntry(const QCString & prefix,bool closeBracket)2459 void RTFGenerator::exceptionEntry(const QCString &prefix,bool closeBracket)
2460 {
2461   DBG_RTF(m_t << "{\\comment (exceptionEntry)}\n")
2462   if (!prefix.isEmpty())
2463   {
2464     m_t << " " << prefix << "(";
2465   }
2466   else if (closeBracket)
2467   {
2468     m_t << ")";
2469   }
2470   m_t << " ";
2471 }
2472 
writeDoc(DocNode * n,const Definition * ctx,const MemberDef *,int)2473 void RTFGenerator::writeDoc(DocNode *n,const Definition *ctx,const MemberDef *,int)
2474 {
2475   RTFDocVisitor *visitor = new RTFDocVisitor(m_t,*this,ctx?ctx->getDefFileExtension():QCString(""));
2476   n->accept(visitor);
2477   delete visitor;
2478   m_omitParagraph = TRUE;
2479 }
2480 
rtfwriteRuler_doubleline()2481 void RTFGenerator::rtfwriteRuler_doubleline()
2482 {
2483   DBG_RTF(m_t << "{\\comment (rtfwriteRuler_doubleline)}\n")
2484   m_t << "{\\pard\\widctlpar\\brdrb\\brdrdb\\brdrw15\\brsp20 \\adjustright \\par}\n";
2485 }
2486 
rtfwriteRuler_emboss()2487 void RTFGenerator::rtfwriteRuler_emboss()
2488 {
2489   DBG_RTF(m_t << "{\\comment (rtfwriteRuler_emboss)}\n")
2490   m_t << "{\\pard\\widctlpar\\brdrb\\brdremboss\\brdrw15\\brsp20 \\adjustright \\par}\n";
2491 }
2492 
rtfwriteRuler_thick()2493 void RTFGenerator::rtfwriteRuler_thick()
2494 {
2495   DBG_RTF(m_t << "{\\comment (rtfwriteRuler_thick)}\n")
2496   m_t << "{\\pard\\widctlpar\\brdrb\\brdrs\\brdrw75\\brsp20 \\adjustright \\par}\n";
2497 }
2498 
rtfwriteRuler_thin()2499 void RTFGenerator::rtfwriteRuler_thin()
2500 {
2501   DBG_RTF(m_t << "{\\comment (rtfwriteRuler_thin)}\n")
2502   m_t << "{\\pard\\widctlpar\\brdrb\\brdrs\\brdrw5\\brsp20 \\adjustright \\par}\n";
2503 }
2504 
startConstraintList(const QCString & header)2505 void RTFGenerator::startConstraintList(const QCString &header)
2506 {
2507   DBG_RTF(m_t << "{\\comment (startConstraintList)}\n")
2508   m_t << "{"; // ends at endConstraintList
2509   m_t << "{";
2510   startBold();
2511   newParagraph();
2512   docify(header);
2513   endBold();
2514   m_t << "}";
2515   newParagraph();
2516   incIndentLevel();
2517   m_t << rtf_Style_Reset << rtf_DList_DepthStyle();
2518 }
2519 
startConstraintParam()2520 void RTFGenerator::startConstraintParam()
2521 {
2522   DBG_RTF(m_t << "{\\comment (startConstraintParam)}\n")
2523   startEmphasis();
2524 }
2525 
endConstraintParam()2526 void RTFGenerator::endConstraintParam()
2527 {
2528   DBG_RTF(m_t << "{\\comment (endConstraintParam)}\n")
2529   endEmphasis();
2530   m_t << " : ";
2531 }
2532 
startConstraintType()2533 void RTFGenerator::startConstraintType()
2534 {
2535   DBG_RTF(m_t << "{\\comment (startConstraintType)}\n")
2536   startEmphasis();
2537 }
2538 
endConstraintType()2539 void RTFGenerator::endConstraintType()
2540 {
2541   DBG_RTF(m_t << "{\\comment (endConstraintType)}\n")
2542   endEmphasis();
2543   m_t << " ";
2544 }
2545 
startConstraintDocs()2546 void RTFGenerator::startConstraintDocs()
2547 {
2548   DBG_RTF(m_t << "{\\comment (startConstraintDocs)}\n")
2549 }
2550 
endConstraintDocs()2551 void RTFGenerator::endConstraintDocs()
2552 {
2553   DBG_RTF(m_t << "{\\comment (endConstraintDocs)}\n")
2554   newParagraph();
2555 }
2556 
endConstraintList()2557 void RTFGenerator::endConstraintList()
2558 {
2559   DBG_RTF(m_t << "{\\comment (endConstraintList)}\n")
2560   newParagraph();
2561   decIndentLevel();
2562   m_omitParagraph = TRUE;
2563   m_t << "}";
2564 }
2565 
startIndexListItem()2566 void RTFGenerator::startIndexListItem()
2567 {
2568   DBG_RTF(m_t << "{\\comment (startIndexListItem)}\n")
2569 }
2570 
endIndexListItem()2571 void RTFGenerator::endIndexListItem()
2572 {
2573   DBG_RTF(m_t << "{\\comment (endIndexListItem)}\n")
2574   m_t << "\\par\n";
2575 }
2576 
startInlineHeader()2577 void RTFGenerator::startInlineHeader()
2578 {
2579   DBG_RTF(m_t << "{\\comment (startInlineHeader)}\n")
2580   m_t << "{\n";
2581   m_t << rtf_Style_Reset << rtf_Style["Heading5"].reference();
2582   startBold();
2583 }
2584 
endInlineHeader()2585 void RTFGenerator::endInlineHeader()
2586 {
2587   DBG_RTF(m_t << "{\\comment (endInlineHeader)}\n")
2588   endBold();
2589   m_t << "\\par";
2590   m_t << "}\n";
2591 }
2592 
startMemberDocSimple(bool isEnum)2593 void RTFGenerator::startMemberDocSimple(bool isEnum)
2594 {
2595   DBG_RTF(m_t << "{\\comment (startMemberDocSimple)}\n")
2596   m_t << "{\\par\n";
2597   m_t << "{" << rtf_Style["Heading5"].reference() << "\n";
2598   if (isEnum)
2599   {
2600     m_t << theTranslator->trEnumerationValues();
2601   }
2602   else
2603   {
2604     m_t << theTranslator->trCompoundMembers();
2605   }
2606   m_t << ":\\par}\n";
2607   m_t << rtf_Style_Reset << rtf_DList_DepthStyle();
2608   m_t << "\\trowd \\trgaph108\\trleft426\\tblind426"
2609        "\\trbrdrt\\brdrs\\brdrw10\\brdrcf15 "
2610        "\\trbrdrl\\brdrs\\brdrw10\\brdrcf15 "
2611        "\\trbrdrb\\brdrs\\brdrw10\\brdrcf15 "
2612        "\\trbrdrr\\brdrs\\brdrw10\\brdrcf15 "
2613        "\\trbrdrh\\brdrs\\brdrw10\\brdrcf15 "
2614        "\\trbrdrv\\brdrs\\brdrw10\\brdrcf15 \n";
2615   int i,n=3,columnPos[3] = { 25, 50, 100 };
2616   if (isEnum)
2617   {
2618     columnPos[0]=30;
2619     columnPos[1]=100;
2620     n=2;
2621   }
2622   for (i=0;i<n;i++)
2623   {
2624     m_t << "\\clvertalt\\clbrdrt\\brdrs\\brdrw10\\brdrcf15 "
2625          "\\clbrdrl\\brdrs\\brdrw10\\brdrcf15 "
2626          "\\clbrdrb\\brdrs\\brdrw10\\brdrcf15 "
2627          "\\clbrdrr \\brdrs\\brdrw10\\brdrcf15 "
2628          "\\cltxlrtb "
2629          "\\cellx" << (rtf_pageWidth*columnPos[i]/100) << "\n";
2630   }
2631   m_t << "\\pard \\widctlpar\\intbl\\adjustright\n";
2632 }
2633 
endMemberDocSimple(bool)2634 void RTFGenerator::endMemberDocSimple(bool)
2635 {
2636   DBG_RTF(m_t << "{\\comment (endMemberDocSimple)}\n")
2637   m_t << "}\n";
2638 }
2639 
startInlineMemberType()2640 void RTFGenerator::startInlineMemberType()
2641 {
2642   DBG_RTF(m_t << "{\\comment (startInlineMemberType)}\n")
2643   m_t << "{\\qr ";
2644 }
2645 
endInlineMemberType()2646 void RTFGenerator::endInlineMemberType()
2647 {
2648   DBG_RTF(m_t << "{\\comment (endInlineMemberType)}\n")
2649   m_t << "\\cell }";
2650 }
2651 
startInlineMemberName()2652 void RTFGenerator::startInlineMemberName()
2653 {
2654   DBG_RTF(m_t << "{\\comment (startInlineMemberName)}\n")
2655   m_t << "{";
2656 }
2657 
endInlineMemberName()2658 void RTFGenerator::endInlineMemberName()
2659 {
2660   DBG_RTF(m_t << "{\\comment (endInlineMemberName)}\n")
2661   m_t << "\\cell }";
2662 }
2663 
startInlineMemberDoc()2664 void RTFGenerator::startInlineMemberDoc()
2665 {
2666   DBG_RTF(m_t << "{\\comment (startInlineMemberDoc)}\n")
2667   m_t << "{";
2668 }
2669 
endInlineMemberDoc()2670 void RTFGenerator::endInlineMemberDoc()
2671 {
2672   DBG_RTF(m_t << "{\\comment (endInlineMemberDoc)}\n")
2673   m_t << "\\cell }{\\row }\n";
2674 }
2675 
writeLineNumber(const QCString & ref,const QCString & fileName,const QCString & anchor,int l,bool writeLineAnchor)2676 void RTFGenerator::writeLineNumber(const QCString &ref,const QCString &fileName,const QCString &anchor,int l,bool writeLineAnchor)
2677 {
2678   bool rtfHyperlinks = Config_getBool(RTF_HYPERLINKS);
2679 
2680   m_doxyCodeLineOpen = true;
2681   if (Config_getBool(SOURCE_BROWSER))
2682   {
2683     QCString lineNumber;
2684     lineNumber.sprintf("%05d",l);
2685 
2686     QCString lineAnchor;
2687     if (!m_sourceFileName.isEmpty())
2688     {
2689       lineAnchor.sprintf("_l%05d",l);
2690       lineAnchor.prepend(stripExtensionGeneral(stripPath(m_sourceFileName), ".rtf"));
2691     }
2692     bool showTarget = rtfHyperlinks && !lineAnchor.isEmpty() && writeLineAnchor;
2693     if (showTarget)
2694     {
2695         m_t << "{\\bkmkstart ";
2696         m_t << rtfFormatBmkStr(lineAnchor);
2697         m_t << "}";
2698         m_t << "{\\bkmkend ";
2699         m_t << rtfFormatBmkStr(lineAnchor);
2700         m_t << "}\n";
2701     }
2702     if (!fileName.isEmpty())
2703     {
2704       writeCodeLink(CodeSymbolType::Default,ref,fileName,anchor,lineNumber,QCString());
2705     }
2706     else
2707     {
2708       m_t << lineNumber;
2709     }
2710     m_t << " ";
2711   }
2712   else
2713   {
2714     m_t << l << " ";
2715   }
2716   m_col=0;
2717 }
startCodeLine(bool)2718 void RTFGenerator::startCodeLine(bool)
2719 {
2720   m_doxyCodeLineOpen = true;
2721   m_col=0;
2722 }
endCodeLine()2723 void RTFGenerator::endCodeLine()
2724 {
2725   if (m_doxyCodeLineOpen) lineBreak();
2726   m_doxyCodeLineOpen = false;
2727 }
2728 
startLabels()2729 void RTFGenerator::startLabels()
2730 {
2731 }
2732 
writeLabel(const QCString & l,bool isLast)2733 void RTFGenerator::writeLabel(const QCString &l,bool isLast)
2734 {
2735   m_t << "{\\f2 [" << l << "]}";
2736   if (!isLast) m_t << ", ";
2737 }
2738 
endLabels()2739 void RTFGenerator::endLabels()
2740 {
2741 }
2742 
startFontClass(const QCString & name)2743 void RTFGenerator::startFontClass(const QCString &name)
2744 {
2745   int cod = 2;
2746   QCString qname(name);
2747   if (qname == "keyword")            cod = 17;
2748   else if (qname == "keywordtype")   cod = 18;
2749   else if (qname == "keywordflow")   cod = 19;
2750   else if (qname == "comment")       cod = 20;
2751   else if (qname == "preprocessor")  cod = 21;
2752   else if (qname == "stringliteral") cod = 22;
2753   else if (qname == "charliteral")   cod = 23;
2754   else if (qname == "vhdldigit")     cod = 24;
2755   else if (qname == "vhdlchar")      cod = 25;
2756   else if (qname == "vhdlkeyword")   cod = 26;
2757   else if (qname == "vhdllogic")     cod = 27;
2758   m_t << "{\\cf" << cod << " ";
2759 }
2760 
endFontClass()2761 void RTFGenerator::endFontClass()
2762 {
2763   m_t << "}";
2764 }
2765