Skip to content

Commit f3a206c

Browse files
committed
issue doxygen#11634 Doxygen Latex Tables not working correctly
1 parent e15e5ff commit f3a206c

File tree

10 files changed

+239
-3323
lines changed

10 files changed

+239
-3323
lines changed

doc/Doxyfile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ ALIASES += TeX="\f({\TeX}\f)"
6161
ALIASES += forceNewPage="\latexonly \newpage \endlatexonly"
6262
ALIASES += startalign=" \latexonly\noalign{\endlatexonly"
6363
ALIASES += endalign=" \latexonly}\endlatexonly"
64+
ALIASES += startalign=
65+
ALIASES += endalign=
6466
ALIASES += startendhtmltag{1}="\startalign\anchor htmltag_\1 \addindex \"\<\1\>\" ^^ \anchor htmltag_end\1 \addindex \"\</\1\>\"\endalign <tt>\<\1\></tt> / <tt>\</\1\></tt>"
6567
LATEX_BATCHMODE = YES
6668
LATEX_EXTRA_STYLESHEET = manual.sty

doc/doxygen_manual.tex

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,6 @@
1616
\pdfminorversion=7
1717
\pdfsuppresswarningpagegroup=1
1818
\documentclass{book}
19-
%% moved from doxygen.sty due to workaround for LaTex 2019 version and unmaintained tabu package
20-
\usepackage{ifthen}
21-
\ifx\requestedLaTeXdate\undefined
22-
\usepackage{array}
23-
\else
24-
\usepackage{array}[=2016-10-06]
25-
\fi
2619
%%
2720
\makeatletter
2821
% suppress package identification of infwarerr as it contains the word "warning"
@@ -41,7 +34,6 @@
4134
\usepackage{geometry}
4235
\usepackage{listings}
4336
\usepackage{color}
44-
%%\usepackage{ifthen} %% moved to top due to workaround for LaTex 2019 version and unmaintained tabu package
4537
\usepackage[table]{xcolor}
4638
\PassOptionsToPackage{warn}{textcomp}
4739
\usepackage{textcomp}

doc/htmlcmds.dox

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -368,7 +368,7 @@ The list of special HTML4 character entities with their descriptions has been ta
368368
| <tt>\&lsaquo;</tt> | &lsaquo; | single left-pointing angle quotation mark |
369369
| <tt>\&rsaquo;</tt> | &rsaquo; | single right-pointing angle quotation mark |
370370
| <tt>\&euro;</tt> | &euro; | euro sign |
371-
| **Doxygen extensions:** |||
371+
| **Doxygen extensions** |||
372372
| <tt>\&tm;</tt> | &tm; | trade mark sign |
373373
| <tt>\&apos;</tt> | &apos; | apostrophe|
374374

src/latexdocvisitor.cpp

Lines changed: 98 additions & 150 deletions
Original file line numberDiff line numberDiff line change
@@ -1256,11 +1256,11 @@ void LatexDocVisitor::writeStartTableCommand(const DocNodeVariant *n,size_t cols
12561256
{
12571257
if (isTableNested(n))
12581258
{
1259-
m_t << "\n\\begin{DoxyTableNested}{" << cols << "}\n";
1259+
m_t << "\n\\begin{DoxyTableNested}{" << cols << "}";
12601260
}
12611261
else
12621262
{
1263-
m_t << "\n\\begin{DoxyTable}{" << cols << "}\n";
1263+
m_t << "\n\\begin{DoxyTable}{" << cols << "}";
12641264
}
12651265
//return isNested ? "TabularNC" : "TabularC";
12661266
}
@@ -1294,33 +1294,40 @@ void LatexDocVisitor::operator()(const DocHtmlTable &t)
12941294
m_t << "\n";
12951295
}
12961296

