Skip to content
Permalink
Browse files

[layout] Import attribute table from composition

  • Loading branch information
elpaso committed Jan 9, 2018
1 parent 2b2dae8 commit f297e8620173187b783db7ecc47d048cd311af3e
@@ -63,7 +63,7 @@ Returns the source for attributes shown in the table body.
.. seealso:: :py:func:`setSource()`
%End

QgsVectorLayer *sourceLayer();
QgsVectorLayer *sourceLayer() const;
%Docstring
Returns the source layer for the table, considering the table source mode. For example,
if the table is set to atlas feature mode, then the source layer will be the
@@ -45,6 +45,9 @@
#include "qgslayoutitemscalebar.h"
#include "qgslayoutitemlegend.h"
#include "qgslayoutitemhtml.h"
#include "qgslayouttable.h"
#include "qgslayoutitemattributetable.h"
#include "qgslayouttablecolumn.h"
#include "qgslayoutmultiframe.h"
#include "qgslayoutframe.h"

@@ -299,11 +302,6 @@ QList<QgsLayoutObject *> QgsCompositionConverter::addItemsFromCompositionXml( Qg
}
}

/* TODO: following item types are not yet converted
// known multi-frame types
LayoutAttributeTable, //!< Attribute table
*/

QgsStringMap mapIdUiidMap;

// Map (this needs to come first to build the uuid <-> ID map for map composer items
@@ -316,7 +314,6 @@ QList<QgsLayoutObject *> QgsCompositionConverter::addItemsFromCompositionXml( Qg
newItems << layoutItem ;
}


// Label
for ( int i = 0; i < parentElement.elementsByTagName( QStringLiteral( "ComposerLabel" ) ).size(); i++ )
{
@@ -412,6 +409,21 @@ QList<QgsLayoutObject *> QgsCompositionConverter::addItemsFromCompositionXml( Qg
newItems << layoutItem ;
}

// Attribute Table
for ( int i = 0; i < parentElement.elementsByTagName( QStringLiteral( "ComposerAttributeTableV2" ) ).size(); i++ )
{
QDomNode itemNode( parentElement.elementsByTagName( QStringLiteral( "ComposerAttributeTableV2" ) ).at( i ) );
QgsLayoutItemAttributeTable *layoutItem = new QgsLayoutItemAttributeTable( layout );
readTableXml( layoutItem, itemNode.toElement(), layout->project() );
// Adjust position for frames
const QList<QgsLayoutFrame *> framesList( layoutItem->frames() );
for ( const auto &frame : framesList )
{
adjustPos( layout, frame, position, pasteInPlace, zOrderOffset, pasteShiftPos, pageNumber );
}
newItems << layoutItem ;
}

return newItems;
}

@@ -1311,6 +1323,126 @@ bool QgsCompositionConverter::readHtmlXml( QgsLayoutItemHtml *layoutItem, const
return true;
}

