[composer] Begin work on calculating rows for QgsComposerTableV2

(sponsored by City of Uster, Switzerland)
This commit is contained in:
Nyall Dawson 2014-09-03 19:05:05 +10:00
parent d1e26f24e5
commit 37dbbd55a8
9 changed files with 171 additions and 50 deletions

View File

@ -95,7 +95,8 @@ class QgsComposerHtml: QgsComposerMultiFrame
void setEvaluateExpressions( bool evaluateExpressions ); void setEvaluateExpressions( bool evaluateExpressions );
QSizeF totalSize() const; QSizeF totalSize() const;
void render( QPainter* p, const QRectF& renderExtent );
void render( QPainter* p, const QRectF& renderExtent, const int frameIndex );
bool writeXML( QDomElement& elem, QDomDocument & doc, bool ignoreFrames = false ) const; bool writeXML( QDomElement& elem, QDomDocument & doc, bool ignoreFrames = false ) const;
bool readXML( const QDomElement& itemElem, const QDomDocument& doc, bool ignoreFrames = false ); bool readXML( const QDomElement& itemElem, const QDomDocument& doc, bool ignoreFrames = false );

View File

@ -28,7 +28,8 @@ class QgsComposerMultiFrame: QgsComposerObject
*/ */
virtual QSizeF fixedFrameSize() const; virtual QSizeF fixedFrameSize() const;
virtual void render( QPainter* p, const QRectF& renderExtent ) = 0; virtual void render( QPainter* p, const QRectF& renderExtent );
virtual void render( QPainter* p, const QRectF& renderExtent, const int frameIndex );
virtual void addFrame( QgsComposerFrame* frame, bool recalcFrameSizes = true ) = 0; virtual void addFrame( QgsComposerFrame* frame, bool recalcFrameSizes = true ) = 0;

View File

