📄 rtfgen.cpp
字号:
ASSERT(reference != 0); size_t size = 1 + strlen(reference); memcpy(this->reference = new char[size], reference, size); ASSERT(definition != 0); size = 1 + strlen(definition); memcpy(this->definition = new char[size], definition, size);}StyleData::~StyleData(){ delete[] reference; delete[] definition;}bool StyleData::setStyle(const char* s, const char* styleName){ static const QRegExp subgroup("^{[^}]*}\\s*"); static const QRegExp any_clause("^\\\\[a-z][a-z0-9-]*\\s*"); int len; int start = s_clause.match(s, 0, &len); if (start < 0) { err("Style sheet '%s' contains no '\\s' clause.\n{%s}\n", styleName, s); return FALSE; } s += start; index = (int)atol(s + 2); ASSERT(index > 0); // search for the end of pure formatting codes const char* end = s + len; bool haveNewDefinition = TRUE; for(;;) { if (*end == '{') { // subgroups are used for \\additive if (0 != subgroup.match(end, 0, &len)) break; else end += len; } else if (*end == '\\') { if (0 == strncmp(end, "\\snext", 6)) break; if (0 == strncmp(end, "\\sbasedon", 9)) break; if (0 != any_clause.match(end, 0, &len)) break; end += len; } else if (*end == 0) { // no style-definition part, keep default value haveNewDefinition = FALSE; break; } else // plain name without leading \\snext break; } delete[] reference; reference = new char[len + 1]; memcpy(reference, s, len); reference[len] = 0; if (haveNewDefinition) { delete[] definition; size_t size = 1 + strlen(end); definition = new char[size]; memcpy(definition, end, size); } return TRUE;}static void loadStylesheet(const char *name, QDict<StyleData>& dict){ QFile file(name); if (!file.open(IO_ReadOnly)) { err("Can't open RTF style sheet file %s. Using defaults.\n",name); return; } msg("Loading RTF style sheet %s...\n",name); static const QRegExp separator("[ \t]*=[ \t]*"); uint lineNr=1; QTextStream t(&file);#if QT_VERSION >= 200 t.setEncoding(QTextStream::Latin1);#endif while (!t.eof()) { QCString s(4096); // string buffer of max line length s = t.readLine().stripWhiteSpace(); if (s.length()==0 || s.at(0)=='#') continue; // skip blanks & comments int sepLength; int sepStart = separator.match(s,0,&sepLength); if (sepStart<=0) // no valid assignment statement { warn(name,lineNr,"Assignment of style sheet name expected!\n"); continue; } QCString key=s.left(sepStart); if (dict[key]==0) // not a valid style sheet name { warn(name,lineNr,"Invalid style sheet name %s ignored.\n",key.data()); continue; } StyleData* styleData = dict.find(key); if (styleData == 0) { warn(name,lineNr,"Unknown style sheet name %s ignored.\n",key.data()); continue; } s+=" "; // add command separator styleData->setStyle(s.data() + sepStart + sepLength, key.data()); lineNr++; }}static QDict<StyleData> Rtf_Style(257);void RTFGenerator::writeExtensionsFile(QFile &file){ QTextStream t(&file); t << "# Generated by doxygen " << versionString << "\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";}static void loadExtensions(const char *name){ QFile file(name); if (!file.open(IO_ReadOnly)) { err("Can't open RTF extensions file %s. Using defaults.\n",name); return; } msg("Loading RTF extensions %s...\n",name); static const QRegExp separator("[ \t]*=[ \t]*"); uint lineNr=1; QTextStream t(&file);#if QT_VERSION >= 200 t.setEncoding(QTextStream::Latin1);#endif while (!t.eof()) { QCString s(4096); // string buffer of max line length s = t.readLine().stripWhiteSpace(); if (s.length()==0 || s.at(0)=='#') continue; // skip blanks & comments int sepLength; int sepStart = separator.match(s,0,&sepLength); if (sepStart<=0) // no valid assignment statement { warn(name,lineNr,"Assignment of extension field expected!\n"); continue; } QCString key=s.left(sepStart); QCString data=s.data() + sepStart + sepLength; if (key == "Title") title = data.data(); if (key == "Subject") subject = data.data(); if (key == "Comments") comments = data.data(); if (key == "Company") company = data.data(); if (key == "LogoFilename") logoFilename = data.data(); if (key == "Author") author = data.data(); if (key == "Manager") manager = data.data(); if (key == "DocumentType") documentType = data.data(); if (key == "DocumentId") documentId = data.data(); if (key == "Keywords") keywords = data.data(); lineNr++; }}void RTFGenerator::init(){ QCString dir=Config_getString("RTF_OUTPUT"); QDir d(dir); if (!d.exists() && !d.mkdir(dir)) { err("Could not create output directory %s\n",dir.data()); exit(1); } Rtf_Style.setAutoDelete(TRUE); // first duplicate strings of Rtf_Style_Default const struct Rtf_Style_Default* def = Rtf_Style_Default; while(def->reference != 0) { if (def->definition == 0) err("Internal error: Rtf_Style_Default[%s] has no definition.\n", def->name); StyleData* styleData = new StyleData(def->reference, def->definition); Rtf_Style.insert(def->name, styleData); 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); }}static QCString makeIndexName(const char *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 */ t <<"{\\rtf1\\ansi\\ansicpg" << theTranslator->trRTFansicp(); t <<"\\uc1 \\deff0\\deflang1033\\deflangfe1033\n"; DBG_RTF(t <<"{\\comment Begining font list}\n") t <<"{\\fonttbl "; t <<"{\\f0\\froman\\fcharset" << theTranslator->trRTFCharSet(); t <<"\\fprq2{\\*\\panose 02020603050405020304}Times New Roman;}\n"; t <<"{\\f1\\fswiss\\fcharset" << theTranslator->trRTFCharSet(); t <<"\\fprq2{\\*\\panose 020b0604020202020204}Arial;}\n"; t <<"{\\f2\\fmodern\\fcharset" << theTranslator->trRTFCharSet(); t <<"\\fprq1{\\*\\panose 02070309020205020404}Courier New;}\n"; t <<"{\\f3\\froman\\fcharset2\\fprq2{\\*\\panose 05050102010706020507}Symbol;}\n"; t <<"}\n"; DBG_RTF(t <<"{\\comment begin colors}\n") t <<"{\\colortbl;"; t <<"\\red0\\green0\\blue0;"; t <<"\\red0\\green0\\blue255;"; t <<"\\red0\\green255\\blue255;"; t <<"\\red0\\green255\\blue0;"; t <<"\\red255\\green0\\blue255;"; t <<"\\red255\\green0\\blue0;"; t <<"\\red255\\green255\\blue0;"; t <<"\\red255\\green255\\blue255;"; t <<"\\red0\\green0\\blue128;"; t <<"\\red0\\green128\\blue128;"; t <<"\\red0\\green128\\blue0;"; t <<"\\red128\\green0\\blue128;"; t <<"\\red128\\green0\\blue0;"; t <<"\\red128\\green128\\blue0;"; t <<"\\red128\\green128\\blue128;"; t <<"\\red192\\green192\\blue192;}" << endl; DBG_RTF(t <<"{\\comment Beginning style list}\n") t <<"{\\stylesheet\n"; t <<"{\\widctlpar\\adjustright \\fs20\\cgrid \\snext0 Normal;}\n"; // sort styles ascending by \s-number via an intermediate QArray QArray<const StyleData*> array(128); array.fill(0); QDictIterator<StyleData> iter(Rtf_Style); const StyleData* style; for(; (style = iter.current()); ++iter) { unsigned index = style->index; unsigned size = array.size(); if (index >= size) { // +1 to add at least one element, then align up to multiple of 8 array.resize((index + 1 + 7) & ~7); array.fill(0, size); ASSERT(index < array.size()); } if (array.at(index) != 0) { QCString key(convertToQCString(iter.currentKey())); msg("Style '%s' redefines \\s%d.\n", key.data(), index); } array.at(index) = style; } // write array elements unsigned size = array.size(); for(unsigned i = 0; i < size; i++) { const StyleData* style = array.at(i); if (style != 0) t <<"{" << style->reference << style->definition << ";}\n"; } t <<"}" << endl; // this comment is needed for postprocessing! t <<"{\\comment begin body}" << endl;}void RTFGenerator::beginRTFChapter(){ t <<"\n"; DBG_RTF(t << "{\\comment Begin Chapter}\n") t << Rtf_Style_Reset; // if we are compact, no extra page breaks... if (Config_getBool("COMPACT_RTF")) { // t <<"\\sect\\sectd\\sbknone\n"; t <<"\\sect\\sbknone\n"; RtfwriteRuler_thick(); } else t <<"\\sect\\sbkpage\n"; //t <<"\\sect\\sectd\\sbkpage\n"; t << Rtf_Style["Heading1"]->reference << "\n";}void RTFGenerator::beginRTFSection(){ t <<"\n"; DBG_RTF(t << "{\\comment Begin Section}\n") t << Rtf_Style_Reset; // if we are compact, no extra page breaks... if (Config_getBool("COMPACT_RTF")) { // t <<"\\sect\\sectd\\sbknone\n"; t <<"\\sect\\sbknone\n"; RtfwriteRuler_emboss(); } else t <<"\\sect\\sbkpage\n"; //t <<"\\sect\\sectd\\sbkpage\n"; t << Rtf_Style["Heading2"]->reference << "\n";}void RTFGenerator::startFile(const char *name,const char *, const char *, bool ){ QCString fileName=name; if (fileName.right(4)!=".rtf" ) fileName+=".rtf"; startPlainFile(fileName); beginRTFDocument();}void RTFGenerator::endFile(){ DBG_RTF(t << "{\\comment endFile}\n") t << "}"; endPlainFile();}void RTFGenerator::startProjectNumber(){ t << " ";}void RTFGenerator::endProjectNumber() {}void RTFGenerator::startIndexSection(IndexSections is){ //QCString paperName; m_listLevel = 0; switch (is) { case isTitlePageStart: // basic RTFstart // get readyfor author etc t << "{\\info \n"; t << "{\\title {\\comment "; break; case isTitlePageAuthor: t << "}\n"; if (subject) t << "{\\subject " << subject << "}\n"; if (comments) t << "{\\comment " << comments << "}\n"; if (company) t << "{\\company " << company << "}\n"; if (author) t << "{\\author " << author << "}\n"; if (manager) t << "{\\manager " << manager << "}\n"; if (documentType) t << "{\\category " << documentType << "}\n"; if (keywords) t << "{\\keywords " << keywords << "}\n"; t << "{\\comment "; break; case isMainPage: //Introduction beginRTFChapter(); break; case isPackageIndex: //Package Index beginRTFChapter(); break; case isModuleIndex: //Module Index beginRTFChapter(); break; case isNamespaceIndex: //Namespace Index beginRTFChapter(); break; case isClassHierarchyIndex: //Hierarchical Index DBG_RTF(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 isPackageDocumentation: { //Package Documentation PackageSDict::Iterator pdi(Doxygen::packageDict); PackageDef *pd=pdi.toFirst(); bool found=FALSE; while (pd && !found)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -