QTextDocument: add css-styling of table cell borders to HTML import/export

Supported style attributes:

<table>
style: supports "border-collapse: collapse" and "border-color".
border: width of the outer border
bordercolor: basic color for all borders

<tr>
style: not supported

<td>/</th>
style: supports the "border", "border-[top|left|bottom|right]]"
       shorthand styles and the "border-width", "border-color"
       and "border-style" (and the top/left/bottom/right variants)
       attributes

<table border=1 style="border-collapse: collapse"> will render
a simple 1px table grid.

Notes:

The QTextDocument table model is much simpler than the HTML table model.
It basically only has <table> and <td> support. So the HTML parser is
forced to map markup and styling to the QTextDocument model which
is not without loss.

In other words: While QTextDocument -> HTML -> QTextDocument should
preserve the QTextDocument structure, HTML -> QTextDocument -> HTML
does not preserve the HTML DOM at all.

So for now the HTML importer and writer only support border styles on
the <td> and <th> nodes. In future updates, the HTML parser might be
enhanced to map <tr> and <table> CSS styles to the cells.

Change-Id: If9e7312fa6cbf270cf8f7b3c72ba1fa094107517
Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
This commit is contained in:
Nils Jeisecke 2015-12-17 16:38:15 +01:00 committed by Nils Jeisecke
parent 8240c24866
commit d8a9bec35f
9 changed files with 412 additions and 40 deletions

View File