1297+
const DocHtmlRow *firstRow = std::get_if<DocHtmlRow>(t.firstRow());
12971298
writeStartTableCommand(t.parent(),t.numColumns());
1298-
1299-
if (c)
1299+
if (!isTableNested(t.parent()))
13001300
{
1301-
m_t << "\\caption{";
1302-
std::visit(*this, *t.caption());
1301+
// write caption
1302+
m_t << "{";
1303+
if (c)
1304+
{
1305+
std::visit(*this, *t.caption());
1306+
}
1307+
m_t << "}";
1308+
// write label
1309+
m_t << "{";
1310+
if (c)
1311+
{
1312+
m_t << stripPath(c->file()) << "_" << c->anchor();
1313+
}
13031314
m_t << "}";
1304-
m_t << "\\label{" << stripPath(c->file()) << "_" << c->anchor() << "}";
1305-
m_t << "\\\\\n";
13061315
}
1307-
1308-
setNumCols(t.numColumns());
1309-
m_t << "\\hline\n";
1310-
1311-
// check if first row is a heading and then render the row already here
1312-
// and end it with \endfirsthead (triggered via m_firstRow==TRUE)
1313-
// then repeat the row as normal and end it with \endhead (m_firstRow==FALSE)
1314-
const DocHtmlRow *firstRow = std::get_if<DocHtmlRow>(t.firstRow());
1316+
// write head row
1317+
m_t << "{";
13151318
if (firstRow && firstRow->isHeading())
13161319
{
1317-
setFirstRow(TRUE);
1318-
if (!isTableNested(t.parent()))
1319-
{
1320-
std::visit(*this,*t.firstRow());
1321-
}
1322-
setFirstRow(FALSE);
1320+
m_t << "1";
1321+
}
1322+
else
1323+
{
1324+
m_t << "0";
13231325
}
1326+
m_t << "}";
1327+
m_t << "\n";
1328+
1329+
setNumCols(t.numColumns());
1330+
13241331
visitChildren(t);
13251332
writeEndTableCommand(t.parent());
13261333
popTableState();
@@ -1339,32 +1346,6 @@ void LatexDocVisitor::operator()(const DocHtmlRow &row)
13391346

13401347
visitChildren(row);
13411348

1342-
size_t c=currentColumn();
1343-
while (c<=numCols()) // end of row while inside a row span?
1344-
{
1345-
for (const auto &span : rowSpans())
1346-
{
1347-
//printf(" found row span: column=%d rs=%d cs=%d rowIdx=%d cell->rowIdx=%d i=%d c=%d\n",
1348-
// span->column, span->rowSpan,span->colSpan,row.rowIndex(),span->cell->rowIndex(),i,c);
1349-
if (span.rowSpan>0 && span.column==c && // we are at a cell in a row span
1350-
row.rowIndex()>span.cell.rowIndex() // but not the row that started the span
1351-
)
1352-
{
1353-
m_t << "&";
1354-
if (span.colSpan>1) // row span is also part of a column span
1355-
{
1356-
m_t << "\\multicolumn{" << span.colSpan << "}{";
1357-
m_t << "}|}{}";
1358-
}
1359-
else // solitary row span
1360-
{
1361-
m_t << "\\multicolumn{1}{c|}{}";
1362-
}
1363-
}
1364-
}
1365-
c++;
1366-
}
1367-
13681349
m_t << "\\\\";
13691350

13701351
size_t col = 1;
@@ -1377,7 +1358,6 @@ void LatexDocVisitor::operator()(const DocHtmlRow &row)
13771358
}
13781359
else if (span.column>col)
13791360
{
1380-
m_t << "\\cline{" << col << "-" << (span.column-1) << "}";
13811361
col = span.column+span.colSpan;
13821362
}
13831363
else
@@ -1386,142 +1366,110 @@ void LatexDocVisitor::operator()(const DocHtmlRow &row)
13861366
}
13871367
}
13881368

1389-
if (col <= numCols())
1390-
{
1391-
m_t << "\\cline{" << col << "-" << numCols() << "}";
1392-
}
1393-
13941369
m_t << "\n";
1395-
1396-
const DocNodeVariant *n = ::parent(row.parent());
1397-
if (row.isHeading() && row.rowIndex()==1 && !isTableNested(n))
1398-
{
1399-
if (firstRow())
1400-
{
1401-
m_t << "\\endfirsthead\n";
1402-
m_t << "\\hline\n";
1403-
m_t << "\\endfoot\n";
1404-
m_t << "\\hline\n";
1405-
}
1406-
else
1407-
{
1408-
m_t << "\\endhead\n";
1409-
}
1410-
}
14111370
}
14121371