bool QgsCompositionConverter::readTableXml( QgsLayoutItemAttributeTable *layoutItem, const QDomElement &itemElem, const QgsProject *project )
{

Q_UNUSED( project );
readOldComposerObjectXml( layoutItem, itemElem );

//first create the frames
layoutItem->setResizeMode( static_cast< QgsLayoutMultiFrame::ResizeMode >( itemElem.attribute( QStringLiteral( "resizeMode" ), QStringLiteral( "0" ) ).toInt() ) );
QDomNodeList frameList = itemElem.elementsByTagName( QStringLiteral( "ComposerFrame" ) );
for ( int i = 0; i < frameList.size(); ++i )
{
QDomElement frameElem = frameList.at( i ).toElement();
QgsLayoutFrame *newFrame = new QgsLayoutFrame( layoutItem->layout(), layoutItem );
restoreGeneralComposeItemProperties( newFrame, frameElem );
// Read frame XML
double x = itemElem.attribute( QStringLiteral( "sectionX" ) ).toDouble();
double y = itemElem.attribute( QStringLiteral( "sectionY" ) ).toDouble();
double width = itemElem.attribute( QStringLiteral( "sectionWidth" ) ).toDouble();
double height = itemElem.attribute( QStringLiteral( "sectionHeight" ) ).toDouble();
newFrame->setContentSection( QRectF( x, y, width, height ) );
newFrame->setHidePageIfEmpty( itemElem.attribute( QStringLiteral( "hidePageIfEmpty" ), QStringLiteral( "0" ) ).toInt() );
newFrame->setHideBackgroundIfEmpty( itemElem.attribute( QStringLiteral( "hideBackgroundIfEmpty" ), QStringLiteral( "0" ) ).toInt() );
layoutItem->addFrame( newFrame, false );
}

layoutItem->setEmptyTableBehavior( static_cast<QgsLayoutTable::EmptyTableMode>( itemElem.attribute( QStringLiteral( "emptyTableMode" ), QStringLiteral( "0" ) ).toInt() ) );
layoutItem->setEmptyTableMessage( itemElem.attribute( QStringLiteral( "emptyTableMessage" ), QObject::tr( "No matching records" ) ) );
layoutItem->setShowEmptyRows( itemElem.attribute( QStringLiteral( "showEmptyRows" ), QStringLiteral( "0" ) ).toInt() );
if ( !QgsFontUtils::setFromXmlChildNode( layoutItem->mHeaderFont, itemElem, QStringLiteral( "headerFontProperties" ) ) )
{
layoutItem->mHeaderFont.fromString( itemElem.attribute( QStringLiteral( "headerFont" ), QLatin1String( "" ) ) );
}
layoutItem->setHeaderFontColor( QgsSymbolLayerUtils::decodeColor( itemElem.attribute( QStringLiteral( "headerFontColor" ), QStringLiteral( "0,0,0,255" ) ) ) );
layoutItem->setHeaderHAlignment( static_cast<QgsLayoutTable::HeaderHAlignment>( itemElem.attribute( QStringLiteral( "headerHAlignment" ), QStringLiteral( "0" ) ).toInt() ) ) ;
layoutItem->setHeaderMode( static_cast<QgsLayoutTable::HeaderMode>( itemElem.attribute( QStringLiteral( "headerMode" ), QStringLiteral( "0" ) ).toInt() ) );
if ( !QgsFontUtils::setFromXmlChildNode( layoutItem->mContentFont, itemElem, QStringLiteral( "contentFontProperties" ) ) )
{
layoutItem->mContentFont.fromString( itemElem.attribute( QStringLiteral( "contentFont" ), QLatin1String( "" ) ) );
}
layoutItem->setContentFontColor( QgsSymbolLayerUtils::decodeColor( itemElem.attribute( QStringLiteral( "contentFontColor" ), QStringLiteral( "0,0,0,255" ) ) ) );
layoutItem->setCellMargin( itemElem.attribute( QStringLiteral( "cellMargin" ), QStringLiteral( "1.0" ) ).toDouble() );
layoutItem->setGridStrokeWidth( itemElem.attribute( QStringLiteral( "gridStrokeWidth" ), QStringLiteral( "0.5" ) ).toDouble() );
layoutItem->setHorizontalGrid( itemElem.attribute( QStringLiteral( "horizontalGrid" ), QStringLiteral( "1" ) ).toInt() );
layoutItem->setVerticalGrid( itemElem.attribute( QStringLiteral( "verticalGrid" ), QStringLiteral( "1" ) ).toInt() );
layoutItem->setShowGrid( itemElem.attribute( QStringLiteral( "showGrid" ), QStringLiteral( "1" ) ).toInt() );
layoutItem->setGridColor( QgsSymbolLayerUtils::decodeColor( itemElem.attribute( QStringLiteral( "gridColor" ), QStringLiteral( "0,0,0,255" ) ) ) );
layoutItem->setBackgroundColor( QgsSymbolLayerUtils::decodeColor( itemElem.attribute( QStringLiteral( "backgroundColor" ), QStringLiteral( "255,255,255,0" ) ) ) );
layoutItem->setWrapBehavior( static_cast<QgsLayoutTable::WrapBehavior>( itemElem.attribute( QStringLiteral( "wrapBehavior" ), QStringLiteral( "0" ) ).toInt() ) );

//restore column specifications
layoutItem->mColumns.clear();
QDomNodeList columnsList = itemElem.elementsByTagName( QStringLiteral( "displayColumns" ) );
if ( !columnsList.isEmpty() )
{
QDomElement columnsElem = columnsList.at( 0 ).toElement();
QDomNodeList columnEntryList = columnsElem.elementsByTagName( QStringLiteral( "column" ) );
for ( int i = 0; i < columnEntryList.size(); ++i )
{
QDomElement columnElem = columnEntryList.at( i ).toElement();
QgsLayoutTableColumn *column = new QgsLayoutTableColumn;
column->mHAlignment = static_cast< Qt::AlignmentFlag >( columnElem.attribute( QStringLiteral( "hAlignment" ), QString::number( Qt::AlignLeft ) ).toInt() );
column->mVAlignment = static_cast< Qt::AlignmentFlag >( columnElem.attribute( QStringLiteral( "vAlignment" ), QString::number( Qt::AlignVCenter ) ).toInt() );
column->mHeading = columnElem.attribute( QStringLiteral( "heading" ), QLatin1String( "" ) );
column->mAttribute = columnElem.attribute( QStringLiteral( "attribute" ), QLatin1String( "" ) );
column->mSortByRank = columnElem.attribute( QStringLiteral( "sortByRank" ), QStringLiteral( "0" ) ).toInt();
column->mSortOrder = static_cast< Qt::SortOrder >( columnElem.attribute( QStringLiteral( "sortOrder" ), QString::number( Qt::AscendingOrder ) ).toInt() );
column->mWidth = columnElem.attribute( QStringLiteral( "width" ), QStringLiteral( "0.0" ) ).toDouble();

QDomNodeList bgColorList = columnElem.elementsByTagName( QStringLiteral( "backgroundColor" ) );
if ( !bgColorList.isEmpty() )
{
QDomElement bgColorElem = bgColorList.at( 0 ).toElement();
bool redOk, greenOk, blueOk, alphaOk;
int bgRed, bgGreen, bgBlue, bgAlpha;
bgRed = bgColorElem.attribute( QStringLiteral( "red" ) ).toDouble( &redOk );
bgGreen = bgColorElem.attribute( QStringLiteral( "green" ) ).toDouble( &greenOk );
bgBlue = bgColorElem.attribute( QStringLiteral( "blue" ) ).toDouble( &blueOk );
bgAlpha = bgColorElem.attribute( QStringLiteral( "alpha" ) ).toDouble( &alphaOk );
if ( redOk && greenOk && blueOk && alphaOk )
{
column->mBackgroundColor = QColor( bgRed, bgGreen, bgBlue, bgAlpha );
}
}
layoutItem->mColumns.append( column );
}
}

//restore cell styles
QDomNodeList stylesList = itemElem.elementsByTagName( QStringLiteral( "cellStyles" ) );
if ( !stylesList.isEmpty() )
{
QDomElement stylesElem = stylesList.at( 0 ).toElement();

QMap< QgsLayoutTable::CellStyleGroup, QString >::const_iterator it = layoutItem->mCellStyleNames.constBegin();
for ( ; it != layoutItem->mCellStyleNames.constEnd(); ++it )
{
QString styleName = it.value();
QDomNodeList styleList = stylesElem.elementsByTagName( styleName );
if ( !styleList.isEmpty() )
{
QDomElement styleElem = styleList.at( 0 ).toElement();
QgsLayoutTableStyle *style = layoutItem->mCellStyles.value( it.key() );
if ( style )
style->readXml( styleElem );
}
}
}

// look for stored layer name
QString layerId = itemElem.attribute( QStringLiteral( "vectorLayer" ) );
QString layerName = itemElem.attribute( QStringLiteral( "vectorLayerName" ) );
QString layerSource = itemElem.attribute( QStringLiteral( "vectorLayerSource" ) );
QString layerProvider = itemElem.attribute( QStringLiteral( "vectorLayerProvider" ) );

QgsVectorLayerRef layerRef( layerId, layerName, layerSource, layerProvider );
layoutItem->setVectorLayer( layerRef.resolveWeakly( project ) );

return true;
}