@ -92,6 +92,7 @@ static const QCssKnownValue properties[NumProperties - 1] = {
{ "border-bottom-right-radius", BorderBottomRightRadius },
{ "border-bottom-style", BorderBottomStyle },
{ "border-bottom-width", BorderBottomWidth },
{ "border-collapse", BorderCollapse },
{ "border-color", BorderColor },
{ "border-image", BorderImage },
{ "border-left", BorderLeft },
@ -1732,6 +1733,14 @@ void Declaration::borderImageValue(QString *image, int *cuts,
*h = *v;
}
bool Declaration::borderCollapseValue() const
{
if (d->values.count() != 1)
return false;
else
return d->values.at(0).toString() == QLatin1String("collapse");
}
QIcon Declaration::iconValue() const
{
if (d->parsed.isValid())

View File

@ -122,6 +122,7 @@ enum Property {
BorderRight,
BorderTop,
BorderBottom,
BorderCollapse,
Padding,
PaddingLeft,
PaddingRight,
@ -478,6 +479,7 @@ struct Q_GUI_EXPORT Declaration
QIcon iconValue() const;
void borderImageValue(QString *image, int *cuts, TileMode *h, TileMode *v) const;
bool borderCollapseValue() const;
};
QT_CSS_DECLARE_TYPEINFO(Declaration, Q_MOVABLE_TYPE)

View File

@ -2593,51 +2593,43 @@ void QTextHtmlExporter::emitFloatStyle(QTextFrameFormat::Position pos, StyleMode
html += QLatin1Char('\"');
}
static QLatin1String richtextBorderStyleToHtmlBorderStyle(QTextFrameFormat::BorderStyle style)
{
switch (style) {
case QTextFrameFormat::BorderStyle_None:
return QLatin1String("none");
case QTextFrameFormat::BorderStyle_Dotted:
return QLatin1String("dotted");
case QTextFrameFormat::BorderStyle_Dashed:
return QLatin1String("dashed");
case QTextFrameFormat::BorderStyle_Solid:
return QLatin1String("solid");
case QTextFrameFormat::BorderStyle_Double:
return QLatin1String("double");
case QTextFrameFormat::BorderStyle_DotDash:
return QLatin1String("dot-dash");
case QTextFrameFormat::BorderStyle_DotDotDash:
return QLatin1String("dot-dot-dash");
case QTextFrameFormat::BorderStyle_Groove:
return QLatin1String("groove");
case QTextFrameFormat::BorderStyle_Ridge:
return QLatin1String("ridge");
case QTextFrameFormat::BorderStyle_Inset:
return QLatin1String("inset");
case QTextFrameFormat::BorderStyle_Outset:
return QLatin1String("outset");
default:
Q_UNREACHABLE();
};
return QLatin1String("");
}
void QTextHtmlExporter::emitBorderStyle(QTextFrameFormat::BorderStyle style)
{
Q_ASSERT(style <= QTextFrameFormat::BorderStyle_Outset);
html += QLatin1String(" border-style:");
switch (style) {
case QTextFrameFormat::BorderStyle_None:
html += QLatin1String("none");
break;
case QTextFrameFormat::BorderStyle_Dotted:
html += QLatin1String("dotted");
break;
case QTextFrameFormat::BorderStyle_Dashed:
html += QLatin1String("dashed");
break;
case QTextFrameFormat::BorderStyle_Solid:
html += QLatin1String("solid");
break;
case QTextFrameFormat::BorderStyle_Double:
html += QLatin1String("double");
break;
case QTextFrameFormat::BorderStyle_DotDash:
html += QLatin1String("dot-dash");
break;
case QTextFrameFormat::BorderStyle_DotDotDash:
html += QLatin1String("dot-dot-dash");
break;
case QTextFrameFormat::BorderStyle_Groove:
html += QLatin1String("groove");
break;
case QTextFrameFormat::BorderStyle_Ridge:
html += QLatin1String("ridge");
break;
case QTextFrameFormat::BorderStyle_Inset:
html += QLatin1String("inset");
break;
case QTextFrameFormat::BorderStyle_Outset:
html += QLatin1String("outset");
break;
default:
Q_ASSERT(false);
break;
};
html += richtextBorderStyleToHtmlBorderStyle(style);
html += QLatin1Char(';');
}
@ -3204,6 +3196,33 @@ void QTextHtmlExporter::emitTable(const QTextTable *table)
if (cellFormat.hasProperty(QTextFormat::TableCellBottomPadding))
styleString += QLatin1String(" padding-bottom:") + QString::number(cellFormat.bottomPadding()) + QLatin1Char(';');
if (cellFormat.hasProperty(QTextFormat::TableCellTopBorder))
styleString += QLatin1String(" border-top:") + QString::number(cellFormat.topBorder()) + QLatin1String("px;");
if (cellFormat.hasProperty(QTextFormat::TableCellRightBorder))
styleString += QLatin1String(" border-right:") + QString::number(cellFormat.rightBorder()) + QLatin1String("px;");
if (cellFormat.hasProperty(QTextFormat::TableCellBottomBorder))
styleString += QLatin1String(" border-bottom:") + QString::number(cellFormat.bottomBorder()) + QLatin1String("px;");
if (cellFormat.hasProperty(QTextFormat::TableCellLeftBorder))
styleString += QLatin1String(" border-left:") + QString::number(cellFormat.leftBorder()) + QLatin1String("px;");
if (cellFormat.hasProperty(QTextFormat::TableCellTopBorderBrush))
styleString += QLatin1String(" border-top-color:") + cellFormat.topBorderBrush().color().name() + QLatin1Char(';');
if (cellFormat.hasProperty(QTextFormat::TableCellRightBorderBrush))
styleString += QLatin1String(" border-right-color:") + cellFormat.rightBorderBrush().color().name() + QLatin1Char(';');
if (cellFormat.hasProperty(QTextFormat::TableCellBottomBorderBrush))
styleString += QLatin1String(" border-bottom-color:") + cellFormat.bottomBorderBrush().color().name() + QLatin1Char(';');
if (cellFormat.hasProperty(QTextFormat::TableCellLeftBorderBrush))
styleString += QLatin1String(" border-left-color:") + cellFormat.leftBorderBrush().color().name() + QLatin1Char(';');
if (cellFormat.hasProperty(QTextFormat::TableCellTopBorderStyle))
styleString += QLatin1String(" border-top-style:") + richtextBorderStyleToHtmlBorderStyle(cellFormat.topBorderStyle()) + QLatin1Char(';');
if (cellFormat.hasProperty(QTextFormat::TableCellRightBorderStyle))
styleString += QLatin1String(" border-right-style:") + richtextBorderStyleToHtmlBorderStyle(cellFormat.rightBorderStyle()) + QLatin1Char(';');
if (cellFormat.hasProperty(QTextFormat::TableCellBottomBorderStyle))
styleString += QLatin1String(" border-bottom-style:") + richtextBorderStyleToHtmlBorderStyle(cellFormat.bottomBorderStyle()) + QLatin1Char(';');
if (cellFormat.hasProperty(QTextFormat::TableCellLeftBorderStyle))
styleString += QLatin1String(" border-left-style:") + richtextBorderStyleToHtmlBorderStyle(cellFormat.leftBorderStyle()) + QLatin1Char(';');
if (!styleString.isEmpty())
html += QLatin1String(" style=\"") + styleString + QLatin1Char('\"');
@ -3310,6 +3329,9 @@ void QTextHtmlExporter::emitFrameStyle(const QTextFrameFormat &format, FrameType
QString::number(format.leftMargin()),
QString::number(format.rightMargin()));
if (format.property(QTextFormat::TableBorderCollapse).toBool())
html += QLatin1String(" border-collapse:collapse;");
if (html.length() == originalHtmlLength) // nothing emitted?
html.chop(styleAttribute.size());
else

View File

@ -986,6 +986,7 @@ QTextHtmlImporter::Table QTextHtmlImporter::scanTable(int tableNodeIdx)
tableFmt.setColumns(table.columns);
tableFmt.setColumnWidthConstraints(columnWidths);
tableFmt.setHeaderRowCount(tableHeaderRowCount);
tableFmt.setBorderCollapse(node.borderCollapse);
fmt = tableFmt;
}
@ -1061,6 +1062,31 @@ QTextHtmlImporter::ProcessNodeResult QTextHtmlImporter::processBlockNode()
fmt.setLeftPadding(leftPadding(currentNodeIdx));
if (rightPadding(currentNodeIdx) >= 0)
fmt.setRightPadding(rightPadding(currentNodeIdx));
if (tableCellBorder(currentNodeIdx, QCss::TopEdge) > 0)
fmt.setTopBorder(tableCellBorder(currentNodeIdx, QCss::TopEdge));
if (tableCellBorder(currentNodeIdx, QCss::RightEdge) > 0)
fmt.setRightBorder(tableCellBorder(currentNodeIdx, QCss::RightEdge));
if (tableCellBorder(currentNodeIdx, QCss::BottomEdge) > 0)
fmt.setBottomBorder(tableCellBorder(currentNodeIdx, QCss::BottomEdge));
if (tableCellBorder(currentNodeIdx, QCss::LeftEdge) > 0)
fmt.setLeftBorder(tableCellBorder(currentNodeIdx, QCss::LeftEdge));
if (tableCellBorderStyle(currentNodeIdx, QCss::TopEdge) != QTextFrameFormat::BorderStyle_None)
fmt.setTopBorderStyle(tableCellBorderStyle(currentNodeIdx, QCss::TopEdge));
if (tableCellBorderStyle(currentNodeIdx, QCss::RightEdge) != QTextFrameFormat::BorderStyle_None)
fmt.setRightBorderStyle(tableCellBorderStyle(currentNodeIdx, QCss::RightEdge));
if (tableCellBorderStyle(currentNodeIdx, QCss::BottomEdge) != QTextFrameFormat::BorderStyle_None)
fmt.setBottomBorderStyle(tableCellBorderStyle(currentNodeIdx, QCss::BottomEdge));
if (tableCellBorderStyle(currentNodeIdx, QCss::LeftEdge) != QTextFrameFormat::BorderStyle_None)
fmt.setLeftBorderStyle(tableCellBorderStyle(currentNodeIdx, QCss::LeftEdge));
if (tableCellBorderBrush(currentNodeIdx, QCss::TopEdge) != Qt::NoBrush)
fmt.setTopBorderBrush(tableCellBorderBrush(currentNodeIdx, QCss::TopEdge));
if (tableCellBorderBrush(currentNodeIdx, QCss::RightEdge) != Qt::NoBrush)
fmt.setRightBorderBrush(tableCellBorderBrush(currentNodeIdx, QCss::RightEdge));
if (tableCellBorderBrush(currentNodeIdx, QCss::BottomEdge) != Qt::NoBrush)
fmt.setBottomBorderBrush(tableCellBorderBrush(currentNodeIdx, QCss::BottomEdge));
if (tableCellBorderBrush(currentNodeIdx, QCss::LeftEdge) != Qt::NoBrush)
fmt.setLeftBorderBrush(tableCellBorderBrush(currentNodeIdx, QCss::LeftEdge));
cell.setFormat(fmt);
cursor.setPosition(cell.firstPosition());

View File

@ -491,12 +491,19 @@ QTextHtmlParserNode::QTextHtmlParserNode()
listStyle(QTextListFormat::ListStyleUndefined), imageWidth(-1), imageHeight(-1), tableBorder(0),
tableCellRowSpan(1), tableCellColSpan(1), tableCellSpacing(2), tableCellPadding(0),
borderBrush(Qt::darkGray), borderStyle(QTextFrameFormat::BorderStyle_Outset),
borderCollapse(false),
userState(-1), cssListIndent(0), wsm(WhiteSpaceModeUndefined)
{
margin[QTextHtmlParser::MarginLeft] = 0;
margin[QTextHtmlParser::MarginRight] = 0;
margin[QTextHtmlParser::MarginTop] = 0;
margin[QTextHtmlParser::MarginBottom] = 0;
for (int i = 0; i < 4; ++i) {
tableCellBorderStyle[i] = QTextFrameFormat::BorderStyle_None;
tableCellBorder[i] = 0;
tableCellBorderBrush[i] = Qt::NoBrush;
}
}
void QTextHtmlParser::dumpHtml()
@ -1169,6 +1176,25 @@ void QTextHtmlParserNode::applyCssDeclarations(const QVector<QCss::Declaration>
QCss::ValueExtractor extractor(declarations);
extractor.extractBox(margin, padding);
if (id == Html_td || id == Html_th) {
QCss::BorderStyle cssStyles[4];
int cssBorder[4];
QSize cssRadii[4]; // unused
for (int i = 0; i < 4; ++i) {
cssStyles[i] = QCss::BorderStyle_None;
cssBorder[i] = 0;
}
// this will parse (and cache) "border-width" as a list so the
// QCss::BorderWidth parsing below which expects a single value
// will not work as expected - which in this case does not matter
// because tableBorder is not relevant for cells.
extractor.extractBorder(cssBorder, tableCellBorderBrush, cssStyles, cssRadii);
for (int i = 0; i < 4; ++i) {
tableCellBorderStyle[i] = static_cast<QTextFrameFormat::BorderStyle>(cssStyles[i] - 1);
tableCellBorder[i] = static_cast<qreal>(cssBorder[i]);
}
}
for (int i = 0; i < declarations.count(); ++i) {
const QCss::Declaration &decl = declarations.at(i);
if (decl.d->values.isEmpty()) continue;
@ -1186,6 +1212,9 @@ void QTextHtmlParserNode::applyCssDeclarations(const QVector<QCss::Declaration>
case QCss::BorderWidth:
tableBorder = extractor.lengthValue(decl);
break;
case QCss::BorderCollapse:
borderCollapse = decl.borderCollapseValue();
break;
case QCss::Color: charFormat.setForeground(decl.colorValue()); break;
case QCss::Float:
cssFloat = QTextFrameFormat::InFlow;
@ -1654,6 +1683,11 @@ void QTextHtmlParser::applyAttributes(const QStringList &attributes)
if (!c.isValid())
qWarning("QTextHtmlParser::applyAttributes: Unknown color name '%s'",value.toLatin1().constData());
node->charFormat.setBackground(c);
} else if (key == QLatin1String("bordercolor")) {
QColor c; c.setNamedColor(value);
if (!c.isValid())
qWarning("QTextHtmlParser::applyAttributes: Unknown color name '%s'",value.toLatin1().constData());
node->borderBrush = c;
} else if (key == QLatin1String("background")) {
node->applyBackgroundImage(value, resourceProvider);
} else if (key == QLatin1String("cellspacing")) {

View File

@ -195,8 +195,12 @@ struct QTextHtmlParserNode {
int tableCellColSpan;
qreal tableCellSpacing;
qreal tableCellPadding;
qreal tableCellBorder[4];
QBrush tableCellBorderBrush[4];
QTextFrameFormat::BorderStyle tableCellBorderStyle[4];
QBrush borderBrush;
QTextFrameFormat::BorderStyle borderStyle;
bool borderCollapse;
int userState;
int cssListIndent;
@ -290,6 +294,10 @@ public:
inline int leftPadding(int i) const { return at(i).padding[MarginLeft]; }
inline int rightPadding(int i) const { return at(i).padding[MarginRight]; }
inline qreal tableCellBorder(int i, int edge) const { return at(i).tableCellBorder[edge]; }
inline QTextFrameFormat::BorderStyle tableCellBorderStyle(int i, int edge) const { return at(i).tableCellBorderStyle[edge]; }
inline QBrush tableCellBorderBrush(int i, int edge) const { return at(i).tableCellBorderBrush[edge]; }
void dumpHtml();
void parse(const QString &text, const QTextDocument *resourceProvider);

View File

@ -50,6 +50,7 @@
#include <QDomDocument>
#include "common.h"
// #define DEBUG_WRITE_OUTPUT
QT_FORWARD_DECLARE_CLASS(QTextDocument)
@ -196,6 +197,7 @@ private:
void backgroundImage_checkExpectedHtml(const QTextDocument &doc);
void buildRegExpData();
static QString cssFontSizeString(const QFont &font);
void writeActualAndExpected(const char* testTag, const QString &actual, const QString &expected);
QTextDocument *doc;
QTextCursor cursor;
@ -224,6 +226,27 @@ QString tst_QTextDocument::cssFontSizeString(const QFont &font)
: QString::number(font.pixelSize()) + QStringLiteral("px");
}
void tst_QTextDocument::writeActualAndExpected(const char *testTag, const QString &actual, const QString &expected)
{
#ifdef DEBUG_WRITE_OUTPUT
{
QFile out(QDir::temp().absoluteFilePath(QLatin1String(testTag) + QLatin1String("-actual.html")));
out.open(QFile::WriteOnly);
out.write(actual.toUtf8());
out.close();
} {
QFile out(QDir::temp().absoluteFilePath(QLatin1String(testTag) + QLatin1String("-expected.html")));
out.open(QFile::WriteOnly);
out.write(expected.toUtf8());
out.close();
}
#else
Q_UNUSED(testTag)
Q_UNUSED(actual)
Q_UNUSED(expected)
#endif
}
// Testing get/set functions
void tst_QTextDocument::getSetCheck()
{
@ -1765,6 +1788,8 @@ void tst_QTextDocument::toHtml()
QString output = doc->toHtml();
writeActualAndExpected(QTest::currentDataTag(), output, expectedOutput);
QCOMPARE(output, expectedOutput);
QDomDocument document;
@ -1962,6 +1987,8 @@ void tst_QTextDocument::toHtmlRootFrameProperties()
expectedOutput.replace("DEFAULTBLOCKSTYLE", "style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"");
expectedOutput.append(htmlTail);
writeActualAndExpected(QTest::currentTestFunction(), doc.toHtml(), expectedOutput);
QCOMPARE(doc.toHtml(), expectedOutput);
}
@ -2734,6 +2761,8 @@ void tst_QTextDocument::backgroundImage_checkExpectedHtml(const QTextDocument &d
.arg(defaultFont.weight() * 8)
.arg((defaultFont.italic() ? "italic" : "normal"));
writeActualAndExpected(QTest::currentTestFunction(), doc.toHtml(), expectedHtml);
QCOMPARE(doc.toHtml(), expectedHtml);
}

View File

@ -181,6 +181,11 @@ private slots:
void html_tableCellBackground();
void css_bodyBackground();
void css_tableCellBackground();
void css_tableCellBorder();
void css_tableCellBorderShorthand();
void css_tableCellAllBordersShorthand();
void css_tableCellOverrideOneBorder();
void css_tableBorderCollapse();
void css_fontWeight();
void css_float();
void css_textIndent();
@ -1753,6 +1758,135 @@ void tst_QTextDocumentFragment::css_tableCellBackground()
QCOMPARE(cell.format().background().style(), Qt::TexturePattern);
}
void tst_QTextDocumentFragment::css_tableCellBorder()
{
const char html[] = "<body><table><tr><td style=\"border-width:8px;border-color:green;border-style:groove;border-left-style:dashed;border-left-color:red;border-left-width:4px\">Foo</td></tr></table></body>";
doc->setHtml(html);
cursor.movePosition(QTextCursor::Start);
cursor.movePosition(QTextCursor::NextBlock);
QTextTable *table = cursor.currentTable();
QVERIFY(table);
QTextTableCell cell = table->cellAt(0, 0);
QTextTableCellFormat cellFormat = cell.format().toTableCellFormat();
QCOMPARE(cellFormat.leftBorder(), qreal(4));
QCOMPARE(cellFormat.leftBorderBrush(), QBrush(QColor("red")));
QCOMPARE(cellFormat.leftBorderStyle(), QTextFrameFormat::BorderStyle_Dashed);
QCOMPARE(cellFormat.rightBorder(), qreal(8));
QCOMPARE(cellFormat.rightBorderBrush(), QBrush(QColor("green")));
QCOMPARE(cellFormat.rightBorderStyle(), QTextFrameFormat::BorderStyle_Groove);
QCOMPARE(cellFormat.bottomBorder(), qreal(8));
QCOMPARE(cellFormat.bottomBorderBrush(), QBrush(QColor("green")));
QCOMPARE(cellFormat.bottomBorderStyle(), QTextFrameFormat::BorderStyle_Groove);
QCOMPARE(cellFormat.topBorder(), qreal(8));
QCOMPARE(cellFormat.topBorderBrush(), QBrush(QColor("green")));
QCOMPARE(cellFormat.topBorderStyle(), QTextFrameFormat::BorderStyle_Groove);
}
void tst_QTextDocumentFragment::css_tableCellBorderShorthand()
{
const char html[] = "<body><table><tr><td style=\"border-left:1px solid green;border-right:2px dashed red;border-bottom:3px dotted yellow;border-top:4px dot-dash blue\">Foo</td></tr></table></body>";
doc->setHtml(html);
cursor.movePosition(QTextCursor::Start);
cursor.movePosition(QTextCursor::NextBlock);
QTextTable *table = cursor.currentTable();
QVERIFY(table);
QTextTableCell cell = table->cellAt(0, 0);
QTextTableCellFormat cellFormat = cell.format().toTableCellFormat();
QCOMPARE(cellFormat.leftBorder(), qreal(1));
QCOMPARE(cellFormat.leftBorderBrush(), QBrush(QColor("green")));
QCOMPARE(cellFormat.leftBorderStyle(), QTextFrameFormat::BorderStyle_Solid);
QCOMPARE(cellFormat.rightBorder(), qreal(2));
QCOMPARE(cellFormat.rightBorderBrush(), QBrush(QColor("red")));
QCOMPARE(cellFormat.rightBorderStyle(), QTextFrameFormat::BorderStyle_Dashed);
QCOMPARE(cellFormat.bottomBorder(), qreal(3));
QCOMPARE(cellFormat.bottomBorderBrush(), QBrush(QColor("yellow")));
QCOMPARE(cellFormat.bottomBorderStyle(), QTextFrameFormat::BorderStyle_Dotted);
QCOMPARE(cellFormat.topBorder(), qreal(4));
QCOMPARE(cellFormat.topBorderBrush(), QBrush(QColor("blue")));
QCOMPARE(cellFormat.topBorderStyle(), QTextFrameFormat::BorderStyle_DotDash);
}
void tst_QTextDocumentFragment::css_tableCellAllBordersShorthand()
{
const char html[] = "<body><table><tr><td style=\"border:2px dashed green\">Foo</td></tr></table></body>";
doc->setHtml(html);
cursor.movePosition(QTextCursor::Start);
cursor.movePosition(QTextCursor::NextBlock);
QTextTable *table = cursor.currentTable();
QVERIFY(table);
QTextTableCell cell = table->cellAt(0, 0);
QTextTableCellFormat cellFormat = cell.format().toTableCellFormat();
QCOMPARE(cellFormat.leftBorder(), qreal(2));
QCOMPARE(cellFormat.leftBorderBrush(), QBrush(QColor("green")));
QCOMPARE(cellFormat.leftBorderStyle(), QTextFrameFormat::BorderStyle_Dashed);
QCOMPARE(cellFormat.rightBorder(), qreal(2));
QCOMPARE(cellFormat.rightBorderBrush(), QBrush(QColor("green")));
QCOMPARE(cellFormat.rightBorderStyle(), QTextFrameFormat::BorderStyle_Dashed);
QCOMPARE(cellFormat.bottomBorder(), qreal(2));
QCOMPARE(cellFormat.bottomBorderBrush(), QBrush(QColor("green")));
QCOMPARE(cellFormat.bottomBorderStyle(), QTextFrameFormat::BorderStyle_Dashed);
QCOMPARE(cellFormat.topBorder(), qreal(2));
QCOMPARE(cellFormat.topBorderBrush(), QBrush(QColor("green")));
QCOMPARE(cellFormat.topBorderStyle(), QTextFrameFormat::BorderStyle_Dashed);
}
void tst_QTextDocumentFragment::css_tableCellOverrideOneBorder()
{
const char html[] = "<body><table><tr><td style=\"border:2px dashed green;border-left:4px solid red\">Foo</td></tr></table></body>";
doc->setHtml(html);
cursor.movePosition(QTextCursor::Start);
cursor.movePosition(QTextCursor::NextBlock);
QTextTable *table = cursor.currentTable();
QVERIFY(table);
QTextTableCell cell = table->cellAt(0, 0);
QTextTableCellFormat cellFormat = cell.format().toTableCellFormat();
QCOMPARE(cellFormat.leftBorder(), qreal(4));
QCOMPARE(cellFormat.leftBorderBrush(), QBrush(QColor("red")));
QCOMPARE(cellFormat.leftBorderStyle(), QTextFrameFormat::BorderStyle_Solid);
QCOMPARE(cellFormat.rightBorder(), qreal(2));
QCOMPARE(cellFormat.rightBorderBrush(), QBrush(QColor("green")));
QCOMPARE(cellFormat.rightBorderStyle(), QTextFrameFormat::BorderStyle_Dashed);
QCOMPARE(cellFormat.bottomBorder(), qreal(2));
QCOMPARE(cellFormat.bottomBorderBrush(), QBrush(QColor("green")));
QCOMPARE(cellFormat.bottomBorderStyle(), QTextFrameFormat::BorderStyle_Dashed);
QCOMPARE(cellFormat.topBorder(), qreal(2));
QCOMPARE(cellFormat.topBorderBrush(), QBrush(QColor("green")));
QCOMPARE(cellFormat.topBorderStyle(), QTextFrameFormat::BorderStyle_Dashed);
}
void tst_QTextDocumentFragment::css_tableBorderCollapse()
{
const char html[] = "<body><table style=\"border-collapse:collapse\"><tr><td>Foo</td></tr></table></body>";
doc->setHtml(html);
cursor.movePosition(QTextCursor::Start);
cursor.movePosition(QTextCursor::NextBlock);
QTextTable *table = cursor.currentTable();
QVERIFY(table);
QCOMPARE(table->format().borderCollapse(), true);
}
void tst_QTextDocumentFragment::css_cellPaddings()
{
const char html[] = "<body><table><tr><td style=\"padding-left:1\">Foo</td>"

View File

@ -50,6 +50,8 @@ typedef QList<int> IntList;
QT_FORWARD_DECLARE_CLASS(QTextDocument)
Q_DECLARE_METATYPE(QTextFrameFormat::BorderStyle);
class tst_QTextTable : public QObject
{
Q_OBJECT
@ -95,6 +97,8 @@ private slots:
#if !defined(QT_NO_PRINTER) && defined(QT_BUILD_INTERNAL)
void QTBUG31330_renderBackground();
#endif
void checkBorderAttributes_data();
void checkBorderAttributes();
private:
QTextTable *create2x2Table();
@ -1170,5 +1174,109 @@ void tst_QTextTable::QTBUG31330_renderBackground()
}
#endif
void tst_QTextTable::checkBorderAttributes_data()
{
QTest::addColumn<QString>("html");
QTest::addColumn<qreal>("topBorderWidth");
QTest::addColumn<qreal>("bottomBorderWidth");
QTest::addColumn<qreal>("leftBorderWidth");
QTest::addColumn<qreal>("rightBorderWidth");
QTest::addColumn<QTextFrameFormat::BorderStyle>("topBorderStyle");
QTest::addColumn<QTextFrameFormat::BorderStyle>("bottomBorderStyle");
QTest::addColumn<QTextFrameFormat::BorderStyle>("leftBorderStyle");
QTest::addColumn<QTextFrameFormat::BorderStyle>("rightBorderStyle");
QTest::addColumn<QBrush>("topBorderBrush");
QTest::addColumn<QBrush>("bottomBorderBrush");
QTest::addColumn<QBrush>("leftBorderBrush");
QTest::addColumn<QBrush>("rightBorderBrush");
const QString tableHtmlStart = QStringLiteral("<html><head><style>");
const QString tableHtmlEnd = QStringLiteral("</style></head><body>"
"<table border=\"1\"><tr><td>One</td><td>Two</td></tr>"
"<tr><td>Three</td><td>Four</td></tr></table></body></html>");
QTest::newRow("1px-solid-colors")
<< QString("%1"
"td {"
"border-top: 1px solid red;"
"border-bottom: 1px solid blue;"
"border-left: 1px solid green;"
"border-right: 1px solid yellow;"
"}"
"%2").arg(tableHtmlStart).arg(tableHtmlEnd)
<< 1.0 << 1.0 << 1.0 << 1.0
<< QTextFrameFormat::BorderStyle_Solid << QTextFrameFormat::BorderStyle_Solid
<< QTextFrameFormat::BorderStyle_Solid << QTextFrameFormat::BorderStyle_Solid
<< QBrush(Qt::red) << QBrush(Qt::blue) << QBrush(Qt::darkGreen) << QBrush(Qt::yellow);
QTest::newRow("MixedWidth-solid-colors")
<< QString("%1"
"td {"
"border-top: 1px solid red;"
"border-bottom: 2px solid blue;"
"border-left: 3px solid green;"
"border-right: 4px solid yellow;"
"}"
"%2").arg(tableHtmlStart).arg(tableHtmlEnd)
<< 1.0 << 2.0 << 3.0 << 4.0
<< QTextFrameFormat::BorderStyle_Solid << QTextFrameFormat::BorderStyle_Solid
<< QTextFrameFormat::BorderStyle_Solid << QTextFrameFormat::BorderStyle_Solid
<< QBrush(Qt::red) << QBrush(Qt::blue) << QBrush(Qt::darkGreen) << QBrush(Qt::yellow);
QTest::newRow("MixedWidth-MixedStyle-colors")
<< QString("%1"
"td {"
"border-top: 1px solid red;"
"border-bottom: 2px dotted blue;"
"border-left: 3px dashed green;"
"border-right: 4px inset yellow;"
"}"
"%2").arg(tableHtmlStart).arg(tableHtmlEnd)
<< 1.0 << 2.0 << 3.0 << 4.0
<< QTextFrameFormat::BorderStyle_Solid << QTextFrameFormat::BorderStyle_Dotted
<< QTextFrameFormat::BorderStyle_Dashed << QTextFrameFormat::BorderStyle_Inset
<< QBrush(Qt::red) << QBrush(Qt::blue) << QBrush(Qt::darkGreen) << QBrush(Qt::yellow);
}
void tst_QTextTable::checkBorderAttributes()
{
QFETCH(QString, html);
QFETCH(qreal, topBorderWidth);
QFETCH(qreal, bottomBorderWidth);
QFETCH(qreal, leftBorderWidth);
QFETCH(qreal, rightBorderWidth);
QFETCH(QTextFrameFormat::BorderStyle, topBorderStyle);
QFETCH(QTextFrameFormat::BorderStyle, bottomBorderStyle);
QFETCH(QTextFrameFormat::BorderStyle, leftBorderStyle);
QFETCH(QTextFrameFormat::BorderStyle, rightBorderStyle);
QFETCH(QBrush, topBorderBrush);
QFETCH(QBrush, bottomBorderBrush);
QFETCH(QBrush, leftBorderBrush);
QFETCH(QBrush, rightBorderBrush);
QTextDocument doc;
doc.setHtml(html);
QTextCursor cursor(doc.firstBlock());
cursor.movePosition(QTextCursor::Right);
QTextTable *currentTable = cursor.currentTable();
QVERIFY(currentTable);
for (int row = 0; row < 2; row++) {
for (int column = 0; column < 2; column++) {
QTextTableCell cell = currentTable->cellAt(row, column);
QTextCharFormat cellFormat = cell.format();
QCOMPARE(cellFormat.doubleProperty(QTextFormat::TableCellTopBorder), topBorderWidth);
QCOMPARE(cellFormat.doubleProperty(QTextFormat::TableCellBottomBorder), bottomBorderWidth);
QCOMPARE(cellFormat.doubleProperty(QTextFormat::TableCellLeftBorder), leftBorderWidth);
QCOMPARE(cellFormat.doubleProperty(QTextFormat::TableCellRightBorder), rightBorderWidth);
QCOMPARE(cellFormat.property(QTextFormat::TableCellTopBorderStyle), topBorderStyle);
QCOMPARE(cellFormat.property(QTextFormat::TableCellBottomBorderStyle), bottomBorderStyle);
QCOMPARE(cellFormat.property(QTextFormat::TableCellLeftBorderStyle), leftBorderStyle);
QCOMPARE(cellFormat.property(QTextFormat::TableCellRightBorderStyle), rightBorderStyle);
QCOMPARE(cellFormat.brushProperty(QTextFormat::TableCellTopBorderBrush), topBorderBrush);
QCOMPARE(cellFormat.brushProperty(QTextFormat::TableCellBottomBorderBrush), bottomBorderBrush);
QCOMPARE(cellFormat.brushProperty(QTextFormat::TableCellLeftBorderBrush), leftBorderBrush);
QCOMPARE(cellFormat.brushProperty(QTextFormat::TableCellRightBorderBrush), rightBorderBrush);
}
}
}
QTEST_MAIN(tst_QTextTable)
#include "tst_qtexttable.moc"