14131372
void LatexDocVisitor::operator()(const DocHtmlCell &c)
14141373
{
14151374
if (m_hide) return;
1416-
1417-
const DocHtmlRow *row = std::get_if<DocHtmlRow>(c.parent());
1375+
//printf("Cell(r=%u,c=%u) rowSpan=%d colSpan=%d currentColumn()=%zu\n",c.rowIndex(),c.columnIndex(),c.rowSpan(),c.colSpan(),currentColumn());
14181376

14191377
setCurrentColumn(currentColumn()+1);
14201378

1421-
//Skip columns that span from above.
1422-
for (const auto &span : rowSpans())
1379+
QCString cellOpts;
1380+
QCString cellSpec;
1381+
auto appendOpt = [&cellOpts](const QCString &s)
14231382
{
1424-
if (span.rowSpan>0 && span.column==currentColumn())
1383+
if (!cellOpts.isEmpty()) cellOpts+=",";
1384+
cellOpts+=s;
1385+
};
1386+
auto appendSpec = [&cellSpec](const QCString &s)
1387+
{
1388+
if (!cellSpec.isEmpty()) cellSpec+=",";
1389+
cellSpec+=s;
1390+
};
1391+
auto writeCell = [this,&cellOpts,&cellSpec]()
1392+
{
1393+
if (!cellOpts.isEmpty() || !cellSpec.isEmpty())
14251394
{
1426-
if (row && span.colSpan>1)
1427-
{
1428-
m_t << "\\multicolumn{" << span.colSpan << "}{";
1429-
if (currentColumn() /*c.columnIndex()*/==1) // add extra | for first column
1430-
{
1431-
m_t << "|";
1432-
}
1433-
m_t << "l|}{" << (c.isHeading()? "\\columncolor{\\tableheadbgcolor}" : "") << "}"; // alignment not relevant, empty column
1434-
setCurrentColumn(currentColumn()+span.colSpan);
1435-
}
1436-
else
1395+
m_t << "\\SetCell";
1396+
if (!cellOpts.isEmpty())
14371397
{
1438-
setCurrentColumn(currentColumn()+1);
1398+
m_t << "[" << cellOpts << "]";
14391399
}
1440-
m_t << "&";
1400+
m_t << "{" << cellSpec << "}";
14411401
}
1442-
}
1402+
};
14431403

