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