/****************************************************************************** * * * * Copyright (C) 1997-2015 by Parker Waechter & Dimitri van Heesch. * * Style sheet additions by Alexander Bartolich * * Permission to use, copy, modify, and distribute this software and its * documentation under the terms of the GNU General Public License is hereby * granted. No representations are made about the suitability of this software * for any purpose. It is provided "as is" without express or implied warranty. * See the GNU General Public License for more details. * * Documents produced by Doxygen are derivative works derived from the * input used in their production; they are not affected by this license. * */ #include #include #include #include "rtfgen.h" #include "config.h" #include "message.h" #include "doxygen.h" #include "util.h" #include "diagram.h" #include "language.h" #include "dot.h" #include "dotcallgraph.h" #include "dotclassgraph.h" #include "dotdirdeps.h" #include "dotincldepgraph.h" #include "version.h" #include "pagedef.h" #include "rtfstyle.h" #include "rtfdocvisitor.h" #include "docparser.h" #include "dirdef.h" #include "vhdldocgen.h" #include "portable.h" #include "groupdef.h" #include "classlist.h" #include "filename.h" #include "namespacedef.h" #include "dir.h" #include "utf8.h" //#define DBG_RTF(x) x; #define DBG_RTF(x) static QCString dateToRTFDateString() { auto now = std::chrono::system_clock::now(); auto time = std::chrono::system_clock::to_time_t(now); auto tm = *localtime(&time); QCString result; result.sprintf("\\yr%d\\mo%d\\dy%d\\hr%d\\min%d\\sec%d", tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); return result; } RTFGenerator::RTFGenerator() : OutputGenerator(Config_getString(RTF_OUTPUT)) { } RTFGenerator::RTFGenerator(const RTFGenerator &og) : OutputGenerator(og) { } RTFGenerator &RTFGenerator::operator=(const RTFGenerator &og) { OutputGenerator::operator=(og); return *this; } std::unique_ptr RTFGenerator::clone() const { return std::make_unique(*this); } RTFGenerator::~RTFGenerator() { } void RTFGenerator::setRelativePath(const QCString &path) { m_relPath = path; } void RTFGenerator::setSourceFileName(const QCString &name) { m_sourceFileName = name; } void RTFGenerator::writeStyleSheetFile(TextStream &t) { t << "# Generated by doxygen " << getDoxygenVersion() << "\n\n"; t << "# This file describes styles used for generating RTF output.\n"; t << "# All text after a hash (#) is considered a comment and will be ignored.\n"; t << "# Remove a hash to activate a line.\n\n"; int i; for ( i=0 ; rtf_Style_Default[i].reference!=0 ; i++ ) { t << "# " << rtf_Style_Default[i].name << " = " << rtf_Style_Default[i].reference << rtf_Style_Default[i].definition << "\n"; } } void RTFGenerator::writeExtensionsFile(TextStream &t) { t << "# Generated by doxygen " << getDoxygenVersion() << "\n\n"; t << "# This file describes extensions used for generating RTF output.\n"; t << "# All text after a hash (#) is considered a comment and will be ignored.\n"; t << "# Remove a hash to activate a line.\n\n"; t << "# Overrides the project title.\n"; t << "#Title = \n\n"; t << "# Name of the company that produced this document.\n"; t << "#Company = \n\n"; t << "# Filename of a company or project logo.\n"; t << "#LogoFilename = \n\n"; t << "# Author of the document.\n"; t << "#Author = \n\n"; t << "# Type of document (e.g. Design Specification, User Manual, etc.).\n"; t << "#DocumentType = \n\n"; t << "# Document tracking number.\n"; t << "#DocumentId = \n\n"; t << "# Name of the author's manager.\n"; t << "# This field is not displayed in the document itself, but it is \n"; t << "# available in the information block of the rtf file. In Microsoft \n"; t << "# Word, it is available under File:Properties.\n"; t << "#Manager = \n\n"; t << "# Subject of the document.\n"; t << "# This field is not displayed in the document itself, but it is \n"; t << "# available in the information block of the rtf file. In Microsoft \n"; t << "# Word, it is available under File:Properties.\n"; t << "#Subject = \n\n"; t << "# Comments regarding the document.\n"; t << "# This field is not displayed in the document itself, but it is \n"; t << "# available in the information block of the rtf file. In Microsoft \n"; t << "# Word, it is available under File:Properties.\n"; t << "#Comments = \n\n"; t << "# Keywords associated with the document.\n"; t << "# This field is not displayed in the document itself, but it is \n"; t << "# available in the information block of the rtf file. In Microsoft \n"; t << "# Word, it is available under File:Properties.\n"; t << "#Keywords = \n\n"; } void RTFGenerator::init() { QCString dir=Config_getString(RTF_OUTPUT); Dir d(dir.str()); if (!d.exists() && !d.mkdir(dir.str())) { term("Could not create output directory %s\n",qPrint(dir)); } // first duplicate strings of rtf_Style_Default const struct Rtf_Style_Default* def = rtf_Style_Default; while (def->reference) { if (def->definition == 0) { err("Internal: rtf_Style_Default[%s] has no definition.\n", def->name); } else { rtf_Style.insert(std::make_pair(def->name, StyleData(def->reference, def->definition))); } def++; } // overwrite some (or all) definitions from file QCString rtfStyleSheetFile = Config_getString(RTF_STYLESHEET_FILE); if (!rtfStyleSheetFile.isEmpty()) { loadStylesheet(rtfStyleSheetFile, rtf_Style); } // If user has defined an extension file, load its contents. QCString rtfExtensionsFile = Config_getString(RTF_EXTENSIONS_FILE); if (!rtfExtensionsFile.isEmpty()) { loadExtensions(rtfExtensionsFile); } createSubDirs(d); } void RTFGenerator::cleanup() { QCString dname = Config_getString(RTF_OUTPUT); Dir d(dname.str()); clearSubDirs(d); } static QCString makeIndexName(const QCString &s,int i) { QCString result=s; result+=(char)(i+'0'); return result; } void RTFGenerator::beginRTFDocument() { /* all the included RTF files should begin with the * same header */ m_t << "{\\rtf1\\ansi\\ansicpg" << theTranslator->trRTFansicp(); m_t << "\\uc1 \\deff0\\deflang1033\\deflangfe1033\n"; DBG_RTF(m_t << "{\\comment Beginning font list}\n") m_t << "{\\fonttbl "; m_t << "{\\f0\\froman\\fcharset" << theTranslator->trRTFCharSet(); m_t << "\\fprq2{\\*\\panose 02020603050405020304}Times New Roman;}\n"; m_t << "{\\f1\\fswiss\\fcharset" << theTranslator->trRTFCharSet(); m_t << "\\fprq2{\\*\\panose 020b0604020202020204}Arial;}\n"; m_t << "{\\f2\\fmodern\\fcharset" << theTranslator->trRTFCharSet(); m_t << "\\fprq1{\\*\\panose 02070309020205020404}Courier New;}\n"; m_t << "{\\f3\\froman\\fcharset2\\fprq2{\\*\\panose 05050102010706020507}Symbol;}\n"; m_t << "}\n"; DBG_RTF(m_t << "{\\comment begin colors}\n") m_t << "{\\colortbl;"; m_t << "\\red0\\green0\\blue0;"; m_t << "\\red0\\green0\\blue255;"; m_t << "\\red0\\green255\\blue255;"; m_t << "\\red0\\green255\\blue0;"; m_t << "\\red255\\green0\\blue255;"; m_t << "\\red255\\green0\\blue0;"; m_t << "\\red255\\green255\\blue0;"; m_t << "\\red255\\green255\\blue255;"; m_t << "\\red0\\green0\\blue128;"; m_t << "\\red0\\green128\\blue128;"; m_t << "\\red0\\green128\\blue0;"; m_t << "\\red128\\green0\\blue128;"; m_t << "\\red128\\green0\\blue0;"; m_t << "\\red128\\green128\\blue0;"; m_t << "\\red128\\green128\\blue128;"; m_t << "\\red192\\green192\\blue192;"; // code highlighting colors. Note order is important see also RTFGenerator::startFontClass m_t << "\\red0\\green128\\blue0;"; // keyword = index 17 m_t << "\\red96\\green64\\blue32;"; // keywordtype m_t << "\\rede0\\green128\\blue0;"; // keywordflow m_t << "\\red128\\green0\\blue0;"; // comment m_t << "\\red128\\green96\\blue32;"; // preprocessor m_t << "\\red0\\green32\\blue128;"; // stringliteral m_t << "\\red0\\green128\\blue128;"; // charliteral m_t << "\\red255\\green0\\blue255;"; // vhdldigit m_t << "\\red0\\green0\\blue0;"; // vhdlchar m_t << "\\red112\\green0\\blue112;"; // vhdlkeyword m_t << "\\red255\\green0\\blue0;"; // vhdllogic m_t << "}\n"; DBG_RTF(m_t << "{\\comment Beginning style list}\n") m_t << "{\\stylesheet\n"; m_t << "{\\widctlpar\\adjustright \\fs20\\cgrid \\snext0 Normal;}\n"; // set the paper dimensions according to PAPER_TYPE QCString paperName = Config_getEnum(PAPER_TYPE); m_t << "{"; if (paperName=="a4") { m_t << "\\paperw11900\\paperh16840"; // width & height values are inches * 1440 } else if (paperName=="letter") { m_t << "\\paperw12240\\paperh15840"; } else if (paperName=="legal") { m_t << "\\paperw12240\\paperh20160"; } else if (paperName=="executive") { m_t << "\\paperw10440\\paperh15120"; } m_t << "\\margl1800\\margr1800\\margt1440\\margb1440\\gutter0\\ltrsect}\n"; // sort styles ascending by \s-number via an intermediate QArray unsigned maxIndex = 0; for (const auto &kv : rtf_Style) { uint index = kv.second.index(); if (index > maxIndex) maxIndex = index; } std::vector array(maxIndex + 1, 0); ASSERT(maxIndex < array.size()); for (const auto &kv : rtf_Style) { uint index = kv.second.index(); if (array[index] != 0) { msg("Style '%s' redefines \\s%d.\n", kv.first.c_str(), index); } array[index] = &kv.second; } // write array elements size_t size = array.size(); for(size_t i = 0; i < size; i++) { const StyleData *pStyle = array[i]; if (pStyle) { m_t << "{" << pStyle->reference() << pStyle->definition() << ";}\n"; } } m_t << "}\n"; // this comment is needed for postprocessing! m_t << "{\\comment begin body}\n"; } void RTFGenerator::beginRTFChapter() { m_t << "\n"; DBG_RTF(m_t << "{\\comment BeginRTFChapter}\n") m_t << rtf_Style_Reset; // if we are compact, no extra page breaks... if (Config_getBool(COMPACT_RTF)) { // m_t << "\\sect\\sectd\\sbknone\n"; m_t << "\\sect\\sbknone\n"; rtfwriteRuler_thick(); } else m_t << "\\sect\\sbkpage\n"; //m_t << "\\sect\\sectd\\sbkpage\n"; m_t << rtf_Style["Heading1"].reference() << "\n"; } void RTFGenerator::beginRTFSection() { m_t << "\n"; DBG_RTF(m_t << "{\\comment BeginRTFSection}\n") m_t << rtf_Style_Reset; // if we are compact, no extra page breaks... if (Config_getBool(COMPACT_RTF)) { m_t << "\\sect\\sbknone\n"; rtfwriteRuler_emboss(); } else { m_t << "\\sect\\sbkpage\n"; } m_t << rtf_Style["Heading2"].reference() << "\n"; } void RTFGenerator::startFile(const QCString &name,const QCString &,const QCString &,int) { //setEncoding(QCString().sprintf("CP%s",theTranslator->trRTFansicp())); QCString fileName=name; m_relPath = relativePathToRoot(fileName); if (fileName.right(4)!=".rtf" ) fileName+=".rtf"; startPlainFile(fileName); setRelativePath(m_relPath); setSourceFileName(stripPath(fileName)); beginRTFDocument(); } void RTFGenerator::endFile() { DBG_RTF(m_t << "{\\comment endFile}\n") m_t << "}"; endPlainFile(); setSourceFileName(""); } void RTFGenerator::startProjectNumber() { DBG_RTF(m_t << "{\\comment startProjectNumber }\n") m_t << " "; } void RTFGenerator::endProjectNumber() { DBG_RTF(m_t << "{\\comment endProjectNumber }\n") } void RTFGenerator::startIndexSection(IndexSections is) { //QCString paperName; m_listLevel = 0; switch (is) { case isTitlePageStart: // basic RTFstart // get readyfor author etc m_t << "{\\info \n"; m_t << "{\\title {\\comment "; break; case isTitlePageAuthor: m_t << "}\n"; if (!rtf_subject.isEmpty()) m_t << "{\\subject " << rtf_subject << "}\n"; if (!rtf_comments.isEmpty()) m_t << "{\\comment " << rtf_comments << "}\n"; if (!rtf_company.isEmpty()) m_t << "{\\company " << rtf_company << "}\n"; if (!rtf_author.isEmpty()) m_t << "{\\author " << rtf_author << "}\n"; if (!rtf_manager.isEmpty()) m_t << "{\\manager " << rtf_manager << "}\n"; if (!rtf_documentType.isEmpty()) m_t << "{\\category " << rtf_documentType << "}\n"; if (!rtf_keywords.isEmpty()) m_t << "{\\keywords " << rtf_keywords << "}\n"; m_t << "{\\comment "; break; case isMainPage: //Introduction beginRTFChapter(); break; //case isPackageIndex: // //Package Index // beginRTFChapter(); // break; case isModuleIndex: //Module Index beginRTFChapter(); break; case isDirIndex: //Directory Index beginRTFChapter(); break; case isNamespaceIndex: //Namespace Index beginRTFChapter(); break; case isConceptIndex: //Concept Index beginRTFChapter(); break; case isClassHierarchyIndex: //Hierarchical Index DBG_RTF(m_t << "{\\comment start classhierarchy}\n") beginRTFChapter(); break; case isCompoundIndex: //Annotated Compound Index beginRTFChapter(); break; case isFileIndex: //Annotated File Index beginRTFChapter(); break; case isPageIndex: //Related Page Index beginRTFChapter(); break; case isModuleDocumentation: { //Module Documentation for (const auto &gd : *Doxygen::groupLinkedMap) { if (!gd->isReference()) { beginRTFChapter(); break; } } } break; case isDirDocumentation: { //Directory Documentation for (const auto &dd : *Doxygen::dirLinkedMap) { if (dd->isLinkableInProject()) { beginRTFChapter(); break; } } } break; case isNamespaceDocumentation: { // Namespace Documentation for (const auto &nd : *Doxygen::namespaceLinkedMap) { if (nd->isLinkableInProject()) { beginRTFChapter(); break; } } } break; case isConceptDocumentation: { // Concept Documentation for (const auto &cd : *Doxygen::conceptLinkedMap) { if (cd->isLinkableInProject()) { beginRTFChapter(); break; } } } break; case isClassDocumentation: { //Compound Documentation for (const auto &cd : *Doxygen::classLinkedMap) { if (cd->isLinkableInProject() && cd->templateMaster()==0 && !cd->isEmbeddedInOuterScope() && !cd->isAlias() ) { beginRTFChapter(); break; } } } break; case isFileDocumentation: { //File Documentation bool isFirst=TRUE; for (const auto &fn : *Doxygen::inputNameLinkedMap) { for (const auto &fd : *fn) { if (fd->isLinkableInProject()) { if (isFirst) { beginRTFChapter(); isFirst=FALSE; break; } } } if (!isFirst) { break; } } } break; case isExampleDocumentation: { //Example Documentation beginRTFChapter(); } break; case isPageDocumentation: { //Page Documentation beginRTFChapter(); } break; case isPageDocumentation2: { m_t << "{\\tc \\v "; } break; case isEndIndex: break; } } void RTFGenerator::endIndexSection(IndexSections is) { bool fortranOpt = Config_getBool(OPTIMIZE_FOR_FORTRAN); bool vhdlOpt = Config_getBool(OPTIMIZE_OUTPUT_VHDL); bool sourceBrowser = Config_getBool(SOURCE_BROWSER); QCString projectName = Config_getString(PROJECT_NAME); switch (is) { case isTitlePageStart: if (!rtf_title.isEmpty()) // User has overridden document title in extensions file m_t << "}" << rtf_title; else m_t << "}" << projectName; break; case isTitlePageAuthor: { m_t << " doxygen" << getDoxygenVersion() << ".}\n"; m_t << "{\\creatim " << dateToRTFDateString() << "}\n}"; DBG_RTF(m_t << "{\\comment end of infoblock}\n"); // setup for this section m_t << rtf_Style_Reset <<"\n"; m_t << "\\sectd\\pgnlcrm\n"; m_t << "{\\footer "<trVersion() << " " << Config_getString(PROJECT_NUMBER) << "\\par"; m_t << "{\\field\\fldedit {\\*\\fldinst CREATEDATE \\\\*MERGEFORMAT}" "{\\fldrslt "<< dateToString(FALSE) << " }}\\par\n"; m_t << "\\page\\page"; DBG_RTF(m_t << "{\\comment End title page}\n") // table of contents section DBG_RTF(m_t << "{\\comment Table of contents}\n") m_t << "\\vertalt\n"; m_t << rtf_Style_Reset << "\n"; m_t << rtf_Style["Heading1"].reference(); m_t << theTranslator->trRTFTableOfContents() << "\\par\n"; m_t << rtf_Style_Reset << "\\par\n"; m_t << "{\\field\\fldedit {\\*\\fldinst TOC \\\\f \\\\*MERGEFORMAT}{\\fldrslt Table of contents}}\\par\n"; m_t << rtf_Style_Reset << "\n"; } break; case isMainPage: m_t << "\\par " << rtf_Style_Reset << "\n"; if (!mainPageHasTitle()) { m_t << "{\\tc \\v " << theTranslator->trMainPage() << "}\n"; } else { m_t << "{\\tc \\v " << substitute(Doxygen::mainPage->title(),"%","") << "}\n"; } m_t << "{\\field\\fldedit{\\*\\fldinst INCLUDETEXT \""; //if (Config_getBool(GENERATE_TREEVIEW)) m_t << "main"; else m_t << "index"; m_t << "index"; m_t << ".rtf\" \\\\*MERGEFORMAT}{\\fldrslt includedstuff}}\n"; break; //case isPackageIndex: // m_t << "\\par " << rtf_Style_Reset << "\n"; // m_t << "{\\tc \\v " << theTranslator->trPackageList() << "}\n"; // m_t << "{\\field\\fldedit{\\*\\fldinst INCLUDETEXT \"packages.rtf\" \\\\*MERGEFORMAT}{\\fldrslt includedstuff}}\n"; // break; case isModuleIndex: m_t << "\\par " << rtf_Style_Reset << "\n"; m_t << "{\\tc \\v " << theTranslator->trModuleIndex() << "}\n"; m_t << "{\\field\\fldedit{\\*\\fldinst INCLUDETEXT \"modules.rtf\" \\\\*MERGEFORMAT}{\\fldrslt includedstuff}}\n"; break; case isDirIndex: m_t << "\\par " << rtf_Style_Reset << "\n"; m_t << "{\\tc \\v " << theTranslator->trDirIndex() << "}\n"; m_t << "{\\field\\fldedit{\\*\\fldinst INCLUDETEXT \"dirs.rtf\" \\\\*MERGEFORMAT}{\\fldrslt includedstuff}}\n"; break; case isNamespaceIndex: m_t << "\\par " << rtf_Style_Reset << "\n"; if (fortranOpt) { m_t << "{\\tc \\v " << theTranslator->trModulesIndex() << "}\n"; } else { m_t << "{\\tc \\v " << theTranslator->trNamespaceIndex() << "}\n"; } m_t << "{\\field\\fldedit{\\*\\fldinst INCLUDETEXT \"namespaces.rtf\" \\\\*MERGEFORMAT}{\\fldrslt includedstuff}}\n"; break; case isConceptIndex: m_t << "\\par " << rtf_Style_Reset << "\n"; m_t << "{\\tc \\v " << theTranslator->trConceptIndex() << "}\n"; m_t << "{\\field\\fldedit{\\*\\fldinst INCLUDETEXT \"concepts.rtf\" \\\\*MERGEFORMAT}{\\fldrslt includedstuff}}\n"; break; case isClassHierarchyIndex: m_t << "\\par " << rtf_Style_Reset << "\n"; m_t << "{\\tc \\v " << theTranslator->trHierarchicalIndex() << "}\n"; m_t << "{\\field\\fldedit{\\*\\fldinst INCLUDETEXT \"hierarchy.rtf\" \\\\*MERGEFORMAT}{\\fldrslt includedstuff}}\n"; break; case isCompoundIndex: m_t << "\\par " << rtf_Style_Reset << "\n"; if (fortranOpt) { m_t << "{\\tc \\v " << theTranslator->trCompoundIndexFortran() << "}\n"; } else if (vhdlOpt) { m_t << "{\\tc \\v " << theTranslator->trDesignUnitIndex() << "}\n"; } else { m_t << "{\\tc \\v " << theTranslator->trCompoundIndex() << "}\n"; } m_t << "{\\field\\fldedit{\\*\\fldinst INCLUDETEXT \"annotated.rtf\" \\\\*MERGEFORMAT}{\\fldrslt includedstuff}}\n"; break; case isFileIndex: m_t << "\\par " << rtf_Style_Reset << "\n"; m_t << "{\\tc \\v " << theTranslator->trFileIndex() << "}\n"; m_t << "{\\field\\fldedit{\\*\\fldinst INCLUDETEXT \"files.rtf\" \\\\*MERGEFORMAT}{\\fldrslt includedstuff}}\n"; break; case isPageIndex: m_t << "\\par " << rtf_Style_Reset << "\n"; m_t << "{\\tc \\v " << theTranslator->trPageIndex() << "}\n"; m_t << "{\\field\\fldedit{\\*\\fldinst INCLUDETEXT \"pages.rtf\" \\\\*MERGEFORMAT}{\\fldrslt includedstuff}}\n"; break; case isModuleDocumentation: { bool first=true; m_t << "{\\tc \\v " << theTranslator->trModuleDocumentation() << "}\n"; for (const auto &gd : *Doxygen::groupLinkedMap) { if (!gd->isReference()) { m_t << "\\par " << rtf_Style_Reset << "\n"; if (!first) { beginRTFSection(); } first=false; m_t << "{\\field\\fldedit{\\*\\fldinst INCLUDETEXT \""; m_t << gd->getOutputFileBase(); m_t << ".rtf\" \\\\*MERGEFORMAT}{\\fldrslt includedstuff}}\n"; } } } break; case isDirDocumentation: { bool first=true; m_t << "{\\tc \\v " << theTranslator->trDirDocumentation() << "}\n"; for (const auto &dd : *Doxygen::dirLinkedMap) { if (dd->isLinkableInProject()) { m_t << "\\par " << rtf_Style_Reset << "\n"; if (!first) { beginRTFSection(); } first=false; m_t << "{\\field\\fldedit{\\*\\fldinst INCLUDETEXT \""; m_t << dd->getOutputFileBase(); m_t << ".rtf\" \\\\*MERGEFORMAT}{\\fldrslt includedstuff}}\n"; } } } break; case isNamespaceDocumentation: { bool first=true; for (const auto &nd : *Doxygen::namespaceLinkedMap) { if (nd->isLinkableInProject() && !nd->isAlias()) { m_t << "\\par " << rtf_Style_Reset << "\n"; if (!first) { beginRTFSection(); } first=false; m_t << "{\\field\\fldedit{\\*\\fldinst INCLUDETEXT \""; m_t << nd->getOutputFileBase(); m_t << ".rtf\" \\\\*MERGEFORMAT}{\\fldrslt includedstuff}}\n"; } } } break; case isConceptDocumentation: { bool first=true; for (const auto &cd : *Doxygen::conceptLinkedMap) { if (cd->isLinkableInProject() && !cd->isAlias()) { m_t << "\\par " << rtf_Style_Reset << "\n"; if (!first) { beginRTFSection(); } first=false; m_t << "{\\field\\fldedit{\\*\\fldinst INCLUDETEXT \""; m_t << cd->getOutputFileBase(); m_t << ".rtf\" \\\\*MERGEFORMAT}{\\fldrslt includedstuff}}\n"; } } } break; case isClassDocumentation: { bool first=true; if (fortranOpt) { m_t << "{\\tc \\v " << theTranslator->trTypeDocumentation() << "}\n"; } else { m_t << "{\\tc \\v " << theTranslator->trClassDocumentation() << "}\n"; } for (const auto &cd : *Doxygen::classLinkedMap) { if (cd->isLinkableInProject() && cd->templateMaster()==0 && !cd->isEmbeddedInOuterScope() && !cd->isAlias() ) { m_t << "\\par " << rtf_Style_Reset << "\n"; if (!first) { beginRTFSection(); } first=false; m_t << "{\\field\\fldedit{\\*\\fldinst INCLUDETEXT \""; m_t << cd->getOutputFileBase(); m_t << ".rtf\" \\\\*MERGEFORMAT}{\\fldrslt includedstuff}}\n"; } } } break; case isFileDocumentation: { bool isFirst=TRUE; m_t << "{\\tc \\v " << theTranslator->trFileDocumentation() << "}\n"; for (const auto &fn : *Doxygen::inputNameLinkedMap) { for (const auto &fd : *fn) { if (fd->isLinkableInProject()) { m_t << "\\par " << rtf_Style_Reset << "\n"; if (!isFirst) { beginRTFSection(); } isFirst=FALSE; m_t << "{\\field\\fldedit{\\*\\fldinst INCLUDETEXT \""; m_t << fd->getOutputFileBase(); m_t << ".rtf\" \\\\*MERGEFORMAT}{\\fldrslt includedstuff}}\n"; if (sourceBrowser && m_prettyCode && fd->generateSourceFile()) { m_t << "\\par " << rtf_Style_Reset << "\n"; m_t << "{\\field\\fldedit{\\*\\fldinst INCLUDETEXT \"" << fd->getSourceFileBase() << ".rtf\" \\\\*MERGEFORMAT}{\\fldrslt includedstuff}}\n"; } } } } } break; case isExampleDocumentation: { //m_t << "}\n"; bool isFirst=true; m_t << "{\\tc \\v " << theTranslator->trExampleDocumentation() << "}\n"; for (const auto &pd : *Doxygen::exampleLinkedMap) { m_t << "\\par " << rtf_Style_Reset << "\n"; if (!isFirst) { beginRTFSection(); } isFirst=false; m_t << "{\\field\\fldedit{\\*\\fldinst INCLUDETEXT \""; m_t << pd->getOutputFileBase(); m_t << ".rtf\" \\\\*MERGEFORMAT}{\\fldrslt includedstuff}}\n"; } } break; case isPageDocumentation: { //#error "fix me in the same way as the latex index..." //m_t << "{\\tc \\v " << theTranslator->trPageDocumentation() << "}\n"; //m_t << "}\n"; //bool first=TRUE; //for (const auto *pd : Doxygen::pageLinkedMap) //{ // if (!pd->getGroupDef() && !pd->isReference()) // { // if (first) m_t << "\\par " << rtf_Style_Reset << "\n"; // m_t << "{\\field\\fldedit{\\*\\fldinst INCLUDETEXT \""; // m_t << pd->getOutputFileBase(); // m_t << ".rtf\" \\\\*MERGEFORMAT}{\\fldrslt includedstuff}}\n"; // first=FALSE; // } //} } break; case isPageDocumentation2: { m_t << "}"; m_t << "\\par " << rtf_Style_Reset << "\n"; } break; case isEndIndex: beginRTFChapter(); m_t << rtf_Style["Heading1"].reference(); m_t << theTranslator->trRTFGeneralIndex() << "\\par \n"; m_t << rtf_Style_Reset << "\n"; m_t << "{\\tc \\v " << theTranslator->trRTFGeneralIndex() << "}\n"; m_t << "{\\field\\fldedit {\\*\\fldinst INDEX \\\\c2 \\\\*MERGEFORMAT}{\\fldrslt INDEX}}\n"; break; } } void RTFGenerator::writePageLink(const QCString &name,bool first) { if (first) m_t << "\\par " << rtf_Style_Reset << "\n"; m_t << "{\\field\\fldedit{\\*\\fldinst INCLUDETEXT \""; m_t << name; m_t << ".rtf\" \\\\*MERGEFORMAT}{\\fldrslt includedstuff}}\n"; } void RTFGenerator::lastIndexPage() { DBG_RTF(m_t << "{\\comment Beginning Body of RTF Document}\n") // end page and setup for rest of document m_t << "\\sect \\sbkpage \\pgndec \\pgnrestart\n"; m_t << "\\sect \\sectd \\sbknone\n"; // set new footer with arabic numbers m_t << "{\\footer "<< rtf_Style["Footer"].reference() << "{\\chpgn}}\n"; } void RTFGenerator::writeStyleInfo(int) { } void RTFGenerator::lineBreak(const QCString &) { DBG_RTF(m_t << "{\\comment (lineBreak)}" << "\n") m_t << "\\par\n"; m_omitParagraph = TRUE; } void RTFGenerator::writeString(const QCString &text) { m_t << text; } void RTFGenerator::startIndexList() { DBG_RTF(m_t << "{\\comment (startIndexList)}\n") m_t << "{\n"; m_t << "\\par\n"; incrementIndentLevel(); m_t << rtf_Style_Reset << rtf_LCList_DepthStyle() << "\n"; m_omitParagraph = TRUE; } void RTFGenerator::endIndexList() { DBG_RTF(m_t << "{\\comment (endIndexList)}\n") if (!m_omitParagraph) { m_t << "\\par"; m_omitParagraph = TRUE; } m_t << "}"; decrementIndentLevel(); } /*! start bullet list */ void RTFGenerator::startItemList() { newParagraph(); DBG_RTF(m_t << "{\\comment (startItemList level=" << m_listLevel << ") }\n") m_t << "{"; incrementIndentLevel(); rtf_listItemInfo[m_listLevel].isEnum = FALSE; } /*! end bullet list */ void RTFGenerator::endItemList() { newParagraph(); DBG_RTF(m_t << "{\\comment (endItemList level=" << m_listLevel << ")}\n") m_t << "}"; decrementIndentLevel(); m_omitParagraph = TRUE; } ///*! start enumeration list */ //void RTFGenerator::startEnumList() // starts an enumeration list //{ // DBG_RTF(m_t << "{\\comment (startEnumList)}\n") // m_t << "{\n"; // incrementIndentLevel(); // rtf_listItemInfo[m_listLevel].isEnum = TRUE; // rtf_listItemInfo[m_listLevel].number = 1; //} // ///*! end enumeration list */ //void RTFGenerator::endEnumList() //{ // newParagraph(); // DBG_RTF(m_t << "{\\comment (endEnumList)}\n") // m_t << "}"; // decrementIndentLevel(); // m_omitParagraph = TRUE; //} /*! write bullet or enum item */ void RTFGenerator::startItemListItem() { DBG_RTF(m_t << "{\\comment (startItemListItem)}\n") newParagraph(); m_t << rtf_Style_Reset; if (rtf_listItemInfo[m_listLevel].isEnum) { m_t << rtf_EList_DepthStyle() << "\n"; m_t << rtf_listItemInfo[m_listLevel].number << ".\\tab "; rtf_listItemInfo[m_listLevel].number++; } else { m_t << rtf_BList_DepthStyle() << "\n"; } m_omitParagraph = TRUE; } void RTFGenerator::endItemListItem() { DBG_RTF(m_t << "{\\comment (endItemListItem)}\n") } void RTFGenerator::startIndexItem(const QCString &,const QCString &) { DBG_RTF(m_t << "{\\comment (startIndexItem)}\n") if (!m_omitParagraph) { m_t << "\\par\n"; m_omitParagraph = TRUE; } } void RTFGenerator::endIndexItem(const QCString &ref,const QCString &fn) { DBG_RTF(m_t << "{\\comment (endIndexItem)}\n") if (ref.isEmpty() && !fn.isEmpty()) { m_t << "\\tab "; writeRTFReference(fn); m_t << "\n"; } else { m_t << "\n"; } m_omitParagraph = TRUE; } //void RTFGenerator::writeIndexFileItem(const QCString &,const QCString &text) //{ // m_t << "\\item\\contentsline{section}{"; // docify(text); // m_t << "}{\\pageref{" << texm_t << "}}\n"; //} void RTFGenerator::startHtmlLink(const QCString &url) { if (Config_getBool(RTF_HYPERLINKS)) { m_t << "{\\field {\\*\\fldinst { HYPERLINK \""; m_t << url; m_t << "\" }{}"; m_t << "}{\\fldrslt {\\cs37\\ul\\cf2 "; } else { startTypewriter(); } } void RTFGenerator::endHtmlLink() { if (Config_getBool(RTF_HYPERLINKS)) { m_t << "}}}\n"; } else { endTypewriter(); } } //void RTFGenerator::writeMailLink(const QCString &url) //{ // startTypewriter(); // docify(url); // endTypewriter(); //} void RTFGenerator::writeStartAnnoItem(const QCString &,const QCString &f, const QCString &path,const QCString &name) { DBG_RTF(m_t << "{\\comment (writeStartAnnoItem)}\n") m_t << "{\\b "; if (!path.isEmpty()) docify(path); if (!f.isEmpty() && Config_getBool(RTF_HYPERLINKS)) { m_t << "{\\field {\\*\\fldinst { HYPERLINK \\\\l \""; m_t << rtfFormatBmkStr(f); m_t << "\" }{}"; m_t << "}{\\fldrslt {\\cs37\\ul\\cf2 "; docify(name); m_t << "}}}\n"; } else { docify(name); } m_t << "} "; } void RTFGenerator::writeEndAnnoItem(const QCString &name) { DBG_RTF(m_t << "{\\comment (writeEndAnnoItem)}\n") if (!name.isEmpty()) { m_t << "\\tab "; writeRTFReference(name); m_t << "\n"; } else { m_t << "\n"; } newParagraph(); } void RTFGenerator::startIndexKey() { DBG_RTF(m_t << "{\\comment (startIndexKey)}\n") m_t << "{\\b "; } void RTFGenerator::endIndexKey() { DBG_RTF(m_t << "{\\comment (endIndexKey)}\n") } void RTFGenerator::startIndexValue(bool hasBrief) { DBG_RTF(m_t << "{\\comment (startIndexValue)}\n") m_t << " "; if (hasBrief) m_t << "("; } void RTFGenerator::endIndexValue(const QCString &name,bool hasBrief) { DBG_RTF(m_t << "{\\comment (endIndexValue)}\n") if (hasBrief) m_t << ")"; m_t << "} "; if (!name.isEmpty()) { m_t << "\\tab "; writeRTFReference(name); m_t << "\n"; } else { m_t << "\n"; } m_omitParagraph=FALSE; newParagraph(); } void RTFGenerator::startSubsection() { //beginRTFSubSection(); m_t << "\n"; DBG_RTF(m_t << "{\\comment Begin SubSection}\n") m_t << rtf_Style_Reset; m_t << rtf_Style["Heading3"].reference() << "\n"; } void RTFGenerator::endSubsection() { newParagraph(); m_t << rtf_Style_Reset << "\n"; } void RTFGenerator::startSubsubsection() { //beginRTFSubSubSection(); m_t << "\n"; DBG_RTF(m_t << "{\\comment Begin SubSubSection}\n") m_t << "{\n"; m_t << rtf_Style_Reset << rtf_Style["Heading4"].reference() << "\n"; } void RTFGenerator::endSubsubsection() { newParagraph(); m_t << "}\n"; } //void RTFGenerator::writeClassLink(const QCString &,const QCString &, // const QCString &,const QCString &name) //{ // m_t << "{\\bf "; // docify(name); // m_t << "}"; //} //void RTFGenerator::startTable(bool,int colNumbers) //{ // DBG_RTF(m_t << "{\\comment startTable}\n";) // m_numCols=colNumbers; // m_t << "\\par\n"; //} // //void RTFGenerator::endTable(bool hasCaption) //{ // DBG_RTF(m_t << "{\\comment endTable}\n";) // if (!hasCaption) // m_t << "\n\\pard \\widctlpar\\intbl\\adjustright\n{\\row }\n"; // m_t << "\\pard\n\n"; //} // //void RTFGenerator::startCaption() //{ // DBG_RTF(m_t << "{\\comment startCaption}\n";) // endTableRow(); // m_t << "\\trowd \\trgaph108\\trleft-108\\trbrdrt\\brdrs\\brdrw10 \\trbrdrl\\brdrs\\brdrw10 \\trbrdrb\\brdrs\\brdrw10 \\trbrdrr\\brdrs\\brdrw10 \\trbrdrh\\brdrs\\brdrw10 \\trbrdrv\\brdrs\\brdrw10\n"; // m_t << "\\clvertalt\\clbrdrt\\brdrs\\brdrw10 \\clbrdrl\\brdrs\\brdrw10 \\clbrdrb\\brdrs\\brdrw10 \\clbrdrr \\brdrs\\brdrw10 \\cltxlrtb \\cellx"<0 && m_numCols<25); // uint columnWidth=rtf_pageWidth/m_numCols; // m_t << "\\trowd \\trgaph108\\trleft-108\\trbrdrt\\brdrs\\brdrw10 " // "\\trbrdrl\\brdrs\\brdrw10 \\trbrdrb\\brdrs\\brdrw10 " // "\\trbrdrr\\brdrs\\brdrw10 \\trbrdrh\\brdrs\\brdrw10 " // "\\trbrdrv\\brdrs\\brdrw10 \n"; // for (int i=0;itrPageAbbreviation()); // writeRTFReference(lab); // m_t << ")\n"; // } //} // //void RTFGenerator::writeSectionRefItem(const QCString &,const QCString &lab, // const QCString &title) //{ // docify(title); // m_t << "\\tab"; // writeRTFReference(lab); // m_t << "\n"; //} // //void RTFGenerator::writeSectionRefAnchor(const QCString &name,const QCString &lab, // const QCString &title) //{ // writeSectionRef(name,lab,title); //} //char* RTFGenerator::getMultiByte(int c) //{ // static char s[10]; // // sprintf(s,"\\'%X",c); // return s; //} void RTFGenerator::docify(const QCString &str) { if (!str.isEmpty()) { const unsigned char *p=(const unsigned char *)str.data(); unsigned char c; //unsigned char pc='\0'; while (*p) { //static bool MultiByte = FALSE; c=*p++; #if 0 if ( MultiByte ) { m_t << getMultiByte( c ); MultiByte = FALSE; continue; } if ( c >= 0x80 ) { MultiByte = TRUE; m_t << getMultiByte( c ); continue; } #endif switch (c) { case '{': m_t << "\\{"; break; case '}': m_t << "\\}"; break; case '\\': m_t << "\\\\"; break; default: { // see if we can insert an hyphenation hint //if (isupper(c) && islower(pc) && !insideTabbing) m_t << "\\-"; m_t << (char)c; } } //pc = c; m_omitParagraph = FALSE; } } } void RTFGenerator::codify(const QCString &str) { // note that RTF does not have a "verbatim", so "\n" means // nothing... add a "newParagraph()"; //static char spaces[]=" "; if (!str.isEmpty()) { const unsigned char *p=(const unsigned char *)str.data(); unsigned char c; int spacesToNextTabStop; while (*p) { //static bool MultiByte = FALSE; c=*p++; switch(c) { case '\t': spacesToNextTabStop = Config_getInt(TAB_SIZE) - (m_col%Config_getInt(TAB_SIZE)); m_t << Doxygen::spaces.left(spacesToNextTabStop); m_col+=spacesToNextTabStop; break; case '\n': newParagraph(); m_t << '\n'; m_col=0; break; case '{': m_t << "\\{"; m_col++; break; case '}': m_t << "\\}"; m_col++; break; case '\\': m_t << "\\\\"; m_col++; break; default: p=(const unsigned char *)writeUTF8Char(m_t,(const char *)p-1); m_col++; break; } } } } void RTFGenerator::writeChar(char c) { char cs[2]; cs[0]=c; cs[1]=0; docify(cs); } void RTFGenerator::startClassDiagram() { DBG_RTF(m_t << "{\\comment startClassDiagram }\n") } void RTFGenerator::endClassDiagram(const ClassDiagram &d, const QCString &fileName,const QCString &) { newParagraph(); // create a png file d.writeImage(m_t,dir(),m_relPath,fileName,FALSE); // display the file m_t << "{\n"; m_t << rtf_Style_Reset << "\n"; m_t << "\\par\\pard \\qc {\\field\\flddirty {\\*\\fldinst INCLUDEPICTURE \""; m_t << fileName << ".png\""; m_t << " \\\\d \\\\*MERGEFORMAT}{\\fldrslt IMAGE}}\\par\n"; m_t << "}\n"; } //void RTFGenerator::writeFormula(const QCString &,const QCString &text) //{ // m_t << text; //} void RTFGenerator::startMemberItem(const QCString &,int,const QCString &) { DBG_RTF(m_t << "{\\comment startMemberItem }\n") m_t << rtf_Style_Reset << rtf_BList_DepthStyle() << "\n"; // set style to appropriate depth } void RTFGenerator::endMemberItem() { DBG_RTF(m_t << "{\\comment endMemberItem }\n") newParagraph(); } void RTFGenerator::writeAnchor(const QCString &fileName,const QCString &name) { QCString anchor; if (!fileName.isEmpty()) { anchor+=fileName; } if (!fileName.isEmpty() && !name.isEmpty()) { anchor+='_'; } if (!name.isEmpty()) { anchor+=name; } DBG_RTF(m_t << "{\\comment writeAnchor (" << anchor << ")}\n") m_t << "{\\bkmkstart " << rtfFormatBmkStr(anchor) << "}\n"; m_t << "{\\bkmkend " << rtfFormatBmkStr(anchor) << "}\n"; } void RTFGenerator::writeRTFReference(const QCString &label) { m_t << "{\\field\\fldedit {\\*\\fldinst PAGEREF "; m_t << rtfFormatBmkStr(label); m_t << " \\\\*MERGEFORMAT}{\\fldrslt pagenum}}"; } void RTFGenerator::startCodeFragment(const QCString &) { DBG_RTF(m_t << "{\\comment (startCodeFragment) }\n") m_t << "{\n"; m_t << rtf_Style_Reset << rtf_Code_DepthStyle(); } void RTFGenerator::endCodeFragment(const QCString &) { endCodeLine(); DBG_RTF(m_t << "{\\comment (endCodeFragment) }\n") m_t << "}\n"; m_omitParagraph = TRUE; } void RTFGenerator::writeNonBreakableSpace(int) { m_t << "\\~ "; } void RTFGenerator::startMemberList() { m_t << "\n"; DBG_RTF(m_t << "{\\comment (startMemberList) }\n") m_t << "{\n"; #ifdef DELETEDCODE if (!insideTabbing) m_t << "\\begin{CompactItemize}\n"; #endif } void RTFGenerator::endMemberList() { DBG_RTF(m_t << "{\\comment (endMemberList) }\n") m_t << "}\n"; #ifdef DELETEDCODE if (!insideTabbing) m_t << "\\end{CompactItemize}\n"; #endif } //void RTFGenerator::startImage(const QCString &name,const QCString &,bool) //{ // newParagraph(); // m_t << "{\n"; // m_t << rtf_Style_Reset << "\n"; // m_t << "\\par\\pard \\qc {\\field\\flddirty {\\*\\fldinst INCLUDEPICTURE "; // m_t << name; // m_t << " \\\\d \\\\*MERGEFORMAT}{\\fldrslt IMAGE}}\\par\n"; // m_t << "}\n"; //} // //void RTFGenerator::endImage(bool) //{ // // not yet implemented //} // //void RTFGenerator::startDotFile(const QCString &name,bool) //{ // QCString baseName=name; // int i; // if ((i=baseName.findRev('/'))!=-1 || (i=baseName.findRev('\\'))!=-1) // { // baseName=baseName.right(baseName.length()-i-1); // } // QCString outDir = Config_getString(RTF_OUTPUT); // writeDotGraphFromFile(name,outDir,baseName,BITMAP); // newParagraph(); // m_t << "{\n"; // m_t << rtf_Style_Reset << "\n"; // m_t << "\\par\\pard \\qc {\\field\\flddirty {\\*\\fldinst INCLUDEPICTURE "; // m_t << outDir << "\\" << baseName; // m_t << " \\\\d \\\\*MERGEFORMAT}{\\fldrslt IMAGE}}\\par\n"; // m_t << "}\n"; //} // //void RTFGenerator::endDotFile(bool) //{ // // not yet implemented //} // void RTFGenerator::startDescTable(const QCString &title) { DBG_RTF(m_t << "{\\comment (startDescTable) }\n") m_t << "{\\par\n"; m_t << "{" << rtf_Style["Heading5"].reference() << "\n"; docify(title); m_t << ":\\par}\n"; m_t << rtf_Style_Reset << rtf_DList_DepthStyle(); m_t << "\\trowd \\trgaph108\\trleft426\\tblind426" "\\trbrdrt\\brdrs\\brdrw10\\brdrcf15 " "\\trbrdrl\\brdrs\\brdrw10\\brdrcf15 " "\\trbrdrb\\brdrs\\brdrw10\\brdrcf15 " "\\trbrdrr\\brdrs\\brdrw10\\brdrcf15 " "\\trbrdrh\\brdrs\\brdrw10\\brdrcf15 " "\\trbrdrv\\brdrs\\brdrw10\\brdrcf15 \n"; int i,columnPos[2] = { 25, 100 }; for (i=0;i<2;i++) { m_t << "\\clvertalt\\clbrdrt\\brdrs\\brdrw10\\brdrcf15 " "\\clbrdrl\\brdrs\\brdrw10\\brdrcf15 " "\\clbrdrb\\brdrs\\brdrw10\\brdrcf15 " "\\clbrdrr \\brdrs\\brdrw10\\brdrcf15 " "\\cltxlrtb " "\\cellx" << (rtf_pageWidth*columnPos[i]/100) << "\n"; } m_t << "\\pard \\widctlpar\\intbl\\adjustright\n"; } void RTFGenerator::endDescTable() { DBG_RTF(m_t << "{\\comment (endDescTable)}\n") m_t << "}\n"; } void RTFGenerator::startDescTableRow() { } void RTFGenerator::endDescTableRow() { } void RTFGenerator::startDescTableTitle() { DBG_RTF(m_t << "{\\comment (startDescTableTitle) }\n") m_t << "{\\qr "; } void RTFGenerator::endDescTableTitle() { DBG_RTF(m_t << "{\\comment (endDescTableTitle) }\n") m_t << "\\cell }"; } void RTFGenerator::startDescTableData() { DBG_RTF(m_t << "{\\comment (startDescTableData) }\n") m_t << "{"; } void RTFGenerator::endDescTableData() { DBG_RTF(m_t << "{\\comment (endDescTableData) }\n") m_t << "\\cell }{\\row }\n"; } // a style for list formatted as a "bulleted list" void RTFGenerator::incrementIndentLevel() { m_listLevel++; if (m_listLevel>rtf_maxIndentLevels-1) { err("Maximum indent level (%d) exceeded while generating RTF output!\n",rtf_maxIndentLevels); m_listLevel=rtf_maxIndentLevels-1; } } void RTFGenerator::decrementIndentLevel() { m_listLevel--; if (m_listLevel<0) { err("Negative indent level while generating RTF output!\n"); m_listLevel=0; } } // a style for list formatted with "list continue" style QCString RTFGenerator::rtf_CList_DepthStyle() { QCString n=makeIndexName("ListContinue",m_listLevel); return rtf_Style[n.str()].reference(); } // a style for list formatted as a "latext style" table of contents QCString RTFGenerator::rtf_LCList_DepthStyle() { QCString n=makeIndexName("LatexTOC",m_listLevel); return rtf_Style[n.str()].reference(); } // a style for list formatted as a "bullet" style QCString RTFGenerator::rtf_BList_DepthStyle() { QCString n=makeIndexName("ListBullet",m_listLevel); return rtf_Style[n.str()].reference(); } // a style for list formatted as a "enumeration" style QCString RTFGenerator::rtf_EList_DepthStyle() { QCString n=makeIndexName("ListEnum",m_listLevel); return rtf_Style[n.str()].reference(); } QCString RTFGenerator::rtf_DList_DepthStyle() { QCString n=makeIndexName("DescContinue",m_listLevel); return rtf_Style[n.str()].reference(); } QCString RTFGenerator::rtf_Code_DepthStyle() { QCString n=makeIndexName("CodeExample",m_listLevel); return rtf_Style[n.str()].reference(); } void RTFGenerator::startTextBlock(bool dense) { DBG_RTF(m_t << "{\\comment startTextBlock}\n") m_t << "{\n"; m_t << rtf_Style_Reset; if (dense) // no spacing between "paragraphs" { m_t << rtf_Style["DenseText"].reference(); } else // some spacing { m_t << rtf_Style["BodyText"].reference(); } } void RTFGenerator::endTextBlock(bool /*paraBreak*/) { newParagraph(); DBG_RTF(m_t << "{\\comment endTextBlock}\n") m_t << "}\n"; //m_omitParagraph = TRUE; } void RTFGenerator::newParagraph() { if (!m_omitParagraph) { DBG_RTF(m_t << "{\\comment (newParagraph)}\n") m_t << "\\par\n"; } m_omitParagraph = FALSE; } void RTFGenerator::startParagraph(const QCString &txt) { DBG_RTF(m_t << "{\\comment startParagraph}\n") newParagraph(); m_t << "{\n"; if (QCString(txt) == "reference") m_t << "\\ql\n"; } void RTFGenerator::endParagraph() { DBG_RTF(m_t << "{\\comment endParagraph}\n") m_t << "}\\par\n"; m_omitParagraph = TRUE; } void RTFGenerator::startMemberSubtitle() { DBG_RTF(m_t << "{\\comment startMemberSubtitle}\n") m_t << "{\n"; m_t << rtf_Style_Reset << rtf_CList_DepthStyle() << "\n"; } void RTFGenerator::endMemberSubtitle() { DBG_RTF(m_t << "{\\comment endMemberSubtitle}\n") newParagraph(); m_t << "}\n"; } //void RTFGenerator::writeUmlaut(char c) //{ // switch(c) // { // case 'A' : m_t << '\304'; break; // case 'E' : m_t << '\313'; break; // case 'I' : m_t << '\317'; break; // case 'O' : m_t << '\326'; break; // case 'U' : m_t << '\334'; break; // case 'Y' : m_t << 'Y'; break; // case 'a' : m_t << '\344'; break; // case 'e' : m_t << '\353'; break; // case 'i' : m_t << '\357'; break; // case 'o' : m_t << '\366'; break; // case 'u' : m_t << '\374'; break; // case 'y' : m_t << '\377'; break; // default: m_t << '?'; break; // } //} // //void RTFGenerator::writeAcute(char c) //{ // switch(c) // { // case 'A' : m_t << '\301'; break; // case 'E' : m_t << '\311'; break; // case 'I' : m_t << '\315'; break; // case 'O' : m_t << '\323'; break; // case 'U' : m_t << '\332'; break; // case 'Y' : m_t << '\335'; break; // case 'a' : m_t << '\341'; break; // case 'e' : m_t << '\351'; break; // case 'i' : m_t << '\355'; break; // case 'o' : m_t << '\363'; break; // case 'u' : m_t << '\372'; break; // case 'y' : m_t << '\375'; break; // default: m_t << '?'; break; // } //} // //void RTFGenerator::writeGrave(char c) //{ // switch(c) // { // case 'A' : m_t << '\300'; break; // case 'E' : m_t << '\310'; break; // case 'I' : m_t << '\314'; break; // case 'O' : m_t << '\322'; break; // case 'U' : m_t << '\331'; break; // case 'a' : m_t << '\340'; break; // case 'e' : m_t << '\350'; break; // case 'i' : m_t << '\354'; break; // case 'o' : m_t << '\362'; break; // case 'u' : m_t << '\371'; break; // default: m_t << '?'; break; // } //} // //void RTFGenerator::writeCirc(char c) //{ // switch(c) // { // case 'A' : m_t << '\302'; break; // case 'E' : m_t << '\312'; break; // case 'I' : m_t << '\316'; break; // case 'O' : m_t << '\324'; break; // case 'U' : m_t << '\333'; break; // case 'a' : m_t << '\342'; break; // case 'e' : m_t << '\352'; break; // case 'i' : m_t << '\356'; break; // case 'o' : m_t << '\364'; break; // case 'u' : m_t << '\373'; break; // default: m_t << '?'; break; // } //} // //void RTFGenerator::writeTilde(char c) //{ // switch(c) // { // case 'A' : m_t << '\303'; break; // case 'N' : m_t << '\321'; break; // case 'O' : m_t << '\325'; break; // case 'a' : m_t << '\343'; break; // case 'n' : m_t << '\361'; break; // case 'o' : m_t << '\365'; break; // default: m_t << '?'; break; // } //} // //void RTFGenerator::writeRing(char c) //{ // switch(c) // { // case 'A' : m_t << '\305'; break; // case 'a' : m_t << '\345'; break; // default: m_t << '?'; break; // } //} // //void RTFGenerator::writeCCedil(char c) //{ // switch(c) // { // case 'C' : m_t << '\307'; break; // case 'c' : m_t << '\347'; break; // default: m_t << '?'; break; // } //} // bool isLeadBytes(int c) { bool result; QCString codePage = theTranslator->trRTFansicp(); if (codePage == "932") // cp932 (Japanese Shift-JIS) { result = (0x81<=c && c<=0x9f) || (0xe0<=c && c<=0xfc); } else if (codePage == "936") // cp936 (Simplified Chinese GBK) { result = 0x81<=c && c<=0xFE; } else if (codePage == "949") // cp949 (Korean) { result = 0x81<=c && c<=0xFE; } else if (codePage == "950") // cp950 (Traditional Chinese Big5) { result = 0x81<=c && c<=0xFE; } else // for SBCS Codepages (cp1252,1251 etc...) { result = false; } return result; } // note: function is not reentrant! static void encodeForOutput(TextStream &t,const QCString &s) { if (s==0) return; QCString encoding; bool converted=FALSE; int l = (int)s.length(); static std::vector enc; if (l*4>(int)enc.size()) enc.resize(l*4); // worst case encoding.sprintf("CP%s",qPrint(theTranslator->trRTFansicp())); if (!encoding.isEmpty()) { // convert from UTF-8 back to the output encoding void *cd = portable_iconv_open(encoding.data(),"UTF-8"); if (cd!=(void *)(-1)) { size_t iLeft=l; size_t oLeft=enc.size(); const char *inputPtr = s.data(); char *outputPtr = &enc[0]; if (!portable_iconv(cd, &inputPtr, &iLeft, &outputPtr, &oLeft)) { enc.resize(enc.size()-(unsigned int)oLeft); converted=TRUE; } portable_iconv_close(cd); } } if (!converted) // if we did not convert anything, copy as is. { memcpy(enc.data(),s.data(),l); enc.resize(l); } uint i; bool multiByte = FALSE; for (i=0;i=0x80 || multiByte) { char esc[10]; sprintf(esc,"\\'%X",c); // escape sequence for SBCS and DBCS(1st&2nd bytes). t << esc; if (!multiByte) { multiByte = isLeadBytes(c); // It may be DBCS Codepages. } else { multiByte = FALSE; // end of Double Bytes Character. } } else { t << (char)c; } } } /** * VERY brittle routine inline RTF's included by other RTF's. * it is recursive and ugly. */ static bool preProcessFile(Dir &d,const QCString &infName, TextStream &t, bool bIncludeHeader=TRUE) { std::ifstream f(infName.str(),std::ifstream::in); if (!f.is_open()) { err("problems opening rtf file %s for reading\n",infName.data()); return false; } const int maxLineLength = 10240; static QCString lineBuf(maxLineLength); // scan until find end of header // this is EXTREEEEEEEMLY brittle. It works on OUR rtf // files because the first line before the body // ALWAYS contains "{\comment begin body}" std::string line; while (getline(f,line)) { line+='\n'; if (line.find("\\comment begin body")!=std::string::npos) break; if (bIncludeHeader) encodeForOutput(t,line.c_str()); } std::string prevLine; bool first=true; while (getline(f,line)) { line+='\n'; size_t pos; if ((pos=prevLine.find("INCLUDETEXT"))!=std::string::npos) { size_t startNamePos = prevLine.find('"',pos)+1; size_t endNamePos = prevLine.find('"',startNamePos); std::string fileName = prevLine.substr(startNamePos,endNamePos-startNamePos); DBG_RTF(m_t << "{\\comment begin include " << fileName << "}\n") if (!preProcessFile(d,fileName.c_str(),t,FALSE)) return FALSE; DBG_RTF(m_t << "{\\comment end include " << fileName << "}\n") } else if (!first) // no INCLUDETEXT on this line { encodeForOutput(t,prevLine.c_str()); } prevLine = line; first=false; } if (!bIncludeHeader) // skip final '}' in case we don't include headers { size_t pos = line.rfind('}'); if (pos==std::string::npos) { err("Strange, the last char was not a '}'\n"); pos = line.length(); } encodeForOutput(t,line.substr(0,pos).c_str()); } else { encodeForOutput(t,line.c_str()); } f.close(); // remove temporary file d.remove(infName.str()); return TRUE; } void RTFGenerator::startDotGraph() { DBG_RTF(m_t << "{\\comment (startDotGraph)}\n") } void RTFGenerator::endDotGraph(DotClassGraph &g) { newParagraph(); QCString fn = g.writeGraph(m_t,GOF_BITMAP,EOF_Rtf,dir(),fileName(),m_relPath,TRUE,FALSE); // display the file m_t << "{\n"; m_t << rtf_Style_Reset << "\n"; m_t << "\\par\\pard \\qc {\\field\\flddirty {\\*\\fldinst INCLUDEPICTURE \""; QCString imgExt = getDotImageExtension(); m_t << fn << "." << imgExt; m_t << "\" \\\\d \\\\*MERGEFORMAT}{\\fldrslt IMAGE}}\\par\n"; m_t << "}\n"; newParagraph(); DBG_RTF(m_t << "{\\comment (endDotGraph)}\n") } void RTFGenerator::startInclDepGraph() { DBG_RTF(m_t << "{\\comment (startInclDepGraph)}\n") } void RTFGenerator::endInclDepGraph(DotInclDepGraph &g) { newParagraph(); QCString fn = g.writeGraph(m_t,GOF_BITMAP,EOF_Rtf,dir(),fileName(),m_relPath,FALSE); // display the file m_t << "{\n"; m_t << rtf_Style_Reset << "\n"; m_t << "\\par\\pard \\qc {\\field\\flddirty {\\*\\fldinst INCLUDEPICTURE \""; QCString imgExt = getDotImageExtension(); m_t << fn << "." << imgExt; m_t << "\" \\\\d \\\\*MERGEFORMAT}{\\fldrslt IMAGE}}\\par\n"; m_t << "}\n"; DBG_RTF(m_t << "{\\comment (endInclDepGraph)}\n") } void RTFGenerator::startGroupCollaboration() { } void RTFGenerator::endGroupCollaboration(DotGroupCollaboration &) { } void RTFGenerator::startCallGraph() { DBG_RTF(m_t << "{\\comment (startCallGraph)}\n") } void RTFGenerator::endCallGraph(DotCallGraph &g) { newParagraph(); QCString fn = g.writeGraph(m_t,GOF_BITMAP,EOF_Rtf,dir(),fileName(),m_relPath,FALSE); // display the file m_t << "{\n"; m_t << rtf_Style_Reset << "\n"; m_t << "\\par\\pard \\qc {\\field\\flddirty {\\*\\fldinst INCLUDEPICTURE \""; QCString imgExt = getDotImageExtension(); m_t << fn << "." << imgExt; m_t << "\" \\\\d \\\\*MERGEFORMAT}{\\fldrslt IMAGE}}\\par\n"; m_t << "}\n"; DBG_RTF(m_t << "{\\comment (endCallGraph)}\n") } void RTFGenerator::startDirDepGraph() { DBG_RTF(m_t << "{\\comment (startDirDepGraph)}\n") } void RTFGenerator::endDirDepGraph(DotDirDeps &g) { newParagraph(); QCString fn = g.writeGraph(m_t,GOF_BITMAP,EOF_Rtf,dir(),fileName(),m_relPath,FALSE); // display the file m_t << "{\n"; m_t << rtf_Style_Reset << "\n"; m_t << "\\par\\pard \\qc {\\field\\flddirty {\\*\\fldinst INCLUDEPICTURE \""; QCString imgExt = getDotImageExtension(); m_t << fn << "." << imgExt; m_t << "\" \\\\d \\\\*MERGEFORMAT}{\\fldrslt IMAGE}}\\par\n"; m_t << "}\n"; DBG_RTF(m_t << "{\\comment (endDirDepGraph)}\n") } /** Tests the integrity of the result by counting brackets. * */ void testRTFOutput(const QCString &name) { int bcount=0; int line=1; int c; std::ifstream f(name.data(),std::ifstream::in); if (f.is_open()) { while ((c=f.get())!=-1) { if (c=='\\') // escape char { c=f.get(); if (c==-1) break; } else if (c=='{') // open bracket { bcount++; } else if (c=='}') // close bracket { bcount--; if (bcount<0) { goto err; break; } } else if (c=='\n') // newline { line++; } } } if (bcount==0) return; // file is OK. err: err("RTF integrity test failed at line %d of %s due to a bracket mismatch.\n" " Please try to create a small code example that produces this error \n" " and send that to doxygen@gmail.com.\n",line,qPrint(name)); } /** * This is an API to a VERY brittle RTF preprocessor that combines nested * RTF files. This version replaces the infile with the new file */ bool RTFGenerator::preProcessFileInplace(const QCString &path,const QCString &name) { Dir d(path.str()); // store the original directory if (!d.exists()) { err("Output dir %s does not exist!\n",qPrint(path)); return FALSE; } std::string oldDir = Dir::currentDirPath(); // go to the html output directory (i.e. path) Dir::setCurrent(d.absPath()); Dir thisDir; QCString combinedName = path+"/combined.rtf"; QCString mainRTFName = path+"/"+name; std::ofstream f(combinedName.str(),std::ofstream::out | std::ofstream::binary); if (!f.is_open()) { err("Failed to open %s for writing!\n",combinedName.data()); Dir::setCurrent(oldDir); return FALSE; } TextStream outt(&f); if (!preProcessFile(thisDir,mainRTFName,outt)) { // it failed, remove the temp file outt.flush(); f.close(); thisDir.remove(combinedName.str()); Dir::setCurrent(oldDir); return FALSE; } // everything worked, move the files outt.flush(); f.close(); thisDir.remove(mainRTFName.str()); thisDir.rename(combinedName.str(),mainRTFName.str()); testRTFOutput(mainRTFName); Dir::setCurrent(oldDir); return TRUE; } void RTFGenerator::startMemberGroupHeader(bool hasHeader) { DBG_RTF(m_t << "{\\comment startMemberGroupHeader}\n") m_t << "{\n"; if (hasHeader) incrementIndentLevel(); m_t << rtf_Style_Reset << rtf_Style["GroupHeader"].reference(); } void RTFGenerator::endMemberGroupHeader() { DBG_RTF(m_t << "{\\comment endMemberGroupHeader}\n") newParagraph(); m_t << rtf_Style_Reset << rtf_CList_DepthStyle(); } void RTFGenerator::startMemberGroupDocs() { DBG_RTF(m_t << "{\\comment startMemberGroupDocs}\n") startEmphasis(); } void RTFGenerator::endMemberGroupDocs() { DBG_RTF(m_t << "{\\comment endMemberGroupDocs}\n") endEmphasis(); newParagraph(); } void RTFGenerator::startMemberGroup() { DBG_RTF(m_t << "{\\comment startMemberGroup}\n") m_t << rtf_Style_Reset << rtf_BList_DepthStyle() << "\n"; } void RTFGenerator::endMemberGroup(bool hasHeader) { DBG_RTF(m_t << "{\\comment endMemberGroup}\n") if (hasHeader) decrementIndentLevel(); m_t << "}"; } void RTFGenerator::startExamples() { DBG_RTF(m_t << "{\\comment (startExamples)}\n") m_t << "{"; // ends at endDescList m_t << "{"; // ends at endDescTitle startBold(); newParagraph(); docify(theTranslator->trExamples()); endBold(); m_t << "}"; newParagraph(); incrementIndentLevel(); m_t << rtf_Style_Reset << rtf_DList_DepthStyle(); } void RTFGenerator::endExamples() { DBG_RTF(m_t << "{\\comment (endExamples)}\n") m_omitParagraph = FALSE; newParagraph(); decrementIndentLevel(); m_omitParagraph = TRUE; m_t << "}"; } void RTFGenerator::startParamList(ParamListTypes,const QCString &title) { DBG_RTF(m_t << "{\\comment (startParamList)}\n") m_t << "{"; // ends at endParamList m_t << "{"; // ends at endDescTitle startBold(); newParagraph(); docify(title); endBold(); m_t << "}"; newParagraph(); incrementIndentLevel(); m_t << rtf_Style_Reset << rtf_DList_DepthStyle(); } void RTFGenerator::endParamList() { DBG_RTF(m_t << "{\\comment (endParamList)}\n") newParagraph(); decrementIndentLevel(); m_omitParagraph = TRUE; m_t << "}"; } void RTFGenerator::startParameterType(bool first,const QCString &key) { DBG_RTF(m_t << "{\\comment (startParameterType)}\n") if (!first && !key.isEmpty()) { m_t << " " << key << " "; } } void RTFGenerator::endParameterType() { DBG_RTF(m_t << "{\\comment (endParameterType)}\n") m_t << " "; } void RTFGenerator::exceptionEntry(const QCString &prefix,bool closeBracket) { DBG_RTF(m_t << "{\\comment (exceptionEntry)}\n") if (!prefix.isEmpty()) { m_t << " " << prefix << "("; } else if (closeBracket) { m_t << ")"; } m_t << " "; } void RTFGenerator::writeDoc(DocNode *n,const Definition *ctx,const MemberDef *,int) { RTFDocVisitor *visitor = new RTFDocVisitor(m_t,*this,ctx?ctx->getDefFileExtension():QCString("")); n->accept(visitor); delete visitor; m_omitParagraph = TRUE; } void RTFGenerator::rtfwriteRuler_doubleline() { DBG_RTF(m_t << "{\\comment (rtfwriteRuler_doubleline)}\n") m_t << "{\\pard\\widctlpar\\brdrb\\brdrdb\\brdrw15\\brsp20 \\adjustright \\par}\n"; } void RTFGenerator::rtfwriteRuler_emboss() { DBG_RTF(m_t << "{\\comment (rtfwriteRuler_emboss)}\n") m_t << "{\\pard\\widctlpar\\brdrb\\brdremboss\\brdrw15\\brsp20 \\adjustright \\par}\n"; } void RTFGenerator::rtfwriteRuler_thick() { DBG_RTF(m_t << "{\\comment (rtfwriteRuler_thick)}\n") m_t << "{\\pard\\widctlpar\\brdrb\\brdrs\\brdrw75\\brsp20 \\adjustright \\par}\n"; } void RTFGenerator::rtfwriteRuler_thin() { DBG_RTF(m_t << "{\\comment (rtfwriteRuler_thin)}\n") m_t << "{\\pard\\widctlpar\\brdrb\\brdrs\\brdrw5\\brsp20 \\adjustright \\par}\n"; } #if 0 void RTFGenerator::postProcess(QByteArray &a) { QByteArray enc(a.size()*4); // worst case int off=0; uint i; bool mbFlag=FALSE; for (i=0;i 0x80 as multibyte characters, except when they // are control characters if (c>0x80 || (mbFlag && c!='\\' && c!='{' && c!='}')) { char s[10]; sprintf(s,"\\'%X",c); qstrcpy(enc.data()+off,s); off+=qstrlen(s); mbFlag=c>0x80; } else { enc.at(off++)=c; } } enc.resize(off); a = enc; } #endif void RTFGenerator::startConstraintList(const QCString &header) { DBG_RTF(m_t << "{\\comment (startConstraintList)}\n") m_t << "{"; // ends at endConstraintList m_t << "{"; startBold(); newParagraph(); docify(header); endBold(); m_t << "}"; newParagraph(); incrementIndentLevel(); m_t << rtf_Style_Reset << rtf_DList_DepthStyle(); } void RTFGenerator::startConstraintParam() { DBG_RTF(m_t << "{\\comment (startConstraintParam)}\n") startEmphasis(); } void RTFGenerator::endConstraintParam() { DBG_RTF(m_t << "{\\comment (endConstraintParam)}\n") endEmphasis(); m_t << " : "; } void RTFGenerator::startConstraintType() { DBG_RTF(m_t << "{\\comment (startConstraintType)}\n") startEmphasis(); } void RTFGenerator::endConstraintType() { DBG_RTF(m_t << "{\\comment (endConstraintType)}\n") endEmphasis(); m_t << " "; } void RTFGenerator::startConstraintDocs() { DBG_RTF(m_t << "{\\comment (startConstraintDocs)}\n") } void RTFGenerator::endConstraintDocs() { DBG_RTF(m_t << "{\\comment (endConstraintDocs)}\n") newParagraph(); } void RTFGenerator::endConstraintList() { DBG_RTF(m_t << "{\\comment (endConstraintList)}\n") newParagraph(); decrementIndentLevel(); m_omitParagraph = TRUE; m_t << "}"; } void RTFGenerator::startIndexListItem() { DBG_RTF(m_t << "{\\comment (startIndexListItem)}\n") } void RTFGenerator::endIndexListItem() { DBG_RTF(m_t << "{\\comment (endIndexListItem)}\n") m_t << "\\par\n"; } void RTFGenerator::startInlineHeader() { DBG_RTF(m_t << "{\\comment (startInlineHeader)}\n") m_t << "{\n"; m_t << rtf_Style_Reset << rtf_Style["Heading5"].reference(); startBold(); } void RTFGenerator::endInlineHeader() { DBG_RTF(m_t << "{\\comment (endInlineHeader)}\n") endBold(); m_t << "\\par"; m_t << "}\n"; } void RTFGenerator::startMemberDocSimple(bool isEnum) { DBG_RTF(m_t << "{\\comment (startMemberDocSimple)}\n") m_t << "{\\par\n"; m_t << "{" << rtf_Style["Heading5"].reference() << "\n"; if (isEnum) { m_t << theTranslator->trEnumerationValues(); } else { m_t << theTranslator->trCompoundMembers(); } m_t << ":\\par}\n"; m_t << rtf_Style_Reset << rtf_DList_DepthStyle(); m_t << "\\trowd \\trgaph108\\trleft426\\tblind426" "\\trbrdrt\\brdrs\\brdrw10\\brdrcf15 " "\\trbrdrl\\brdrs\\brdrw10\\brdrcf15 " "\\trbrdrb\\brdrs\\brdrw10\\brdrcf15 " "\\trbrdrr\\brdrs\\brdrw10\\brdrcf15 " "\\trbrdrh\\brdrs\\brdrw10\\brdrcf15 " "\\trbrdrv\\brdrs\\brdrw10\\brdrcf15 \n"; int i,n=3,columnPos[3] = { 25, 50, 100 }; if (isEnum) { columnPos[0]=30; columnPos[1]=100; n=2; } for (i=0;i