summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/classdef.cpp4
-rw-r--r--src/commentscan.h13
-rw-r--r--src/commentscan.l52
-rw-r--r--src/config.xml13
-rw-r--r--src/debug.cpp1
-rw-r--r--src/debug.h3
-rw-r--r--src/docbookvisitor.cpp4
-rw-r--r--src/docparser.cpp2
-rw-r--r--src/doxygen.cpp5
-rw-r--r--src/fortranscanner.l7
-rw-r--r--src/growbuf.h10
-rw-r--r--src/htmldocvisitor.cpp118
-rw-r--r--src/latexdocvisitor.cpp6
-rw-r--r--src/markdown.cpp9
-rw-r--r--src/memberdef.cpp19
-rw-r--r--src/plantuml.cpp398
-rw-r--r--src/plantuml.h65
-rw-r--r--src/pyscanner.l5
-rw-r--r--src/rtfdocvisitor.cpp4
-rw-r--r--src/scanner.l19
-rw-r--r--src/tclscanner.l19
-rw-r--r--src/util.cpp32
-rw-r--r--src/util.h2
-rw-r--r--src/vhdldocgen.cpp4
-rw-r--r--src/vhdljjparser.cpp7
-rw-r--r--src/xmldocvisitor.cpp6
26 files changed, 624 insertions, 203 deletions
diff --git a/src/classdef.cpp b/src/classdef.cpp
index e9d39d5..a48df76 100644
--- a/src/classdef.cpp
+++ b/src/classdef.cpp
@@ -620,6 +620,10 @@ void ClassDef::internalInsertMember(MemberDef *md,
{
addMemberToList(MemberListType_relatedMembers,md,FALSE);
}
+ else if (md->isFunction() && md->protection()==Private && md->virtualness()!=Normal && Config_getBool(EXTRACT_PRIV_VIRTUAL))
+ {
+ addMemberToList(MemberListType_functionMembers,md,FALSE);
+ }
else
{
switch (md->memberType())
diff --git a/src/commentscan.h b/src/commentscan.h
index d324969..75cd99f 100644
--- a/src/commentscan.h
+++ b/src/commentscan.h
@@ -24,6 +24,19 @@ class ParserInterface;
/** @file
* @brief Interface for the comment block parser */
+/** Invokes the comment block parser with the request to preprocess a
+ * single comment block.
+ * @param[in] comment A string representing the actual comment block.
+ * Note that leading *'s are already stripped from the comment block.
+ * @param[in] fileName The name of the file in which the comment is found.
+ * Mainly used for producing warnings.
+ * @param[in] lineNr The line number at which the comment block was found.
+ * @returns The prepocessed comment block
+ */
+QCString preprocessCommentBlock(const QCString &comment,
+ const QCString &fileName,
+ int lineNr);
+
/** Invokes the comment block parser with the request to parse a
* single comment block.
* @param[in] parser The language parse that invoked this function.
diff --git a/src/commentscan.l b/src/commentscan.l
index 235cd7c..7fab755 100644
--- a/src/commentscan.l
+++ b/src/commentscan.l
@@ -277,6 +277,8 @@ static DocCmdMap docCmdMap[] =
{ "verbinclude", 0, FALSE },
{ "version", 0, TRUE },
{ "warning", 0, TRUE },
+ { "snippet", 0, TRUE },
+ { "snippetlineno", 0, TRUE },
{ 0, 0, FALSE }
};
@@ -1191,6 +1193,7 @@ RCSTAG "$"{ID}":"[^\n$]+"$"
}
}
<Comment>{B}*{CMD}"f{"[^}\n]+"}"("{"?) { // start of a formula with custom environment
+ setOutput(OutputDoc);
formulaText="\\begin";
formulaEnv=QString(yytext).stripWhiteSpace().data()+2;
if (formulaEnv.at(formulaEnv.length()-1)=='{')
@@ -1208,6 +1211,7 @@ RCSTAG "$"{ID}":"[^\n$]+"$"
BEGIN(ReadFormulaShort);
}
<Comment>{B}*{CMD}"f[" { // start of a block formula
+ setOutput(OutputDoc);
formulaText="\\[";
formulaNewLines=0;
BEGIN(ReadFormulaLong);
@@ -3074,6 +3078,33 @@ static void checkFormula()
//----------------------------------------------------------------------------
+QCString preprocessCommentBlock(const QCString &comment,
+ const QCString &fileName,
+ int lineNr)
+{
+ if (!comment.isEmpty() && Doxygen::markdownSupport)
+ {
+ QCString result = processMarkdown(fileName,lineNr,0,comment);
+ const char *p = result.data();
+ if (p)
+ {
+ while (*p==' ') p++; // skip over spaces
+ while (*p=='\n') p++; // skip over newlines
+ if (qstrncmp(p,"<br>",4)==0) p+=4; // skip over <br>
+ }
+ if (p>result.data())
+ {
+ // strip part of the input
+ result = result.mid(p-result.data());
+ }
+ return result;
+ }
+ else
+ {
+ return comment;
+ }
+}
+
bool parseCommentBlock(/* in */ ParserInterface *parser,
/* in */ Entry *curEntry,
/* in */ const QCString &comment,
@@ -3096,26 +3127,7 @@ bool parseCommentBlock(/* in */ ParserInterface *parser,
langParser = parser;
current = curEntry;
if (comment.isEmpty()) return FALSE; // avoid empty strings
- if (Doxygen::markdownSupport)
- {
- inputString = processMarkdown(fileName,lineNr,NULL,comment);
- const char *p = inputString.data();
- if (p)
- {
- while (*p==' ') p++; // skip over spaces
- while (*p=='\n') p++; // skip over newlines
- if (qstrncmp(p,"<br>",4)==0) p+=4; // skip over <br>
- }
- if (p>inputString.data())
- {
- // strip part of the input
- inputString = inputString.mid(p-inputString.data());
- }
- }
- else
- {
- inputString = comment;
- }
+ inputString = comment;
inputString.append(" ");
inputPosition = position;
yyLineNr = lineNr;
diff --git a/src/config.xml b/src/config.xml
index fdc562d..a62040b 100644
--- a/src/config.xml
+++ b/src/config.xml
@@ -838,6 +838,14 @@ Go to the <a href="commands.html">next</a> section or return to the
]]>
</docs>
</option>
+ <option type='bool' id='EXTRACT_PRIV_VIRTUAL' defval='0'>
+ <docs>
+<![CDATA[
+ If the \c EXTRACT_PRIV_VIRTUAL tag is set to \c YES, documented private
+ virtual methods of a class will be included in the documentation.
+]]>
+ </docs>
+ </option>
<option type='bool' id='EXTRACT_PACKAGE' defval='0'>
<docs>
<![CDATA[
@@ -2594,11 +2602,12 @@ EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
]]>
</docs>
</option>
- <option type='string' id='LATEX_MAKEINDEX_CMD' defval='\makeindex' depends='GENERATE_LATEX'>
+ <option type='string' id='LATEX_MAKEINDEX_CMD' defval='makeindex' depends='GENERATE_LATEX'>
<docs>
<![CDATA[
The \c LATEX_MAKEINDEX_CMD tag can be used to specify the command name to
- generate index for \f$\mbox{\LaTeX}\f$.
+ generate index for \f$\mbox{\LaTeX}\f$. In case there is no backslash (`\`) as first character it
+ will be automatically added in the \f$\mbox{\LaTeX}\f$ code.
@note This tag is used in the generated output file (`.tex`).
\sa \ref cfg_makeindex_cmd_name "MAKEINDEX_CMD_NAME" for the part in the `Makefile` / `make.bat`.
diff --git a/src/debug.cpp b/src/debug.cpp
index c81a1af..2f343ac 100644
--- a/src/debug.cpp
+++ b/src/debug.cpp
@@ -48,6 +48,7 @@ static LabelMap s_labels[] =
{ "markdown", Debug::Markdown },
{ "filteroutput", Debug::FilterOutput },
{ "lex", Debug::Lex },
+ { "plantuml", Debug::Plantuml },
{ 0, (Debug::DebugMask)0 }
};
diff --git a/src/debug.h b/src/debug.h
index 8a28c7a..9a2070c 100644
--- a/src/debug.h
+++ b/src/debug.h
@@ -37,7 +37,8 @@ class Debug
ExtCmd = 0x00000400,
Markdown = 0x00000800,
FilterOutput = 0x00001000,
- Lex = 0x00002000
+ Lex = 0x00002000,
+ Plantuml = 0x00004000
};
static void print(DebugMask mask,int prio,const char *fmt,...);
static int setFlag(const char *label);
diff --git a/src/docbookvisitor.cpp b/src/docbookvisitor.cpp
index 99df99c..3988390 100644
--- a/src/docbookvisitor.cpp
+++ b/src/docbookvisitor.cpp
@@ -353,7 +353,7 @@ DB_VIS_C
case DocVerbatim::PlantUML:
{
static QCString docbookOutput = Config_getString(DOCBOOK_OUTPUT);
- QCString baseName = writePlantUMLSource(docbookOutput,s->exampleFile(),s->text());
+ QCString baseName = PlantumlManager::instance()->writePlantUMLSource(docbookOutput,s->exampleFile(),s->text(),PlantumlManager::PUML_BITMAP);
QCString shortName = baseName;
int i;
if ((i=shortName.findRev('/'))!=-1)
@@ -1642,7 +1642,7 @@ DB_VIS_C
shortName=shortName.right(shortName.length()-i-1);
}
QCString outDir = Config_getString(DOCBOOK_OUTPUT);
- generatePlantUMLOutput(baseName,outDir,PUML_BITMAP);
+ PlantumlManager::instance()->generatePlantUMLOutput(baseName,outDir,PlantumlManager::PUML_BITMAP);
visitPreStart(m_t, s->children(), s->hasCaption(), s->relPath() + shortName + ".png", s->width(),s->height());
visitCaption(s->children());
visitPostEnd(m_t, s->hasCaption());
diff --git a/src/docparser.cpp b/src/docparser.cpp
index c91dcde..20ee1f0 100644
--- a/src/docparser.cpp
+++ b/src/docparser.cpp
@@ -422,7 +422,7 @@ static void checkArgumentName(const QCString &name,bool isParam)
argName=argName.stripWhiteSpace();
//printf("argName=`%s' aName=%s\n",argName.data(),aName.data());
if (argName.right(3)=="...") argName=argName.left(argName.length()-3);
- if (aName==argName)
+ if (aName==argName && isParam)
{
g_paramsFound.insert(aName,(void *)(0x8));
found=TRUE;
diff --git a/src/doxygen.cpp b/src/doxygen.cpp
index 2d55ae6..26f7637 100644
--- a/src/doxygen.cpp
+++ b/src/doxygen.cpp
@@ -104,6 +104,7 @@
#include "context.h"
#include "fileparser.h"
#include "emoji.h"
+#include "plantuml.h"
// provided by the generated file resources.cpp
extern void initResources();
@@ -11924,6 +11925,10 @@ void generateOutput()
g_s.end();
}
+ g_s.begin("Running plantuml with JAVA...\n");
+ PlantumlManager::instance()->run();
+ g_s.end();
+
if (Config_getBool(HAVE_DOT))
{
g_s.begin("Running dot...\n");
diff --git a/src/fortranscanner.l b/src/fortranscanner.l
index 5f10669..1f0c356 100644
--- a/src/fortranscanner.l
+++ b/src/fortranscanner.l
@@ -2411,9 +2411,7 @@ static void startCommentBlock(bool brief)
static void handleCommentBlock(const QCString &doc,bool brief)
{
- bool needsEntry = FALSE;
static bool hideInBodyDocs = Config_getBool(HIDE_IN_BODY_DOCS);
- int position=0;
if (docBlockInBody && hideInBodyDocs)
{
docBlockInBody = FALSE;
@@ -2421,10 +2419,13 @@ static void handleCommentBlock(const QCString &doc,bool brief)
}
DBG_CTX((stderr,"call parseCommentBlock [%s]\n",doc.data()));
int lineNr = brief ? current->briefLine : current->docLine;
+ int position=0;
+ bool needsEntry = FALSE;
+ QCString processedDoc = preprocessCommentBlock(doc,yyFileName,lineNr);
while (parseCommentBlock(
g_thisParser,
docBlockInBody ? subrCurrent.getFirst() : current,
- doc, // text
+ processedDoc, // text
yyFileName, // file
lineNr,
docBlockInBody ? FALSE : brief,
diff --git a/src/growbuf.h b/src/growbuf.h
index bc8e4b5..4c49dce 100644
--- a/src/growbuf.h
+++ b/src/growbuf.h
@@ -11,11 +11,21 @@ class GrowBuf
{
public:
GrowBuf() : str(0), pos(0), len(0) {}
+ GrowBuf(int initialSize) : pos(0), len(initialSize) { str=(char*)malloc(len); }
~GrowBuf() { free(str); str=0; pos=0; len=0; }
void clear() { pos=0; }
void addChar(char c) { if (pos>=len) { len+=GROW_AMOUNT; str = (char*)realloc(str,len); }
str[pos++]=c;
}
+ void addStr(const QCString &s) {
+ if (!s.isEmpty())
+ {
+ int l=s.length();
+ if (pos+l>=len) { len+=l+GROW_AMOUNT; str = (char*)realloc(str,len); }
+ strcpy(&str[pos],s.data());
+ pos+=l;
+ }
+ }
void addStr(const char *s) {
if (s)
{
diff --git a/src/htmldocvisitor.cpp b/src/htmldocvisitor.cpp
index f89f79e..25166bc 100644
--- a/src/htmldocvisitor.cpp
+++ b/src/htmldocvisitor.cpp
@@ -126,7 +126,6 @@ static bool mustBeOutsideParagraph(DocNode *n)
case DocNode::Kind_Internal:
/* <div> */
case DocNode::Kind_Include:
- case DocNode::Kind_Image:
case DocNode::Kind_SecRefList:
/* <hr> */
case DocNode::Kind_HorRuler:
@@ -152,6 +151,8 @@ static bool mustBeOutsideParagraph(DocNode *n)
((DocStyleChange*)n)->style()==DocStyleChange::Center;
case DocNode::Kind_Formula:
return !((DocFormula*)n)->isInline();
+ case DocNode::Kind_Image:
+ return !((DocImage*)n)->isInlineImage();
default:
break;
}
@@ -210,29 +211,31 @@ static bool isInvisibleNode(DocNode *node)
;
}
-static QString htmlAttribsToString(const HtmlAttribList &attribs, bool img_tag = FALSE)
+static QCString htmlAttribsToString(const HtmlAttribList &attribs, QCString *pAltValue = 0)
{
- QString result;
+ QCString result;
HtmlAttribListIterator li(attribs);
HtmlAttrib *att;
- bool alt_set = FALSE;
-
for (li.toFirst();(att=li.current());++li)
{
if (!att->value.isEmpty()) // ignore attribute without values as they
// are not XHTML compliant, with the exception
// of the alt attribute with the img tag
{
- result+=" ";
- result+=att->name;
- result+="=\""+convertToXML(att->value)+"\"";
- if (att->name == "alt") alt_set = TRUE;
+ if (att->name=="alt" && pAltValue) // optionally return the value of alt separately
+ // need to convert <img> to <object> for SVG images,
+ // which do not support the alt attribute
+ {
+ *pAltValue = att->value;
+ }
+ else
+ {
+ result+=" ";
+ result+=att->name;
+ result+="=\""+convertToXML(att->value)+"\"";
+ }
}
}
- if (!alt_set && img_tag)
- {
- result+=" alt=\"\"";
- }
return result;
}
@@ -588,9 +591,14 @@ void HtmlDocVisitor::visit(DocVerbatim *s)
case DocVerbatim::PlantUML:
{
forceEndParagraph(s);
-
static QCString htmlOutput = Config_getString(HTML_OUTPUT);
- QCString baseName = writePlantUMLSource(htmlOutput,s->exampleFile(),s->text());
+ QCString imgExt = getDotImageExtension();
+ PlantumlManager::OutputFormat format = PlantumlManager::PUML_BITMAP; // default : PUML_BITMAP
+ if (imgExt=="svg")
+ {
+ format = PlantumlManager::PUML_SVG;
+ }
+ QCString baseName = PlantumlManager::instance()->writePlantUMLSource(htmlOutput,s->exampleFile(),s->text(),format);
m_t << "<div class=\"plantumlgraph\">" << endl;
writePlantUMLFile(baseName,s->relPath(),s->context());
visitPreCaption(m_t, s);
@@ -1205,6 +1213,10 @@ void HtmlDocVisitor::visitPre(DocPara *p)
void HtmlDocVisitor::visitPost(DocPara *p)
{
+
+ //printf("DocPara::visitPost: parent of kind %d ",
+ // p->parent() ? p->parent()->kind() : -1);
+
bool needsTag = FALSE;
if (p->parent())
{
@@ -1577,7 +1589,7 @@ void HtmlDocVisitor::visitPre(DocHRef *href)
else
{
QCString url = correctURL(href->url(),href->relPath());
- m_t << "<a href=\"" << convertToXML(url) << "\""
+ m_t << "<a href=\"" << convertToHtml(url) << "\""
<< htmlAttribsToString(href->attribs()) << ">";
}
}
@@ -1635,62 +1647,40 @@ void HtmlDocVisitor::visitPre(DocImage *img)
sizeAttribs+=" height=\""+img->height()+"\"";
}
// 16 cases: url.isEmpty() | typeSVG | inlineImage | img->hasCaption()
+ QCString alt;
+ QCString attrs = htmlAttribsToString(img->attribs(),&alt);
+ QCString src;
if (url.isEmpty())
{
- if (typeSVG)
+ src = img->relPath()+img->name();
+ }
+ else
+ {
+ src = correctURL(url,img->relPath());
+ }
+ if (typeSVG)
+ {
+ m_t << "<object type=\"image/svg+xml\" style=\"pointer-events: none;\" data=\"" << src
+ << "\"" << sizeAttribs << attrs;
+ if (inlineImage)
{
- m_t << "<object type=\"image/svg+xml\" style=\"pointer-events: none;\" data=\"" << img->relPath() << img->name()
- << "\"" << sizeAttribs << htmlAttribsToString(img->attribs());
- if (inlineImage)
- {
- // skip closing tag
- }
- else
- {
- m_t << "></object>" << endl;
- }
+ // skip closing tag
}
else
{
- m_t << "<img src=\"" << img->relPath() << img->name() << "\" alt=\""
- << baseName << "\"" << sizeAttribs << htmlAttribsToString(img->attribs());
- if (inlineImage)
- {
- m_t << " class=\"inline\"";
- }
- else
- {
- m_t << "/>\n";
- }
+ m_t << ">" << alt << "</object>" << endl;
}
}
- else // link to URL
+ else
{
- if (typeSVG)
+ m_t << "<img src=\"" << convertToHtml(src) << "\" alt=\"" << alt << "\"" << sizeAttribs << attrs;
+ if (inlineImage)
{
- m_t << "<object type=\"image/svg+xml\" style=\"pointer-events: none;\" data=\"" << correctURL(url,img->relPath())
- << "\"" << sizeAttribs << htmlAttribsToString(img->attribs());
- if (inlineImage)
- {
- // skip closing >
- }
- else
- {
- m_t << "></object>" << endl;
- }
+ m_t << " class=\"inline\"";
}
else
{
- m_t << "<img src=\"" << correctURL(url,img->relPath()) << "\""
- << sizeAttribs << htmlAttribsToString(img->attribs(), TRUE);
- if (inlineImage)
- {
- m_t << " class=\"inline\""; // skip closing >
- }
- else
- {
- m_t << "/>\n";
- }
+ m_t << "/>\n";
}
}
if (img->hasCaption())
@@ -1709,7 +1699,7 @@ void HtmlDocVisitor::visitPre(DocImage *img)
{
if (typeSVG)
{
- m_t << "></object>";
+ m_t << ">" << alt << "</object>";
}
else
{
@@ -1736,7 +1726,9 @@ void HtmlDocVisitor::visitPost(DocImage *img)
{
if (img->isSVG())
{
- m_t << "\"></object>";
+ QCString alt;
+ QCString attrs = htmlAttribsToString(img->attribs(),&alt);
+ m_t << "\">" << alt << "</object>";
}
else
{
@@ -2318,7 +2310,7 @@ void HtmlDocVisitor::writePlantUMLFile(const QCString &fileName,
QCString imgExt = getDotImageExtension();
if (imgExt=="svg")
{
- generatePlantUMLOutput(fileName,outDir,PUML_SVG);
+ PlantumlManager::instance()->generatePlantUMLOutput(fileName,outDir,PlantumlManager::PUML_SVG);
//m_t << "<iframe scrolling=\"no\" frameborder=\"0\" src=\"" << relPath << baseName << ".svg" << "\" />" << endl;
//m_t << "<p><b>This browser is not able to show SVG: try Firefox, Chrome, Safari, or Opera instead.</b></p>";
//m_t << "</iframe>" << endl;
@@ -2326,7 +2318,7 @@ void HtmlDocVisitor::writePlantUMLFile(const QCString &fileName,
}
else
{
- generatePlantUMLOutput(fileName,outDir,PUML_BITMAP);
+ PlantumlManager::instance()->generatePlantUMLOutput(fileName,outDir,PlantumlManager::PUML_BITMAP);
m_t << "<img src=\"" << relPath << baseName << ".png" << "\" />" << endl;
}
}
diff --git a/src/latexdocvisitor.cpp b/src/latexdocvisitor.cpp
index 5be3fc9..463eedf 100644
--- a/src/latexdocvisitor.cpp
+++ b/src/latexdocvisitor.cpp
@@ -280,7 +280,7 @@ void LatexDocVisitor::visit(DocLineBreak *)
void LatexDocVisitor::visit(DocHorRuler *)
{
if (m_hide) return;
- m_t << "\n\n";
+ m_t << "\\DoxyHorRuler\n";
}
void LatexDocVisitor::visit(DocStyleChange *s)
@@ -428,7 +428,7 @@ void LatexDocVisitor::visit(DocVerbatim *s)
case DocVerbatim::PlantUML:
{
QCString latexOutput = Config_getString(LATEX_OUTPUT);
- QCString baseName = writePlantUMLSource(latexOutput,s->exampleFile(),s->text());
+ QCString baseName = PlantumlManager::instance()->writePlantUMLSource(latexOutput,s->exampleFile(),s->text(),PlantumlManager::PUML_EPS);
writePlantUMLFile(baseName, s);
}
@@ -1927,7 +1927,7 @@ void LatexDocVisitor::writePlantUMLFile(const QCString &baseName, DocVerbatim *s
shortName=shortName.right(shortName.length()-i-1);
}
QCString outDir = Config_getString(LATEX_OUTPUT);
- generatePlantUMLOutput(baseName,outDir,PUML_EPS);
+ PlantumlManager::instance()->generatePlantUMLOutput(baseName,outDir,PlantumlManager::PUML_EPS);
visitPreStart(m_t, s->hasCaption(), shortName, s->width(), s->height());
visitCaption(this, s->children());
visitPostEnd(m_t, s->hasCaption());
diff --git a/src/markdown.cpp b/src/markdown.cpp
index b00070e..5253333 100644
--- a/src/markdown.cpp
+++ b/src/markdown.cpp
@@ -2451,8 +2451,8 @@ static QCString extractPageTitle(QCString &docs,QCString &id)
static QCString detab(const QCString &s,int &refIndent)
{
static int tabSize = Config_getInt(TAB_SIZE);
- GrowBuf out;
int size = s.length();
+ GrowBuf out(size);
const char *data = s.data();
int i=0;
int col=0;
@@ -2601,19 +2601,20 @@ void MarkdownFileParser::parseInput(const char *fileName,
}
}
int lineNr=1;
- int position=0;
// even without markdown support enabled, we still
// parse markdown files as such
bool markdownEnabled = Doxygen::markdownSupport;
Doxygen::markdownSupport = TRUE;
- bool needsEntry = FALSE;
Protection prot=Public;
+ bool needsEntry = FALSE;
+ int position=0;
+ QCString processedDocs = preprocessCommentBlock(docs,fileName,lineNr);
while (parseCommentBlock(
this,
current,
- docs,
+ processedDocs,
fileName,
lineNr,
FALSE, // isBrief
diff --git a/src/memberdef.cpp b/src/memberdef.cpp
index a2fcf69..bcef5ac 100644
--- a/src/memberdef.cpp
+++ b/src/memberdef.cpp
@@ -1080,6 +1080,7 @@ QCString MemberDef::anchor() const
void MemberDef::_computeLinkableInProject()
{
static bool extractStatic = Config_getBool(EXTRACT_STATIC);
+ static bool extractPrivateVirtual = Config_getBool(EXTRACT_PRIV_VIRTUAL);
m_isLinkableCached = 2; // linkable
//printf("MemberDef::isLinkableInProject(name=%s)\n",name().data());
if (isHidden())
@@ -1133,7 +1134,8 @@ void MemberDef::_computeLinkableInProject()
m_isLinkableCached = 1; // in file (and not in namespace) but file not linkable
return;
}
- if (!protectionLevelVisible(m_impl->prot) && m_impl->mtype!=MemberType_Friend)
+ if ((!protectionLevelVisible(m_impl->prot) && m_impl->mtype!=MemberType_Friend) &&
+ !(m_impl->prot==Private && m_impl->virt!=Normal && extractPrivateVirtual))
{
//printf("private and invisible!\n");
m_isLinkableCached = 1; // hidden due to protection
@@ -1315,6 +1317,7 @@ ClassDef *MemberDef::getClassDefOfAnonymousType()
bool MemberDef::isBriefSectionVisible() const
{
static bool extractStatic = Config_getBool(EXTRACT_STATIC);
+ static bool extractPrivateVirtual = Config_getBool(EXTRACT_PRIV_VIRTUAL);
static bool hideUndocMembers = Config_getBool(HIDE_UNDOC_MEMBERS);
static bool briefMemberDesc = Config_getBool(BRIEF_MEMBER_DESC);
static bool repeatBrief = Config_getBool(REPEAT_BRIEF);
@@ -1365,9 +1368,12 @@ bool MemberDef::isBriefSectionVisible() const
);
// only include members that are non-private unless EXTRACT_PRIVATE is
- // set to YES or the member is part of a group
+ // set to YES or the member is part of a group. And as a special case,
+ // private *documented* virtual members are shown if EXTRACT_PRIV_VIRTUAL
+ // is set to YES
bool visibleIfPrivate = (protectionLevelVisible(protection()) ||
- m_impl->mtype==MemberType_Friend
+ m_impl->mtype==MemberType_Friend ||
+ (m_impl->prot==Private && m_impl->virt!=Normal && extractPrivateVirtual && hasDocs)
);
// hide member if it overrides a member in a superclass and has no
@@ -1639,11 +1645,12 @@ void MemberDef::writeDeclaration(OutputList &ol,
if (!name().isEmpty() && name().at(0)!='@') // hide anonymous stuff
{
static bool extractPrivate = Config_getBool(EXTRACT_PRIVATE);
+ static bool extractPrivateVirtual = Config_getBool(EXTRACT_PRIV_VIRTUAL);
static bool extractStatic = Config_getBool(EXTRACT_STATIC);
//printf("Member name=`%s gd=%p md->groupDef=%p inGroup=%d isLinkable()=%d hasDocumentation=%d\n",name().data(),gd,getGroupDef(),inGroup,isLinkable(),hasDocumentation());
if (!(name().isEmpty() || name().at(0)=='@') && // name valid
(hasDocumentation() || isReference()) && // has docs
- !(m_impl->prot==Private && !extractPrivate && m_impl->mtype!=MemberType_Friend) && // hidden due to protection
+ !(m_impl->prot==Private && !extractPrivate && (m_impl->virt==Normal || !extractPrivateVirtual) && m_impl->mtype!=MemberType_Friend) && // hidden due to protection
!(isStatic() && m_impl->classDef==0 && !extractStatic) // hidden due to static-ness
)
{
@@ -1896,6 +1903,7 @@ bool MemberDef::isDetailedSectionLinkable() const
static bool briefMemberDesc = Config_getBool(BRIEF_MEMBER_DESC);
static bool hideUndocMembers = Config_getBool(HIDE_UNDOC_MEMBERS);
static bool extractStatic = Config_getBool(EXTRACT_STATIC);
+ static bool extractPrivateVirtual = Config_getBool(EXTRACT_PRIV_VIRTUAL);
// the member has details documentation for any of the following reasons
bool docFilter =
@@ -1933,7 +1941,8 @@ bool MemberDef::isDetailedSectionLinkable() const
// only include members that are non-private unless EXTRACT_PRIVATE is
// set to YES or the member is part of a group
- bool privateFilter = protectionLevelVisible(protection()) || m_impl->mtype==MemberType_Friend;
+ bool privateFilter = protectionLevelVisible(protection()) || m_impl->mtype==MemberType_Friend ||
+ (m_impl->prot==Private && m_impl->virt!=Normal && extractPrivateVirtual);
// member is part of an anonymous scope that is the type of
// another member in the list.
diff --git a/src/plantuml.cpp b/src/plantuml.cpp
index ada035b..ff4ebd3 100644
--- a/src/plantuml.cpp
+++ b/src/plantuml.cpp
@@ -14,23 +14,32 @@
*/
#include "plantuml.h"
+#include "util.h"
#include "portable.h"
#include "config.h"
#include "doxygen.h"
#include "index.h"
#include "message.h"
+#include "debug.h"
#include <qdir.h>
+#include <qdict.h>
+#include <qlist.h>
-static const int maxCmdLine = 40960;
-QCString writePlantUMLSource(const QCString &outDir,const QCString &fileName,const QCString &content)
+QCString PlantumlManager::writePlantUMLSource(const QCString &outDir,const QCString &fileName,const QCString &content,OutputFormat format)
{
- QCString baseName(4096);
+ QCString baseName;
+ QCString puName;
+ QCString imgName;
static int umlindex=1;
+ Debug::print(Debug::Plantuml,0,"*** %s fileName: %s\n","writePlantUMLSource",qPrint(fileName));
+ Debug::print(Debug::Plantuml,0,"*** %s outDir: %s\n","writePlantUMLSource",qPrint(outDir));
+
if (fileName.isEmpty()) // generate name
{
+ puName = "inline_umlgraph_"+QCString().setNum(umlindex);
baseName = outDir+"/inline_umlgraph_"+QCString().setNum(umlindex++);
}
else // user specified name
@@ -38,29 +47,158 @@ QCString writePlantUMLSource(const QCString &outDir,const QCString &fileName,con
baseName = fileName;
int i=baseName.findRev('.');
if (i!=-1) baseName = baseName.left(i);
+ puName = baseName;
baseName.prepend(outDir+"/");
}
- QFile file(baseName+".pu");
- if (!file.open(IO_WriteOnly))
+
+ switch (format)
{
- err("Could not open file %s for writing\n",baseName.data());
+ case PUML_BITMAP:
+ imgName =puName+".png";
+ break;
+ case PUML_EPS:
+ imgName =puName+".eps";
+ break;
+ case PUML_SVG:
+ imgName =puName+".svg";
+ break;
}
- QCString text = "@startuml\n";
+
+ Debug::print(Debug::Plantuml,0,"*** %s baseName: %s\n","writePlantUMLSource",qPrint(baseName));
+ Debug::print(Debug::Plantuml,0,"*** %s puName: %s\n","writePlantUMLSource",qPrint(puName));
+ Debug::print(Debug::Plantuml,0,"*** %s imgName: %s\n","writePlantUMLSource",qPrint(imgName));
+
+ QCString text = "@startuml "+imgName+"\n";
text+=content;
text+="\n@enduml\n";
- file.writeBlock( text, text.length() );
- file.close();
+
+ QCString qcOutDir(outDir);
+ uint pos = qcOutDir.findRev("/");
+ QCString generateType(qcOutDir.right(qcOutDir.length() - (pos + 1)) );
+ Debug::print(Debug::Plantuml,0,"*** %s generateType: %s\n","writePlantUMLSource",qPrint(generateType));
+ PlantumlManager::instance()->insert(generateType,puName,format,text);
+ Debug::print(Debug::Plantuml,0,"*** %s generateType: %s\n","writePlantUMLSource",qPrint(generateType));
+
return baseName;
}
-void generatePlantUMLOutput(const char *baseName,const char *outDir,PlantUMLOutputFormat format)
+void PlantumlManager::generatePlantUMLOutput(const char *baseName,const char *outDir,OutputFormat format)
+{
+ QCString plantumlJarPath = Config_getString(PLANTUML_JAR_PATH);
+ QCString plantumlConfigFile = Config_getString(PLANTUML_CFG_FILE);
+ QCString dotPath = Config_getString(DOT_PATH);
+
+ QCString imgName = baseName;
+ // The basename contains path, we need to strip the path from the filename in order
+ // to create the image file name which should be included in the index.qhp (Qt help index file).
+ int i;
+ if ((i=imgName.findRev('/'))!=-1) // strip path
+ {
+ imgName=imgName.right(imgName.length()-i-1);
+ }
+ switch (format)
+ {
+ case PUML_BITMAP:
+ imgName+=".png";
+ break;
+ case PUML_EPS:
+ imgName+=".eps";
+ break;
+ case PUML_SVG:
+ imgName+=".svg";
+ break;
+ }
+
+ Doxygen::indexList->addImageFile(imgName);
+}
+
+//--------------------------------------------------------------------
+
+PlantumlManager *PlantumlManager::m_theInstance = 0;
+
+PlantumlManager *PlantumlManager::instance()
+{
+ if (!m_theInstance)
+ {
+ m_theInstance = new PlantumlManager;
+ QCString outputFilename = Config_getString(OUTPUT_DIRECTORY) + "/" + CACHE_FILENAME;
+ QFileInfo fi(outputFilename);
+ if (fi.exists())
+ {
+ m_theInstance->m_cachedPlantumlAllContent = fileToString(outputFilename);
+ }
+ else
+ {
+ m_theInstance->m_cachedPlantumlAllContent = "";
+ }
+ Debug::print(Debug::Plantuml,0,"*** instance() : m_cachedPlantumlAllContent = [%s]\n",qPrint(m_theInstance->m_cachedPlantumlAllContent));
+ m_theInstance->m_pngPlantumlContent.clear();
+ m_theInstance->m_svgPlantumlContent.clear();
+ m_theInstance->m_epsPlantumlContent.clear();
+ }
+ return m_theInstance;
+}
+
+PlantumlManager::PlantumlManager()
{
- static QCString plantumlJarPath = Config_getString(PLANTUML_JAR_PATH);
- static QCString plantumlConfigFile = Config_getString(PLANTUML_CFG_FILE);
- static QCString dotPath = Config_getString(DOT_PATH);
+}
+
+PlantumlManager::~PlantumlManager()
+{
+ {
+ QDictIterator< QList<QCString> > it( m_pngPlantumlFiles); // See QDictIterator
+ QList<QCString> *list;
+ for (it.toFirst();(list=it.current());++it)
+ {
+ (*list).clear();
+ }
+ m_pngPlantumlFiles.clear();
+ m_pngPlantumlContent.clear();
+ }
+ {
+ QDictIterator< QList<QCString> > it( m_epsPlantumlFiles); // See QDictIterator
+ QList<QCString> *list;
+ for (it.toFirst();(list=it.current());++it)
+ {
+ (*list).clear();
+ }
+ m_epsPlantumlFiles.clear();
+ m_epsPlantumlContent.clear();
+ }
+ {
+ QDictIterator< QList<QCString> > it( m_svgPlantumlFiles); // See QDictIterator
+ QList<QCString> *list;
+ for (it.toFirst();(list=it.current());++it)
+ {
+ (*list).clear();
+ }
+ m_svgPlantumlFiles.clear();
+ m_svgPlantumlContent.clear();
+ }
+}
+
+static void runPlantumlContent(const QDict< QList <QCString> > &plantumlFiles,
+ const QDict< QCString > &plantumlContent,
+ PlantumlManager::OutputFormat format)
+{
+ /* example : running: java -Djava.awt.headless=true
+ -jar "/usr/local/bin/plantuml.jar"
+ -o "test_doxygen/DOXYGEN_OUTPUT/html"
+ -tpng
+ "test_doxygen/DOXYGEN_OUTPUT/html/A.pu"
+ -charset UTF-8
+ outDir:test_doxygen/DOXYGEN_OUTPUT/html
+ test_doxygen/DOXYGEN_OUTPUT/html/A
+ */
+ int exitCode;
+ QCString plantumlJarPath = Config_getString(PLANTUML_JAR_PATH);
+ QCString plantumlConfigFile = Config_getString(PLANTUML_CFG_FILE);
+ QCString dotPath = Config_getString(DOT_PATH);
QCString pumlExe = "java";
QCString pumlArgs = "";
+ QCString pumlType = "";
+ QCString pumlOutDir = "";
QStrList &pumlIncludePathList = Config_getList(PLANTUML_INCLUDE_PATH);
char *s=pumlIncludePathList.first();
@@ -92,61 +230,211 @@ void generatePlantUMLOutput(const char *baseName,const char *outDir,PlantUMLOutp
pumlArgs += portable_commandExtension();
pumlArgs += "\" ";
}
- pumlArgs+="-o \"";
- pumlArgs+=outDir;
- pumlArgs+="\" ";
- QCString imgName = baseName;
- // The basename contains path, we need to strip the path from the filename in order
- // to create the image file name which should be included in the index.qhp (Qt help index file).
- int i;
- if ((i=imgName.findRev('/'))!=-1) // strip path
- {
- imgName=imgName.right(imgName.length()-i-1);
- }
switch (format)
{
- case PUML_BITMAP:
- pumlArgs+="-tpng";
- imgName+=".png";
+ case PlantumlManager::PUML_BITMAP:
+ pumlType="png";
break;
- case PUML_EPS:
- pumlArgs+="-teps";
- imgName+=".eps";
+ case PlantumlManager::PUML_EPS:
+ pumlType="eps";
break;
- case PUML_SVG:
- pumlArgs+="-tsvg";
- imgName+=".svg";
+ case PlantumlManager::PUML_SVG:
+ pumlType="svg";
break;
}
- pumlArgs+=" \"";
- pumlArgs+=baseName;
- pumlArgs+=".pu\" ";
- pumlArgs+="-charset UTF-8 ";
- int exitCode;
- //printf("*** running: %s %s outDir:%s %s\n",pumlExe.data(),pumlArgs.data(),outDir,baseName);
- msg("Running PlantUML on generated file %s.pu\n",baseName);
- portable_sysTimerStart();
- if ((exitCode=portable_system(pumlExe,pumlArgs,TRUE))!=0)
+
{
- err("Problems running PlantUML. Verify that the command 'java -jar \"%splantuml.jar\" -h' works from the command line. Exit code: %d\n",
- plantumlJarPath.data(),exitCode);
+ QDictIterator< QCString > it( plantumlContent); // See QDictIterator
+ QCString *nb;
+ for (it.toFirst();(nb=it.current());++it)
+ {
+ QCString pumlArguments(pumlArgs);
+ msg("Generating PlantUML %s Files in %s\n",qPrint(pumlType),qPrint(it.currentKey()));
+ pumlArguments+="-o \"";
+ pumlArguments+=Config_getString(OUTPUT_DIRECTORY);
+ pumlArguments+="/";
+ pumlArguments+=it.currentKey();
+ pumlArguments+="\" ";
+ pumlArguments+="-charset UTF-8 -t";
+ pumlArguments+=pumlType;
+ pumlArguments+=" ";
+
+ QCString puFileName("");
+ puFileName+=Config_getString(OUTPUT_DIRECTORY);
+ puFileName+="/";
+ puFileName+=it.currentKey();
+ puFileName+="/";
+ pumlOutDir=puFileName;
+ puFileName+="inline_umlgraph_";
+ puFileName+=pumlType;
+ puFileName+=it.currentKey();
+ puFileName+=".pu";
+
+ pumlArguments+="\"";
+ pumlArguments+=puFileName;
+ pumlArguments+="\" ";
+
+ QFile file(puFileName);
+ if (!file.open(IO_WriteOnly))
+ {
+ err("Could not open file %s for writing\n",puFileName.data());
+ }
+ file.writeBlock( *nb, nb->length() );
+ file.close();
+ Debug::print(Debug::Plantuml,0,"*** %s Running Plantuml arguments:%s\n","PlantumlManager::runPlantumlContent",qPrint(pumlArguments));
+
+ portable_sysTimerStart();
+ if ((exitCode=portable_system(pumlExe,pumlArguments,TRUE))!=0)
+ {
+ err("Problems running PlantUML. Verify that the command 'java -jar \"%splantuml.jar\" -h' works from the command line. Exit code: %d\n",
+ plantumlJarPath.data(),exitCode);
+ }
+ else if (Config_getBool(DOT_CLEANUP))
+ {
+ Debug::print(Debug::Plantuml,0,"*** %s Remove %s file\n","PlantumlManager::runPlantumlContent",qPrint(puFileName));
+ file.remove();
+ }
+ portable_sysTimerStop();
+
+ if ( (format==PlantumlManager::PUML_EPS) && (Config_getBool(USE_PDFLATEX)) )
+ {
+ Debug::print(Debug::Plantuml,0,"*** %s Running epstopdf\n","PlantumlManager::runPlantumlContent");
+ QList<QCString> *list = plantumlFiles[it.currentKey()];
+ if (list)
+ {
+ QListIterator<QCString> li(*list);
+ QCString *nb;
+ for (li.toFirst();(nb=li.current());++li)
+ {
+ const int maxCmdLine = 40960;
+ QCString epstopdfArgs(maxCmdLine);
+ epstopdfArgs.sprintf("\"%s%s.eps\" --outfile=\"%s%s.pdf\"",qPrint(pumlOutDir),qPrint(*nb),qPrint(pumlOutDir),qPrint(*nb));
+ portable_sysTimerStart();
+ if ((exitCode=portable_system("epstopdf",epstopdfArgs))!=0)
+ {
+ err("Problems running epstopdf. Check your TeX installation! Exit code: %d\n",exitCode);
+ }
+ portable_sysTimerStop();
+ }
+ }
+ }
+ }
}
- else if (Config_getBool(DOT_CLEANUP))
+}
+
+void PlantumlManager::run()
+{
+ Debug::print(Debug::Plantuml,0,"*** %s\n","PlantumlManager::run");
+ if (m_currentPlantumlAllContent.isEmpty()) return;
+ runPlantumlContent(m_pngPlantumlFiles, m_pngPlantumlContent, PUML_BITMAP);
+ runPlantumlContent(m_svgPlantumlFiles, m_svgPlantumlContent, PUML_SVG);
+ runPlantumlContent(m_epsPlantumlFiles, m_epsPlantumlContent, PUML_EPS);
+ QCString outputFilename = Config_getString(OUTPUT_DIRECTORY) + "/" + CACHE_FILENAME;
+ QFile file(outputFilename);
+ if (!file.open(IO_WriteOnly))
{
- QFile(QCString(baseName)+".pu").remove();
+ err("Could not open file %s for writing\n",CACHE_FILENAME);
}
- portable_sysTimerStop();
- if ( (format==PUML_EPS) && (Config_getBool(USE_PDFLATEX)) )
+ file.writeBlock( m_currentPlantumlAllContent, m_currentPlantumlAllContent.length() );
+ file.close();
+}
+
+static void print(const QDict< QList <QCString> > &plantumlFiles)
+{
+ if (Debug::isFlagSet(Debug::Plantuml))
{
- QCString epstopdfArgs(maxCmdLine);
- epstopdfArgs.sprintf("\"%s.eps\" --outfile=\"%s.pdf\"",baseName,baseName);
- portable_sysTimerStart();
- if ((exitCode=portable_system("epstopdf",epstopdfArgs))!=0)
+ QDictIterator< QList<QCString> > it( plantumlFiles); // See QDictIterator
+ QList<QCString> *list;
+ for (it.toFirst();(list=it.current());++it)
{
- err("Problems running epstopdf. Check your TeX installation! Exit code: %d\n",exitCode);
+ Debug::print(Debug::Plantuml,0,"*** %s PlantumlFiles key:%s size:%d\n","PlantumlManager::print Files",qPrint(it.currentKey()),(*list).count());
+ QListIterator<QCString> li(*list);
+ QCString *nb;
+ for (li.toFirst();(nb=li.current());++li)
+ {
+ Debug::print(Debug::Plantuml,0,"*** %s list:%s\n","PlantumlManager::print",qPrint(*nb));
+ }
}
- portable_sysTimerStop();
}
- Doxygen::indexList->addImageFile(imgName);
}
+static void print(const QDict<QCString> &plantumlContent)
+{
+ if (Debug::isFlagSet(Debug::Plantuml))
+ {
+ QDictIterator< QCString > it( plantumlContent); // See QDictIterator
+ QCString *nb;
+ for (it.toFirst();(nb=it.current());++it)
+ {
+ Debug::print(Debug::Plantuml,0,"*** %s PlantumlContent key:%s\n","PlantumlManager::print Content",qPrint(it.currentKey()));
+ Debug::print(Debug::Plantuml,0,"*** %s Content :%s\n","PlantumlManager::print",qPrint(*nb));
+ }
+ }
+}
+
+static void addPlantumlFiles(QDict< QList<QCString> > &plantumlFiles,
+ const QCString &key , const QCString &value)
+{
+ QList<QCString> *list = plantumlFiles.find(key);
+ if (list==0)
+ {
+ list = new QList<QCString>;
+ plantumlFiles.insert(key,list);
+ }
+ list->append(new QCString(value));
+}
+
+static void addPlantumlContent(QDict< QCString > &plantumlContent,
+ const QCString &key, const QCString &puContent)
+{
+ QCString* content = plantumlContent.find(key);
+ if (content == 0)
+ {
+ content = new QCString("");
+ plantumlContent.insert(key,content);
+ }
+ (*content)+=puContent;
+}
+
+
+
+void PlantumlManager::insert(const QCString &key, const QCString &value,
+ OutputFormat format,const QCString &puContent)
+{
+ int find;
+
+ Debug::print(Debug::Plantuml,0,"*** %s key:%s ,value:%s\n","PlantumlManager::insert",qPrint(key),qPrint(value));
+
+ m_currentPlantumlAllContent+=puContent;
+
+ find = m_cachedPlantumlAllContent.find(puContent);
+ Debug::print(Debug::Plantuml,0,"*** %s find: %d\n","PlantumlManager::addPlantumlContent",find);
+ if (find >=0)
+ { // matched in cache. so we skip to run java for this plantuml
+ return ;
+ }
+
+ switch (format)
+ {
+ case PUML_BITMAP:
+ addPlantumlFiles(m_pngPlantumlFiles,key,value);
+ print(m_pngPlantumlFiles);
+ addPlantumlContent(m_pngPlantumlContent,key,puContent);
+ print(m_pngPlantumlContent);
+ break;
+ case PUML_EPS:
+ addPlantumlFiles(m_epsPlantumlFiles,key,value);
+ print(m_epsPlantumlFiles);
+ addPlantumlContent(m_epsPlantumlContent,key,puContent);
+ print(m_epsPlantumlContent);
+ break;
+ case PUML_SVG:
+ addPlantumlFiles(m_svgPlantumlFiles,key,value);
+ print(m_svgPlantumlFiles);
+ addPlantumlContent(m_svgPlantumlContent,key,puContent);
+ print(m_svgPlantumlContent);
+ break;
+ }
+}
+
+//--------------------------------------------------------------------
diff --git a/src/plantuml.h b/src/plantuml.h
index 54ab8a2..6c99eba 100644
--- a/src/plantuml.h
+++ b/src/plantuml.h
@@ -16,25 +16,60 @@
#ifndef PLANTUML_H
#define PLANTUML_H
+#include <qdict.h>
+#include <qlist.h>
+
+#define CACHE_FILENAME "inline_umlgraph_cache_all.pu"
+#define DIVIDE_COUNT 4
+#define MIN_PLANTUML_COUNT 8
+
class QCString;
-/** Plant UML output image formats */
-enum PlantUMLOutputFormat { PUML_BITMAP, PUML_EPS, PUML_SVG };
+/** Singleton that manages plantuml relation actions */
+class PlantumlManager
+{
+ public:
+ /** Plant UML output image formats */
+ enum OutputFormat { PUML_BITMAP, PUML_EPS, PUML_SVG };
-/** Write a PlantUML compatible file.
- * @param[in] outDir the output directory to write the file to.
- * @param[in] fileName the name of the file. If empty a name will be chosen automatically.
- * @param[in] content the contents of the PlantUML file.
- * @returns The name of the generated file.
- */
-QCString writePlantUMLSource(const QCString &outDir,const QCString &fileName,const QCString &content);
+ static PlantumlManager *instance();
-/** Convert a PlantUML file to an image.
- * @param[in] baseName the name of the generated file (as returned by writePlantUMLSource())
- * @param[in] outDir the directory to write the resulting image into.
- * @param[in] format the image format to generate.
- */
-void generatePlantUMLOutput(const char *baseName,const char *outDir,PlantUMLOutputFormat format);
+ /** Run plant UML tool for all images */
+ void run();
+
+ /** Write a PlantUML compatible file.
+ * @param[in] outDir the output directory to write the file to.
+ * @param[in] fileName the name of the file. If empty a name will be chosen automatically.
+ * @param[in] content the contents of the PlantUML file.
+ * @param[in] format the image format to generate.
+ * @returns The name of the generated file.
+ */
+ QCString writePlantUMLSource(const QCString &outDir,const QCString &fileName,const QCString &content, OutputFormat format);
+
+ /** Convert a PlantUML file to an image.
+ * @param[in] baseName the name of the generated file (as returned by writePlantUMLSource())
+ * @param[in] outDir the directory to write the resulting image into.
+ * @param[in] format the image format to generate.
+ */
+ void generatePlantUMLOutput(const char *baseName,const char *outDir,OutputFormat format);
+
+ private:
+ PlantumlManager();
+ ~PlantumlManager();
+ void insert(const QCString &key,
+ const QCString &value,
+ OutputFormat format,
+ const QCString &puContent);
+ static PlantumlManager *m_theInstance;
+ QDict< QList<QCString> > m_pngPlantumlFiles;
+ QDict< QList<QCString> > m_svgPlantumlFiles;
+ QDict< QList<QCString> > m_epsPlantumlFiles;
+ QDict< QCString > m_pngPlantumlContent; // use circular queue for using multi-proecessor (multi threading)
+ QDict< QCString > m_svgPlantumlContent;
+ QDict< QCString > m_epsPlantumlContent;
+ QCString m_cachedPlantumlAllContent; // read from CACHE_FILENAME file
+ QCString m_currentPlantumlAllContent; // processing plantuml then write it into CACHE_FILENAME to reuse the next time as cache information
+};
#endif
diff --git a/src/pyscanner.l b/src/pyscanner.l
index 1596b9d..655b6e2 100644
--- a/src/pyscanner.l
+++ b/src/pyscanner.l
@@ -324,11 +324,12 @@ static void handleCommentBlock(const QCString &doc,bool brief)
int position = 0;
bool needsEntry;
int lineNr = brief ? current->briefLine : current->docLine;
+ QCString processedDoc = preprocessCommentBlock(doc,yyFileName,lineNr);
while (parseCommentBlock(
g_thisParser,
(docBlockInBody && previous) ? previous : current,
- doc, // text
- yyFileName, // file
+ processedDoc, // text
+ yyFileName, // file
lineNr,
docBlockInBody ? FALSE : brief,
docBlockJavaStyle, // javadoc style // or FALSE,
diff --git a/src/rtfdocvisitor.cpp b/src/rtfdocvisitor.cpp
index f2edf8b..1e2bb89 100644
--- a/src/rtfdocvisitor.cpp
+++ b/src/rtfdocvisitor.cpp
@@ -383,7 +383,7 @@ void RTFDocVisitor::visit(DocVerbatim *s)
case DocVerbatim::PlantUML:
{
static QCString rtfOutput = Config_getString(RTF_OUTPUT);
- QCString baseName = writePlantUMLSource(rtfOutput,s->exampleFile(),s->text());
+ QCString baseName = PlantumlManager::instance()->writePlantUMLSource(rtfOutput,s->exampleFile(),s->text(),PlantumlManager::PUML_BITMAP);
writePlantUMLFile(baseName, s->hasCaption());
visitCaption(this, s->children());
@@ -1868,6 +1868,6 @@ void RTFDocVisitor::writePlantUMLFile(const QCString &fileName, bool hasCaption)
baseName=baseName.right(baseName.length()-i-1);
}
QCString outDir = Config_getString(RTF_OUTPUT);
- generatePlantUMLOutput(fileName,outDir,PUML_BITMAP);
+ PlantumlManager::instance()->generatePlantUMLOutput(fileName,outDir,PlantumlManager::PUML_BITMAP);
includePicturePreRTF(baseName + ".png", true, hasCaption);
}
diff --git a/src/scanner.l b/src/scanner.l
index 7559e0b..ee04dd9 100644
--- a/src/scanner.l
+++ b/src/scanner.l
@@ -2438,6 +2438,10 @@ OPERATOR "operator"{B}*({ARITHOP}|{ASSIGNOP}|{LOGICOP}|{BITOP})
{
current->protection = Protected;
}
+ else if ((insideCS || insideD || insidePHP || insideJS) && qstrcmp(yytext,"internal")==0)
+ {
+ current->protection = Package;
+ }
else if (javaLike && qstrcmp(yytext,"private")==0)
{
current->protection = Private;
@@ -6908,12 +6912,10 @@ static void newEntry()
static void handleCommentBlock(const QCString &doc,bool brief)
{
static bool hideInBodyDocs = Config_getBool(HIDE_IN_BODY_DOCS);
- int position=0;
- bool needsEntry=FALSE;
if (docBlockInBody && hideInBodyDocs) return;
//printf("parseCommentBlock [%s] brief=%d\n",doc.data(),brief);
int lineNr = brief ? current->briefLine : current->docLine; // line of block start
-
+
// fill in inbodyFile && inbodyLine the first time, see bug 633891
Entry *docEntry = docBlockInBody && previous ? previous : current;
if (docBlockInBody && docEntry && docEntry->inbodyLine==-1)
@@ -6922,12 +6924,15 @@ static void handleCommentBlock(const QCString &doc,bool brief)
docEntry->inbodyLine = lineNr;
}
+ int position=0;
+ bool needsEntry=FALSE;
+ QCString processedDoc = preprocessCommentBlock(stripIndentation(doc),yyFileName,lineNr);
while (parseCommentBlock(
g_thisParser,
docBlockInBody && previous ? previous : current,
- stripIndentation(doc), // text
- yyFileName, // file
- lineNr, // line of block start
+ processedDoc, // text
+ yyFileName, // file
+ lineNr, // line of block start
docBlockInBody ? FALSE : brief, // isBrief
docBlockInBody ? FALSE : docBlockAutoBrief, // isJavaDocStyle
docBlockInBody, // isInBody
@@ -6935,7 +6940,7 @@ static void handleCommentBlock(const QCString &doc,bool brief)
position,
needsEntry
)
- )
+ )
{
//printf("parseCommentBlock position=%d [%s]\n",position,doc.data()+position);
if (needsEntry)
diff --git a/src/tclscanner.l b/src/tclscanner.l
index ca5294b..88714ce 100644
--- a/src/tclscanner.l
+++ b/src/tclscanner.l
@@ -1507,6 +1507,7 @@ tcl_inf("-> %s\n",(const char *)tcl.string_comment);
myO.shrink(myO.curPos()-2);
myO.addChar('\0');
QCString myDoc = myO.data();
+ QCString processedDoc;
if (what==99)
{ // inbody comment file or namespace or class or proc/method
int myPos0;
@@ -1526,14 +1527,16 @@ tcl_inf("-> %s\n",(const char *)tcl.string_comment);
myPos0=myPos;
myLine0=myLine;
- while (parseCommentBlock(tcl.this_parser, &myEntry0, myDoc, tcl.file_name,
+ processedDoc = preprocessCommentBlock(myDoc,tcl.file_name,myLine);
+ while (parseCommentBlock(tcl.this_parser, &myEntry0, processedDoc, tcl.file_name,
myLine, FALSE, tcl.config_autobrief, FALSE, myProt, myPos, myNew))
{
if (myNew)
{ // we need a new entry in this case
myNew=0;
myEntry = tcl_entry_new();
- parseCommentBlock(tcl.this_parser, myEntry, myDoc, tcl.file_name,
+ processedDoc = preprocessCommentBlock(myDoc,tcl.file_name,myLine0);
+ parseCommentBlock(tcl.this_parser, myEntry, processedDoc, tcl.file_name,
myLine0, FALSE, tcl.config_autobrief, FALSE, myProt, myPos0, myNew);
tcl.entry_inside->addSubEntry(myEntry);
}
@@ -1543,7 +1546,8 @@ tcl_inf("-> %s\n",(const char *)tcl.string_comment);
{
myEntry1=tcl_entry_namespace(tcl.scan.at(0)->ns);
}
- parseCommentBlock(tcl.this_parser, myEntry1, myDoc, tcl.file_name,
+ processedDoc = preprocessCommentBlock(myDoc,tcl.file_name,myLine0);
+ parseCommentBlock(tcl.this_parser, myEntry1, processedDoc, tcl.file_name,
myLine0, FALSE, tcl.config_autobrief, FALSE, myProt, myPos0, myNew);
}
myPos0=myPos;
@@ -1553,7 +1557,8 @@ tcl_inf("-> %s\n",(const char *)tcl.string_comment);
{ // we need a new entry
myNew=0;
myEntry = tcl_entry_new();
- parseCommentBlock(tcl.this_parser, myEntry, myDoc, tcl.file_name,
+ processedDoc = preprocessCommentBlock(myDoc,tcl.file_name,myLine0);
+ parseCommentBlock(tcl.this_parser, myEntry, processedDoc, tcl.file_name,
myLine0, FALSE, tcl.config_autobrief, FALSE, myProt, myPos0, myNew);
tcl.entry_inside->addSubEntry(myEntry);
}
@@ -1563,14 +1568,16 @@ tcl_inf("-> %s\n",(const char *)tcl.string_comment);
{
myEntry1=tcl_entry_namespace(tcl.scan.at(0)->ns);
}
- parseCommentBlock(tcl.this_parser, myEntry1, myDoc, tcl.file_name,
+ processedDoc = preprocessCommentBlock(myDoc,tcl.file_name,myLine0);
+ parseCommentBlock(tcl.this_parser, myEntry1, processedDoc, tcl.file_name,
myLine0, FALSE, tcl.config_autobrief, FALSE, myProt, myPos0, myNew);
}
}
else
{ // new entry
tcl.entry_current = tcl_entry_new();
- while (parseCommentBlock(tcl.this_parser, tcl.entry_current, myDoc,
+ processedDoc = preprocessCommentBlock(myDoc,tcl.file_name,myLine);
+ while (parseCommentBlock(tcl.this_parser, tcl.entry_current, processedDoc,
tcl.file_name, myLine, FALSE, tcl.config_autobrief, FALSE,
myProt, myPos, myNew))
{
diff --git a/src/util.cpp b/src/util.cpp
index 24e8898..9a0e513 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -5444,6 +5444,7 @@ QCString escapeCharsInString(const char *name,bool allowDots,bool allowUnderscor
static bool allowUnicodeNames = Config_getBool(ALLOW_UNICODE_NAMES);
static GrowBuf growBuf;
growBuf.clear();
+ if (name==0) return "";
char c;
const char *p=name;
while ((c=*p++)!=0)
@@ -5914,7 +5915,7 @@ QCString convertToId(const char *s)
}
/*! Converts a string to an XML-encoded string */
-QCString convertToXML(const char *s)
+QCString convertToXML(const char *s, bool keepEntities)
{
static GrowBuf growBuf;
growBuf.clear();
@@ -5927,7 +5928,30 @@ QCString convertToXML(const char *s)
{
case '<': growBuf.addStr("&lt;"); break;
case '>': growBuf.addStr("&gt;"); break;
- case '&': growBuf.addStr("&amp;"); break;
+ case '&': if (keepEntities)
+ {
+ const char *e=p;
+ char ce;
+ while ((ce=*e++))
+ {
+ if (ce==';' || (!(isId(ce) || ce=='#'))) break;
+ }
+ if (ce==';') // found end of an entity
+ {
+ // copy entry verbatim
+ growBuf.addChar(c);
+ while (p<e) growBuf.addChar(*p++);
+ }
+ else
+ {
+ growBuf.addStr("&amp;");
+ }
+ }
+ else
+ {
+ growBuf.addStr("&amp;");
+ }
+ break;
case '\'': growBuf.addStr("&apos;"); break;
case '"': growBuf.addStr("&quot;"); break;
case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 8:
@@ -6939,6 +6963,7 @@ void filterLatexString(FTextStream &t,const char *str,
QCString latexEscapeLabelName(const char *s)
{
+ if (s==0) return "";
QGString result;
QCString tmp(qstrlen(s)+1);
FTextStream t(&result);
@@ -6976,6 +7001,7 @@ QCString latexEscapeLabelName(const char *s)
QCString latexEscapeIndexChars(const char *s)
{
+ if (s==0) return "";
QGString result;
QCString tmp(qstrlen(s)+1);
FTextStream t(&result);
@@ -7014,6 +7040,7 @@ QCString latexEscapeIndexChars(const char *s)
QCString latexEscapePDFString(const char *s)
{
+ if (s==0) return "";
QGString result;
FTextStream t(&result);
const char *p=s;
@@ -7038,6 +7065,7 @@ QCString latexEscapePDFString(const char *s)
QCString latexFilterURL(const char *s)
{
+ if (s==0) return "";
QGString result;
FTextStream t(&result);
const char *p=s;
diff --git a/src/util.h b/src/util.h
index 3305332..31691af 100644
--- a/src/util.h
+++ b/src/util.h
@@ -284,7 +284,7 @@ QCString convertToHtml(const char *s,bool keepEntities=TRUE);
QCString convertToLaTeX(const QCString &s,bool insideTabbing=FALSE,bool keepSpaces=FALSE);
-QCString convertToXML(const char *s);
+QCString convertToXML(const char *s, bool keepEntities=FALSE);
QCString convertToDocBook(const char *s);
diff --git a/src/vhdldocgen.cpp b/src/vhdldocgen.cpp
index b18bd3f..808b32b 100644
--- a/src/vhdldocgen.cpp
+++ b/src/vhdldocgen.cpp
@@ -3774,8 +3774,8 @@ void FlowChart::printUmlTree()
QCString n=convertNameToFileName();
QCString tmp=htmlOutDir;
- n=writePlantUMLSource(tmp,n,qcs);
- generatePlantUMLOutput(n.data(),tmp.data(),PUML_SVG);
+ n=PlantumlManager::instance()->writePlantUMLSource(tmp,n,qcs,PlantumlManager::PUML_SVG);
+ PlantumlManager::instance()->generatePlantUMLOutput(n.data(),tmp.data(),PlantumlManager::PUML_SVG);
}
QCString FlowChart::convertNameToFileName()
diff --git a/src/vhdljjparser.cpp b/src/vhdljjparser.cpp
index 81a7ca1..4a312bd 100644
--- a/src/vhdljjparser.cpp
+++ b/src/vhdljjparser.cpp
@@ -244,7 +244,6 @@ void VhdlParser::handleFlowComment(const char* doc)
void VhdlParser::handleCommentBlock(const char* doc1,bool brief)
{
- int position=0;
QCString doc;
doc.append(doc1);
// fprintf(stderr,"\n %s",doc.data());
@@ -258,7 +257,6 @@ void VhdlParser::handleCommentBlock(const char* doc1,bool brief)
VhdlDocGen::prepareComment(doc);
- bool needsEntry=FALSE;
Protection protection=Public;
if (oldEntry==current)
@@ -290,10 +288,13 @@ void VhdlParser::handleCommentBlock(const char* doc1,bool brief)
current->stat=true;
}
+ int position=0;
+ bool needsEntry=FALSE;
+ QCString processedDoc = preprocessCommentBlock(doc,yyFileName,iDocLine);
while (parseCommentBlock(
g_thisParser,
current,
- doc, // text
+ processedDoc, // text
yyFileName, // file
iDocLine, // line of block start
brief,
diff --git a/src/xmldocvisitor.cpp b/src/xmldocvisitor.cpp
index e464088..01e0a6d 100644
--- a/src/xmldocvisitor.cpp
+++ b/src/xmldocvisitor.cpp
@@ -60,7 +60,7 @@ static void visitPreStart(FTextStream &t, const char *cmd, bool doCaption,
}
if (!name.isEmpty())
{
- t << " name=\"" << name << "\"";
+ t << " name=\"" << convertToXML(name, TRUE) << "\"";
}
if (!width.isEmpty())
{
@@ -770,9 +770,7 @@ void XmlDocVisitor::visitPost(DocInternal *)
void XmlDocVisitor::visitPre(DocHRef *href)
{
if (m_hide) return;
- m_t << "<ulink url=\"";
- filter(href->url());
- m_t << "\">";
+ m_t << "<ulink url=\"" << convertToXML(href->url(), TRUE) << "\">";
}
void XmlDocVisitor::visitPost(DocHRef *)