diff --git a/python/core/layout/qgslayoutframe.sip b/python/core/layout/qgslayoutframe.sip
index 2b60d1fac88..dea3a4e2966 100644
--- a/python/core/layout/qgslayoutframe.sip
+++ b/python/core/layout/qgslayoutframe.sip
@@ -56,6 +56,11 @@ class QgsLayoutFrame: QgsLayoutItem
:rtype: QgsLayoutMultiFrame
%End
+ virtual QgsLayoutSize minimumSize() const;
+
+ virtual QgsLayoutSize fixedSize() const;
+
+
QRectF extent() const;
%Docstring
diff --git a/python/core/layout/qgslayoutitem.sip b/python/core/layout/qgslayoutitem.sip
index ea914223f3a..154fa389647 100644
--- a/python/core/layout/qgslayoutitem.sip
+++ b/python/core/layout/qgslayoutitem.sip
@@ -276,7 +276,7 @@ class QgsLayoutItem : QgsLayoutObject, QGraphicsRectItem, QgsLayoutUndoObjectInt
:rtype: ReferencePoint
%End
- QgsLayoutSize fixedSize() const;
+ virtual QgsLayoutSize fixedSize() const;
%Docstring
Returns the fixed size of the item, if applicable, or an empty size if item can be freely
resized.
diff --git a/python/core/layout/qgslayoutitemattributetable.sip b/python/core/layout/qgslayoutitemattributetable.sip
index 8088e3a0e59..aa2dcc03c17 100644
--- a/python/core/layout/qgslayoutitemattributetable.sip
+++ b/python/core/layout/qgslayoutitemattributetable.sip
@@ -29,9 +29,11 @@ class QgsLayoutItemAttributeTable: QgsLayoutTable
RelationChildren
};
- QgsLayoutItemAttributeTable( QgsLayout *layout );
+ QgsLayoutItemAttributeTable( QgsLayout *layout /TransferThis/ );
%Docstring
Constructor for QgsLayoutItemAttributeTable, attached to the specified ``layout``.
+
+ Ownership is transferred to the layout.
%End
virtual int type() const;
diff --git a/python/core/layout/qgslayoutitemhtml.sip b/python/core/layout/qgslayoutitemhtml.sip
index 4bb98c15b95..71f4df6acdd 100644
--- a/python/core/layout/qgslayoutitemhtml.sip
+++ b/python/core/layout/qgslayoutitemhtml.sip
@@ -27,9 +27,11 @@ class QgsLayoutItemHtml: QgsLayoutMultiFrame
ManualHtml
};
- QgsLayoutItemHtml( QgsLayout *layout );
+ QgsLayoutItemHtml( QgsLayout *layout /TransferThis/ );
%Docstring
Constructor for QgsLayoutItemHtml, with the specified parent ``layout``.
+
+ Ownership is transferred to the layout.
%End
~QgsLayoutItemHtml();
diff --git a/python/core/layout/qgslayoutitemtexttable.sip b/python/core/layout/qgslayoutitemtexttable.sip
index 2ee363663c4..439e35a3b59 100644
--- a/python/core/layout/qgslayoutitemtexttable.sip
+++ b/python/core/layout/qgslayoutitemtexttable.sip
@@ -21,9 +21,11 @@ class QgsLayoutItemTextTable : QgsLayoutTable
%End
public:
- QgsLayoutItemTextTable( QgsLayout *layout );
+ QgsLayoutItemTextTable( QgsLayout *layout /TransferThis/ );
%Docstring
Constructor for QgsLayoutItemTextTable, for the specified ``layout``.
+
+ Ownership is transferred to the layout.
%End
virtual int type() const;
diff --git a/src/core/layout/qgslayoutframe.cpp b/src/core/layout/qgslayoutframe.cpp
index deaa17c101e..88358d75f67 100644
--- a/src/core/layout/qgslayoutframe.cpp
+++ b/src/core/layout/qgslayoutframe.cpp
@@ -35,10 +35,8 @@ QgsLayoutFrame::QgsLayoutFrame( QgsLayout *layout, QgsLayoutMultiFrame *multiFra
update();
} );
-#if 0 //TODO
//force recalculation of rect, so that multiframe specified sizes can be applied
- setSceneRect( QRectF( pos().x(), pos().y(), rect().width(), rect().height() ) );
-#endif
+ refreshItemSize();
}
}
@@ -51,6 +49,29 @@ QgsLayoutMultiFrame *QgsLayoutFrame::multiFrame() const
{
return mMultiFrame;
}
+
+QgsLayoutSize QgsLayoutFrame::minimumSize() const
+{
+ if ( !mMultiFrame )
+ return QgsLayoutSize();
+
+ //calculate index of frame
+ int frameIndex = mMultiFrame->frameIndex( const_cast< QgsLayoutFrame * >( this ) );
+ //check minimum size
+ return QgsLayoutSize( mMultiFrame->minFrameSize( frameIndex ), QgsUnitTypes::LayoutMillimeters );
+}
+
+QgsLayoutSize QgsLayoutFrame::fixedSize() const
+{
+ if ( !mMultiFrame )
+ return QgsLayoutSize();
+
+ //calculate index of frame
+ int frameIndex = mMultiFrame->frameIndex( const_cast< QgsLayoutFrame * >( this ) );
+ //check fixed size
+ return QgsLayoutSize( mMultiFrame->fixedFrameSize( frameIndex ), QgsUnitTypes::LayoutMillimeters );
+}
+
#if 0// TODO - save/restore multiframe uuid!
bool QgsLayoutFrame::writeXml( QDomElement &elem, QDomDocument &doc ) const
{
@@ -168,37 +189,6 @@ QString QgsLayoutFrame::displayName() const
return tr( "" );
}
-#if 0 //TODO
-void QgsLayoutFrame::setSceneRect( const QRectF &rectangle )
-{
- QRectF fixedRect = rectangle;
-
- if ( mMultiFrame )
- {
- //calculate index of frame
- int frameIndex = mMultiFrame->frameIndex( this );
-
- QSizeF fixedSize = mMultiFrame->fixedFrameSize( frameIndex );
- if ( fixedSize.width() > 0 )
- {
- fixedRect.setWidth( fixedSize.width() );
- }
- if ( fixedSize.height() > 0 )
- {
- fixedRect.setHeight( fixedSize.height() );
- }
-
- //check minimum size
- QSizeF minSize = mMultiFrame->minFrameSize( frameIndex );
- fixedRect.setWidth( std::max( minSize.width(), fixedRect.width() ) );
- fixedRect.setHeight( std::max( minSize.height(), fixedRect.height() ) );
- }
-
- QgsComposerItem::setSceneRect( fixedRect );
-}
-#endif
-
-
void QgsLayoutFrame::draw( QgsRenderContext &context, const QStyleOptionGraphicsItem *itemStyle )
{
if ( mMultiFrame )
diff --git a/src/core/layout/qgslayoutframe.h b/src/core/layout/qgslayoutframe.h
index 59fd475e5e0..1b589157169 100644
--- a/src/core/layout/qgslayoutframe.h
+++ b/src/core/layout/qgslayoutframe.h
@@ -64,11 +64,10 @@ class CORE_EXPORT QgsLayoutFrame: public QgsLayoutItem
*/
QgsLayoutMultiFrame *multiFrame() const;
-#if 0 //TODO
- //Overridden to handle fixed frame sizes set by multi frame
- void setSceneRect( const QRectF &rectangle ) override;
+ QgsLayoutSize minimumSize() const override;
+ QgsLayoutSize fixedSize() const override;
- void paint( QPainter *painter, const QStyleOptionGraphicsItem *itemStyle, QWidget *pWidget ) override;
+#if 0 //TODO
void beginItemCommand( const QString &text ) override;
void endItemCommand() override;
bool writeXml( QDomElement &elem, QDomDocument &doc ) const override;
diff --git a/src/core/layout/qgslayoutitem.cpp b/src/core/layout/qgslayoutitem.cpp
index a9a3e831500..21761a7a012 100644
--- a/src/core/layout/qgslayoutitem.cpp
+++ b/src/core/layout/qgslayoutitem.cpp
@@ -1200,8 +1200,15 @@ QSizeF QgsLayoutItem::applyFixedSize( const QSizeF &targetSize )
{
return targetSize;
}
+
+ QSizeF size = targetSize;
QSizeF fixedSizeLayoutUnits = mLayout->convertToLayoutUnits( fixedSize() );
- return targetSize.expandedTo( fixedSizeLayoutUnits );
+ if ( fixedSizeLayoutUnits.width() > 0 )
+ size.setWidth( fixedSizeLayoutUnits.width() );
+ if ( fixedSizeLayoutUnits.height() > 0 )
+ size.setHeight( fixedSizeLayoutUnits.height() );
+
+ return size;
}
void QgsLayoutItem::refreshItemRotation( QPointF *origin )
diff --git a/src/core/layout/qgslayoutitem.h b/src/core/layout/qgslayoutitem.h
index 23bcccdbed5..59b4fae0f85 100644
--- a/src/core/layout/qgslayoutitem.h
+++ b/src/core/layout/qgslayoutitem.h
@@ -299,7 +299,7 @@ class CORE_EXPORT QgsLayoutItem : public QgsLayoutObject, public QGraphicsRectIt
* \see setFixedSize()
* \see minimumSize()
*/
- QgsLayoutSize fixedSize() const { return mFixedSize; }
+ virtual QgsLayoutSize fixedSize() const { return mFixedSize; }
/**
* Returns the minimum allowed size of the item, if applicable, or an empty size if item can be freely
diff --git a/src/core/layout/qgslayoutitemattributetable.cpp b/src/core/layout/qgslayoutitemattributetable.cpp
index 9a6812cccea..a4f14162f83 100644
--- a/src/core/layout/qgslayoutitemattributetable.cpp
+++ b/src/core/layout/qgslayoutitemattributetable.cpp
@@ -679,8 +679,11 @@ void QgsLayoutItemAttributeTable::setWrapString( const QString &wrapString )
emit changed();
}
-bool QgsLayoutItemAttributeTable::writePropertiesToElement( QDomElement &tableElem, QDomDocument &, const QgsReadWriteContext & ) const
+bool QgsLayoutItemAttributeTable::writePropertiesToElement( QDomElement &tableElem, QDomDocument &doc, const QgsReadWriteContext &context ) const
{
+ if ( !QgsLayoutTable::writePropertiesToElement( tableElem, doc, context ) )
+ return false;
+
tableElem.setAttribute( QStringLiteral( "source" ), QString::number( static_cast< int >( mSource ) ) );
tableElem.setAttribute( QStringLiteral( "relationId" ), mRelationId );
tableElem.setAttribute( QStringLiteral( "showUniqueRowsOnly" ), mShowUniqueRowsOnly );
@@ -706,7 +709,7 @@ bool QgsLayoutItemAttributeTable::writePropertiesToElement( QDomElement &tableEl
return true;
}
-bool QgsLayoutItemAttributeTable::readPropertiesFromElement( const QDomElement &itemElem, const QDomDocument &, const QgsReadWriteContext & )
+bool QgsLayoutItemAttributeTable::readPropertiesFromElement( const QDomElement &itemElem, const QDomDocument &doc, const QgsReadWriteContext &context )
{
QgsVectorLayer *prevLayer = sourceLayer();
if ( prevLayer )
@@ -715,6 +718,9 @@ bool QgsLayoutItemAttributeTable::readPropertiesFromElement( const QDomElement &
disconnect( prevLayer, &QgsVectorLayer::layerModified, this, &QgsLayoutTable::refreshAttributes );
}
+ if ( !QgsLayoutTable::readPropertiesFromElement( itemElem, doc, context ) )
+ return false;
+
mSource = QgsLayoutItemAttributeTable::ContentSource( itemElem.attribute( QStringLiteral( "source" ), QStringLiteral( "0" ) ).toInt() );
mRelationId = itemElem.attribute( QStringLiteral( "relationId" ), QLatin1String( "" ) );
diff --git a/src/core/layout/qgslayoutitemattributetable.h b/src/core/layout/qgslayoutitemattributetable.h
index cb388ac26e7..02ff3ef6792 100644
--- a/src/core/layout/qgslayoutitemattributetable.h
+++ b/src/core/layout/qgslayoutitemattributetable.h
@@ -50,8 +50,10 @@ class CORE_EXPORT QgsLayoutItemAttributeTable: public QgsLayoutTable
/**
* Constructor for QgsLayoutItemAttributeTable, attached to the specified \a layout.
+ *
+ * Ownership is transferred to the layout.
*/
- QgsLayoutItemAttributeTable( QgsLayout *layout );
+ QgsLayoutItemAttributeTable( QgsLayout *layout SIP_TRANSFERTHIS );
int type() const override;
QString stringType() const override;
diff --git a/src/core/layout/qgslayoutitemhtml.h b/src/core/layout/qgslayoutitemhtml.h
index 8cc63bc51e5..696d2a2ef2b 100644
--- a/src/core/layout/qgslayoutitemhtml.h
+++ b/src/core/layout/qgslayoutitemhtml.h
@@ -48,8 +48,10 @@ class CORE_EXPORT QgsLayoutItemHtml: public QgsLayoutMultiFrame
/**
* Constructor for QgsLayoutItemHtml, with the specified parent \a layout.
+ *
+ * Ownership is transferred to the layout.
*/
- QgsLayoutItemHtml( QgsLayout *layout );
+ QgsLayoutItemHtml( QgsLayout *layout SIP_TRANSFERTHIS );
~QgsLayoutItemHtml();
diff --git a/src/core/layout/qgslayoutitemtexttable.h b/src/core/layout/qgslayoutitemtexttable.h
index 2722b3cabcd..186a842fddc 100644
--- a/src/core/layout/qgslayoutitemtexttable.h
+++ b/src/core/layout/qgslayoutitemtexttable.h
@@ -36,8 +36,10 @@ class CORE_EXPORT QgsLayoutItemTextTable : public QgsLayoutTable
/**
* Constructor for QgsLayoutItemTextTable, for the specified \a layout.
+ *
+ * Ownership is transferred to the layout.
*/
- QgsLayoutItemTextTable( QgsLayout *layout );
+ QgsLayoutItemTextTable( QgsLayout *layout SIP_TRANSFERTHIS );
int type() const override;
QString stringType() const override;
diff --git a/src/core/layout/qgslayoutmultiframe.cpp b/src/core/layout/qgslayoutmultiframe.cpp
index cf74bf93a76..d1c696f086d 100644
--- a/src/core/layout/qgslayoutmultiframe.cpp
+++ b/src/core/layout/qgslayoutmultiframe.cpp
@@ -220,7 +220,6 @@ void QgsLayoutMultiFrame::recalculateFrameSizes()
void QgsLayoutMultiFrame::recalculateFrameRects()
{
-#if 0 //TODO
if ( mFrameItems.empty() )
{
//no frames, nothing to do
@@ -230,10 +229,8 @@ void QgsLayoutMultiFrame::recalculateFrameRects()
const QList< QgsLayoutFrame * > frames = mFrameItems;
for ( QgsLayoutFrame *frame : frames )
{
- frame->setSceneRect( QRectF( frame->scenePos().x(), frame->scenePos().y(),
- frame->rect().width(), frame->rect().height() ) );
+ frame->refreshItemSize();
}
-#endif
}
QgsLayoutFrame *QgsLayoutMultiFrame::createNewFrame( QgsLayoutFrame *currentFrame, QPointF pos, QSizeF size )
diff --git a/tests/src/core/CMakeLists.txt b/tests/src/core/CMakeLists.txt
index 2d3be0d0d26..36fe423c438 100755
--- a/tests/src/core/CMakeLists.txt
+++ b/tests/src/core/CMakeLists.txt
@@ -147,6 +147,7 @@ SET(TESTS
testqgslayoutpicture.cpp
testqgslayoutscalebar.cpp
testqgslayoutshapes.cpp
+ testqgslayouttable.cpp
testqgslayoutunits.cpp
testqgslayoututils.cpp
testqgslegendrenderer.cpp
diff --git a/tests/src/core/testqgslayoutitem.cpp b/tests/src/core/testqgslayoutitem.cpp
index c6d8ca9c230..5ce9d773165 100644
--- a/tests/src/core/testqgslayoutitem.cpp
+++ b/tests/src/core/testqgslayoutitem.cpp
@@ -1074,6 +1074,11 @@ void TestQgsLayoutItem::fixedSize()
QGSCOMPARENEAR( item->rect().width(), 2.0 * 25.4, 4 * DBL_EPSILON );
QGSCOMPARENEAR( item->rect().height(), 4.0 * 25.4, 4 * DBL_EPSILON );
+ item->attemptResize( QgsLayoutSize( 7.0, 8.0, QgsUnitTypes::LayoutInches ) );
+ //check size matches fixed item size converted to mm
+ QGSCOMPARENEAR( item->rect().width(), 2.0 * 25.4, 4 * DBL_EPSILON );
+ QGSCOMPARENEAR( item->rect().height(), 4.0 * 25.4, 4 * DBL_EPSILON );
+
//check that setting a fixed size applies this size immediately
item->updateFixedSize( QgsLayoutSize( 150, 250, QgsUnitTypes::LayoutMillimeters ) );
QGSCOMPARENEAR( item->rect().width(), 150.0, 4 * DBL_EPSILON );
@@ -1119,8 +1124,8 @@ void TestQgsLayoutItem::minSize()
//try to resize to less than minimum size
fixedMinItem->attemptResize( QgsLayoutSize( 1.0, 0.5, QgsUnitTypes::LayoutPoints ) );
//check size matches fixed item size, not minimum size (converted to mm)
- QGSCOMPARENEAR( fixedMinItem->rect().width(), 50.0, 4 * DBL_EPSILON );
- QGSCOMPARENEAR( fixedMinItem->rect().height(), 90.0, 4 * DBL_EPSILON );
+ QGSCOMPARENEAR( fixedMinItem->rect().width(), 20.0, 4 * DBL_EPSILON );
+ QGSCOMPARENEAR( fixedMinItem->rect().height(), 40.0, 4 * DBL_EPSILON );
}
void TestQgsLayoutItem::move()
diff --git a/tests/src/core/testqgslayouttable.cpp b/tests/src/core/testqgslayouttable.cpp
new file mode 100644
index 00000000000..3fb8ef8e1cd
--- /dev/null
+++ b/tests/src/core/testqgslayouttable.cpp
@@ -0,0 +1,1332 @@
+/***************************************************************************
+ testqgslayouttable.cpp
+ ----------------------
+ begin : November 2017
+ copyright : (C) 2017 by Nyall Dawson
+ email : nyall dot dawson at gmail dot com
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include "qgsapplication.h"
+#include "qgslayout.h"
+#include "qgslayoutitemmap.h"
+#include "qgslayoutitemattributetable.h"
+#include "qgslayouttablecolumn.h"
+#include "qgslayoutframe.h"
+#include "qgsmapsettings.h"
+#include "qgsvectorlayer.h"
+#include "qgsvectordataprovider.h"
+#include "qgsfeature.h"
+#include "qgsmultirenderchecker.h"
+#include "qgsfontutils.h"
+#include "qgsproject.h"
+#include "qgsrelationmanager.h"
+#include "qgsreadwritecontext.h"
+
+#include
+#include "qgstest.h"
+
+class TestQgsLayoutTable : public QObject
+{
+ Q_OBJECT
+
+ public:
+ TestQgsLayoutTable() = default;
+
+ private slots:
+ void initTestCase();// will be called before the first testfunction is executed.
+ void cleanupTestCase();// will be called after the last testfunction was executed.
+ void init();// will be called before each testfunction is executed.
+ void cleanup();// will be called after every testfunction.
+
+ void attributeTableHeadings(); //test retrieving attribute table headers
+ void attributeTableRows(); //test retrieving attribute table rows
+ void attributeTableFilterFeatures(); //test filtering attribute table rows
+ void attributeTableSetAttributes(); //test subset of attributes in table
+ void attributeTableVisibleOnly(); //test displaying only visible attributes
+ void attributeTableRender(); //test rendering attribute table
+ void manualColumnWidth(); //test setting manual column widths
+ void attributeTableEmpty(); //test empty modes for attribute table
+ void showEmptyRows(); //test showing empty rows
+ void attributeTableExtend();
+ void attributeTableRepeat();
+ void attributeTableAtlasSource(); //test attribute table in atlas feature mode
+ void attributeTableRelationSource(); //test attribute table in relation mode
+ void contentsContainsRow(); //test the contentsContainsRow function
+ void removeDuplicates(); //test removing duplicate rows
+ void multiLineText(); //test rendering a table with multiline text
+ void horizontalGrid(); //test rendering a table with horizontal-only grid
+ void verticalGrid(); //test rendering a table with vertical-only grid
+ void align(); //test alignment of table cells
+ void wrapChar(); //test setting wrap character
+ void autoWrap(); //test auto word wrap
+ void cellStyles(); //test cell styles
+ void cellStylesRender(); //test rendering cell styles
+
+ private:
+ QgsVectorLayer *mVectorLayer = nullptr;
+ QString mReport;
+
+ //compares rows in table to expected rows
+ void compareTable( QgsLayoutItemAttributeTable *table, const QVector &expectedRows );
+};
+
+void TestQgsLayoutTable::initTestCase()
+{
+ QgsApplication::init();
+ QgsApplication::initQgis();
+
+ //create maplayers from testdata and add to layer registry
+ QFileInfo vectorFileInfo( QStringLiteral( TEST_DATA_DIR ) + "/points.shp" );
+ mVectorLayer = new QgsVectorLayer( vectorFileInfo.filePath(),
+ vectorFileInfo.completeBaseName(),
+ QStringLiteral( "ogr" ) );
+ QgsProject::instance()->addMapLayer( mVectorLayer );
+
+ mReport = QStringLiteral( "Layout Table Tests
\n" );
+}
+
+void TestQgsLayoutTable::cleanupTestCase()
+{
+ QString myReportFile = QDir::tempPath() + "/qgistest.html";
+ QFile myFile( myReportFile );
+ if ( myFile.open( QIODevice::WriteOnly | QIODevice::Append ) )
+ {
+ QTextStream myQTextStream( &myFile );
+ myQTextStream << mReport;
+ myFile.close();
+ }
+ QgsApplication::exitQgis();
+}
+
+void TestQgsLayoutTable::init()
+{
+ QgsLayout l( QgsProject::instance() );
+ l.initializeDefaults();
+ QgsLayoutItemAttributeTable *table = new QgsLayoutItemAttributeTable( &l );
+ QgsLayoutFrame *frame1 = new QgsLayoutFrame( &l, table );
+ frame1->attemptSetSceneRect( QRectF( 5, 5, 100, 30 ) );
+ QgsLayoutFrame *frame2 = new QgsLayoutFrame( &l, table );
+ frame2->attemptSetSceneRect( QRectF( 5, 40, 100, 30 ) );
+ frame1->setFrameEnabled( true );
+ frame2->setFrameEnabled( true );
+ table->addFrame( frame1 );
+ table->addFrame( frame2 );
+ table->setVectorLayer( mVectorLayer );
+ table->setDisplayOnlyVisibleFeatures( false );
+ table->setMaximumNumberOfFeatures( 10 );
+ table->setContentFont( QgsFontUtils::getStandardTestFont() );
+ table->setHeaderFont( QgsFontUtils::getStandardTestFont() );
+ table->setBackgroundColor( Qt::yellow );
+}
+
+void TestQgsLayoutTable::cleanup()
+{
+}
+
+void TestQgsLayoutTable::attributeTableHeadings()
+{
+ QgsLayout l( QgsProject::instance() );
+ l.initializeDefaults();
+ QgsLayoutItemAttributeTable *table = new QgsLayoutItemAttributeTable( &l );
+ table->setVectorLayer( mVectorLayer );
+
+ //test retrieving attribute table headers
+ QStringList expectedHeaders;
+ expectedHeaders << QStringLiteral( "Class" ) << QStringLiteral( "Heading" ) << QStringLiteral( "Importance" ) << QStringLiteral( "Pilots" ) << QStringLiteral( "Cabin Crew" ) << QStringLiteral( "Staff" );
+
+ //get header labels and compare
+ QMap headerMap = table->headerLabels();
+ QMap::const_iterator headerIt = headerMap.constBegin();
+ QString expected;
+ QString evaluated;
+ for ( ; headerIt != headerMap.constEnd(); ++headerIt )
+ {
+ evaluated = headerIt.value();
+ expected = expectedHeaders.at( headerIt.key() );
+ QCOMPARE( evaluated, expected );
+ }
+}
+
+void TestQgsLayoutTable::compareTable( QgsLayoutItemAttributeTable *table, const QVector &expectedRows )
+{
+ //retrieve rows and check
+ QgsLayoutTableContents tableContents;
+ bool result = table->getTableContents( tableContents );
+ QCOMPARE( result, true );
+
+ QgsLayoutTableContents::const_iterator resultIt = tableContents.constBegin();
+ int rowNumber = 0;
+ int colNumber = 0;
+
+ //check that number of rows matches expected
+ QCOMPARE( tableContents.count(), expectedRows.count() );
+
+ for ( ; resultIt != tableContents.constEnd(); ++resultIt )
+ {
+ colNumber = 0;
+ QgsLayoutTableRow::const_iterator cellIt = ( *resultIt ).constBegin();
+ for ( ; cellIt != ( *resultIt ).constEnd(); ++cellIt )
+ {
+ QCOMPARE( ( *cellIt ).toString(), expectedRows.at( rowNumber ).at( colNumber ) );
+ colNumber++;
+ }
+ //also check that number of columns matches expected
+ QCOMPARE( ( *resultIt ).count(), expectedRows.at( rowNumber ).count() );
+
+ rowNumber++;
+ }
+}
+
+void TestQgsLayoutTable::attributeTableRows()
+{
+ //test retrieving attribute table rows
+
+ QVector expectedRows;
+ QStringList row;
+ row << QStringLiteral( "Jet" ) << QStringLiteral( "90" ) << QStringLiteral( "3" ) << QStringLiteral( "2" ) << QStringLiteral( "0" ) << QStringLiteral( "2" );
+ expectedRows.append( row );
+ row.clear();
+ row << QStringLiteral( "Biplane" ) << QStringLiteral( "0" ) << QStringLiteral( "1" ) << QStringLiteral( "3" ) << QStringLiteral( "3" ) << QStringLiteral( "6" );
+ expectedRows.append( row );
+ row.clear();
+ row << QStringLiteral( "Jet" ) << QStringLiteral( "85" ) << QStringLiteral( "3" ) << QStringLiteral( "1" ) << QStringLiteral( "1" ) << QStringLiteral( "2" );
+ expectedRows.append( row );
+
+ QgsLayout l( QgsProject::instance() );
+ l.initializeDefaults();
+ QgsLayoutItemAttributeTable *table = new QgsLayoutItemAttributeTable( &l );
+ table->setVectorLayer( mVectorLayer );
+
+ //retrieve rows and check
+ table->setMaximumNumberOfFeatures( 3 );
+ compareTable( table, expectedRows );
+}
+
+void TestQgsLayoutTable::attributeTableFilterFeatures()
+{
+ //test filtering attribute table rows
+ QgsLayout l( QgsProject::instance() );
+ l.initializeDefaults();
+ QgsLayoutItemAttributeTable *table = new QgsLayoutItemAttributeTable( &l );
+ table->setVectorLayer( mVectorLayer );
+
+ table->setMaximumNumberOfFeatures( 10 );
+ table->setFeatureFilter( QStringLiteral( "\"Class\"='B52'" ) );
+ table->setFilterFeatures( true );
+
+ QVector expectedRows;
+ QStringList row;
+ row << QStringLiteral( "B52" ) << QStringLiteral( "0" ) << QStringLiteral( "10" ) << QStringLiteral( "2" ) << QStringLiteral( "1" ) << QStringLiteral( "3" );
+ expectedRows.append( row );
+ row.clear();
+ row << QStringLiteral( "B52" ) << QStringLiteral( "12" ) << QStringLiteral( "10" ) << QStringLiteral( "1" ) << QStringLiteral( "1" ) << QStringLiteral( "2" );
+ expectedRows.append( row );
+ row.clear();
+ row << QStringLiteral( "B52" ) << QStringLiteral( "34" ) << QStringLiteral( "10" ) << QStringLiteral( "2" ) << QStringLiteral( "1" ) << QStringLiteral( "3" );
+ expectedRows.append( row );
+ row.clear();
+ row << QStringLiteral( "B52" ) << QStringLiteral( "80" ) << QStringLiteral( "10" ) << QStringLiteral( "2" ) << QStringLiteral( "1" ) << QStringLiteral( "3" );
+ expectedRows.append( row );
+
+ //retrieve rows and check
+ compareTable( table, expectedRows );
+}
+
+void TestQgsLayoutTable::attributeTableSetAttributes()
+{
+ QgsLayout l( QgsProject::instance() );
+ l.initializeDefaults();
+ QgsLayoutItemAttributeTable *table = new QgsLayoutItemAttributeTable( &l );
+ table->setVectorLayer( mVectorLayer );
+
+ //test subset of attributes in table
+ QStringList attributes;
+ attributes << QStringLiteral( "Class" ) << QStringLiteral( "Pilots" ) << QStringLiteral( "Cabin Crew" );
+ table->setDisplayedFields( attributes );
+ table->setMaximumNumberOfFeatures( 3 );
+
+ //check headers
+ QStringList expectedHeaders;
+ expectedHeaders << QStringLiteral( "Class" ) << QStringLiteral( "Pilots" ) << QStringLiteral( "Cabin Crew" );
+
+ //get header labels and compare
+ QMap headerMap = table->headerLabels();
+ QMap::const_iterator headerIt = headerMap.constBegin();
+ QString expected;
+ QString evaluated;
+ for ( ; headerIt != headerMap.constEnd(); ++headerIt )
+ {
+ evaluated = headerIt.value();
+ expected = expectedHeaders.at( headerIt.key() );
+ QCOMPARE( evaluated, expected );
+ }
+
+ QVector expectedRows;
+ QStringList row;
+ row << QStringLiteral( "Jet" ) << QStringLiteral( "2" ) << QStringLiteral( "0" );
+ expectedRows.append( row );
+ row.clear();
+ row << QStringLiteral( "Biplane" ) << QStringLiteral( "3" ) << QStringLiteral( "3" );
+ expectedRows.append( row );
+ row.clear();
+ row << QStringLiteral( "Jet" ) << QStringLiteral( "1" ) << QStringLiteral( "1" );
+ expectedRows.append( row );
+
+ //retrieve rows and check
+ compareTable( table, expectedRows );
+}
+
+void TestQgsLayoutTable::attributeTableVisibleOnly()
+{
+ //test displaying only visible attributes
+ QgsLayout l( QgsProject::instance() );
+ l.initializeDefaults();
+ QgsLayoutItemAttributeTable *table = new QgsLayoutItemAttributeTable( &l );
+ table->setVectorLayer( mVectorLayer );
+
+ QgsLayoutItemMap *map = new QgsLayoutItemMap( &l );
+ map->attemptSetSceneRect( QRectF( 20, 20, 200, 100 ) );
+ map->setFrameEnabled( true );
+ map->setExtent( QgsRectangle( -131.767, 30.558, -110.743, 41.070 ) );
+ l.addLayoutItem( map );
+
+ table->setMap( map );
+ table->setDisplayOnlyVisibleFeatures( true );
+
+ QVector expectedRows;
+ QStringList row;
+ row << QStringLiteral( "Jet" ) << QStringLiteral( "90" ) << QStringLiteral( "3" ) << QStringLiteral( "2" ) << QStringLiteral( "0" ) << QStringLiteral( "2" );
+ expectedRows.append( row );
+ row.clear();
+ row << QStringLiteral( "Biplane" ) << QStringLiteral( "240" ) << QStringLiteral( "1" ) << QStringLiteral( "3" ) << QStringLiteral( "2" ) << QStringLiteral( "5" );
+ expectedRows.append( row );
+ row.clear();
+ row << QStringLiteral( "Jet" ) << QStringLiteral( "180" ) << QStringLiteral( "3" ) << QStringLiteral( "1" ) << QStringLiteral( "0" ) << QStringLiteral( "1" );
+ expectedRows.append( row );
+
+ //retrieve rows and check
+ compareTable( table, expectedRows );
+}
+
+void TestQgsLayoutTable::attributeTableRender()
+{
+ QgsLayout l( QgsProject::instance() );
+ l.initializeDefaults();
+ QgsLayoutItemAttributeTable *table = new QgsLayoutItemAttributeTable( &l );
+ QgsLayoutFrame *frame1 = new QgsLayoutFrame( &l, table );
+ frame1->attemptSetSceneRect( QRectF( 5, 5, 100, 30 ) );
+ QgsLayoutFrame *frame2 = new QgsLayoutFrame( &l, table );
+ frame2->attemptSetSceneRect( QRectF( 5, 40, 100, 30 ) );
+ frame1->setFrameEnabled( true );
+ frame2->setFrameEnabled( true );
+ table->addFrame( frame1 );
+ table->addFrame( frame2 );
+ table->setVectorLayer( mVectorLayer );
+ table->setDisplayOnlyVisibleFeatures( false );
+ table->setMaximumNumberOfFeatures( 10 );
+ table->setContentFont( QgsFontUtils::getStandardTestFont() );
+ table->setHeaderFont( QgsFontUtils::getStandardTestFont() );
+ table->setBackgroundColor( Qt::yellow );
+
+ table->setMaximumNumberOfFeatures( 20 );
+ QgsLayoutChecker checker( QStringLiteral( "composerattributetable_render" ), &l );
+ checker.setControlPathPrefix( QStringLiteral( "composer_table" ) );
+ bool result = checker.testLayout( mReport );
+ QVERIFY( result );
+}
+
+void TestQgsLayoutTable::manualColumnWidth()
+{
+ QgsLayout l( QgsProject::instance() );
+ l.initializeDefaults();
+ QgsLayoutItemAttributeTable *table = new QgsLayoutItemAttributeTable( &l );
+ QgsLayoutFrame *frame1 = new QgsLayoutFrame( &l, table );
+ frame1->attemptSetSceneRect( QRectF( 5, 5, 100, 30 ) );
+ QgsLayoutFrame *frame2 = new QgsLayoutFrame( &l, table );
+ frame2->attemptSetSceneRect( QRectF( 5, 40, 100, 30 ) );
+ frame1->setFrameEnabled( true );
+ frame2->setFrameEnabled( true );
+ table->addFrame( frame1 );
+ table->addFrame( frame2 );
+ table->setVectorLayer( mVectorLayer );
+ table->setDisplayOnlyVisibleFeatures( false );
+ table->setMaximumNumberOfFeatures( 10 );
+ table->setContentFont( QgsFontUtils::getStandardTestFont() );
+ table->setHeaderFont( QgsFontUtils::getStandardTestFont() );
+ table->setBackgroundColor( Qt::yellow );
+
+ table->setMaximumNumberOfFeatures( 20 );
+ table->columns().at( 0 )->setWidth( 5 );
+ QgsLayoutChecker checker( QStringLiteral( "composerattributetable_columnwidth" ), &l );
+ checker.setControlPathPrefix( QStringLiteral( "composer_table" ) );
+ bool result = checker.testLayout( mReport, 0 );
+ QVERIFY( result );
+}
+
+void TestQgsLayoutTable::attributeTableEmpty()
+{
+ QgsLayout l( QgsProject::instance() );
+ l.initializeDefaults();
+ QgsLayoutItemAttributeTable *table = new QgsLayoutItemAttributeTable( &l );
+ QgsLayoutFrame *frame1 = new QgsLayoutFrame( &l, table );
+ frame1->attemptSetSceneRect( QRectF( 5, 5, 100, 30 ) );
+ QgsLayoutFrame *frame2 = new QgsLayoutFrame( &l, table );
+ frame2->attemptSetSceneRect( QRectF( 5, 40, 100, 30 ) );
+ frame1->setFrameEnabled( true );
+ frame2->setFrameEnabled( true );
+ table->addFrame( frame1 );
+ table->addFrame( frame2 );
+ table->setVectorLayer( mVectorLayer );
+ table->setDisplayOnlyVisibleFeatures( false );
+ table->setMaximumNumberOfFeatures( 10 );
+ table->setContentFont( QgsFontUtils::getStandardTestFont() );
+ table->setHeaderFont( QgsFontUtils::getStandardTestFont() );
+ table->setBackgroundColor( Qt::yellow );
+
+ table->setMaximumNumberOfFeatures( 20 );
+ //hide all features from table
+ table->setFeatureFilter( QStringLiteral( "1=2" ) );
+ table->setFilterFeatures( true );
+
+ table->setEmptyTableBehavior( QgsLayoutTable::HeadersOnly );
+ QgsLayoutChecker checker( QStringLiteral( "composerattributetable_headersonly" ), &l );
+ checker.setControlPathPrefix( QStringLiteral( "composer_table" ) );
+ QVERIFY( checker.testLayout( mReport, 0 ) );
+
+ table->setEmptyTableBehavior( QgsLayoutTable::HideTable );
+ QgsLayoutChecker checker2( QStringLiteral( "composerattributetable_hidetable" ), &l );
+ checker2.setControlPathPrefix( QStringLiteral( "composer_table" ) );
+ QVERIFY( checker2.testLayout( mReport, 0 ) );
+
+ table->setEmptyTableBehavior( QgsLayoutTable::ShowMessage );
+ table->setEmptyTableMessage( QStringLiteral( "no rows" ) );
+ QgsLayoutChecker checker3( QStringLiteral( "composerattributetable_showmessage" ), &l );
+ checker3.setControlPathPrefix( QStringLiteral( "composer_table" ) );
+ QVERIFY( checker3.testLayout( mReport, 0 ) );
+}
+
+void TestQgsLayoutTable::showEmptyRows()
+{
+ QgsLayout l( QgsProject::instance() );
+ l.initializeDefaults();
+ QgsLayoutItemAttributeTable *table = new QgsLayoutItemAttributeTable( &l );
+ QgsLayoutFrame *frame1 = new QgsLayoutFrame( &l, table );
+ frame1->attemptSetSceneRect( QRectF( 5, 5, 100, 30 ) );
+ QgsLayoutFrame *frame2 = new QgsLayoutFrame( &l, table );
+ frame2->attemptSetSceneRect( QRectF( 5, 40, 100, 30 ) );
+ frame1->setFrameEnabled( true );
+ frame2->setFrameEnabled( true );
+ table->addFrame( frame1 );
+ table->addFrame( frame2 );
+ table->setVectorLayer( mVectorLayer );
+ table->setDisplayOnlyVisibleFeatures( false );
+ table->setMaximumNumberOfFeatures( 10 );
+ table->setContentFont( QgsFontUtils::getStandardTestFont() );
+ table->setHeaderFont( QgsFontUtils::getStandardTestFont() );
+ table->setBackgroundColor( Qt::yellow );
+
+ table->setMaximumNumberOfFeatures( 3 );
+ table->setShowEmptyRows( true );
+ QgsLayoutChecker checker( QStringLiteral( "composerattributetable_drawempty" ), &l );
+ checker.setControlPathPrefix( QStringLiteral( "composer_table" ) );
+ QVERIFY( checker.testLayout( mReport, 0 ) );
+}
+
+void TestQgsLayoutTable::attributeTableExtend()
+{
+ QgsLayout l( QgsProject::instance() );
+ l.initializeDefaults();
+ QgsLayoutItemAttributeTable *table = new QgsLayoutItemAttributeTable( &l );
+ QgsLayoutFrame *frame1 = new QgsLayoutFrame( &l, table );
+ frame1->attemptSetSceneRect( QRectF( 5, 5, 100, 30 ) );
+ QgsLayoutFrame *frame2 = new QgsLayoutFrame( &l, table );
+ frame2->attemptSetSceneRect( QRectF( 5, 40, 100, 30 ) );
+ frame1->setFrameEnabled( true );
+ frame2->setFrameEnabled( true );
+ table->addFrame( frame1 );
+ table->addFrame( frame2 );
+ table->setVectorLayer( mVectorLayer );
+ table->setDisplayOnlyVisibleFeatures( false );
+ table->setMaximumNumberOfFeatures( 10 );
+ table->setContentFont( QgsFontUtils::getStandardTestFont() );
+ table->setHeaderFont( QgsFontUtils::getStandardTestFont() );
+ table->setBackgroundColor( Qt::yellow );
+
+ //test that adding and removing frames automatically does not result in a crash
+ table->removeFrame( 1 );
+
+ //force auto creation of some new frames
+ table->setResizeMode( QgsLayoutMultiFrame::ExtendToNextPage );
+
+ l.setSelectedItem( table->frame( 1 ) );
+
+ //now auto remove extra created frames
+ table->setMaximumNumberOfFeatures( 1 );
+}
+
+void TestQgsLayoutTable::attributeTableRepeat()
+{
+ QgsLayout l( QgsProject::instance() );
+ l.initializeDefaults();
+ QgsLayoutItemAttributeTable *table = new QgsLayoutItemAttributeTable( &l );
+ QgsLayoutFrame *frame1 = new QgsLayoutFrame( &l, table );
+ frame1->attemptSetSceneRect( QRectF( 5, 5, 100, 30 ) );
+ QgsLayoutFrame *frame2 = new QgsLayoutFrame( &l, table );
+ frame2->attemptSetSceneRect( QRectF( 5, 40, 100, 30 ) );
+ frame1->setFrameEnabled( true );
+ frame2->setFrameEnabled( true );
+ table->addFrame( frame1 );
+ table->addFrame( frame2 );
+ table->setVectorLayer( mVectorLayer );
+ table->setDisplayOnlyVisibleFeatures( false );
+ table->setMaximumNumberOfFeatures( 10 );
+ table->setContentFont( QgsFontUtils::getStandardTestFont() );
+ table->setHeaderFont( QgsFontUtils::getStandardTestFont() );
+ table->setBackgroundColor( Qt::yellow );
+
+ //test that creating and removing new frames in repeat mode does not crash
+
+ table->setResizeMode( QgsLayoutMultiFrame::UseExistingFrames );
+ //remove extra frames
+ for ( int idx = table->frameCount(); idx > 0; --idx )
+ {
+ table->removeFrame( idx - 1 );
+ }
+
+ table->setMaximumNumberOfFeatures( 1 );
+
+ //force auto creation of some new frames
+ table->setResizeMode( QgsLayoutMultiFrame::RepeatUntilFinished );
+
+ for ( int features = 0; features < 50; ++features )
+ {
+ table->setMaximumNumberOfFeatures( features );
+ }
+
+ //and then the reverse....
+ for ( int features = 50; features > 1; --features )
+ {
+ table->setMaximumNumberOfFeatures( features );
+ }
+}
+
+void TestQgsLayoutTable::attributeTableAtlasSource()
+{
+#if 0 //TODO
+ QgsLayoutItemAttributeTable *table = new QgsLayoutItemAttributeTable( mComposition, false );
+
+
+ table->setSource( QgsLayoutItemAttributeTable::AtlasFeature );
+
+ //setup atlas
+ QgsVectorLayer *vectorLayer = nullptr;
+ QFileInfo vectorFileInfo( QStringLiteral( TEST_DATA_DIR ) + "/points.shp" );
+ vectorLayer = new QgsVectorLayer( vectorFileInfo.filePath(),
+ vectorFileInfo.completeBaseName(),
+ QStringLiteral( "ogr" ) );
+ QgsProject::instance()->addMapLayer( vectorLayer );
+ mComposition->atlasComposition().setCoverageLayer( vectorLayer );
+ mComposition->atlasComposition().setEnabled( true );
+ QVERIFY( mComposition->atlasComposition().beginRender() );
+
+ QVERIFY( mComposition->atlasComposition().prepareForFeature( 0 ) );
+ QCOMPARE( table->contents()->length(), 1 );
+ QgsComposerTableRow row = table->contents()->at( 0 );
+
+ //check a couple of results
+ QCOMPARE( row.at( 0 ), QVariant( "Jet" ) );
+ QCOMPARE( row.at( 1 ), QVariant( 90 ) );
+ QCOMPARE( row.at( 2 ), QVariant( 3 ) );
+ QCOMPARE( row.at( 3 ), QVariant( 2 ) );
+ QCOMPARE( row.at( 4 ), QVariant( 0 ) );
+ QCOMPARE( row.at( 5 ), QVariant( 2 ) );
+
+ //next atlas feature
+ QVERIFY( mComposition->atlasComposition().prepareForFeature( 1 ) );
+ QCOMPARE( table->contents()->length(), 1 );
+ row = table->contents()->at( 0 );
+ QCOMPARE( row.at( 0 ), QVariant( "Biplane" ) );
+ QCOMPARE( row.at( 1 ), QVariant( 0 ) );
+ QCOMPARE( row.at( 2 ), QVariant( 1 ) );
+ QCOMPARE( row.at( 3 ), QVariant( 3 ) );
+ QCOMPARE( row.at( 4 ), QVariant( 3 ) );
+ QCOMPARE( row.at( 5 ), QVariant( 6 ) );
+
+ //next atlas feature
+ QVERIFY( mComposition->atlasComposition().prepareForFeature( 2 ) );
+ QCOMPARE( table->contents()->length(), 1 );
+ row = table->contents()->at( 0 );
+ QCOMPARE( row.at( 0 ), QVariant( "Jet" ) );
+ QCOMPARE( row.at( 1 ), QVariant( 85 ) );
+ QCOMPARE( row.at( 2 ), QVariant( 3 ) );
+ QCOMPARE( row.at( 3 ), QVariant( 1 ) );
+ QCOMPARE( row.at( 4 ), QVariant( 1 ) );
+ QCOMPARE( row.at( 5 ), QVariant( 2 ) );
+
+ mComposition->atlasComposition().endRender();
+
+ //try for a crash when removing current atlas layer
+ QgsProject::instance()->removeMapLayer( vectorLayer->id() );
+ table->refreshAttributes();
+
+ mComposition->removeMultiFrame( table );
+ delete table;
+#endif
+}
+
+
+void TestQgsLayoutTable::attributeTableRelationSource()
+{
+ QgsLayout l( QgsProject::instance() );
+ l.initializeDefaults();
+ QgsLayoutItemAttributeTable *table = new QgsLayoutItemAttributeTable( &l );
+ QgsLayoutFrame *frame1 = new QgsLayoutFrame( &l, table );
+ frame1->attemptSetSceneRect( QRectF( 5, 5, 100, 30 ) );
+ QgsLayoutFrame *frame2 = new QgsLayoutFrame( &l, table );
+ frame2->attemptSetSceneRect( QRectF( 5, 40, 100, 30 ) );
+ frame1->setFrameEnabled( true );
+ frame2->setFrameEnabled( true );
+ table->addFrame( frame1 );
+ table->addFrame( frame2 );
+ table->setVectorLayer( mVectorLayer );
+ table->setDisplayOnlyVisibleFeatures( false );
+ table->setMaximumNumberOfFeatures( 10 );
+ table->setContentFont( QgsFontUtils::getStandardTestFont() );
+ table->setHeaderFont( QgsFontUtils::getStandardTestFont() );
+ table->setBackgroundColor( Qt::yellow );
+
+ QFileInfo vectorFileInfo( QStringLiteral( TEST_DATA_DIR ) + "/points_relations.shp" );
+ QgsVectorLayer *atlasLayer = new QgsVectorLayer( vectorFileInfo.filePath(),
+ vectorFileInfo.completeBaseName(),
+ QStringLiteral( "ogr" ) );
+
+ QgsProject::instance()->addMapLayer( atlasLayer );
+
+#if 0 //TODO
+ //setup atlas
+ mComposition->atlasComposition().setCoverageLayer( atlasLayer );
+ mComposition->atlasComposition().setEnabled( true );
+
+ //create a relation
+ QgsRelation relation;
+ relation.setId( QStringLiteral( "testrelation" ) );
+ relation.setReferencedLayer( atlasLayer->id() );
+ relation.setReferencingLayer( mVectorLayer->id() );
+ relation.addFieldPair( QStringLiteral( "Class" ), QStringLiteral( "Class" ) );
+ QgsProject::instance()->relationManager()->addRelation( relation );
+
+ QgsLayoutItemAttributeTable *table = new QgsLayoutItemAttributeTable( mComposition, false );
+ table->setMaximumNumberOfFeatures( 50 );
+ table->setSource( QgsLayoutItemAttributeTable::RelationChildren );
+ table->setRelationId( relation.id() );
+
+ QVERIFY( mComposition->atlasComposition().beginRender() );
+ QVERIFY( mComposition->atlasComposition().prepareForFeature( 0 ) );
+
+ QCOMPARE( mComposition->atlasComposition().feature().attribute( "Class" ).toString(), QString( "Jet" ) );
+ QCOMPARE( table->contents()->length(), 8 );
+
+ QgsComposerTableRow row = table->contents()->at( 0 );
+
+ //check a couple of results
+ QCOMPARE( row.at( 0 ), QVariant( "Jet" ) );
+ QCOMPARE( row.at( 1 ), QVariant( 90 ) );
+ QCOMPARE( row.at( 2 ), QVariant( 3 ) );
+ QCOMPARE( row.at( 3 ), QVariant( 2 ) );
+ QCOMPARE( row.at( 4 ), QVariant( 0 ) );
+ QCOMPARE( row.at( 5 ), QVariant( 2 ) );
+ row = table->contents()->at( 1 );
+ QCOMPARE( row.at( 0 ), QVariant( "Jet" ) );
+ QCOMPARE( row.at( 1 ), QVariant( 85 ) );
+ QCOMPARE( row.at( 2 ), QVariant( 3 ) );
+ QCOMPARE( row.at( 3 ), QVariant( 1 ) );
+ QCOMPARE( row.at( 4 ), QVariant( 1 ) );
+ QCOMPARE( row.at( 5 ), QVariant( 2 ) );
+ row = table->contents()->at( 2 );
+ QCOMPARE( row.at( 0 ), QVariant( "Jet" ) );
+ QCOMPARE( row.at( 1 ), QVariant( 95 ) );
+ QCOMPARE( row.at( 2 ), QVariant( 3 ) );
+ QCOMPARE( row.at( 3 ), QVariant( 1 ) );
+ QCOMPARE( row.at( 4 ), QVariant( 1 ) );
+ QCOMPARE( row.at( 5 ), QVariant( 2 ) );
+
+ //next atlas feature
+ QVERIFY( mComposition->atlasComposition().prepareForFeature( 1 ) );
+ QCOMPARE( mComposition->atlasComposition().feature().attribute( "Class" ).toString(), QString( "Biplane" ) );
+ QCOMPARE( table->contents()->length(), 5 );
+ row = table->contents()->at( 0 );
+ QCOMPARE( row.at( 0 ), QVariant( "Biplane" ) );
+ QCOMPARE( row.at( 1 ), QVariant( 0 ) );
+ QCOMPARE( row.at( 2 ), QVariant( 1 ) );
+ QCOMPARE( row.at( 3 ), QVariant( 3 ) );
+ QCOMPARE( row.at( 4 ), QVariant( 3 ) );
+ QCOMPARE( row.at( 5 ), QVariant( 6 ) );
+ row = table->contents()->at( 1 );
+ QCOMPARE( row.at( 0 ), QVariant( "Biplane" ) );
+ QCOMPARE( row.at( 1 ), QVariant( 340 ) );
+ QCOMPARE( row.at( 2 ), QVariant( 1 ) );
+ QCOMPARE( row.at( 3 ), QVariant( 3 ) );
+ QCOMPARE( row.at( 4 ), QVariant( 3 ) );
+ QCOMPARE( row.at( 5 ), QVariant( 6 ) );
+
+ mComposition->atlasComposition().endRender();
+
+ //try for a crash when removing current atlas layer
+ QgsProject::instance()->removeMapLayer( atlasLayer->id() );
+
+ table->refreshAttributes();
+
+ mComposition->removeMultiFrame( table );
+ delete table;
+#endif
+}
+
+void TestQgsLayoutTable::contentsContainsRow()
+{
+ QgsLayout l( QgsProject::instance() );
+ l.initializeDefaults();
+ QgsLayoutItemAttributeTable *table = new QgsLayoutItemAttributeTable( &l );
+ table->setVectorLayer( mVectorLayer );
+ table->setDisplayOnlyVisibleFeatures( false );
+ table->setMaximumNumberOfFeatures( 10 );
+
+ QgsLayoutTableContents testContents;
+ QgsLayoutTableRow row1;
+ row1 << QVariant( QStringLiteral( "string 1" ) ) << QVariant( 2 ) << QVariant( 1.5 ) << QVariant( QStringLiteral( "string 2" ) );
+ QgsLayoutTableRow row2;
+ row2 << QVariant( QStringLiteral( "string 2" ) ) << QVariant( 2 ) << QVariant( 1.5 ) << QVariant( QStringLiteral( "string 2" ) );
+ //same as row1
+ QgsLayoutTableRow row3;
+ row3 << QVariant( QStringLiteral( "string 1" ) ) << QVariant( 2 ) << QVariant( 1.5 ) << QVariant( QStringLiteral( "string 2" ) );
+ QgsLayoutTableRow row4;
+ row4 << QVariant( QStringLiteral( "string 1" ) ) << QVariant( 2 ) << QVariant( 1.7 ) << QVariant( QStringLiteral( "string 2" ) );
+
+ testContents << row1;
+ testContents << row2;
+
+ QVERIFY( table->contentsContainsRow( testContents, row1 ) );
+ QVERIFY( table->contentsContainsRow( testContents, row2 ) );
+ QVERIFY( table->contentsContainsRow( testContents, row3 ) );
+ QVERIFY( !table->contentsContainsRow( testContents, row4 ) );
+}
+
+void TestQgsLayoutTable::removeDuplicates()
+{
+ QgsVectorLayer *dupesLayer = new QgsVectorLayer( QStringLiteral( "Point?field=col1:integer&field=col2:integer&field=col3:integer" ), QStringLiteral( "dupes" ), QStringLiteral( "memory" ) );
+ QVERIFY( dupesLayer->isValid() );
+ QgsFeature f1( dupesLayer->dataProvider()->fields(), 1 );
+ f1.setAttribute( QStringLiteral( "col1" ), 1 );
+ f1.setAttribute( QStringLiteral( "col2" ), 1 );
+ f1.setAttribute( QStringLiteral( "col3" ), 1 );
+ QgsFeature f2( dupesLayer->dataProvider()->fields(), 2 );
+ f2.setAttribute( QStringLiteral( "col1" ), 1 );
+ f2.setAttribute( QStringLiteral( "col2" ), 2 );
+ f2.setAttribute( QStringLiteral( "col3" ), 2 );
+ QgsFeature f3( dupesLayer->dataProvider()->fields(), 3 );
+ f3.setAttribute( QStringLiteral( "col1" ), 1 );
+ f3.setAttribute( QStringLiteral( "col2" ), 2 );
+ f3.setAttribute( QStringLiteral( "col3" ), 3 );
+ QgsFeature f4( dupesLayer->dataProvider()->fields(), 4 );
+ f4.setAttribute( QStringLiteral( "col1" ), 1 );
+ f4.setAttribute( QStringLiteral( "col2" ), 1 );
+ f4.setAttribute( QStringLiteral( "col3" ), 1 );
+ dupesLayer->dataProvider()->addFeatures( QgsFeatureList() << f1 << f2 << f3 << f4 );
+
+ QgsLayout l( QgsProject::instance() );
+ l.initializeDefaults();
+ QgsLayoutItemAttributeTable *table = new QgsLayoutItemAttributeTable( &l );
+ table->setSource( QgsLayoutItemAttributeTable::LayerAttributes );
+ table->setVectorLayer( dupesLayer );
+ table->setMaximumNumberOfFeatures( 50 );
+ QCOMPARE( table->contents().length(), 4 );
+
+ table->setUniqueRowsOnly( true );
+ QCOMPARE( table->contents().length(), 3 );
+
+ //check if removing attributes in unique mode works correctly (should result in duplicate rows,
+ //which will be stripped out)
+ delete table->columns().takeLast();
+ table->refreshAttributes();
+ QCOMPARE( table->contents().length(), 2 );
+ delete table->columns().takeLast();
+ table->refreshAttributes();
+ QCOMPARE( table->contents().length(), 1 );
+ table->setUniqueRowsOnly( false );
+ QCOMPARE( table->contents().length(), 4 );
+
+ delete dupesLayer;
+}
+
+void TestQgsLayoutTable::multiLineText()
+{
+ QgsLayout l( QgsProject::instance() );
+ l.initializeDefaults();
+ QgsLayoutItemAttributeTable *table = new QgsLayoutItemAttributeTable( &l );
+ QgsLayoutFrame *frame1 = new QgsLayoutFrame( &l, table );
+ frame1->attemptSetSceneRect( QRectF( 5, 5, 100, 30 ) );
+ QgsLayoutFrame *frame2 = new QgsLayoutFrame( &l, table );
+ frame2->attemptSetSceneRect( QRectF( 5, 40, 100, 30 ) );
+ frame1->setFrameEnabled( true );
+ frame2->setFrameEnabled( true );
+ table->addFrame( frame1 );
+ table->addFrame( frame2 );
+ table->setVectorLayer( mVectorLayer );
+ table->setDisplayOnlyVisibleFeatures( false );
+ table->setMaximumNumberOfFeatures( 10 );
+ table->setContentFont( QgsFontUtils::getStandardTestFont() );
+ table->setHeaderFont( QgsFontUtils::getStandardTestFont() );
+ table->setBackgroundColor( Qt::yellow );
+
+ QgsVectorLayer *multiLineLayer = new QgsVectorLayer( QStringLiteral( "Point?field=col1:string&field=col2:string&field=col3:string" ), QStringLiteral( "multiline" ), QStringLiteral( "memory" ) );
+ QVERIFY( multiLineLayer->isValid() );
+ QgsFeature f1( multiLineLayer->dataProvider()->fields(), 1 );
+ f1.setAttribute( QStringLiteral( "col1" ), "multiline\nstring" );
+ f1.setAttribute( QStringLiteral( "col2" ), "singleline string" );
+ f1.setAttribute( QStringLiteral( "col3" ), "singleline" );
+ QgsFeature f2( multiLineLayer->dataProvider()->fields(), 2 );
+ f2.setAttribute( QStringLiteral( "col1" ), "singleline string" );
+ f2.setAttribute( QStringLiteral( "col2" ), "multiline\nstring" );
+ f2.setAttribute( QStringLiteral( "col3" ), "singleline" );
+ QgsFeature f3( multiLineLayer->dataProvider()->fields(), 3 );
+ f3.setAttribute( QStringLiteral( "col1" ), "singleline" );
+ f3.setAttribute( QStringLiteral( "col2" ), "singleline" );
+ f3.setAttribute( QStringLiteral( "col3" ), "multiline\nstring" );
+ QgsFeature f4( multiLineLayer->dataProvider()->fields(), 4 );
+ f4.setAttribute( QStringLiteral( "col1" ), "long triple\nline\nstring" );
+ f4.setAttribute( QStringLiteral( "col2" ), "double\nlinestring" );
+ f4.setAttribute( QStringLiteral( "col3" ), "singleline" );
+ multiLineLayer->dataProvider()->addFeatures( QgsFeatureList() << f1 << f2 << f3 << f4 );
+
+ frame2->attemptSetSceneRect( QRectF( 5, 40, 100, 90 ) );
+
+ table->setMaximumNumberOfFeatures( 20 );
+ table->setVectorLayer( multiLineLayer );
+ QgsLayoutChecker checker( QStringLiteral( "composerattributetable_multiline" ), &l );
+ checker.setControlPathPrefix( QStringLiteral( "composer_table" ) );
+ bool result = checker.testLayout( mReport );
+ QVERIFY( result );
+
+ delete multiLineLayer;
+}
+
+void TestQgsLayoutTable::horizontalGrid()
+{
+ QgsLayout l( QgsProject::instance() );
+ l.initializeDefaults();
+ QgsLayoutItemAttributeTable *table = new QgsLayoutItemAttributeTable( &l );
+ QgsLayoutFrame *frame1 = new QgsLayoutFrame( &l, table );
+ frame1->attemptSetSceneRect( QRectF( 5, 5, 100, 30 ) );
+ QgsLayoutFrame *frame2 = new QgsLayoutFrame( &l, table );
+ frame2->attemptSetSceneRect( QRectF( 5, 40, 100, 30 ) );
+ frame1->setFrameEnabled( true );
+ frame2->setFrameEnabled( true );
+ table->addFrame( frame1 );
+ table->addFrame( frame2 );
+ table->setVectorLayer( mVectorLayer );
+ table->setDisplayOnlyVisibleFeatures( false );
+ table->setMaximumNumberOfFeatures( 10 );
+ table->setContentFont( QgsFontUtils::getStandardTestFont() );
+ table->setHeaderFont( QgsFontUtils::getStandardTestFont() );
+ table->setBackgroundColor( Qt::yellow );
+
+ QgsVectorLayer *multiLineLayer = new QgsVectorLayer( QStringLiteral( "Point?field=col1:string&field=col2:string&field=col3:string" ), QStringLiteral( "multiline" ), QStringLiteral( "memory" ) );
+ QVERIFY( multiLineLayer->isValid() );
+ QgsFeature f1( multiLineLayer->dataProvider()->fields(), 1 );
+ f1.setAttribute( QStringLiteral( "col1" ), "multiline\nstring" );
+ f1.setAttribute( QStringLiteral( "col2" ), "singleline string" );
+ f1.setAttribute( QStringLiteral( "col3" ), "singleline" );
+ QgsFeature f2( multiLineLayer->dataProvider()->fields(), 2 );
+ f2.setAttribute( QStringLiteral( "col1" ), "singleline string" );
+ f2.setAttribute( QStringLiteral( "col2" ), "multiline\nstring" );
+ f2.setAttribute( QStringLiteral( "col3" ), "singleline" );
+ QgsFeature f3( multiLineLayer->dataProvider()->fields(), 3 );
+ f3.setAttribute( QStringLiteral( "col1" ), "singleline" );
+ f3.setAttribute( QStringLiteral( "col2" ), "singleline" );
+ f3.setAttribute( QStringLiteral( "col3" ), "multiline\nstring" );
+ QgsFeature f4( multiLineLayer->dataProvider()->fields(), 4 );
+ f4.setAttribute( QStringLiteral( "col1" ), "long triple\nline\nstring" );
+ f4.setAttribute( QStringLiteral( "col2" ), "double\nlinestring" );
+ f4.setAttribute( QStringLiteral( "col3" ), "singleline" );
+ multiLineLayer->dataProvider()->addFeatures( QgsFeatureList() << f1 << f2 << f3 << f4 );
+
+ frame1->setFrameEnabled( false );
+ frame2->setFrameEnabled( false );
+ frame2->attemptSetSceneRect( QRectF( 5, 40, 100, 90 ) );
+
+ table->setMaximumNumberOfFeatures( 20 );
+ table->setShowGrid( true );
+ table->setHorizontalGrid( true );
+ table->setVerticalGrid( false );
+ table->setVectorLayer( multiLineLayer );
+ QgsLayoutChecker checker( QStringLiteral( "composerattributetable_horizontalgrid" ), &l );
+ checker.setControlPathPrefix( QStringLiteral( "composer_table" ) );
+ bool result = checker.testLayout( mReport );
+ QVERIFY( result );
+
+ delete multiLineLayer;
+}
+
+void TestQgsLayoutTable::verticalGrid()
+{
+ QgsLayout l( QgsProject::instance() );
+ l.initializeDefaults();
+ QgsLayoutItemAttributeTable *table = new QgsLayoutItemAttributeTable( &l );
+ QgsLayoutFrame *frame1 = new QgsLayoutFrame( &l, table );
+ frame1->attemptSetSceneRect( QRectF( 5, 5, 100, 30 ) );
+ QgsLayoutFrame *frame2 = new QgsLayoutFrame( &l, table );
+ frame2->attemptSetSceneRect( QRectF( 5, 40, 100, 30 ) );
+ frame1->setFrameEnabled( true );
+ frame2->setFrameEnabled( true );
+ table->addFrame( frame1 );
+ table->addFrame( frame2 );
+ table->setVectorLayer( mVectorLayer );
+ table->setDisplayOnlyVisibleFeatures( false );
+ table->setMaximumNumberOfFeatures( 10 );
+ table->setContentFont( QgsFontUtils::getStandardTestFont() );
+ table->setHeaderFont( QgsFontUtils::getStandardTestFont() );
+ table->setBackgroundColor( Qt::yellow );
+
+ QgsVectorLayer *multiLineLayer = new QgsVectorLayer( QStringLiteral( "Point?field=col1:string&field=col2:string&field=col3:string" ), QStringLiteral( "multiline" ), QStringLiteral( "memory" ) );
+ QVERIFY( multiLineLayer->isValid() );
+ QgsFeature f1( multiLineLayer->dataProvider()->fields(), 1 );
+ f1.setAttribute( QStringLiteral( "col1" ), "multiline\nstring" );
+ f1.setAttribute( QStringLiteral( "col2" ), "singleline string" );
+ f1.setAttribute( QStringLiteral( "col3" ), "singleline" );
+ QgsFeature f2( multiLineLayer->dataProvider()->fields(), 2 );
+ f2.setAttribute( QStringLiteral( "col1" ), "singleline string" );
+ f2.setAttribute( QStringLiteral( "col2" ), "multiline\nstring" );
+ f2.setAttribute( QStringLiteral( "col3" ), "singleline" );
+ QgsFeature f3( multiLineLayer->dataProvider()->fields(), 3 );
+ f3.setAttribute( QStringLiteral( "col1" ), "singleline" );
+ f3.setAttribute( QStringLiteral( "col2" ), "singleline" );
+ f3.setAttribute( QStringLiteral( "col3" ), "multiline\nstring" );
+ QgsFeature f4( multiLineLayer->dataProvider()->fields(), 4 );
+ f4.setAttribute( QStringLiteral( "col1" ), "long triple\nline\nstring" );
+ f4.setAttribute( QStringLiteral( "col2" ), "double\nlinestring" );
+ f4.setAttribute( QStringLiteral( "col3" ), "singleline" );
+ multiLineLayer->dataProvider()->addFeatures( QgsFeatureList() << f1 << f2 << f3 << f4 );
+
+ frame1->setFrameEnabled( false );
+ frame2->setFrameEnabled( false );
+ frame2->attemptSetSceneRect( QRectF( 5, 40, 100, 90 ) );
+
+ table->setMaximumNumberOfFeatures( 20 );
+ table->setShowGrid( true );
+ table->setHorizontalGrid( false );
+ table->setVerticalGrid( true );
+ table->setVectorLayer( multiLineLayer );
+ QgsLayoutChecker checker( QStringLiteral( "composerattributetable_verticalgrid" ), &l );
+ checker.setControlPathPrefix( QStringLiteral( "composer_table" ) );
+ bool result = checker.testLayout( mReport );
+ QVERIFY( result );
+
+ delete multiLineLayer;
+}
+
+void TestQgsLayoutTable::align()
+{
+ QgsLayout l( QgsProject::instance() );
+ l.initializeDefaults();
+ QgsLayoutItemAttributeTable *table = new QgsLayoutItemAttributeTable( &l );
+ QgsLayoutFrame *frame1 = new QgsLayoutFrame( &l, table );
+ frame1->attemptSetSceneRect( QRectF( 5, 5, 100, 30 ) );
+ QgsLayoutFrame *frame2 = new QgsLayoutFrame( &l, table );
+ frame2->attemptSetSceneRect( QRectF( 5, 40, 100, 30 ) );
+ frame1->setFrameEnabled( true );
+ frame2->setFrameEnabled( true );
+ table->addFrame( frame1 );
+ table->addFrame( frame2 );
+ table->setVectorLayer( mVectorLayer );
+ table->setDisplayOnlyVisibleFeatures( false );
+ table->setMaximumNumberOfFeatures( 10 );
+ table->setContentFont( QgsFontUtils::getStandardTestFont() );
+ table->setHeaderFont( QgsFontUtils::getStandardTestFont() );
+ table->setBackgroundColor( Qt::yellow );
+
+ QgsVectorLayer *multiLineLayer = new QgsVectorLayer( QStringLiteral( "Point?field=col1:string&field=col2:string&field=col3:string" ), QStringLiteral( "multiline" ), QStringLiteral( "memory" ) );
+ QVERIFY( multiLineLayer->isValid() );
+ QgsFeature f1( multiLineLayer->dataProvider()->fields(), 1 );
+ f1.setAttribute( QStringLiteral( "col1" ), "multiline\nstring" );
+ f1.setAttribute( QStringLiteral( "col2" ), "singleline string" );
+ f1.setAttribute( QStringLiteral( "col3" ), "singleline" );
+ QgsFeature f2( multiLineLayer->dataProvider()->fields(), 2 );
+ f2.setAttribute( QStringLiteral( "col1" ), "singleline string" );
+ f2.setAttribute( QStringLiteral( "col2" ), "multiline\nstring" );
+ f2.setAttribute( QStringLiteral( "col3" ), "singleline" );
+ QgsFeature f3( multiLineLayer->dataProvider()->fields(), 3 );
+ f3.setAttribute( QStringLiteral( "col1" ), "singleline" );
+ f3.setAttribute( QStringLiteral( "col2" ), "singleline" );
+ f3.setAttribute( QStringLiteral( "col3" ), "multiline\nstring" );
+ QgsFeature f4( multiLineLayer->dataProvider()->fields(), 4 );
+ f4.setAttribute( QStringLiteral( "col1" ), "long triple\nline\nstring" );
+ f4.setAttribute( QStringLiteral( "col2" ), "double\nlinestring" );
+ f4.setAttribute( QStringLiteral( "col3" ), "singleline" );
+ multiLineLayer->dataProvider()->addFeatures( QgsFeatureList() << f1 << f2 << f3 << f4 );
+
+ frame2->attemptSetSceneRect( QRectF( 5, 40, 100, 90 ) );
+
+ table->setMaximumNumberOfFeatures( 20 );
+ table->setVectorLayer( multiLineLayer );
+
+ table->columns().at( 0 )->setHAlignment( Qt::AlignLeft );
+ table->columns().at( 0 )->setVAlignment( Qt::AlignTop );
+ table->columns().at( 1 )->setHAlignment( Qt::AlignHCenter );
+ table->columns().at( 1 )->setVAlignment( Qt::AlignVCenter );
+ table->columns().at( 2 )->setHAlignment( Qt::AlignRight );
+ table->columns(). at( 2 )->setVAlignment( Qt::AlignBottom );
+ QgsLayoutChecker checker( QStringLiteral( "composerattributetable_align" ), &l );
+ checker.setControlPathPrefix( QStringLiteral( "composer_table" ) );
+ bool result = checker.testLayout( mReport );
+ QVERIFY( result );
+
+ delete multiLineLayer;
+}
+
+void TestQgsLayoutTable::wrapChar()
+{
+ QgsLayout l( QgsProject::instance() );
+ l.initializeDefaults();
+ QgsLayoutItemAttributeTable *table = new QgsLayoutItemAttributeTable( &l );
+ table->setVectorLayer( mVectorLayer );
+ table->setDisplayOnlyVisibleFeatures( false );
+ table->setMaximumNumberOfFeatures( 10 );
+ table->setContentFont( QgsFontUtils::getStandardTestFont() );
+ table->setHeaderFont( QgsFontUtils::getStandardTestFont() );
+ table->setBackgroundColor( Qt::yellow );
+
+ QgsVectorLayer *multiLineLayer = new QgsVectorLayer( QStringLiteral( "Point?field=col1:string&field=col2:string&field=col3:string" ), QStringLiteral( "multiline" ), QStringLiteral( "memory" ) );
+ QVERIFY( multiLineLayer->isValid() );
+ QgsFeature f1( multiLineLayer->dataProvider()->fields(), 1 );
+ f1.setAttribute( QStringLiteral( "col1" ), "multiline\nstring" );
+ f1.setAttribute( QStringLiteral( "col2" ), "singleline string" );
+ f1.setAttribute( QStringLiteral( "col3" ), "singleline" );
+ multiLineLayer->dataProvider()->addFeatures( QgsFeatureList() << f1 );
+
+ table->setMaximumNumberOfFeatures( 1 );
+ table->setVectorLayer( multiLineLayer );
+ table->setWrapString( QStringLiteral( "in" ) );
+
+ QVector expectedRows;
+ QStringList row;
+ row << QStringLiteral( "multil\ne\nstr\ng" ) << QStringLiteral( "s\nglel\ne str\ng" ) << QStringLiteral( "s\nglel\ne" );
+ expectedRows.append( row );
+
+ //retrieve rows and check
+ compareTable( table, expectedRows );
+}
+
+void TestQgsLayoutTable::autoWrap()
+{
+ QgsLayout l( QgsProject::instance() );
+ l.initializeDefaults();
+ QgsLayoutItemAttributeTable *table = new QgsLayoutItemAttributeTable( &l );
+ QgsLayoutFrame *frame1 = new QgsLayoutFrame( &l, table );
+ frame1->attemptSetSceneRect( QRectF( 5, 5, 100, 30 ) );
+ QgsLayoutFrame *frame2 = new QgsLayoutFrame( &l, table );
+ frame2->attemptSetSceneRect( QRectF( 5, 40, 100, 30 ) );
+ frame1->setFrameEnabled( true );
+ frame2->setFrameEnabled( true );
+ table->addFrame( frame1 );
+ table->addFrame( frame2 );
+ table->setVectorLayer( mVectorLayer );
+ table->setDisplayOnlyVisibleFeatures( false );
+ table->setMaximumNumberOfFeatures( 10 );
+ table->setContentFont( QgsFontUtils::getStandardTestFont() );
+ table->setHeaderFont( QgsFontUtils::getStandardTestFont() );
+ table->setBackgroundColor( Qt::yellow );
+
+ QgsVectorLayer *multiLineLayer = new QgsVectorLayer( QStringLiteral( "Point?field=col1:string&field=col2:string&field=col3:string" ), QStringLiteral( "multiline" ), QStringLiteral( "memory" ) );
+ QVERIFY( multiLineLayer->isValid() );
+ QgsFeature f1( multiLineLayer->dataProvider()->fields(), 1 );
+ f1.setAttribute( QStringLiteral( "col1" ), "long multiline\nstring" );
+ f1.setAttribute( QStringLiteral( "col2" ), "singleline string" );
+ f1.setAttribute( QStringLiteral( "col3" ), "singleline" );
+ QgsFeature f2( multiLineLayer->dataProvider()->fields(), 2 );
+ f2.setAttribute( QStringLiteral( "col1" ), "singleline string" );
+ f2.setAttribute( QStringLiteral( "col2" ), "multiline\nstring" );
+ f2.setAttribute( QStringLiteral( "col3" ), "singleline" );
+ QgsFeature f3( multiLineLayer->dataProvider()->fields(), 3 );
+ f3.setAttribute( QStringLiteral( "col1" ), "singleline" );
+ f3.setAttribute( QStringLiteral( "col2" ), "singleline" );
+ f3.setAttribute( QStringLiteral( "col3" ), "multiline\nstring" );
+ QgsFeature f4( multiLineLayer->dataProvider()->fields(), 4 );
+ f4.setAttribute( QStringLiteral( "col1" ), "a bit long triple line string" );
+ f4.setAttribute( QStringLiteral( "col2" ), "double toolongtofitononeline string with some more lines on the end andanotherreallylongline" );
+ f4.setAttribute( QStringLiteral( "col3" ), "singleline" );
+ multiLineLayer->dataProvider()->addFeatures( QgsFeatureList() << f1 << f2 << f3 << f4 );
+
+ frame2->attemptSetSceneRect( QRectF( 5, 40, 100, 90 ) );
+
+ table->setMaximumNumberOfFeatures( 20 );
+ table->setVectorLayer( multiLineLayer );
+ table->setWrapBehavior( QgsLayoutTable::WrapText );
+
+ table->columns().at( 0 )->setWidth( 25 );
+ table->columns().at( 1 )->setWidth( 25 );
+ QgsLayoutChecker checker( QStringLiteral( "composerattributetable_autowrap" ), &l );
+ checker.setControlPathPrefix( QStringLiteral( "composer_table" ) );
+ bool result = checker.testLayout( mReport, 0 );
+ QVERIFY( result );
+}
+
+void TestQgsLayoutTable::cellStyles()
+{
+ QgsLayout l( QgsProject::instance() );
+ l.initializeDefaults();
+ QgsLayoutItemAttributeTable *table = new QgsLayoutItemAttributeTable( &l );
+ QgsLayoutFrame *frame1 = new QgsLayoutFrame( &l, table );
+ frame1->attemptSetSceneRect( QRectF( 5, 5, 100, 30 ) );
+ QgsLayoutFrame *frame2 = new QgsLayoutFrame( &l, table );
+ frame2->attemptSetSceneRect( QRectF( 5, 40, 100, 30 ) );
+ frame1->setFrameEnabled( true );
+ frame2->setFrameEnabled( true );
+ table->addFrame( frame1 );
+ table->addFrame( frame2 );
+ table->setVectorLayer( mVectorLayer );
+ table->setDisplayOnlyVisibleFeatures( false );
+ table->setMaximumNumberOfFeatures( 10 );
+ table->setContentFont( QgsFontUtils::getStandardTestFont() );
+ table->setHeaderFont( QgsFontUtils::getStandardTestFont() );
+ table->setBackgroundColor( Qt::yellow );
+
+ QgsLayoutTableStyle original;
+ original.enabled = true;
+ original.cellBackgroundColor = QColor( 200, 100, 150, 90 );
+
+ //write to xml
+ QDomImplementation DomImplementation;
+ QDomDocumentType documentType =
+ DomImplementation.createDocumentType(
+ QStringLiteral( "qgis" ), QStringLiteral( "http://mrcc.com/qgis.dtd" ), QStringLiteral( "SYSTEM" ) );
+ QDomDocument doc( documentType );
+
+ //test writing with no node
+ QDomElement node = doc.createElement( QStringLiteral( "style" ) );
+ QVERIFY( original.writeXml( node, doc ) );
+
+ //read from xml
+ QgsLayoutTableStyle styleFromXml;
+ QVERIFY( styleFromXml.readXml( node ) );
+
+ //check
+ QCOMPARE( original.enabled, styleFromXml.enabled );
+ QCOMPARE( original.cellBackgroundColor, styleFromXml.cellBackgroundColor );
+
+
+ // check writing/reading whole set of styles
+ QgsLayoutItemAttributeTable *originalTable = new QgsLayoutItemAttributeTable( &l );
+
+ QgsLayoutTableStyle style1;
+ style1.enabled = true;
+ style1.cellBackgroundColor = QColor( 25, 50, 75, 100 );
+ originalTable->setCellStyle( QgsLayoutTable::FirstRow, style1 );
+ QgsLayoutTableStyle style2;
+ style1.enabled = false;
+ style1.cellBackgroundColor = QColor( 60, 62, 64, 68 );
+ originalTable->setCellStyle( QgsLayoutTable::LastColumn, style2 );
+
+ //write to XML
+ QDomElement tableElement = doc.createElement( QStringLiteral( "table" ) );
+ QVERIFY( originalTable->writeXml( tableElement, doc, QgsReadWriteContext(), true ) );
+
+ //read from XML
+ QgsLayoutItemAttributeTable *tableFromXml = new QgsLayoutItemAttributeTable( &l );
+ QVERIFY( tableFromXml->readXml( tableElement.firstChildElement(), doc, QgsReadWriteContext(), true ) );
+
+ //check that styles were correctly read
+ QCOMPARE( tableFromXml->cellStyle( QgsLayoutTable::FirstRow )->enabled, originalTable->cellStyle( QgsLayoutTable::FirstRow )->enabled );
+ QCOMPARE( tableFromXml->cellStyle( QgsLayoutTable::FirstRow )->cellBackgroundColor, originalTable->cellStyle( QgsLayoutTable::FirstRow )->cellBackgroundColor );
+ QCOMPARE( tableFromXml->cellStyle( QgsLayoutTable::LastColumn )->enabled, originalTable->cellStyle( QgsLayoutTable::LastColumn )->enabled );
+ QCOMPARE( tableFromXml->cellStyle( QgsLayoutTable::LastColumn )->cellBackgroundColor, originalTable->cellStyle( QgsLayoutTable::LastColumn )->cellBackgroundColor );
+
+ //check backgroundColor method
+ //build up rules in descending order of precedence
+ table->setBackgroundColor( QColor( 50, 50, 50, 50 ) );
+ QgsLayoutTableStyle style;
+ style.enabled = true;
+ style.cellBackgroundColor = QColor( 25, 50, 75, 100 );
+ table->setCellStyle( QgsLayoutTable::OddColumns, style );
+ QCOMPARE( table->backgroundColor( 0, 0 ), QColor( 25, 50, 75, 100 ) );
+ QCOMPARE( table->backgroundColor( 0, 1 ), QColor( 50, 50, 50, 50 ) );
+ QCOMPARE( table->backgroundColor( 0, 2 ), QColor( 25, 50, 75, 100 ) );
+ QCOMPARE( table->backgroundColor( 0, 3 ), QColor( 50, 50, 50, 50 ) );
+ QCOMPARE( table->backgroundColor( 1, 0 ), QColor( 25, 50, 75, 100 ) );
+ QCOMPARE( table->backgroundColor( 1, 1 ), QColor( 50, 50, 50, 50 ) );
+ QCOMPARE( table->backgroundColor( 1, 2 ), QColor( 25, 50, 75, 100 ) );
+ QCOMPARE( table->backgroundColor( 1, 3 ), QColor( 50, 50, 50, 50 ) );
+ style.cellBackgroundColor = QColor( 30, 80, 90, 23 );
+ table->setCellStyle( QgsLayoutTable::EvenColumns, style );
+ QCOMPARE( table->backgroundColor( 0, 0 ), QColor( 25, 50, 75, 100 ) );
+ QCOMPARE( table->backgroundColor( 0, 1 ), QColor( 30, 80, 90, 23 ) );
+ QCOMPARE( table->backgroundColor( 0, 2 ), QColor( 25, 50, 75, 100 ) );
+ QCOMPARE( table->backgroundColor( 0, 3 ), QColor( 30, 80, 90, 23 ) );
+ QCOMPARE( table->backgroundColor( 1, 0 ), QColor( 25, 50, 75, 100 ) );
+ QCOMPARE( table->backgroundColor( 1, 1 ), QColor( 30, 80, 90, 23 ) );
+ QCOMPARE( table->backgroundColor( 1, 2 ), QColor( 25, 50, 75, 100 ) );
+ QCOMPARE( table->backgroundColor( 1, 3 ), QColor( 30, 80, 90, 23 ) );
+ style.cellBackgroundColor = QColor( 111, 112, 113, 114 );
+ table->setCellStyle( QgsLayoutTable::OddRows, style );
+ QCOMPARE( table->backgroundColor( 0, 0 ), QColor( 111, 112, 113, 114 ) );
+ QCOMPARE( table->backgroundColor( 0, 1 ), QColor( 111, 112, 113, 114 ) );
+ QCOMPARE( table->backgroundColor( 0, 2 ), QColor( 111, 112, 113, 114 ) );
+ QCOMPARE( table->backgroundColor( 0, 3 ), QColor( 111, 112, 113, 114 ) );
+ QCOMPARE( table->backgroundColor( 1, 0 ), QColor( 25, 50, 75, 100 ) );
+ QCOMPARE( table->backgroundColor( 1, 1 ), QColor( 30, 80, 90, 23 ) );
+ QCOMPARE( table->backgroundColor( 1, 2 ), QColor( 25, 50, 75, 100 ) );
+ QCOMPARE( table->backgroundColor( 1, 3 ), QColor( 30, 80, 90, 23 ) );
+ QCOMPARE( table->backgroundColor( 2, 0 ), QColor( 111, 112, 113, 114 ) );
+ QCOMPARE( table->backgroundColor( 2, 1 ), QColor( 111, 112, 113, 114 ) );
+ QCOMPARE( table->backgroundColor( 2, 2 ), QColor( 111, 112, 113, 114 ) );
+ QCOMPARE( table->backgroundColor( 2, 3 ), QColor( 111, 112, 113, 114 ) );
+ style.cellBackgroundColor = QColor( 222, 223, 224, 225 );
+ table->setCellStyle( QgsLayoutTable::EvenRows, style );
+ QCOMPARE( table->backgroundColor( 0, 0 ), QColor( 111, 112, 113, 114 ) );
+ QCOMPARE( table->backgroundColor( 0, 1 ), QColor( 111, 112, 113, 114 ) );
+ QCOMPARE( table->backgroundColor( 0, 2 ), QColor( 111, 112, 113, 114 ) );
+ QCOMPARE( table->backgroundColor( 0, 3 ), QColor( 111, 112, 113, 114 ) );
+ QCOMPARE( table->backgroundColor( 1, 0 ), QColor( 222, 223, 224, 225 ) );
+ QCOMPARE( table->backgroundColor( 1, 1 ), QColor( 222, 223, 224, 225 ) );
+ QCOMPARE( table->backgroundColor( 1, 2 ), QColor( 222, 223, 224, 225 ) );
+ QCOMPARE( table->backgroundColor( 1, 3 ), QColor( 222, 223, 224, 225 ) );
+ QCOMPARE( table->backgroundColor( 2, 0 ), QColor( 111, 112, 113, 114 ) );
+ QCOMPARE( table->backgroundColor( 2, 1 ), QColor( 111, 112, 113, 114 ) );
+ QCOMPARE( table->backgroundColor( 2, 2 ), QColor( 111, 112, 113, 114 ) );
+ QCOMPARE( table->backgroundColor( 2, 3 ), QColor( 111, 112, 113, 114 ) );
+ QCOMPARE( table->backgroundColor( 3, 0 ), QColor( 222, 223, 224, 225 ) );
+ QCOMPARE( table->backgroundColor( 3, 1 ), QColor( 222, 223, 224, 225 ) );
+ QCOMPARE( table->backgroundColor( 3, 2 ), QColor( 222, 223, 224, 225 ) );
+ QCOMPARE( table->backgroundColor( 3, 3 ), QColor( 222, 223, 224, 225 ) );
+ style.cellBackgroundColor = QColor( 1, 2, 3, 4 );
+ table->setCellStyle( QgsLayoutTable::FirstColumn, style );
+ QCOMPARE( table->backgroundColor( 0, 0 ), QColor( 1, 2, 3, 4 ) );
+ QCOMPARE( table->backgroundColor( 0, 1 ), QColor( 111, 112, 113, 114 ) );
+ QCOMPARE( table->backgroundColor( 0, 2 ), QColor( 111, 112, 113, 114 ) );
+ QCOMPARE( table->backgroundColor( 0, 3 ), QColor( 111, 112, 113, 114 ) );
+ QCOMPARE( table->backgroundColor( 1, 0 ), QColor( 1, 2, 3, 4 ) );
+ QCOMPARE( table->backgroundColor( 1, 1 ), QColor( 222, 223, 224, 225 ) );
+ QCOMPARE( table->backgroundColor( 1, 2 ), QColor( 222, 223, 224, 225 ) );
+ QCOMPARE( table->backgroundColor( 1, 3 ), QColor( 222, 223, 224, 225 ) );
+ QCOMPARE( table->backgroundColor( 2, 0 ), QColor( 1, 2, 3, 4 ) );
+ style.cellBackgroundColor = QColor( 7, 8, 9, 10 );
+ table->setCellStyle( QgsLayoutTable::LastColumn, style );
+ QCOMPARE( table->backgroundColor( 0, 0 ), QColor( 1, 2, 3, 4 ) );
+ QCOMPARE( table->backgroundColor( 0, 1 ), QColor( 111, 112, 113, 114 ) );
+ QCOMPARE( table->backgroundColor( 0, 2 ), QColor( 111, 112, 113, 114 ) );
+ QCOMPARE( table->backgroundColor( 0, 5 ), QColor( 7, 8, 9, 10 ) );
+ QCOMPARE( table->backgroundColor( 1, 0 ), QColor( 1, 2, 3, 4 ) );
+ QCOMPARE( table->backgroundColor( 1, 1 ), QColor( 222, 223, 224, 225 ) );
+ QCOMPARE( table->backgroundColor( 1, 2 ), QColor( 222, 223, 224, 225 ) );
+ QCOMPARE( table->backgroundColor( 1, 5 ), QColor( 7, 8, 9, 10 ) );
+ QCOMPARE( table->backgroundColor( 2, 0 ), QColor( 1, 2, 3, 4 ) );
+ QCOMPARE( table->backgroundColor( 2, 5 ), QColor( 7, 8, 9, 10 ) );
+ style.cellBackgroundColor = QColor( 87, 88, 89, 90 );
+ table->setCellStyle( QgsLayoutTable::HeaderRow, style );
+ QCOMPARE( table->backgroundColor( -1, 0 ), QColor( 87, 88, 89, 90 ) );
+ QCOMPARE( table->backgroundColor( -1, 1 ), QColor( 87, 88, 89, 90 ) );
+ QCOMPARE( table->backgroundColor( -1, 2 ), QColor( 87, 88, 89, 90 ) );
+ QCOMPARE( table->backgroundColor( -1, 5 ), QColor( 87, 88, 89, 90 ) );
+ QCOMPARE( table->backgroundColor( 0, 0 ), QColor( 1, 2, 3, 4 ) );
+ QCOMPARE( table->backgroundColor( 0, 1 ), QColor( 111, 112, 113, 114 ) );
+ QCOMPARE( table->backgroundColor( 0, 2 ), QColor( 111, 112, 113, 114 ) );
+ QCOMPARE( table->backgroundColor( 0, 5 ), QColor( 7, 8, 9, 10 ) );
+ QCOMPARE( table->backgroundColor( 1, 0 ), QColor( 1, 2, 3, 4 ) );
+ QCOMPARE( table->backgroundColor( 1, 1 ), QColor( 222, 223, 224, 225 ) );
+ QCOMPARE( table->backgroundColor( 1, 2 ), QColor( 222, 223, 224, 225 ) );
+ QCOMPARE( table->backgroundColor( 1, 5 ), QColor( 7, 8, 9, 10 ) );
+ QCOMPARE( table->backgroundColor( 2, 0 ), QColor( 1, 2, 3, 4 ) );
+ QCOMPARE( table->backgroundColor( 2, 5 ), QColor( 7, 8, 9, 10 ) );
+ style.cellBackgroundColor = QColor( 187, 188, 189, 190 );
+ table->setCellStyle( QgsLayoutTable::FirstRow, style );
+ QCOMPARE( table->backgroundColor( -1, 0 ), QColor( 87, 88, 89, 90 ) );
+ QCOMPARE( table->backgroundColor( -1, 1 ), QColor( 87, 88, 89, 90 ) );
+ QCOMPARE( table->backgroundColor( -1, 2 ), QColor( 87, 88, 89, 90 ) );
+ QCOMPARE( table->backgroundColor( -1, 5 ), QColor( 87, 88, 89, 90 ) );
+ QCOMPARE( table->backgroundColor( 0, 0 ), QColor( 187, 188, 189, 190 ) );
+ QCOMPARE( table->backgroundColor( 0, 1 ), QColor( 187, 188, 189, 190 ) );
+ QCOMPARE( table->backgroundColor( 0, 2 ), QColor( 187, 188, 189, 190 ) );
+ QCOMPARE( table->backgroundColor( 0, 5 ), QColor( 187, 188, 189, 190 ) );
+ QCOMPARE( table->backgroundColor( 1, 0 ), QColor( 1, 2, 3, 4 ) );
+ QCOMPARE( table->backgroundColor( 1, 1 ), QColor( 222, 223, 224, 225 ) );
+ QCOMPARE( table->backgroundColor( 1, 2 ), QColor( 222, 223, 224, 225 ) );
+ QCOMPARE( table->backgroundColor( 1, 5 ), QColor( 7, 8, 9, 10 ) );
+ QCOMPARE( table->backgroundColor( 2, 0 ), QColor( 1, 2, 3, 4 ) );
+ QCOMPARE( table->backgroundColor( 2, 5 ), QColor( 7, 8, 9, 10 ) );
+ style.cellBackgroundColor = QColor( 147, 148, 149, 150 );
+ table->setCellStyle( QgsLayoutTable::LastRow, style );
+ QCOMPARE( table->backgroundColor( -1, 0 ), QColor( 87, 88, 89, 90 ) );
+ QCOMPARE( table->backgroundColor( -1, 1 ), QColor( 87, 88, 89, 90 ) );
+ QCOMPARE( table->backgroundColor( -1, 2 ), QColor( 87, 88, 89, 90 ) );
+ QCOMPARE( table->backgroundColor( -1, 5 ), QColor( 87, 88, 89, 90 ) );
+ QCOMPARE( table->backgroundColor( 0, 0 ), QColor( 187, 188, 189, 190 ) );
+ QCOMPARE( table->backgroundColor( 0, 1 ), QColor( 187, 188, 189, 190 ) );
+ QCOMPARE( table->backgroundColor( 0, 2 ), QColor( 187, 188, 189, 190 ) );
+ QCOMPARE( table->backgroundColor( 0, 5 ), QColor( 187, 188, 189, 190 ) );
+ QCOMPARE( table->backgroundColor( 1, 0 ), QColor( 1, 2, 3, 4 ) );
+ QCOMPARE( table->backgroundColor( 1, 1 ), QColor( 222, 223, 224, 225 ) );
+ QCOMPARE( table->backgroundColor( 1, 2 ), QColor( 222, 223, 224, 225 ) );
+ QCOMPARE( table->backgroundColor( 1, 5 ), QColor( 7, 8, 9, 10 ) );
+ QCOMPARE( table->backgroundColor( 2, 0 ), QColor( 1, 2, 3, 4 ) );
+ QCOMPARE( table->backgroundColor( 2, 5 ), QColor( 7, 8, 9, 10 ) );
+ QCOMPARE( table->backgroundColor( 9, 0 ), QColor( 147, 148, 149, 150 ) );
+ QCOMPARE( table->backgroundColor( 9, 1 ), QColor( 147, 148, 149, 150 ) );
+ QCOMPARE( table->backgroundColor( 9, 2 ), QColor( 147, 148, 149, 150 ) );
+ QCOMPARE( table->backgroundColor( 9, 5 ), QColor( 147, 148, 149, 150 ) );
+}
+
+void TestQgsLayoutTable::cellStylesRender()
+{
+ QgsLayout l( QgsProject::instance() );
+ l.initializeDefaults();
+ QgsLayoutItemAttributeTable *table = new QgsLayoutItemAttributeTable( &l );
+ QgsLayoutFrame *frame1 = new QgsLayoutFrame( &l, table );
+ frame1->attemptSetSceneRect( QRectF( 5, 5, 100, 30 ) );
+ QgsLayoutFrame *frame2 = new QgsLayoutFrame( &l, table );
+ frame2->attemptSetSceneRect( QRectF( 5, 40, 100, 30 ) );
+ frame1->setFrameEnabled( true );
+ frame2->setFrameEnabled( true );
+ table->addFrame( frame1 );
+ table->addFrame( frame2 );
+ table->setVectorLayer( mVectorLayer );
+ table->setDisplayOnlyVisibleFeatures( false );
+ table->setMaximumNumberOfFeatures( 10 );
+ table->setContentFont( QgsFontUtils::getStandardTestFont() );
+ table->setHeaderFont( QgsFontUtils::getStandardTestFont() );
+ table->setBackgroundColor( Qt::yellow );
+
+ table->setMaximumNumberOfFeatures( 3 );
+ table->setShowEmptyRows( true );
+
+ QgsLayoutTableStyle style;
+ style.enabled = true;
+ style.cellBackgroundColor = QColor( 25, 50, 75, 100 );
+ table->setCellStyle( QgsLayoutTable::OddColumns, style );
+ style.cellBackgroundColor = QColor( 90, 110, 150, 200 );
+ table->setCellStyle( QgsLayoutTable::EvenRows, style );
+ style.cellBackgroundColor = QColor( 150, 160, 210, 200 );
+ table->setCellStyle( QgsLayoutTable::HeaderRow, style );
+ style.cellBackgroundColor = QColor( 0, 200, 50, 200 );
+ table->setCellStyle( QgsLayoutTable::FirstColumn, style );
+ style.cellBackgroundColor = QColor( 200, 50, 0, 200 );
+ table->setCellStyle( QgsLayoutTable::LastColumn, style );
+ style.cellBackgroundColor = QColor( 200, 50, 200, 200 );
+ table->setCellStyle( QgsLayoutTable::FirstRow, style );
+ style.cellBackgroundColor = QColor( 50, 200, 200, 200 );
+ table->setCellStyle( QgsLayoutTable::LastRow, style );
+
+ QgsLayoutChecker checker( QStringLiteral( "composerattributetable_cellstyle" ), &l );
+ checker.setColorTolerance( 10 );
+ checker.setControlPathPrefix( QStringLiteral( "composer_table" ) );
+ QVERIFY( checker.testLayout( mReport, 0 ) );
+}
+
+QGSTEST_MAIN( TestQgsLayoutTable )
+#include "testqgslayouttable.moc"
diff --git a/tests/testdata/control_images/composer_table/expected_composerattributetable_align/expected_composerattributetable_align_mask.png b/tests/testdata/control_images/composer_table/expected_composerattributetable_align/expected_composerattributetable_align_mask.png
index c466948df33..1f9670f456b 100755
Binary files a/tests/testdata/control_images/composer_table/expected_composerattributetable_align/expected_composerattributetable_align_mask.png and b/tests/testdata/control_images/composer_table/expected_composerattributetable_align/expected_composerattributetable_align_mask.png differ
diff --git a/tests/testdata/control_images/composer_table/expected_composerattributetable_autowrap/expected_composerattributetable_autowrap_mask.png b/tests/testdata/control_images/composer_table/expected_composerattributetable_autowrap/expected_composerattributetable_autowrap_mask.png
index 34659ec7c9b..6adb3a7fcf4 100644
Binary files a/tests/testdata/control_images/composer_table/expected_composerattributetable_autowrap/expected_composerattributetable_autowrap_mask.png and b/tests/testdata/control_images/composer_table/expected_composerattributetable_autowrap/expected_composerattributetable_autowrap_mask.png differ
diff --git a/tests/testdata/control_images/composer_table/expected_composerattributetable_cellstyle/expected_composerattributetable_cellstyle_mask.png b/tests/testdata/control_images/composer_table/expected_composerattributetable_cellstyle/expected_composerattributetable_cellstyle_mask.png
index 117abd6f079..5569e9987a1 100644
Binary files a/tests/testdata/control_images/composer_table/expected_composerattributetable_cellstyle/expected_composerattributetable_cellstyle_mask.png and b/tests/testdata/control_images/composer_table/expected_composerattributetable_cellstyle/expected_composerattributetable_cellstyle_mask.png differ
diff --git a/tests/testdata/control_images/composer_table/expected_composerattributetable_columnwidth/expected_composerattributetable_columnwidth_mask.png b/tests/testdata/control_images/composer_table/expected_composerattributetable_columnwidth/expected_composerattributetable_columnwidth_mask.png
index f81fc4b2e27..e320ff2fc7d 100644
Binary files a/tests/testdata/control_images/composer_table/expected_composerattributetable_columnwidth/expected_composerattributetable_columnwidth_mask.png and b/tests/testdata/control_images/composer_table/expected_composerattributetable_columnwidth/expected_composerattributetable_columnwidth_mask.png differ
diff --git a/tests/testdata/control_images/composer_table/expected_composerattributetable_drawempty/expected_composerattributetable_drawempty_mask.png b/tests/testdata/control_images/composer_table/expected_composerattributetable_drawempty/expected_composerattributetable_drawempty_mask.png
index bb9da9ae7f0..b9ed7227294 100644
Binary files a/tests/testdata/control_images/composer_table/expected_composerattributetable_drawempty/expected_composerattributetable_drawempty_mask.png and b/tests/testdata/control_images/composer_table/expected_composerattributetable_drawempty/expected_composerattributetable_drawempty_mask.png differ
diff --git a/tests/testdata/control_images/composer_table/expected_composerattributetable_headersonly/expected_composerattributetable_headersonly_mask.png b/tests/testdata/control_images/composer_table/expected_composerattributetable_headersonly/expected_composerattributetable_headersonly_mask.png
index 0b93efaa20c..3500ed3ff18 100644
Binary files a/tests/testdata/control_images/composer_table/expected_composerattributetable_headersonly/expected_composerattributetable_headersonly_mask.png and b/tests/testdata/control_images/composer_table/expected_composerattributetable_headersonly/expected_composerattributetable_headersonly_mask.png differ
diff --git a/tests/testdata/control_images/composer_table/expected_composerattributetable_hidetable/expected_composerattributetable_hidetable_mask.png b/tests/testdata/control_images/composer_table/expected_composerattributetable_hidetable/expected_composerattributetable_hidetable_mask.png
index 557505618ae..4a5f82fbc5c 100644
Binary files a/tests/testdata/control_images/composer_table/expected_composerattributetable_hidetable/expected_composerattributetable_hidetable_mask.png and b/tests/testdata/control_images/composer_table/expected_composerattributetable_hidetable/expected_composerattributetable_hidetable_mask.png differ
diff --git a/tests/testdata/control_images/composer_table/expected_composerattributetable_horizontalgrid/expected_composerattributetable_horizontalgrid_mask.png b/tests/testdata/control_images/composer_table/expected_composerattributetable_horizontalgrid/expected_composerattributetable_horizontalgrid_mask.png
index 466cdb25892..ecb302706ba 100644
Binary files a/tests/testdata/control_images/composer_table/expected_composerattributetable_horizontalgrid/expected_composerattributetable_horizontalgrid_mask.png and b/tests/testdata/control_images/composer_table/expected_composerattributetable_horizontalgrid/expected_composerattributetable_horizontalgrid_mask.png differ
diff --git a/tests/testdata/control_images/composer_table/expected_composerattributetable_multiline/expected_composerattributetable_multiline_mask.png b/tests/testdata/control_images/composer_table/expected_composerattributetable_multiline/expected_composerattributetable_multiline_mask.png
index b9fe73b0492..e2170547644 100644
Binary files a/tests/testdata/control_images/composer_table/expected_composerattributetable_multiline/expected_composerattributetable_multiline_mask.png and b/tests/testdata/control_images/composer_table/expected_composerattributetable_multiline/expected_composerattributetable_multiline_mask.png differ
diff --git a/tests/testdata/control_images/composer_table/expected_composerattributetable_render/expected_composerattributetable_render_mask.png b/tests/testdata/control_images/composer_table/expected_composerattributetable_render/expected_composerattributetable_render_mask.png
index 73b242e4d94..ad5fce3f79d 100644
Binary files a/tests/testdata/control_images/composer_table/expected_composerattributetable_render/expected_composerattributetable_render_mask.png and b/tests/testdata/control_images/composer_table/expected_composerattributetable_render/expected_composerattributetable_render_mask.png differ
diff --git a/tests/testdata/control_images/composer_table/expected_composerattributetable_showmessage/expected_composerattributetable_showmessage_mask.png b/tests/testdata/control_images/composer_table/expected_composerattributetable_showmessage/expected_composerattributetable_showmessage_mask.png
index 109b5bdc8f6..cb0ef5141c7 100644
Binary files a/tests/testdata/control_images/composer_table/expected_composerattributetable_showmessage/expected_composerattributetable_showmessage_mask.png and b/tests/testdata/control_images/composer_table/expected_composerattributetable_showmessage/expected_composerattributetable_showmessage_mask.png differ
diff --git a/tests/testdata/control_images/composer_table/expected_composerattributetable_verticalgrid/expected_composerattributetable_verticalgrid_mask.png b/tests/testdata/control_images/composer_table/expected_composerattributetable_verticalgrid/expected_composerattributetable_verticalgrid_mask.png
index 5cc5479901b..d8c26a598dd 100644
Binary files a/tests/testdata/control_images/composer_table/expected_composerattributetable_verticalgrid/expected_composerattributetable_verticalgrid_mask.png and b/tests/testdata/control_images/composer_table/expected_composerattributetable_verticalgrid/expected_composerattributetable_verticalgrid_mask.png differ