@ -106,7 +106,9 @@ void QgsComposerFrame::paint( QPainter* painter, const QStyleOptionGraphicsItem*
drawBackground( painter ); drawBackground( painter );
if ( mMultiFrame ) if ( mMultiFrame )
{ {
mMultiFrame->render( painter, mSection ); //calculate index of frame
int frameIndex = mMultiFrame->frameIndex( this );
mMultiFrame->render( painter, mSection, frameIndex );
} }
drawFrame( painter ); drawFrame( painter );

View File

@ -252,8 +252,10 @@ QSizeF QgsComposerHtml::totalSize() const
return mSize; return mSize;
} }
void QgsComposerHtml::render( QPainter* p, const QRectF& renderExtent ) void QgsComposerHtml::render( QPainter* p, const QRectF& renderExtent, const int frameIndex )
{ {
Q_UNUSED( frameIndex );
if ( !mWebPage ) if ( !mWebPage )
{ {
return; return;

View File

@ -118,7 +118,7 @@ class CORE_EXPORT QgsComposerHtml: public QgsComposerMultiFrame
void setEvaluateExpressions( bool evaluateExpressions ); void setEvaluateExpressions( bool evaluateExpressions );
QSizeF totalSize() const; QSizeF totalSize() const;
void render( QPainter* p, const QRectF& renderExtent ); void render( QPainter* p, const QRectF& renderExtent, const int frameIndex );
bool writeXML( QDomElement& elem, QDomDocument & doc, bool ignoreFrames = false ) const; bool writeXML( QDomElement& elem, QDomDocument & doc, bool ignoreFrames = false ) const;
bool readXML( const QDomElement& itemElem, const QDomDocument& doc, bool ignoreFrames = false ); bool readXML( const QDomElement& itemElem, const QDomDocument& doc, bool ignoreFrames = false );

View File

@ -40,6 +40,22 @@ QgsComposerMultiFrame::~QgsComposerMultiFrame()
deleteFrames(); deleteFrames();
} }
void QgsComposerMultiFrame::render( QPainter *p, const QRectF &renderExtent )
{
//base implementation does nothing
Q_UNUSED( p );
Q_UNUSED( renderExtent );
}
void QgsComposerMultiFrame::render( QPainter *p, const QRectF &renderExtent, const int frameIndex )
{
Q_UNUSED( frameIndex );
//base implementation ignores frameIndex
Q_NOWARN_DEPRECATED_PUSH
render( p, renderExtent );
Q_NOWARN_DEPRECATED_POP
}
void QgsComposerMultiFrame::setResizeMode( ResizeMode mode ) void QgsComposerMultiFrame::setResizeMode( ResizeMode mode )
{ {
if ( mode != mResizeMode ) if ( mode != mResizeMode )
@ -307,6 +323,11 @@ QgsComposerFrame* QgsComposerMultiFrame::frame( int i ) const
return mFrameItems.at( i ); return mFrameItems.at( i );
} }
int QgsComposerMultiFrame::frameIndex( QgsComposerFrame *frame ) const
{
return mFrameItems.indexOf( frame );
}
bool QgsComposerMultiFrame::_writeXML( QDomElement& elem, QDomDocument& doc, bool ignoreFrames ) const bool QgsComposerMultiFrame::_writeXML( QDomElement& elem, QDomDocument& doc, bool ignoreFrames ) const
{ {
elem.setAttribute( "resizeMode", mResizeMode ); elem.setAttribute( "resizeMode", mResizeMode );

View File

@ -55,7 +55,9 @@ class CORE_EXPORT QgsComposerMultiFrame: public QgsComposerObject
*/ */
virtual QSizeF fixedFrameSize() const { return QSizeF( 0, 0 ); } virtual QSizeF fixedFrameSize() const { return QSizeF( 0, 0 ); }
virtual void render( QPainter* p, const QRectF& renderExtent ) = 0; Q_DECL_DEPRECATED virtual void render( QPainter* p, const QRectF& renderExtent );
virtual void render( QPainter* p, const QRectF& renderExtent, const int frameIndex );
virtual void addFrame( QgsComposerFrame* frame, bool recalcFrameSizes = true ) = 0; virtual void addFrame( QgsComposerFrame* frame, bool recalcFrameSizes = true ) = 0;
@ -91,8 +93,16 @@ class CORE_EXPORT QgsComposerMultiFrame: public QgsComposerObject
@note added in 2.0, replaces nFrames @note added in 2.0, replaces nFrames
**/ **/
int frameCount() const { return mFrameItems.size(); } int frameCount() const { return mFrameItems.size(); }
QgsComposerFrame* frame( int i ) const; QgsComposerFrame* frame( int i ) const;
/**Returns the index of a frame within the multiframe
* @param frame frame to find index of
* @returns index for frame if found, -1 if frame not found in multiframe
* @note added in version 2.5
*/
int frameIndex( QgsComposerFrame *frame ) const;
/**Creates a new frame and adds it to the multi frame and composition. /**Creates a new frame and adds it to the multi frame and composition.
* @param currentFrame an existing QgsComposerFrame from which to copy the size * @param currentFrame an existing QgsComposerFrame from which to copy the size
* and general frame properties (eg frame style, background, rendering settings). * and general frame properties (eg frame style, background, rendering settings).

View File

@ -122,20 +122,55 @@ bool QgsComposerTableV2::readXML( const QDomElement &itemElem, const QDomDocumen
QSizeF QgsComposerTableV2::totalSize() const QSizeF QgsComposerTableV2::totalSize() const
{ {
//TODO - handle multiple cell headers //TODO - handle multiple cell headers
//also check height calculation function
return mTableSize; return mTableSize;
} }
void QgsComposerTableV2::render( QPainter *p, const QRectF &renderExtent )
{
//do this via rows
//eg, calculate how rows to->from
//and render them
QPair< int, int > QgsComposerTableV2::rowRange( const QRectF extent, const int frameIndex ) const
{
//calculate row height
//TODO - handle different header modes
//TODO - need to traverse all previous frames to calculate what is visible in each
//as the entire height of a frame may not be used for content
double headerHeight = 0;
double firstHeaderHeight = 2 * mGridStrokeWidth + 2 * mCellMargin + QgsComposerUtils::fontAscentMM( mHeaderFont );
//int frameNumber = mFrameItems.indexOf( this );
if ( frameIndex < 1 )
{
//currently only header on first
headerHeight = firstHeaderHeight;
}
else
{
headerHeight = mGridStrokeWidth;
}
//remaining height available for content rows
double contentHeight = extent.height() - headerHeight;
double rowHeight = mGridStrokeWidth + 2 * mCellMargin + QgsComposerUtils::fontAscentMM( mContentFont );
//using zero based indexes
int firstVisible = qMax( floor(( extent.top() - firstHeaderHeight ) / rowHeight ), 0.0 );
int rowsVisible = qMax( floor( contentHeight / rowHeight ), 0.0 );
int lastVisible = qMin( firstVisible + rowsVisible, mTableContents.length() );
return qMakePair( firstVisible, lastVisible );
}
void QgsComposerTableV2::render( QPainter *p, const QRectF &renderExtent, const int frameIndex )
{
if ( !p ) if ( !p )
{ {
return; return;
} }
//calculate which rows to show in this frame
QPair< int, int > rowsToShow = rowRange( renderExtent, frameIndex );
if ( mComposition->plotStyle() == QgsComposition::Print || if ( mComposition->plotStyle() == QgsComposition::Print ||
mComposition->plotStyle() == QgsComposition::Postscript ) mComposition->plotStyle() == QgsComposition::Postscript )
{ {
@ -160,43 +195,52 @@ void QgsComposerTableV2::render( QPainter *p, const QRectF &renderExtent )
double cellHeaderHeight = QgsComposerUtils::fontAscentMM( mHeaderFont ) + 2 * mCellMargin; double cellHeaderHeight = QgsComposerUtils::fontAscentMM( mHeaderFont ) + 2 * mCellMargin;
double cellBodyHeight = QgsComposerUtils::fontAscentMM( mContentFont ) + 2 * mCellMargin; double cellBodyHeight = QgsComposerUtils::fontAscentMM( mContentFont ) + 2 * mCellMargin;
QRectF cell; QRectF cell;
//TODO - should be controlled via a property, eg an enum with values
//always/never/first frame
bool drawHeader = frameIndex < 1;
for ( ; columnIt != mColumns.constEnd(); ++columnIt ) for ( ; columnIt != mColumns.constEnd(); ++columnIt )
{ {
currentY = mGridStrokeWidth; currentY = mGridStrokeWidth;
currentX += mCellMargin; currentX += mCellMargin;
cell = QRectF( currentX, currentY, mMaxColumnWidthMap[col], cellHeaderHeight ); if ( drawHeader )
//calculate alignment of header
Qt::AlignmentFlag headerAlign = Qt::AlignLeft;
switch ( mHeaderHAlignment )
{ {
case FollowColumn: //draw the header
headerAlign = ( *columnIt )->hAlignment(); cell = QRectF( currentX, currentY, mMaxColumnWidthMap[col], cellHeaderHeight );
break;
case HeaderLeft: //calculate alignment of header
headerAlign = Qt::AlignLeft; Qt::AlignmentFlag headerAlign = Qt::AlignLeft;
break; switch ( mHeaderHAlignment )
case HeaderCenter: {
headerAlign = Qt::AlignHCenter; case FollowColumn:
break; headerAlign = ( *columnIt )->hAlignment();
case HeaderRight: break;
headerAlign = Qt::AlignRight; case HeaderLeft:
break; headerAlign = Qt::AlignLeft;
break;
case HeaderCenter:
headerAlign = Qt::AlignHCenter;
break;
case HeaderRight:
headerAlign = Qt::AlignRight;
break;
}
QgsComposerUtils::drawText( p, cell, ( *columnIt )->heading(), mHeaderFont, mHeaderFontColor, headerAlign, Qt::AlignVCenter, Qt::TextDontClip );
currentY += cellHeaderHeight;
currentY += mGridStrokeWidth;
} }
QgsComposerUtils::drawText( p, cell, ( *columnIt )->heading(), mHeaderFont, mHeaderFontColor, headerAlign, Qt::AlignVCenter, Qt::TextDontClip );
currentY += cellHeaderHeight;
currentY += mGridStrokeWidth;
//draw the attribute values //draw the attribute values
QgsComposerTableContents::const_iterator attIt = mTableContents.begin(); for ( int row = rowsToShow.first; row < rowsToShow.second; ++row )
for ( ; attIt != mTableContents.end(); ++attIt )
{ {
cell = QRectF( currentX, currentY, mMaxColumnWidthMap[col], cellBodyHeight ); cell = QRectF( currentX, currentY, mMaxColumnWidthMap[col], cellBodyHeight );
QVariant cellContents = ( *attIt ).at( col ); QVariant cellContents = mTableContents.at( row ).at( col );
QString str = cellContents.toString(); QString str = cellContents.toString();
QgsComposerUtils::drawText( p, cell, str, mContentFont, mContentFontColor, ( *columnIt )->hAlignment(), Qt::AlignVCenter, Qt::TextDontClip ); QgsComposerUtils::drawText( p, cell, str, mContentFont, mContentFontColor, ( *columnIt )->hAlignment(), Qt::AlignVCenter, Qt::TextDontClip );
@ -210,6 +254,7 @@ void QgsComposerTableV2::render( QPainter *p, const QRectF &renderExtent )
col++; col++;
} }
//and the borders //and the borders
if ( mShowGrid ) if ( mShowGrid )
{ {
@ -218,13 +263,12 @@ void QgsComposerTableV2::render( QPainter *p, const QRectF &renderExtent )
gridPen.setColor( mGridColor ); gridPen.setColor( mGridColor );
gridPen.setJoinStyle( Qt::MiterJoin ); gridPen.setJoinStyle( Qt::MiterJoin );
p->setPen( gridPen ); p->setPen( gridPen );
drawHorizontalGridLines( p, mTableContents.size() ); drawHorizontalGridLines( p, rowsToShow.second - rowsToShow.first, drawHeader );
drawVerticalGridLines( p, mMaxColumnWidthMap ); drawVerticalGridLines( p, mMaxColumnWidthMap, rowsToShow.second - rowsToShow.first, drawHeader );
} }
p->restore(); p->restore();
} }
void QgsComposerTableV2::setCellMargin( const double margin ) void QgsComposerTableV2::setCellMargin( const double margin )
@ -438,14 +482,23 @@ double QgsComposerTableV2::totalHeight() const
return totalHeight; return totalHeight;
} }
void QgsComposerTableV2::drawHorizontalGridLines( QPainter *painter, const int rows ) const void QgsComposerTableV2::drawHorizontalGridLines( QPainter *painter, const int rows, const bool drawHeaderLines ) const
{ {
//horizontal lines //horizontal lines
if ( rows < 1 && !drawHeaderLines )
{
return;
}
double halfGridStrokeWidth = mGridStrokeWidth / 2.0; double halfGridStrokeWidth = mGridStrokeWidth / 2.0;
double currentY = halfGridStrokeWidth; double currentY = 0;
painter->drawLine( QPointF( halfGridStrokeWidth, currentY ), QPointF( mTableSize.width() - halfGridStrokeWidth, currentY ) ); currentY = halfGridStrokeWidth;
currentY += mGridStrokeWidth; if ( drawHeaderLines )
currentY += ( QgsComposerUtils::fontAscentMM( mHeaderFont ) + 2 * mCellMargin ); {
painter->drawLine( QPointF( halfGridStrokeWidth, currentY ), QPointF( mTableSize.width() - halfGridStrokeWidth, currentY ) );
currentY += mGridStrokeWidth;
currentY += ( QgsComposerUtils::fontAscentMM( mHeaderFont ) + 2 * mCellMargin );
}
for ( int row = 0; row < rows; ++row ) for ( int row = 0; row < rows; ++row )
{ {
painter->drawLine( QPointF( halfGridStrokeWidth, currentY ), QPointF( mTableSize.width() - halfGridStrokeWidth, currentY ) ); painter->drawLine( QPointF( halfGridStrokeWidth, currentY ), QPointF( mTableSize.width() - halfGridStrokeWidth, currentY ) );
@ -455,18 +508,33 @@ void QgsComposerTableV2::drawHorizontalGridLines( QPainter *painter, const int r
painter->drawLine( QPointF( halfGridStrokeWidth, currentY ), QPointF( mTableSize.width() - halfGridStrokeWidth, currentY ) ); painter->drawLine( QPointF( halfGridStrokeWidth, currentY ), QPointF( mTableSize.width() - halfGridStrokeWidth, currentY ) );
} }
void QgsComposerTableV2::drawVerticalGridLines( QPainter *painter, const QMap<int, double> &maxWidthMap ) const void QgsComposerTableV2::drawVerticalGridLines( QPainter *painter, const QMap<int, double> &maxWidthMap, const int numberRows, const bool hasHeader ) const
{ {
//vertical lines //vertical lines
if ( numberRows < 1 && !hasHeader )
{
return;
}
//calculate height of table within frame
double tableHeight = 0;
if ( hasHeader )
{
tableHeight += mGridStrokeWidth + mCellMargin * 2 + QgsComposerUtils::fontAscentMM( mHeaderFont );
}
tableHeight += numberRows * ( mGridStrokeWidth + mCellMargin * 2 + QgsComposerUtils::fontAscentMM( mContentFont ) );
tableHeight += mGridStrokeWidth;
double halfGridStrokeWidth = mGridStrokeWidth / 2.0; double halfGridStrokeWidth = mGridStrokeWidth / 2.0;
double currentX = halfGridStrokeWidth; double currentX = halfGridStrokeWidth;
painter->drawLine( QPointF( currentX, halfGridStrokeWidth ), QPointF( currentX, mTableSize.height() - halfGridStrokeWidth ) ); painter->drawLine( QPointF( currentX, halfGridStrokeWidth ), QPointF( currentX, tableHeight - halfGridStrokeWidth ) );
currentX += mGridStrokeWidth; currentX += mGridStrokeWidth;
QMap<int, double>::const_iterator maxColWidthIt = maxWidthMap.constBegin(); QMap<int, double>::const_iterator maxColWidthIt = maxWidthMap.constBegin();
for ( ; maxColWidthIt != maxWidthMap.constEnd(); ++maxColWidthIt ) for ( ; maxColWidthIt != maxWidthMap.constEnd(); ++maxColWidthIt )
{ {
currentX += ( maxColWidthIt.value() + 2 * mCellMargin ); currentX += ( maxColWidthIt.value() + 2 * mCellMargin );
painter->drawLine( QPointF( currentX, halfGridStrokeWidth ), QPointF( currentX, mTableSize.height() - halfGridStrokeWidth ) ); painter->drawLine( QPointF( currentX, halfGridStrokeWidth ), QPointF( currentX, tableHeight - halfGridStrokeWidth ) );
currentX += mGridStrokeWidth; currentX += mGridStrokeWidth;
} }
} }

View File

@ -21,6 +21,7 @@
#include "qgscomposermultiframe.h" #include "qgscomposermultiframe.h"
#include <QFont> #include <QFont>
#include <QColor> #include <QColor>
#include <QPair>
class QgsComposerTableColumn; class QgsComposerTableColumn;
@ -49,6 +50,7 @@ class CORE_EXPORT QgsComposerTableV2: public QgsComposerMultiFrame
{ {
Q_OBJECT Q_OBJECT
public: public:
/*! Controls how headers are horizontally aligned in a table /*! Controls how headers are horizontally aligned in a table
@ -71,7 +73,9 @@ class CORE_EXPORT QgsComposerTableV2: public QgsComposerMultiFrame
virtual bool readXML( const QDomElement& itemElem, const QDomDocument& doc, bool ignoreFrames = false ); virtual bool readXML( const QDomElement& itemElem, const QDomDocument& doc, bool ignoreFrames = false );
virtual QSizeF totalSize() const; virtual QSizeF totalSize() const;
virtual void render( QPainter* p, const QRectF& renderExtent );
virtual void render( QPainter* p, const QRectF& renderExtent, const int frameIndex );
/**Sets the margin distance between cell borders and their contents. /**Sets the margin distance between cell borders and their contents.
* @param margin margin for cell contents * @param margin margin for cell contents
@ -291,22 +295,34 @@ class CORE_EXPORT QgsComposerTableV2: public QgsComposerMultiFrame
double totalHeight() const; double totalHeight() const;
/**Calculates a range of rows which should be visible in a given
* rectangle.
* @param extent visible extent
* @param frameIndex index number for frame
* @returns row range
*/
QPair<int, int> rowRange( const QRectF extent, const int frameIndex ) const;
/**Draws the horizontal grid lines for the table. /**Draws the horizontal grid lines for the table.
* @param painter destination painter for grid lines * @param painter destination painter for grid lines
* @param rows number of rows shown in table * @param rows number of rows shown in table
* @param drawHeaderLines set to true to include for the table header
* @see drawVerticalGridLines * @see drawVerticalGridLines
*/ */
void drawHorizontalGridLines( QPainter* painter, const int rows ) const; void drawHorizontalGridLines( QPainter* painter, const int rows, const bool drawHeaderLines ) const;
/**Draws the vertical grid lines for the table. /**Draws the vertical grid lines for the table.
* @param painter destination painter for grid lines * @param painter destination painter for grid lines
* @param maxWidthMap QMap of int to double, where the int contains the column number and the double is the * @param maxWidthMap QMap of int to double, where the int contains the column number and the double is the
* maximum width of text present in the column. * maximum width of text present in the column.
* @param numberRows number of rows of content in table frame
* @param hasHeader set to true if table frame includes header cells
* @note not available in python bindings * @note not available in python bindings
* @see drawVerticalGridLines * @see drawVerticalGridLines
* @see calculateMaxColumnWidths * @see calculateMaxColumnWidths
*/ */
void drawVerticalGridLines( QPainter* painter, const QMap<int, double>& maxWidthMap ) const; void drawVerticalGridLines( QPainter* painter, const QMap<int, double>& maxWidthMap, const int numberRows, const bool hasHeader ) const;
void adjustFrameToSize(); void adjustFrameToSize();
}; };