template <class T, class T2>
bool QgsCompositionConverter::readPolyXml( T *layoutItem, const QDomElement &itemElem, const QgsProject *project )
@@ -43,6 +43,7 @@ class QgsLayoutItemMap;
class QgsLayoutItemScaleBar;
class QgsLayoutItemLegend;
class QgsLayoutItemHtml;
class QgsLayoutItemAttributeTable;


/**
@@ -195,6 +196,10 @@ class CORE_EXPORT QgsCompositionConverter
const QDomElement &itemElem,
const QgsProject *project );

static bool readTableXml( QgsLayoutItemAttributeTable *layoutItem,
const QDomElement &itemElem,
const QgsProject *project );

static bool readOldComposerObjectXml( QgsLayoutObject *layoutItem, const QDomElement &itemElem );

static void readOldDataDefinedPropertyMap( const QDomElement &itemElem,
@@ -549,7 +549,7 @@ QVariant QgsLayoutItemAttributeTable::replaceWrapChar( const QVariant &variant )
return replaced;
}

QgsVectorLayer *QgsLayoutItemAttributeTable::sourceLayer()
QgsVectorLayer *QgsLayoutItemAttributeTable::sourceLayer() const
{
switch ( mSource )
{
@@ -82,7 +82,7 @@ class CORE_EXPORT QgsLayoutItemAttributeTable: public QgsLayoutTable
* atlas coverage layer. If the table is set to layer attributes mode, then
* the source layer will be the user specified vector layer.
*/
QgsVectorLayer *sourceLayer();
QgsVectorLayer *sourceLayer() const;

