From f037b11f8e99633b0b5ec953e688d9232a5429f1 Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Mon, 22 Jun 2015 07:31:13 +1000 Subject: [PATCH] [georef] Allow report to flow onto multiple pages to show all GCPs (fix #4602) --- .../core/composer/qgscomposertablecolumn.sip | 6 +- python/core/composer/qgscomposertexttable.sip | 38 ++++++++ src/core/CMakeLists.txt | 1 + src/core/composer/qgscomposertablecolumn.cpp | 4 +- src/core/composer/qgscomposertablecolumn.h | 6 +- src/core/composer/qgscomposertablev2.cpp | 6 +- src/core/composer/qgscomposertexttable.cpp | 70 +++++++++++++++ src/core/composer/qgscomposertexttable.h | 37 ++++++++ .../georeferencer/qgsgeorefplugingui.cpp | 90 +++++++++++-------- 9 files changed, 216 insertions(+), 42 deletions(-) diff --git a/python/core/composer/qgscomposertablecolumn.sip b/python/core/composer/qgscomposertablecolumn.sip index 9446d6a06b3..62d779b5118 100644 --- a/python/core/composer/qgscomposertablecolumn.sip +++ b/python/core/composer/qgscomposertablecolumn.sip @@ -8,7 +8,11 @@ class QgsComposerTableColumn: QObject %End public: - QgsComposerTableColumn(); + /** Constructor for QgsComposerTableColumn. + * @param heading column heading + */ + QgsComposerTableColumn( const QString& heading = QString() ); + virtual ~QgsComposerTableColumn(); /**Writes the column's properties to xml for storage. diff --git a/python/core/composer/qgscomposertexttable.sip b/python/core/composer/qgscomposertexttable.sip index 896ab3e14af..e827fcf9378 100644 --- a/python/core/composer/qgscomposertexttable.sip +++ b/python/core/composer/qgscomposertexttable.sip @@ -46,3 +46,41 @@ class QgsComposerTextTable: QgsComposerTable */ // bool getFeatureAttributes( QList& attributeMaps ); }; + + + +/**A text table item that reads text from string lists + * @note added in QGIS 2.10 +*/ +class QgsComposerTextTableV2 : QgsComposerTableV2 +{ + +%TypeHeaderCode +#include +%End + + public: + QgsComposerTextTableV2( QgsComposition* c /TransferThis/, bool createUndoCommands ); + ~QgsComposerTextTableV2(); + + /** Adds a row to the table + * @param row list of strings to use for each cell's value in the newly added row + * @note If row is shorter than the number of columns in the table than blank cells + * will be inserted at the end of the row. If row co ntains more strings then the number + * of columns in the table then these extra strings will be ignored. + * @note if adding many rows, @link setContents @endlink is much faster + */ + void addRow( const QStringList& row ); + + /** Sets the contents of the text table. + * @param contents list of table rows + * @see addRow + */ + void setContents( const QList< QStringList >& contents ); + + bool getTableContents( QgsComposerTableContents &contents ); + + virtual void addFrame( QgsComposerFrame* frame, bool recalcFrameSizes = true ); + +}; + diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index f5d293ea0d0..b7c882025e9 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -433,6 +433,7 @@ SET(QGIS_CORE_MOC_HDRS composer/qgscomposertable.h composer/qgscomposertablev2.h composer/qgscomposertablecolumn.h + composer/qgscomposertexttable.h composer/qgscomposerhtml.h composer/qgscomposermultiframe.h composer/qgscomposereffect.h diff --git a/src/core/composer/qgscomposertablecolumn.cpp b/src/core/composer/qgscomposertablecolumn.cpp index b16b5044d6d..0601b9557a1 100644 --- a/src/core/composer/qgscomposertablecolumn.cpp +++ b/src/core/composer/qgscomposertablecolumn.cpp @@ -17,9 +17,10 @@ #include "qgscomposertablecolumn.h" -QgsComposerTableColumn::QgsComposerTableColumn() : +QgsComposerTableColumn::QgsComposerTableColumn( const QString& heading ) : mBackgroundColor( Qt::transparent ), mHAlignment( Qt::AlignLeft ), + mHeading( heading ), mSortByRank( 0 ), mSortOrder( Qt::AscendingOrder ), mWidth( 0.0 ) @@ -27,6 +28,7 @@ QgsComposerTableColumn::QgsComposerTableColumn() : } + QgsComposerTableColumn::~QgsComposerTableColumn() { diff --git a/src/core/composer/qgscomposertablecolumn.h b/src/core/composer/qgscomposertablecolumn.h index 76ab6b437c7..82e2a05bf1a 100644 --- a/src/core/composer/qgscomposertablecolumn.h +++ b/src/core/composer/qgscomposertablecolumn.h @@ -30,7 +30,11 @@ class CORE_EXPORT QgsComposerTableColumn: public QObject public: - QgsComposerTableColumn(); + /** Constructor for QgsComposerTableColumn. + * @param heading column heading + */ + QgsComposerTableColumn( const QString& heading = QString() ); + virtual ~QgsComposerTableColumn(); /**Writes the column's properties to xml for storage. diff --git a/src/core/composer/qgscomposertablev2.cpp b/src/core/composer/qgscomposertablev2.cpp index 172a6eea81a..e5b26a3957a 100644 --- a/src/core/composer/qgscomposertablev2.cpp +++ b/src/core/composer/qgscomposertablev2.cpp @@ -265,9 +265,6 @@ void QgsComposerTableV2::render( QPainter *p, const QRectF &renderExtent, const return; } - //calculate which rows to show in this frame - QPair< int, int > rowsToShow = rowRange( renderExtent, frameIndex ); - if ( mComposition->plotStyle() == QgsComposition::Print || mComposition->plotStyle() == QgsComposition::Postscript ) { @@ -276,6 +273,9 @@ void QgsComposerTableV2::render( QPainter *p, const QRectF &renderExtent, const refreshAttributes(); } + //calculate which rows to show in this frame + QPair< int, int > rowsToShow = rowRange( renderExtent, frameIndex ); + double gridSize = mShowGrid ? mGridStrokeWidth : 0; QList::const_iterator columnIt = mColumns.constBegin(); diff --git a/src/core/composer/qgscomposertexttable.cpp b/src/core/composer/qgscomposertexttable.cpp index 5bedc1931bb..5ae1f2c2912 100644 --- a/src/core/composer/qgscomposertexttable.cpp +++ b/src/core/composer/qgscomposertexttable.cpp @@ -17,6 +17,7 @@ #include "qgscomposertexttable.h" #include "qgscomposertablecolumn.h" +#include "qgscomposerframe.h" QgsComposerTextTable::QgsComposerTextTable( QgsComposition* c ): QgsComposerTable( c ) { @@ -84,3 +85,72 @@ bool QgsComposerTextTable::getFeatureAttributes( QList& attribu return true; } + + +QgsComposerTextTableV2::QgsComposerTextTableV2( QgsComposition* c, bool createUndoCommands ) + : QgsComposerTableV2( c, createUndoCommands ) +{ + +} + +QgsComposerTextTableV2::~QgsComposerTextTableV2() +{ + +} + +void QgsComposerTextTableV2::addRow( const QStringList& row ) +{ + mRowText.append( row ); + refreshAttributes(); +} + +void QgsComposerTextTableV2::setContents( const QList& contents ) +{ + mRowText = contents; + refreshAttributes(); +} + +bool QgsComposerTextTableV2::getTableContents( QgsComposerTableContents& contents ) +{ + contents.clear(); + + QList< QStringList >::const_iterator rowIt = mRowText.constBegin(); + for ( ; rowIt != mRowText.constEnd(); ++rowIt ) + { + QgsComposerTableRow currentRow; + + for ( int i = 0; i < mColumns.count(); ++i ) + { + if ( i < ( *rowIt ).count() ) + { + currentRow << ( *rowIt ).at( i ); + } + else + { + currentRow << QString(); + } + } + contents << currentRow; + } + + recalculateTableSize(); + return true; +} + +void QgsComposerTextTableV2::addFrame( QgsComposerFrame* frame, bool recalcFrameSizes ) +{ + mFrameItems.push_back( frame ); + connect( frame, SIGNAL( sizeChanged() ), this, SLOT( recalculateFrameSizes() ) ); + + if ( mComposition ) + { + //TODO - if QgsComposerTextTableV2 gains a UI, this will need a dedicated add method + //added to QgsComposition + mComposition->addItem( frame ); + } + + if ( recalcFrameSizes ) + { + recalculateFrameSizes(); + } +} diff --git a/src/core/composer/qgscomposertexttable.h b/src/core/composer/qgscomposertexttable.h index 28df9ef95b0..1d3f0eea3d2 100644 --- a/src/core/composer/qgscomposertexttable.h +++ b/src/core/composer/qgscomposertexttable.h @@ -19,6 +19,7 @@ #define QGSCOMPOSERTEXTTABLE_H #include "qgscomposertable.h" +#include "qgscomposertablev2.h" /**A text table item that reads text from string lists*/ class CORE_EXPORT QgsComposerTextTable: public QgsComposerTable @@ -70,4 +71,40 @@ class CORE_EXPORT QgsComposerTextTable: public QgsComposerTable QList< QStringList > mRowText; }; +/**A text table item that reads text from string lists + * @note added in QGIS 2.10 +*/ +class CORE_EXPORT QgsComposerTextTableV2 : public QgsComposerTableV2 +{ + + Q_OBJECT + + public: + QgsComposerTextTableV2( QgsComposition* c, bool createUndoCommands ); + ~QgsComposerTextTableV2(); + + /** Adds a row to the table + * @param row list of strings to use for each cell's value in the newly added row + * @note If row is shorter than the number of columns in the table than blank cells + * will be inserted at the end of the row. If row contains more strings then the number + * of columns in the table then these extra strings will be ignored. + * @note if adding many rows, @link setContents @endlink is much faster + */ + void addRow( const QStringList& row ); + + /** Sets the contents of the text table. + * @param contents list of table rows + * @see addRow + */ + void setContents( const QList< QStringList >& contents ); + + bool getTableContents( QgsComposerTableContents &contents ) override; + + virtual void addFrame( QgsComposerFrame* frame, bool recalcFrameSizes = true ) override; + + private: + /**One stringlist per row*/ + QList< QStringList > mRowText; +}; + #endif // QGSCOMPOSERTEXTTABLE_H diff --git a/src/plugins/georeferencer/qgsgeorefplugingui.cpp b/src/plugins/georeferencer/qgsgeorefplugingui.cpp index 991f4d6e3f4..7e18e88cec4 100644 --- a/src/plugins/georeferencer/qgsgeorefplugingui.cpp +++ b/src/plugins/georeferencer/qgsgeorefplugingui.cpp @@ -38,6 +38,8 @@ #include "qgscomposerlabel.h" #include "qgscomposermap.h" #include "qgscomposertexttable.h" +#include "qgscomposertablecolumn.h" +#include "qgscomposerframe.h" #include "qgsmapcanvas.h" #include "qgsmapcoordsdialog.h" #include "qgsmaplayerregistry.h" @@ -1585,15 +1587,11 @@ bool QgsGeorefPluginGui::writePDFReportFile( const QString& fileName, const QgsG return false; } - QPrinter printer; - printer.setOutputFormat( QPrinter::PdfFormat ); - printer.setOutputFileName( fileName ); - //create composition A4 with 300 dpi QgsComposition* composition = new QgsComposition( mCanvas->mapSettings() ); composition->setPaperSize( 210, 297 ); //A4 composition->setPrintResolution( 300 ); - printer.setPaperSize( QSizeF( composition->paperWidth(), composition->paperHeight() ), QPrinter::Millimeter ); + composition->setNumPages( 2 ); QFont titleFont; titleFont.setPointSize( 9 ); @@ -1646,10 +1644,8 @@ bool QgsGeorefPluginGui::writePDFReportFile( const QString& fileName, const QgsG composerMap->zoomToExtent( layerExtent ); composerMap->setMapCanvas( mCanvas ); composition->addItem( composerMap ); - printer.setFullPage( true ); - printer.setColorMode( QPrinter::Color ); - QgsComposerTextTable* parameterTable = 0; + QgsComposerTextTableV2* parameterTable = 0; double scaleX, scaleY, rotation; QgsPoint origin; @@ -1667,6 +1663,7 @@ bool QgsGeorefPluginGui::writePDFReportFile( const QString& fileName, const QgsG residualUnits = tr( "pixels" ); } + QGraphicsRectItem* previousItem = composerMap; if ( wldTransform ) { QString parameterTitle = tr( "Transformation parameters" ) + QString( " (" ) + convertTransformEnumToString( transform.transformParametrisation() ) + QString( ")" ); @@ -1682,25 +1679,30 @@ bool QgsGeorefPluginGui::writePDFReportFile( const QString& fileName, const QgsG double meanError = 0; calculateMeanError( meanError ); - parameterTable = new QgsComposerTextTable( composition ); + parameterTable = new QgsComposerTextTableV2( composition, false ); parameterTable->setHeaderFont( tableHeaderFont ); parameterTable->setContentFont( tableContentFont ); - QStringList headers; - headers << tr( "Translation x" ) << tr( "Translation y" ) << tr( "Scale x" ) << tr( "Scale y" ) << tr( "Rotation [degrees]" ) << tr( "Mean error [%1]" ).arg( residualUnits ); - parameterTable->setHeaderLabels( headers ); + + QgsComposerTableColumns columns; + columns << new QgsComposerTableColumn( tr( "Translation x" ) ) + << new QgsComposerTableColumn( tr( "Translation y" ) ) + << new QgsComposerTableColumn( tr( "Scale x" ) ) + << new QgsComposerTableColumn( tr( "Scale y" ) ) + << new QgsComposerTableColumn( tr( "Rotation [degrees]" ) ) + << new QgsComposerTableColumn( tr( "Mean error [%1]" ).arg( residualUnits ) ); + + parameterTable->setColumns( columns ); QStringList row; row << QString::number( origin.x(), 'f', 3 ) << QString::number( origin.y(), 'f', 3 ) << QString::number( scaleX ) << QString::number( scaleY ) << QString::number( rotation * 180 / M_PI ) << QString::number( meanError ); parameterTable->addRow( row ); - composition->addItem( parameterTable ); - parameterTable->setSceneRect( QRectF( leftMargin, parameterLabel->rect().bottom() + parameterLabel->pos().y() + 5, contentWidth, 20 ) ); - parameterTable->setGridStrokeWidth( 0.1 ); - parameterTable->adjustFrameToSize(); - } - QGraphicsRectItem* previousItem = composerMap; - if ( parameterTable ) - { - previousItem = parameterTable; + QgsComposerFrame* tableFrame = new QgsComposerFrame( composition, parameterTable, leftMargin, parameterLabel->rect().bottom() + parameterLabel->pos().y() + 5, contentWidth, 12 ); + parameterTable->addFrame( tableFrame ); + + composition->addItem( tableFrame ); + parameterTable->setGridStrokeWidth( 0.1 ); + + previousItem = tableFrame; } QgsComposerLabel* residualLabel = new QgsComposerLabel( composition ); @@ -1720,14 +1722,25 @@ bool QgsGeorefPluginGui::writePDFReportFile( const QString& fileName, const QgsG //necessary for the correct scale bar unit label resPlotItem->setConvertScaleToMapUnits( residualUnits == tr( "map units" ) ); - QgsComposerTextTable* gcpTable = new QgsComposerTextTable( composition ); + QgsComposerTextTableV2* gcpTable = new QgsComposerTextTableV2( composition, false ); gcpTable->setHeaderFont( tableHeaderFont ); gcpTable->setContentFont( tableContentFont ); - QStringList gcpHeader; - gcpHeader << "id" << "enabled" << "pixelX" << "pixelY" << "mapX" << "mapY" << "resX [" + residualUnits + "]" << "resY [" + residualUnits + "]" << "resTot [" + residualUnits + "]"; - gcpTable->setHeaderLabels( gcpHeader ); + gcpTable->setHeaderMode( QgsComposerTableV2::AllFrames ); + QgsComposerTableColumns columns; + columns << new QgsComposerTableColumn( tr( "ID" ) ) + << new QgsComposerTableColumn( tr( "Enabled" ) ) + << new QgsComposerTableColumn( tr( "Pixel X" ) ) + << new QgsComposerTableColumn( tr( "Pixel Y" ) ) + << new QgsComposerTableColumn( tr( "Map X" ) ) + << new QgsComposerTableColumn( tr( "Map Y" ) ) + << new QgsComposerTableColumn( tr( "Res X (%1)" ).arg( residualUnits ) ) + << new QgsComposerTableColumn( tr( "Res Y (%1)" ).arg( residualUnits ) ) + << new QgsComposerTableColumn( tr( "Res Total (%1)" ).arg( residualUnits ) ); + + gcpTable->setColumns( columns ); QgsGCPList::const_iterator gcpIt = mPoints.constBegin(); + QList< QStringList > gcpTableContents; for ( ; gcpIt != mPoints.constEnd(); ++gcpIt ) { QStringList currentGCPStrings; @@ -1745,27 +1758,32 @@ bool QgsGeorefPluginGui::writePDFReportFile( const QString& fileName, const QgsG } currentGCPStrings << QString::number(( *gcpIt )->pixelCoords().x(), 'f', 0 ) << QString::number(( *gcpIt )->pixelCoords().y(), 'f', 0 ) << QString::number(( *gcpIt )->mapCoords().x(), 'f', 3 ) << QString::number(( *gcpIt )->mapCoords().y(), 'f', 3 ) << QString::number( residual.x() ) << QString::number( residual.y() ) << QString::number( residualTot ); - gcpTable->addRow( currentGCPStrings ); + gcpTableContents << currentGCPStrings ; } - composition->addItem( gcpTable ); + gcpTable->setContents( gcpTableContents ); + + double firstFrameY = resPlotItem->rect().bottom() + resPlotItem->pos().y() + 5; + double firstFrameHeight = 287 - firstFrameY; + QgsComposerFrame* gcpFirstFrame = new QgsComposerFrame( composition, gcpTable, leftMargin, firstFrameY, contentWidth, firstFrameHeight ); + gcpTable->addFrame( gcpFirstFrame ); + composition->addItem( gcpFirstFrame ); + + QgsComposerFrame* gcpSecondFrame = new QgsComposerFrame( composition, gcpTable, leftMargin, 10, contentWidth, 277.0 ); + gcpSecondFrame->setItemPosition( leftMargin, 10, QgsComposerItem::UpperLeft, 2 ); + gcpSecondFrame->setHidePageIfEmpty( true ); + gcpTable->addFrame( gcpSecondFrame ); + composition->addItem( gcpSecondFrame ); - gcpTable->setSceneRect( QRectF( leftMargin, resPlotItem->rect().bottom() + resPlotItem->pos().y() + 5, contentWidth, 100 ) ); gcpTable->setGridStrokeWidth( 0.1 ); + gcpTable->setResizeMode( QgsComposerMultiFrame::RepeatUntilFinished ); - printer.setResolution( composition->printResolution() ); - QPainter p( &printer ); - composition->setPlotStyle( QgsComposition::Print ); - QRectF paperRectMM = printer.pageRect( QPrinter::Millimeter ); - QRectF paperRectPixel = printer.pageRect( QPrinter::DevicePixel ); - composition->render( &p, paperRectPixel, paperRectMM ); + composition->exportAsPDF( fileName ); delete titleLabel; delete parameterLabel; delete residualLabel; delete resPlotItem; - delete parameterTable; - delete gcpTable; delete composerMap; delete composition; return true;