From 883989fced827524354297009fde396ca6264a31 Mon Sep 17 00:00:00 2001 From: Dimitri van Heesch Date: Tue, 18 Aug 2015 19:40:03 +0200 Subject: Fixes to support nested tables again --- src/ftvhelp.cpp | 1 + src/htmldocvisitor.cpp | 18 ++---- src/latexdocvisitor.cpp | 136 +++++++++++++++++++++++++++----------------- src/latexdocvisitor.h | 84 ++++++++++++++++++++++++--- templates/html/doxygen.css | 4 ++ templates/latex/doxygen.sty | 8 ++- 6 files changed, 180 insertions(+), 71 deletions(-) diff --git a/src/ftvhelp.cpp b/src/ftvhelp.cpp index e2774a9..a70e243 100644 --- a/src/ftvhelp.cpp +++ b/src/ftvhelp.cpp @@ -171,6 +171,7 @@ void FTVHelp::decContentsDepth() /*! Add a list item to the contents file. * \param isDir TRUE if the item is a directory, FALSE if it is a text + * \param name The name of the item. * \param ref the URL of to the item. * \param file the file containing the definition of the item * \param anchor the anchor within the file. diff --git a/src/htmldocvisitor.cpp b/src/htmldocvisitor.cpp index 296a957..2e9795e 100644 --- a/src/htmldocvisitor.cpp +++ b/src/htmldocvisitor.cpp @@ -1301,6 +1301,11 @@ void HtmlDocVisitor::visitPre(DocHtmlTable *t) forceEndParagraph(t); + if (t->hasCaption()) + { + m_t << "caption()->anchor() << "\">\n"; + } + QString attrs = htmlAttribsToString(t->attribs()); if (attrs.isEmpty()) { @@ -1353,21 +1358,11 @@ void HtmlDocVisitor::visitPost(DocHtmlCell *c) void HtmlDocVisitor::visitPre(DocHtmlCaption *c) { if (m_hide) return; - if (c->hasCaptionId()) - { - m_t << "anchor() << "\">\n"; - } bool hasAlign = FALSE; HtmlAttribListIterator li(c->attribs()); HtmlAttrib *att; QCString id; - for (li.toFirst();(att=li.current());++li) - { - if (att->name=="align") hasAlign=TRUE; - } - m_t << "attribs()); - if (!hasAlign) m_t << " align=\"bottom\""; - m_t << ">"; + m_t << "attribs()) << ">"; } void HtmlDocVisitor::visitPost(DocHtmlCaption *) @@ -1813,7 +1808,6 @@ void HtmlDocVisitor::visitPre(DocHtmlBlockQuote *b) { if (m_hide) return; forceEndParagraph(b); - QString attrs = htmlAttribsToString(b->attribs()); if (attrs.isEmpty()) { diff --git a/src/latexdocvisitor.cpp b/src/latexdocvisitor.cpp index 22b3b32..5e7278c 100644 --- a/src/latexdocvisitor.cpp +++ b/src/latexdocvisitor.cpp @@ -172,10 +172,9 @@ LatexDocVisitor::LatexDocVisitor(FTextStream &t,CodeOutputInterface &ci, const char *langExt,bool insideTabbing) : DocVisitor(DocVisitor_Latex), m_t(t), m_ci(ci), m_insidePre(FALSE), m_insideItem(FALSE), m_hide(FALSE), m_hideCaption(FALSE), m_insideTabbing(insideTabbing), - m_insideTable(FALSE), m_langExt(langExt), m_currentColumn(0), - m_inRowspan(FALSE), m_inColspan(FALSE), m_firstRow(FALSE) + m_langExt(langExt) { - m_rowSpans.setAutoDelete(TRUE); + m_tableStateStack.setAutoDelete(TRUE); } //-------------------------------------- @@ -890,7 +889,7 @@ void LatexDocVisitor::visitPost(DocHtmlDescData *) { } -static const char *getTableName(const DocNode *n) +static bool tableIsNested(const DocNode *n) { bool isNested=FALSE; while (n && !isNested) @@ -898,14 +897,39 @@ static const char *getTableName(const DocNode *n) isNested = n->kind()==DocNode::Kind_HtmlTable || n->kind()==DocNode::Kind_ParamSect; n = n->parent(); } - return isNested ? "TabularNC" : "TabularC"; + return isNested; +} + +static void writeStartTableCommand(FTextStream &t,const DocNode *n,int cols) +{ + if (tableIsNested(n)) + { + t << "\\begin{tabularx}{\\linewidth}{|*{" << cols << "}{>{\\raggedright\\arraybackslash}X|}}"; + } + else + { + t << "\\tabulinesep=1mm\n\\begin{longtabu} spread 0pt [c]{*" << cols << "{|X[-1]}|}\n"; + } + //return isNested ? "TabularNC" : "TabularC"; +} + +static void writeEndTableCommand(FTextStream &t,const DocNode *n) +{ + if (tableIsNested(n)) + { + t << "\\end{tabularx}\n"; + } + else + { + t << "\\end{longtabu}\n"; + } + //return isNested ? "TabularNC" : "TabularC"; } void LatexDocVisitor::visitPre(DocHtmlTable *t) { - m_rowSpans.clear(); - m_insideTable=TRUE; if (m_hide) return; + pushTableState(); if (t->hasCaption()) { DocHtmlCaption *c = t->caption(); @@ -918,7 +942,7 @@ void LatexDocVisitor::visitPre(DocHtmlTable *t) m_t << endl; } - m_t << "\\begin{" << getTableName(t->parent()) << "}{" << t->numColumns() << "}\n"; + writeStartTableCommand(m_t,t->parent(),t->numColumns()); if (t->hasCaption()) { @@ -930,7 +954,7 @@ void LatexDocVisitor::visitPre(DocHtmlTable *t) m_t << "\\\\\n"; } - m_numCols = t->numColumns(); + setNumCols(t->numColumns()); m_t << "\\hline\n"; // check if first row is a heading and then render the row already here @@ -939,17 +963,17 @@ void LatexDocVisitor::visitPre(DocHtmlTable *t) DocHtmlRow *firstRow = t->firstRow(); if (firstRow && firstRow->isHeading()) { - m_firstRow=TRUE; + setFirstRow(TRUE); firstRow->accept(this); - m_firstRow=FALSE; + setFirstRow(FALSE); } } void LatexDocVisitor::visitPost(DocHtmlTable *t) { - m_insideTable=FALSE; if (m_hide) return; - m_t << "\\end{" << getTableName(t->parent()) << "}\n"; + writeEndTableCommand(m_t,t->parent()); + popTableState(); } void LatexDocVisitor::visitPre(DocHtmlCaption *c) @@ -965,7 +989,7 @@ void LatexDocVisitor::visitPost(DocHtmlCaption *c) void LatexDocVisitor::visitPre(DocHtmlRow *r) { - m_currentColumn = 0; + setCurrentColumn(0); if (r->isHeading()) m_t << "\\rowcolor{\\tableheadbgcolor}"; } @@ -973,15 +997,15 @@ void LatexDocVisitor::visitPost(DocHtmlRow *row) { if (m_hide) return; - int c=m_currentColumn; - while (c<=m_numCols) // end of row while inside a row span? + int c=currentColumn(); + while (c<=numCols()) // end of row while inside a row span? { uint i; - for (i=0;irowIdx=%d\n", - // span->column, span->rowSpan,span->colSpan,row->rowIndex(),span->cell->rowIndex()); + ActiveRowSpan *span = rowSpans().at(i); + //printf(" found row span: column=%d rs=%d cs=%d rowIdx=%d cell->rowIdx=%d i=%d c=%d\n", + // span->column, span->rowSpan,span->colSpan,row->rowIndex(),span->cell->rowIndex(),i,c); if (span->rowSpan>0 && span->column==c && // we are at a cell in a row span row->rowIndex()>span->cell->rowIndex() // but not the row that started the span ) @@ -991,9 +1015,9 @@ void LatexDocVisitor::visitPost(DocHtmlRow *row) { m_t << "\\multicolumn{" << span->colSpan << "}{"; m_t << "p{(\\linewidth-\\tabcolsep*" - << m_numCols << "-\\arrayrulewidth*" + << numCols() << "-\\arrayrulewidth*" << row->visibleCells() << ")*" - << span->colSpan <<"/"<< m_numCols << "}|}{}"; + << span->colSpan <<"/"<< numCols() << "}|}{}"; } else // solitary row span { @@ -1008,9 +1032,9 @@ void LatexDocVisitor::visitPost(DocHtmlRow *row) int col = 1; uint i; - for (i=0;irowSpan>0) span->rowSpan--; if (span->rowSpan<=0) { @@ -1027,16 +1051,16 @@ void LatexDocVisitor::visitPost(DocHtmlRow *row) } } - if (col <= m_numCols) + if (col <= numCols()) { - m_t << "\\cline{" << col << "-" << m_numCols << "}"; + m_t << "\\cline{" << col << "-" << numCols() << "}"; } m_t << "\n"; if (row->isHeading() && row->rowIndex()==1) { - if (m_firstRow) + if (firstRow()) { m_t << "\\endfirsthead" << endl; m_t << "\\hline" << endl; @@ -1059,32 +1083,32 @@ void LatexDocVisitor::visitPre(DocHtmlCell *c) { row = (DocHtmlRow*)c->parent(); } - - m_currentColumn++; + + setCurrentColumn(currentColumn()+1); //Skip columns that span from above. uint i; - for (i=0;irowSpan>0 && span->column==m_currentColumn) + ActiveRowSpan *span = rowSpans().at(i); + if (span->rowSpan>0 && span->column==currentColumn()) { if (row && span->colSpan>1) { m_t << "\\multicolumn{" << span->colSpan << "}{"; - if (m_currentColumn /*c->columnIndex()*/==1) // add extra | for first column + if (currentColumn() /*c->columnIndex()*/==1) // add extra | for first column { m_t << "|"; } m_t << "p{(\\linewidth-\\tabcolsep*" - << m_numCols << "-\\arrayrulewidth*" + << numCols() << "-\\arrayrulewidth*" << row->visibleCells() << ")*" - << span->colSpan <<"/"<< m_numCols << "}|}{}"; - m_currentColumn+=span->colSpan; + << span->colSpan <<"/"<< numCols() << "}|}{}"; + setCurrentColumn(currentColumn()+span->colSpan); } else { - m_currentColumn++; + setCurrentColumn(currentColumn()+1); } m_t << "&"; } @@ -1093,23 +1117,26 @@ void LatexDocVisitor::visitPre(DocHtmlCell *c) int cs = c->colSpan(); if (cs>1 && row) { - m_inColspan = TRUE; + setInColSpan(TRUE); m_t << "\\multicolumn{" << cs << "}{"; if (c->columnIndex()==1) // add extra | for first column { m_t << "|"; } m_t << "p{(\\linewidth-\\tabcolsep*" - << m_numCols << "-\\arrayrulewidth*" + << numCols() << "-\\arrayrulewidth*" << row->visibleCells() << ")*" - << cs <<"/"<< m_numCols << "}|}{"; + << cs <<"/"<< numCols() << "}|}{"; if (c->isHeading()) m_t << "\\cellcolor{\\tableheadbgcolor}"; } int rs = c->rowSpan(); if (rs>0) { - m_inRowspan = TRUE; - m_rowSpans.append(new ActiveRowSpan(c,rs,cs,m_currentColumn)); + setInRowSpan(TRUE); + //printf("adding row span: cell={r=%d c=%d rs=%d cs=%d} curCol=%d\n", + // c->rowIndex(),c->columnIndex(),c->rowSpan(),c->colSpan(), + // currentColumn()); + addRowSpan(new ActiveRowSpan(c,rs,cs,currentColumn())); m_t << "\\multirow{" << rs << "}{\\linewidth}{"; } int a = c->alignment(); @@ -1127,7 +1154,7 @@ void LatexDocVisitor::visitPre(DocHtmlCell *c) } if (cs>1) { - m_currentColumn+=cs-1; + setCurrentColumn(currentColumn()+cs-1); } } @@ -1138,14 +1165,14 @@ void LatexDocVisitor::visitPost(DocHtmlCell *c) { m_t << "}"; } - if (m_inRowspan) + if (inRowSpan()) { - m_inRowspan = FALSE; + setInRowSpan(FALSE); m_t << "}"; } - if (m_inColspan) + if (inColSpan()) { - m_inColspan = FALSE; + setInColSpan(FALSE); m_t << "}"; } if (!c->isLast()) m_t << "&"; @@ -1603,15 +1630,22 @@ void LatexDocVisitor::filter(const char *str) void LatexDocVisitor::startLink(const QCString &ref,const QCString &file,const QCString &anchor,bool refToTable) { static bool pdfHyperLinks = Config_getBool("PDF_HYPERLINKS"); - if (ref.isEmpty() && pdfHyperLinks) // internal PDF link + if (ref.isEmpty() && pdfHyperLinks) // internal PDF link { - m_t << "\\hyperlink{"; + if (refToTable) + { + m_t << "\\doxytablelink{"; + } + else + { + m_t << "\\hyperlink{"; + } if (!file.isEmpty()) m_t << stripPath(file); if (!file.isEmpty() && !anchor.isEmpty()) m_t << "_"; if (!anchor.isEmpty()) m_t << anchor; m_t << "}{"; } - else if (refToTable) + else if (ref.isEmpty() && refToTable) { m_t << "\\doxytableref{"; } @@ -1620,7 +1654,7 @@ void LatexDocVisitor::startLink(const QCString &ref,const QCString &file,const Q m_t << "\\doxyref{"; } else // external link - { + { m_t << "{\\bf "; } } diff --git a/src/latexdocvisitor.h b/src/latexdocvisitor.h index de797ae..02df1ef 100644 --- a/src/latexdocvisitor.h +++ b/src/latexdocvisitor.h @@ -192,15 +192,85 @@ class LatexDocVisitor : public DocVisitor bool m_hide; bool m_hideCaption; bool m_insideTabbing; - bool m_insideTable; - int m_numCols; QStack m_enabled; QCString m_langExt; - RowSpanList m_rowSpans; - int m_currentColumn; - bool m_inRowspan; - bool m_inColspan; - bool m_firstRow; + + struct TableState + { + TableState() : numCols(0), currentColumn(0), inRowSpan(FALSE), + inColSpan(FALSE), firstRow(FALSE) + { rowSpans.setAutoDelete(TRUE); } + RowSpanList rowSpans; + int numCols; + int currentColumn; + bool inRowSpan; + bool inColSpan; + bool firstRow; + }; + QStack m_tableStateStack; // needed for nested tables + RowSpanList m_emptyRowSpanList; + + void pushTableState() + { + m_tableStateStack.push(new TableState); + } + void popTableState() + { + delete m_tableStateStack.pop(); + } + int currentColumn() const + { + return !m_tableStateStack.isEmpty() ? m_tableStateStack.top()->currentColumn : 0; + } + void setCurrentColumn(int col) + { + if (!m_tableStateStack.isEmpty()) m_tableStateStack.top()->currentColumn = col; + } + int numCols() const + { + return !m_tableStateStack.isEmpty() ? m_tableStateStack.top()->numCols : 0; + } + void setNumCols(int num) + { + if (!m_tableStateStack.isEmpty()) m_tableStateStack.top()->numCols = num; + } + bool inRowSpan() const + { + return !m_tableStateStack.isEmpty() ? m_tableStateStack.top()->inRowSpan : FALSE; + } + void setInRowSpan(bool b) + { + if (!m_tableStateStack.isEmpty()) m_tableStateStack.top()->inRowSpan = b; + } + bool inColSpan() const + { + return !m_tableStateStack.isEmpty() ? m_tableStateStack.top()->inColSpan : FALSE; + } + void setInColSpan(bool b) + { + if (!m_tableStateStack.isEmpty()) m_tableStateStack.top()->inColSpan = b; + } + bool firstRow() const + { + return !m_tableStateStack.isEmpty() ? m_tableStateStack.top()->firstRow : FALSE; + } + void setFirstRow(bool b) + { + if (!m_tableStateStack.isEmpty()) m_tableStateStack.top()->firstRow = b; + } + const RowSpanList &rowSpans() + { + return !m_tableStateStack.isEmpty() ? m_tableStateStack.top()->rowSpans : m_emptyRowSpanList; + } + void addRowSpan(ActiveRowSpan *span) + { + if (!m_tableStateStack.isEmpty()) m_tableStateStack.top()->rowSpans.append(span); + } + bool insideTable() const + { + return !m_tableStateStack.isEmpty(); + } + }; #endif diff --git a/templates/html/doxygen.css b/templates/html/doxygen.css index e41b0d7..8383f5a 100644 --- a/templates/html/doxygen.css +++ b/templates/html/doxygen.css @@ -832,6 +832,10 @@ address { color: ##33; } +table.doxtable caption { + caption-side: top; +} + table.doxtable { border-collapse:collapse; margin-top: 4px; diff --git a/templates/latex/doxygen.sty b/templates/latex/doxygen.sty index 64fb0f0..803b662 100644 --- a/templates/latex/doxygen.sty +++ b/templates/latex/doxygen.sty @@ -11,6 +11,7 @@ \RequirePackage[table]{xcolor} \RequirePackage{longtable} \RequirePackage{tabu} +\RequirePackage{tabularx} %---------- Internal commands used in this style file ---------------- @@ -421,7 +422,7 @@ \newcommand{\PBS}[1]{\let\temp=\\#1\let\\=\temp}% \newenvironment{TabularC}[1]% {\tabulinesep=1mm -\begin{longtabu} spread 0pt [l]{*#1{|X[-1]}|}}% +\begin{longtabu} spread 0pt [c]{*#1{|X[-1]}|}}% {\end{longtabu}\par}% \newenvironment{TabularNC}[1]% @@ -444,6 +445,11 @@ \textbf{#1} (\textnormal{#2}\,\pageref{#3})% } +% Used to link to a table when hyperlinks are turned on +\newcommand{\doxytablelink}[2]{% + \ref{#1}% +} + % Used to link to a table when hyperlinks are turned off \newcommand{\doxytableref}[3]{% \ref{#3}% -- cgit v0.12