1444-
int cs = c.colSpan();
1445-
int a = c.alignment();
1446-
if (cs>1 && row)
1404+
// skip over columns that have a row span starting at an earlier row
1405+
for (const auto &span : rowSpans())
14471406
{
1448-
setInColSpan(TRUE);
1449-
m_t << "\\multicolumn{" << cs << "}{";
1450-
if (c.columnIndex()==1) // add extra | for first column
1451-
{
1452-
m_t << "|";
1453-
}
1454-
switch (a)
1407+
//printf("span(r=%u,c=%u): column=%zu colSpan=%zu,rowSpan=%zu currentColumn()=%zu\n",
1408+
// span.cell.rowIndex(),span.cell.columnIndex(),
1409+
// span.column,span.colSpan,span.rowSpan,
1410+
// currentColumn());
1411+
if (span.rowSpan>0 && span.column==currentColumn())
14551412
{
1456-
case DocHtmlCell::Right:
1457-
m_t << "r|}{";
1458-
break;
1459-
case DocHtmlCell::Center:
1460-
m_t << "c|}{";
1461-
break;
1462-
default:
1463-
m_t << "l|}{";
1464-
break;
1413+
setCurrentColumn(currentColumn()+span.colSpan);
1414+
for (size_t i=0;i<span.colSpan;i++)
1415+
{
1416+
m_t << "&";
1417+
}
14651418
}
14661419
}
1420+
1421+
int cs = c.colSpan();
1422+
int ha = c.alignment();
14671423
int rs = c.rowSpan();
14681424
int va = c.valignment();
1469-
if (rs>0)
1425+
1426+
switch (ha) // horizontal alignment
14701427
{
1471-
setInRowSpan(TRUE);
1472-
m_t << "\\multirow";
1473-
switch(va)
1474-
{
1475-
case DocHtmlCell::Top:
1476-
m_t << "[t]";
1477-
break;
1478-
case DocHtmlCell::Bottom:
1479-
m_t << "[b]";
1480-
break;
1481-
case DocHtmlCell::Middle:
1482-
break; // No alignment option needed
1483-
default:
1484-
break;
1485-
}
1486-
//printf("adding row span: cell={r=%d c=%d rs=%d cs=%d} curCol=%d\n",
1428+
case DocHtmlCell::Right:
1429+
appendSpec("r");
1430+
break;
1431+
case DocHtmlCell::Center:
1432+
appendSpec("c");
1433+
break;
1434+
default:
1435+
// default
1436+
break;
1437+
}
1438+
if (rs>0) // row span
1439+
{
1440+
appendOpt("r="+QCString().setNum(rs));
1441+
//printf("adding row span: cell={r=%d c=%d rs=%d cs=%d} curCol=%zu\n",
14871442
// c.rowIndex(),c.columnIndex(),c.rowSpan(),c.colSpan(),
14881443
// currentColumn());
14891444
addRowSpan(ActiveRowSpan(c,rs,cs,currentColumn()));
1490-
m_t << "{" << rs << "}{*}{";
14911445
}
1492-
if (a==DocHtmlCell::Center)
1446+
if (cs>1) // column span
14931447
{
1494-
m_t << "\\PBS\\centering ";
1495-
}
1496-
else if (a==DocHtmlCell::Right)
1497-
{
1498-
m_t << "\\PBS\\raggedleft ";
1499-
}
1500-
if (c.isHeading())
1501-
{
1502-
m_t << "\\cellcolor{\\tableheadbgcolor}\\textbf{ ";
1448+
// update column to the end of the span, needs to be done *after* calling addRowSpan()
1449+
setCurrentColumn(currentColumn()+cs-1);
1450+
appendOpt("c="+QCString().setNum(cs));
15031451
}
1504-
if (cs>1)
1452+
switch(va) // vertical alignment
15051453
{
1506-
setCurrentColumn(currentColumn()+cs-1);
1454+
case DocHtmlCell::Top:
1455+
appendSpec("h");
1456+
break;
1457+
case DocHtmlCell::Bottom:
1458+
appendSpec("f");
1459+
break;
1460+
case DocHtmlCell::Middle:
1461+
// default
1462+
break;
15071463
}
1464+
writeCell();
15081465

15091466
visitChildren(c);
15101467

1511-
if (c.isHeading())
1468+
for (int i=0;i<cs-1;i++)
15121469
{
1513-
m_t << "}";
1514-
}
1515-
if (inRowSpan())
1516-
{
1517-
setInRowSpan(FALSE);
1518-
m_t << "}";
1519-
}
1520-
if (inColSpan())
1521-
{
1522-
setInColSpan(FALSE);
1523-
m_t << "}";
1470+
m_t << "&"; // placeholder for invisible cell
15241471
}
1472+
15251473
if (!c.isLast()) m_t << "&";
15261474
}
15271475

src/latexdocvisitor.h

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -188,8 +188,6 @@ class LatexDocVisitor : public DocVisitor
188188
RowSpanList rowSpans;
189189
size_t numCols = 0;
190190
size_t currentColumn = 0;
191-
bool inRowSpan = false;
192-
bool inColSpan = false;
193191
bool firstRow = false;
194192
};
195193
std::stack<TableState> m_tableStateStack; // needed for nested tables
@@ -229,22 +227,6 @@ class LatexDocVisitor : public DocVisitor
229227
{
230228
if (!m_tableStateStack.empty()) m_tableStateStack.top().numCols = num;
231229
}
232-
bool inRowSpan() const
233-
{
234-
return !m_tableStateStack.empty() ? m_tableStateStack.top().inRowSpan : FALSE;
235-
}
236-
void setInRowSpan(bool b)
237-
{
238-
if (!m_tableStateStack.empty()) m_tableStateStack.top().inRowSpan = b;
239-
}
240-
bool inColSpan() const
241-
{
242-
return !m_tableStateStack.empty() ? m_tableStateStack.top().inColSpan : FALSE;
243-
}
244-
void setInColSpan(bool b)
245-
{
246-
if (!m_tableStateStack.empty()) m_tableStateStack.top().inColSpan = b;
247-
}
248230
bool firstRow() const
249231
{
250232
return !m_tableStateStack.empty() ? m_tableStateStack.top().firstRow : FALSE;

0 commit comments

Comments
 (0)