/**
* Sets the vector \a layer from which to display feature attributes.
@@ -678,6 +678,7 @@ class CORE_EXPORT QgsLayoutTable: public QgsLayoutMultiFrame
QColor backgroundColor( int row, int column ) const;

friend class TestQgsLayoutTable;
friend class QgsCompositionConverter;
};

#endif // QGSLAYOUTTABLE_H
@@ -199,6 +199,8 @@ class CORE_EXPORT QgsLayoutTableColumn : public QObject
Qt::SortOrder mSortOrder = Qt::AscendingOrder;
double mWidth = 0.0;

friend class QgsCompositionConverter;

};

#endif //QGSLAYOUTTABLECOLUMN_H
@@ -41,6 +41,7 @@
#include "qgslayoutitemlegend.h"
#include "qgslayoutatlas.h"
#include "qgslayoutitemhtml.h"
#include "qgslayoutitemattributetable.h"


class TestQgsCompositionConverter: public QObject
@@ -61,6 +62,11 @@ class TestQgsCompositionConverter: public QObject
*/
void importComposerTemplateLegend();

/**
* Test import attribute table from a composer template
*/
void importComposerTemplateAttributeTable();

/**
* Test import HTML from a composer template
*/
@@ -440,6 +446,30 @@ void TestQgsCompositionConverter::importComposerTemplateLegend()

}

void TestQgsCompositionConverter::importComposerTemplateAttributeTable()
{
QDomElement composerElem( loadComposer( "2x_template_attributetable.qpt" ) );
QgsProject project;
project.read( QStringLiteral( TEST_DATA_DIR ) + "/layouts/sample_project.qgs" );
QDomElement docElem = composerElem.elementsByTagName( QStringLiteral( "Composition" ) ).at( 0 ).toElement();
std::unique_ptr< QgsPrintLayout > layout( QgsCompositionConverter::createLayoutFromCompositionXml( docElem, &project ) );

QVERIFY( layout.get() );
QCOMPARE( layout->pageCollection()->pageCount(), 1 );

QList<QgsLayoutMultiFrame *> items = layout->multiFrames();
QVERIFY( items.size() > 0 );

// Check the HTML
const QgsLayoutItemAttributeTable *table = qobject_cast<QgsLayoutItemAttributeTable * >( items.at( 0 ) );
QVERIFY( table );
QVERIFY( table->sourceLayer() );
QVERIFY( table->sourceLayer()->isValid() );

checkRenderedImage( layout.get(), QTest::currentTestFunction(), 0 );

}

void TestQgsCompositionConverter::importComposerTemplateHtml()
{
QDomElement composerElem( loadComposer( "2x_template_html.qpt" ) );
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,70 @@
<Composer title="composer title" visible="1">
<Composition resizeToContentsMarginLeft="0" snapping="0" showPages="1" guidesVisible="1" resizeToContentsMarginTop="0" worldFileMap="" alignmentSnap="1" printResolution="305" paperWidth="297" gridVisible="0" snapGridOffsetX="0" smartGuides="1" snapGridOffsetY="0" resizeToContentsMarginRight="0" snapTolerancePixels="5" printAsRaster="0" generateWorldFile="0" paperHeight="210" numPages="1" snapGridResolution="10" resizeToContentsMarginBottom="0">
<symbol alpha="1" clip_to_extent="1" type="fill" name="">
<layer pass="0" class="SimpleFill" locked="0">
<prop k="border_width_map_unit_scale" v="0,0,0,0,0,0"/>
<prop k="color" v="241,244,199,255"/>
<prop k="joinstyle" v="bevel"/>
<prop k="offset" v="0,0"/>
<prop k="offset_map_unit_scale" v="0,0,0,0,0,0"/>
<prop k="offset_unit" v="MM"/>
<prop k="outline_color" v="175,179,138,255"/>
<prop k="outline_style" v="solid"/>
<prop k="outline_width" v="0.26"/>
<prop k="outline_width_unit" v="MM"/>
<prop k="style" v="solid"/>
</layer>
</symbol>
<ComposerAttributeTableV2 vectorLayerName="points" source="0" showGrid="1" maxFeatures="30" resizeMode="0" filterFeatures="false" featureFilter="" emptyTableMode="1" wrapString="" wrapBehaviour="0" headerMode="1" backgroundColor="240,33,33,255" showEmptyRows="0" emptyTableMessage="" showOnlyVisibleFeatures="1" vectorLayer="points20171212162310546" vectorLayerSource="../points.shp" composerMap="0" headerHAlignment="2" contentFontColor="115,115,115,255" headerFontColor="194,143,12,255" cellMargin="1.2" filterToAtlasIntersection="0" relationId="" gridStrokeWidth="0.7" gridColor="245,57,220,255" showUniqueRowsOnly="1" vectorLayerProvider="ogr">
<headerFontProperties description="MS Shell Dlg 2,8.25,-1,5,50,0,0,0,0,0" style=""/>
<contentFontProperties description="MS Shell Dlg 2,8.25,-1,5,50,0,0,0,0,0" style=""/>
<displayColumns>
<column width="0" vAlignment="128" attribute="Class" sortByRank="0" hAlignment="1" heading="Class" sortOrder="0">
<backgroundColor alpha="0" red="0" blue="0" green="0"/>
</column>
<column width="0" vAlignment="128" attribute="Heading" sortByRank="0" hAlignment="1" heading="Heading" sortOrder="0">
<backgroundColor alpha="0" red="0" blue="0" green="0"/>
</column>
<column width="0" vAlignment="128" attribute="Importance" sortByRank="0" hAlignment="1" heading="Importance" sortOrder="0">
<backgroundColor alpha="0" red="0" blue="0" green="0"/>
</column>
<column width="0" vAlignment="128" attribute="Pilots" sortByRank="0" hAlignment="1" heading="Pilots" sortOrder="0">
<backgroundColor alpha="0" red="0" blue="0" green="0"/>
</column>
<column width="0" vAlignment="128" attribute="Cabin Crew" sortByRank="0" hAlignment="1" heading="Cabin Crew" sortOrder="0">
<backgroundColor alpha="0" red="0" blue="0" green="0"/>
</column>
<column width="0" vAlignment="128" attribute="Staff" sortByRank="0" hAlignment="1" heading="Staff" sortOrder="0">
<backgroundColor alpha="0" red="0" blue="0" green="0"/>
</column>
</displayColumns>
<cellStyles>
<oddColumns enabled="0" cellBackgroundColor="255,255,255,255"/>
<evenColumns enabled="1" cellBackgroundColor="255,255,255,255"/>
<oddRows enabled="0" cellBackgroundColor="255,255,255,255"/>
<evenRows enabled="0" cellBackgroundColor="255,255,255,255"/>
<firstColumn enabled="0" cellBackgroundColor="255,255,255,255"/>
<lastColumn enabled="0" cellBackgroundColor="255,255,255,255"/>
<headerRow enabled="0" cellBackgroundColor="255,255,255,255"/>
<firstRow enabled="0" cellBackgroundColor="255,255,255,255"/>
<lastRow enabled="0" cellBackgroundColor="255,255,255,255"/>
</cellStyles>
<ComposerFrame sectionWidth="89.7078" sectionHeight="74.6091" hideBackgroundIfEmpty="0" hidePageIfEmpty="0" sectionX="0" sectionY="0">
<ComposerItem pagey="16.737" page="1" id="" lastValidViewScaleFactor="-1" positionMode="0" positionLock="false" x="21.5722" y="16.737" visibility="1" zValue="14" background="false" transparency="0" frameJoinStyle="miter" blendMode="0" width="89.7078" outlineWidth="0.3" excludeFromExports="0" uuid="{cd165488-e216-4dcb-a56e-06cddbe0c7e7}" height="74.6091" itemRotation="0" frame="false" pagex="21.5722">
<FrameColor alpha="255" red="0" blue="0" green="0"/>
<BackgroundColor alpha="255" red="255" blue="255" green="255"/>
<customproperties/>
</ComposerItem>
</ComposerFrame>
<ComposerFrame sectionWidth="89.7078" sectionHeight="46.3787" hideBackgroundIfEmpty="0" hidePageIfEmpty="0" sectionX="0" sectionY="74.6091">
<ComposerItem pagey="66.4954" page="1" id="" lastValidViewScaleFactor="-1" positionMode="0" positionLock="false" x="111.28" y="66.4954" visibility="1" zValue="15" background="false" transparency="0" frameJoinStyle="miter" blendMode="0" width="89.7078" outlineWidth="0.3" excludeFromExports="0" uuid="{72ab9ed3-6c68-49cb-9593-209a38f72d75}" height="46.3787" itemRotation="0" frame="false" pagex="111.28">
<FrameColor alpha="255" red="0" blue="0" green="0"/>
<BackgroundColor alpha="255" red="255" blue="255" green="255"/>
<customproperties/>
</ComposerItem>
</ComposerFrame>
<customproperties/>
</ComposerAttributeTableV2>
<customproperties/>
</Composition>
</Composer>

0 comments on commit f297e86

Please sign in to comment.
You can’t perform that action at this time.