mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-15 00:04:00 -04:00
[FEATURE][composer] Add choice of display style for empty tables. Options
include hiding the entire table, showing empty cells, or displaying a set message in the table body. Sponsored by City of Uster, Switzerland.
This commit is contained in:
parent
c3ec4b9eb0
commit
14690d0716
@ -73,6 +73,14 @@ class QgsComposerAttributeTableV2 : QgsComposerTableV2
|
|||||||
*/
|
*/
|
||||||
ContentSource source() const;
|
ContentSource source() const;
|
||||||
|
|
||||||
|
/**Returns the source layer for the table, considering the table source mode. Eg,
|
||||||
|
* if the table is set to atlas feature mode, then the source layer will be the
|
||||||
|
* atlas coverage layer. If the table is set to layer attributes mode, then
|
||||||
|
* the source layer will be the user specified vector layer.
|
||||||
|
* @returns actual source layer
|
||||||
|
*/
|
||||||
|
QgsVectorLayer* sourceLayer();
|
||||||
|
|
||||||
/**Sets the vector layer from which to display feature attributes
|
/**Sets the vector layer from which to display feature attributes
|
||||||
* @param layer Vector layer for attribute table
|
* @param layer Vector layer for attribute table
|
||||||
* @see vectorLayer
|
* @see vectorLayer
|
||||||
|
@ -46,6 +46,16 @@ class QgsComposerTableV2: QgsComposerMultiFrame
|
|||||||
NoHeaders /*!< no headers shown for table */
|
NoHeaders /*!< no headers shown for table */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*! Controls how empty tables are displayed
|
||||||
|
*/
|
||||||
|
enum EmptyTableMode
|
||||||
|
{
|
||||||
|
HeadersOnly, /*!< show header rows only */
|
||||||
|
HideTable, /*!< hides entire table if empty */
|
||||||
|
DrawEmptyCells, /*!< draws empty cells */
|
||||||
|
ShowMessage /*!< shows preset message instead of table contents*/
|
||||||
|
};
|
||||||
|
|
||||||
QgsComposerTableV2( QgsComposition* composition /TransferThis/, bool createUndoCommands );
|
QgsComposerTableV2( QgsComposition* composition /TransferThis/, bool createUndoCommands );
|
||||||
QgsComposerTableV2();
|
QgsComposerTableV2();
|
||||||
|
|
||||||
@ -63,6 +73,37 @@ class QgsComposerTableV2: QgsComposerMultiFrame
|
|||||||
*/
|
*/
|
||||||
double cellMargin() const;
|
double cellMargin() const;
|
||||||
|
|
||||||
|
/**Sets the behaviour for empty tables with no content rows.
|
||||||
|
* @param mode behaviour mode for empty tables
|
||||||
|
* @see emptyTableBehaviour
|
||||||
|
*/
|
||||||
|
void setEmptyTableBehaviour( const EmptyTableMode mode );
|
||||||
|
|
||||||
|
/**Returns the behaviour mode for empty tables. This property controls
|
||||||
|
* how the table is drawn if it contains no content rows.
|
||||||
|
* @returns behaviour mode for empty tables
|
||||||
|
* @see setEmptyTableBehaviour
|
||||||
|
*/
|
||||||
|
EmptyTableMode emptyTableBehaviour() const;
|
||||||
|
|
||||||
|
/**Sets the message for empty tables with no content rows. This message
|
||||||
|
* is displayed in the table body if the empty table behaviour is
|
||||||
|
* set to ShowMessage
|
||||||
|
* @param message message to show for empty tables
|
||||||
|
* @see emptyTableMessage
|
||||||
|
* @see setEmptyTableBehaviour
|
||||||
|
*/
|
||||||
|
void setEmptyTableMessage( const QString message );
|
||||||
|
|
||||||
|
/**Returns the message for empty tables with no content rows. This message
|
||||||
|
* is displayed in the table body if the empty table behaviour is
|
||||||
|
* set to ShowMessage
|
||||||
|
* @returns message to show for empty tables
|
||||||
|
* @see setEmptyTableMessage
|
||||||
|
* @see emptyTableBehaviour
|
||||||
|
*/
|
||||||
|
QString emptyTableMessage() const;
|
||||||
|
|
||||||
/**Sets the font used to draw header text in the table.
|
/**Sets the font used to draw header text in the table.
|
||||||
* @param font font for header cells
|
* @param font font for header cells
|
||||||
* @see headerFont
|
* @see headerFont
|
||||||
@ -305,12 +346,13 @@ class QgsComposerTableV2: QgsComposerMultiFrame
|
|||||||
* 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 numberRows number of rows of content in table frame
|
||||||
* @param hasHeader set to true if table frame includes header cells
|
* @param hasHeader set to true if table frame includes header cells
|
||||||
|
* @param mergeCells set to true to merge table content cells
|
||||||
* @note not available in python bindings
|
* @note not available in python bindings
|
||||||
* @see drawVerticalGridLines
|
* @see drawVerticalGridLines
|
||||||
* @see calculateMaxColumnWidths
|
* @see calculateMaxColumnWidths
|
||||||
* @note not available in python bindings
|
* @note not available in python bindings
|
||||||
*/
|
*/
|
||||||
//void drawVerticalGridLines( QPainter* painter, const QMap<int, double>& maxWidthMap, const int numberRows, const bool hasHeader ) const;
|
//void drawVerticalGridLines( QPainter* painter, const QMap<int, double>& maxWidthMap, const int numberRows, const bool hasHeader, const bool mergeCells = false ) const;
|
||||||
|
|
||||||
/**Recalculates and updates the size of the table and all table frames.
|
/**Recalculates and updates the size of the table and all table frames.
|
||||||
*/
|
*/
|
||||||
|
@ -47,6 +47,11 @@ QgsComposerAttributeTableWidget::QgsComposerAttributeTableWidget( QgsComposerAtt
|
|||||||
mResizeModeComboBox->addItem( tr( "Extend to next page" ), QgsComposerMultiFrame::ExtendToNextPage );
|
mResizeModeComboBox->addItem( tr( "Extend to next page" ), QgsComposerMultiFrame::ExtendToNextPage );
|
||||||
mResizeModeComboBox->addItem( tr( "Repeat until finished" ), QgsComposerMultiFrame::RepeatUntilFinished );
|
mResizeModeComboBox->addItem( tr( "Repeat until finished" ), QgsComposerMultiFrame::RepeatUntilFinished );
|
||||||
|
|
||||||
|
mEmptyModeComboBox->addItem( tr( "Draw headers only" ), QgsComposerTableV2::HeadersOnly );
|
||||||
|
mEmptyModeComboBox->addItem( tr( "Hide entire table" ), QgsComposerTableV2::HideTable );
|
||||||
|
mEmptyModeComboBox->addItem( tr( "Draw empty cells" ), QgsComposerTableV2::DrawEmptyCells );
|
||||||
|
mEmptyModeComboBox->addItem( tr( "Show set message" ), QgsComposerTableV2::ShowMessage );
|
||||||
|
|
||||||
bool atlasEnabled = atlasComposition() && atlasComposition()->enabled();
|
bool atlasEnabled = atlasComposition() && atlasComposition()->enabled();
|
||||||
mSourceComboBox->addItem( tr( "Layer features" ), QgsComposerAttributeTableV2::LayerAttributes );
|
mSourceComboBox->addItem( tr( "Layer features" ), QgsComposerAttributeTableV2::LayerAttributes );
|
||||||
toggleAtlasSpecificControls( atlasEnabled );
|
toggleAtlasSpecificControls( atlasEnabled );
|
||||||
@ -494,6 +499,11 @@ void QgsComposerAttributeTableWidget::updateGuiElements()
|
|||||||
mHeaderHAlignmentComboBox->setCurrentIndex(( int )mComposerTable->headerHAlignment() );
|
mHeaderHAlignmentComboBox->setCurrentIndex(( int )mComposerTable->headerHAlignment() );
|
||||||
mHeaderModeComboBox->setCurrentIndex(( int )mComposerTable->headerMode() );
|
mHeaderModeComboBox->setCurrentIndex(( int )mComposerTable->headerMode() );
|
||||||
|
|
||||||
|
mEmptyModeComboBox->setCurrentIndex( mEmptyModeComboBox->findData( mComposerTable->emptyTableBehaviour() ) );
|
||||||
|
mEmptyMessageLineEdit->setText( mComposerTable->emptyTableMessage() );
|
||||||
|
mEmptyMessageLineEdit->setEnabled( mComposerTable->emptyTableBehaviour() == QgsComposerTableV2::ShowMessage );
|
||||||
|
mEmptyMessageLabel->setEnabled( mComposerTable->emptyTableBehaviour() == QgsComposerTableV2::ShowMessage );
|
||||||
|
|
||||||
mResizeModeComboBox->setCurrentIndex( mResizeModeComboBox->findData( mComposerTable->resizeMode() ) );
|
mResizeModeComboBox->setCurrentIndex( mResizeModeComboBox->findData( mComposerTable->resizeMode() ) );
|
||||||
mAddFramePushButton->setEnabled( mComposerTable->resizeMode() == QgsComposerMultiFrame::UseExistingFrames );
|
mAddFramePushButton->setEnabled( mComposerTable->resizeMode() == QgsComposerMultiFrame::UseExistingFrames );
|
||||||
|
|
||||||
@ -585,6 +595,8 @@ void QgsComposerAttributeTableWidget::blockAllSignals( bool b )
|
|||||||
mContentFontColorButton->blockSignals( b );
|
mContentFontColorButton->blockSignals( b );
|
||||||
mResizeModeComboBox->blockSignals( b );
|
mResizeModeComboBox->blockSignals( b );
|
||||||
mRelationsComboBox->blockSignals( b );
|
mRelationsComboBox->blockSignals( b );
|
||||||
|
mEmptyModeComboBox->blockSignals( b );
|
||||||
|
mEmptyMessageLineEdit->blockSignals( b );
|
||||||
}
|
}
|
||||||
|
|
||||||
void QgsComposerAttributeTableWidget::setMaximumNumberOfFeatures( int n )
|
void QgsComposerAttributeTableWidget::setMaximumNumberOfFeatures( int n )
|
||||||
@ -850,6 +862,44 @@ void QgsComposerAttributeTableWidget::on_mRelationsComboBox_currentIndexChanged(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QgsComposerAttributeTableWidget::on_mEmptyModeComboBox_currentIndexChanged( int index )
|
||||||
|
{
|
||||||
|
if ( !mComposerTable )
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QgsComposition* composition = mComposerTable->composition();
|
||||||
|
if ( composition )
|
||||||
|
{
|
||||||
|
composition->beginMultiFrameCommand( mComposerTable, tr( "Change empty table behaviour" ) );
|
||||||
|
mComposerTable->setEmptyTableBehaviour(( QgsComposerTableV2::EmptyTableMode ) mEmptyModeComboBox->itemData( index ).toInt() );
|
||||||
|
composition->endMultiFrameCommand();
|
||||||
|
mEmptyMessageLineEdit->setEnabled( mComposerTable->emptyTableBehaviour() == QgsComposerTableV2::ShowMessage );
|
||||||
|
mEmptyMessageLabel->setEnabled( mComposerTable->emptyTableBehaviour() == QgsComposerTableV2::ShowMessage );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void QgsComposerAttributeTableWidget::on_mEmptyMessageLineEdit_editingFinished()
|
||||||
|
{
|
||||||
|
if ( !mComposerTable )
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QgsComposition* composition = mComposerTable->composition();
|
||||||
|
if ( composition )
|
||||||
|
{
|
||||||
|
composition->beginMultiFrameCommand( mComposerTable, tr( "Empty table message changed" ) );
|
||||||
|
}
|
||||||
|
mComposerTable->setEmptyTableMessage( mEmptyMessageLineEdit->text() );
|
||||||
|
mComposerTable->update();
|
||||||
|
if ( composition )
|
||||||
|
{
|
||||||
|
composition->endMultiFrameCommand();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void QgsComposerAttributeTableWidget::toggleSourceControls()
|
void QgsComposerAttributeTableWidget::toggleSourceControls()
|
||||||
{
|
{
|
||||||
switch ( mComposerTable->source() )
|
switch ( mComposerTable->source() )
|
||||||
|
@ -70,6 +70,8 @@ class QgsComposerAttributeTableWidget: public QgsComposerItemBaseWidget, private
|
|||||||
void on_mResizeModeComboBox_currentIndexChanged( int index );
|
void on_mResizeModeComboBox_currentIndexChanged( int index );
|
||||||
void on_mSourceComboBox_currentIndexChanged( int index );
|
void on_mSourceComboBox_currentIndexChanged( int index );
|
||||||
void on_mRelationsComboBox_currentIndexChanged( int index );
|
void on_mRelationsComboBox_currentIndexChanged( int index );
|
||||||
|
void on_mEmptyModeComboBox_currentIndexChanged( int index );
|
||||||
|
void on_mEmptyMessageLineEdit_editingFinished();
|
||||||
|
|
||||||
/**Inserts a new maximum number of features into the spin box (without the spinbox emitting a signal)*/
|
/**Inserts a new maximum number of features into the spin box (without the spinbox emitting a signal)*/
|
||||||
void setMaximumNumberOfFeatures( int n );
|
void setMaximumNumberOfFeatures( int n );
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
QgsComposerTableV2::QgsComposerTableV2( QgsComposition *composition, bool createUndoCommands )
|
QgsComposerTableV2::QgsComposerTableV2( QgsComposition *composition, bool createUndoCommands )
|
||||||
: QgsComposerMultiFrame( composition, createUndoCommands )
|
: QgsComposerMultiFrame( composition, createUndoCommands )
|
||||||
, mCellMargin( 1.0 )
|
, mCellMargin( 1.0 )
|
||||||
|
, mEmptyTableMode( HeadersOnly )
|
||||||
, mHeaderFontColor( Qt::black )
|
, mHeaderFontColor( Qt::black )
|
||||||
, mHeaderHAlignment( FollowColumn )
|
, mHeaderHAlignment( FollowColumn )
|
||||||
, mHeaderMode( FirstFrame )
|
, mHeaderMode( FirstFrame )
|
||||||
@ -63,6 +64,8 @@ QgsComposerTableV2::~QgsComposerTableV2()
|
|||||||
bool QgsComposerTableV2::writeXML( QDomElement& elem, QDomDocument & doc, bool ignoreFrames ) const
|
bool QgsComposerTableV2::writeXML( QDomElement& elem, QDomDocument & doc, bool ignoreFrames ) const
|
||||||
{
|
{
|
||||||
elem.setAttribute( "cellMargin", QString::number( mCellMargin ) );
|
elem.setAttribute( "cellMargin", QString::number( mCellMargin ) );
|
||||||
|
elem.setAttribute( "emptyTableMode", QString::number(( int )mEmptyTableMode ) );
|
||||||
|
elem.setAttribute( "emptyTableMessage", mEmptyTableMessage );
|
||||||
elem.setAttribute( "headerFont", mHeaderFont.toString() );
|
elem.setAttribute( "headerFont", mHeaderFont.toString() );
|
||||||
elem.setAttribute( "headerFontColor", QgsSymbolLayerV2Utils::encodeColor( mHeaderFontColor ) );
|
elem.setAttribute( "headerFontColor", QgsSymbolLayerV2Utils::encodeColor( mHeaderFontColor ) );
|
||||||
elem.setAttribute( "headerHAlignment", QString::number(( int )mHeaderHAlignment ) );
|
elem.setAttribute( "headerHAlignment", QString::number(( int )mHeaderHAlignment ) );
|
||||||
@ -103,6 +106,8 @@ bool QgsComposerTableV2::readXML( const QDomElement &itemElem, const QDomDocumen
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mEmptyTableMode = QgsComposerTableV2::EmptyTableMode( itemElem.attribute( "emptyTableMode", "0" ).toInt() );
|
||||||
|
mEmptyTableMessage = itemElem.attribute( "emptyTableMessage", tr( "No matching records" ) );
|
||||||
mHeaderFont.fromString( itemElem.attribute( "headerFont", "" ) );
|
mHeaderFont.fromString( itemElem.attribute( "headerFont", "" ) );
|
||||||
mHeaderFontColor = QgsSymbolLayerV2Utils::decodeColor( itemElem.attribute( "headerFontColor", "0,0,0,255" ) );
|
mHeaderFontColor = QgsSymbolLayerV2Utils::decodeColor( itemElem.attribute( "headerFontColor", "0,0,0,255" ) );
|
||||||
mHeaderHAlignment = QgsComposerTableV2::HeaderHAlignment( itemElem.attribute( "headerHAlignment", "0" ).toInt() );
|
mHeaderHAlignment = QgsComposerTableV2::HeaderHAlignment( itemElem.attribute( "headerHAlignment", "0" ).toInt() );
|
||||||
@ -229,6 +234,13 @@ void QgsComposerTableV2::render( QPainter *p, const QRectF &renderExtent, const
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool emptyTable = mTableContents.length() == 0;
|
||||||
|
if ( emptyTable && mEmptyTableMode == QgsComposerTableV2::HideTable )
|
||||||
|
{
|
||||||
|
//empty table set to hide table mode, so don't draw anything
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
//calculate which rows to show in this frame
|
//calculate which rows to show in this frame
|
||||||
QPair< int, int > rowsToShow = rowRange( renderExtent, frameIndex );
|
QPair< int, int > rowsToShow = rowRange( renderExtent, frameIndex );
|
||||||
|
|
||||||
@ -260,6 +272,8 @@ void QgsComposerTableV2::render( QPainter *p, const QRectF &renderExtent, const
|
|||||||
//calculate whether a header is required
|
//calculate whether a header is required
|
||||||
bool drawHeader = (( mHeaderMode == QgsComposerTableV2::FirstFrame && frameIndex < 1 )
|
bool drawHeader = (( mHeaderMode == QgsComposerTableV2::FirstFrame && frameIndex < 1 )
|
||||||
|| ( mHeaderMode == QgsComposerTableV2::AllFrames ) );
|
|| ( mHeaderMode == QgsComposerTableV2::AllFrames ) );
|
||||||
|
//calculate whether drawing table contents is required
|
||||||
|
bool drawContents = !( emptyTable && mEmptyTableMode == QgsComposerTableV2::ShowMessage );
|
||||||
|
|
||||||
for ( ; columnIt != mColumns.constEnd(); ++columnIt )
|
for ( ; columnIt != mColumns.constEnd(); ++columnIt )
|
||||||
{
|
{
|
||||||
@ -304,6 +318,8 @@ void QgsComposerTableV2::render( QPainter *p, const QRectF &renderExtent, const
|
|||||||
currentY += ( mShowGrid ? mGridStrokeWidth : 0 );
|
currentY += ( mShowGrid ? mGridStrokeWidth : 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( drawContents )
|
||||||
|
{
|
||||||
//draw the attribute values
|
//draw the attribute values
|
||||||
for ( int row = rowsToShow.first; row < rowsToShow.second; ++row )
|
for ( int row = rowsToShow.first; row < rowsToShow.second; ++row )
|
||||||
{
|
{
|
||||||
@ -317,6 +333,7 @@ void QgsComposerTableV2::render( QPainter *p, const QRectF &renderExtent, const
|
|||||||
currentY += cellBodyHeight;
|
currentY += cellBodyHeight;
|
||||||
currentY += ( mShowGrid ? mGridStrokeWidth : 0 );
|
currentY += ( mShowGrid ? mGridStrokeWidth : 0 );
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
currentX += mMaxColumnWidthMap[ col ];
|
currentX += mMaxColumnWidthMap[ col ];
|
||||||
currentX += mCellMargin;
|
currentX += mCellMargin;
|
||||||
@ -324,17 +341,39 @@ void QgsComposerTableV2::render( QPainter *p, const QRectF &renderExtent, const
|
|||||||
col++;
|
col++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//and the borders
|
//and the borders
|
||||||
if ( mShowGrid )
|
if ( mShowGrid )
|
||||||
{
|
{
|
||||||
|
int numberRowsToDraw = rowsToShow.second - rowsToShow.first;
|
||||||
|
if ( mEmptyTableMode == QgsComposerTableV2::DrawEmptyCells )
|
||||||
|
{
|
||||||
|
numberRowsToDraw = rowsVisible( frameIndex );
|
||||||
|
}
|
||||||
|
bool mergeCells = false;
|
||||||
|
if ( emptyTable && mEmptyTableMode == QgsComposerTableV2::ShowMessage )
|
||||||
|
{
|
||||||
|
//draw a merged row for the empty table message
|
||||||
|
numberRowsToDraw++;
|
||||||
|
mergeCells = true;
|
||||||
|
}
|
||||||
|
|
||||||
QPen gridPen;
|
QPen gridPen;
|
||||||
gridPen.setWidthF( mGridStrokeWidth );
|
gridPen.setWidthF( mGridStrokeWidth );
|
||||||
gridPen.setColor( mGridColor );
|
gridPen.setColor( mGridColor );
|
||||||
gridPen.setJoinStyle( Qt::MiterJoin );
|
gridPen.setJoinStyle( Qt::MiterJoin );
|
||||||
p->setPen( gridPen );
|
p->setPen( gridPen );
|
||||||
drawHorizontalGridLines( p, rowsToShow.second - rowsToShow.first, drawHeader );
|
drawHorizontalGridLines( p, numberRowsToDraw, drawHeader );
|
||||||
drawVerticalGridLines( p, mMaxColumnWidthMap, rowsToShow.second - rowsToShow.first, drawHeader );
|
drawVerticalGridLines( p, mMaxColumnWidthMap, numberRowsToDraw, drawHeader, mergeCells );
|
||||||
|
}
|
||||||
|
|
||||||
|
//special case - no records and table is set to ShowMessage mode
|
||||||
|
if ( emptyTable && mEmptyTableMode == QgsComposerTableV2::ShowMessage )
|
||||||
|
{
|
||||||
|
double messageX = ( mShowGrid ? mGridStrokeWidth : 0 ) + mCellMargin;
|
||||||
|
double messageY = ( mShowGrid ? mGridStrokeWidth : 0 ) +
|
||||||
|
( drawHeader ? cellHeaderHeight + ( mShowGrid ? mGridStrokeWidth : 0 ) : 0 );
|
||||||
|
cell = QRectF( messageX, messageY, mTableSize.width() - messageX, cellBodyHeight );
|
||||||
|
QgsComposerUtils::drawText( p, cell, mEmptyTableMessage, mContentFont, mContentFontColor, Qt::AlignHCenter, Qt::AlignVCenter, ( Qt::TextFlag )0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
p->restore();
|
p->restore();
|
||||||
@ -356,6 +395,36 @@ void QgsComposerTableV2::setCellMargin( const double margin )
|
|||||||
emit changed();
|
emit changed();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QgsComposerTableV2::setEmptyTableBehaviour( const QgsComposerTableV2::EmptyTableMode mode )
|
||||||
|
{
|
||||||
|
if ( mode == mEmptyTableMode )
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mEmptyTableMode = mode;
|
||||||
|
|
||||||
|
//since appearance has changed, we need to recalculate the table size
|
||||||
|
recalculateTableSize();
|
||||||
|
|
||||||
|
emit changed();
|
||||||
|
}
|
||||||
|
|
||||||
|
void QgsComposerTableV2::setEmptyTableMessage( const QString message )
|
||||||
|
{
|
||||||
|
if ( message == mEmptyTableMessage )
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mEmptyTableMessage = message;
|
||||||
|
|
||||||
|
//since message has changed, we need to recalculate the table size
|
||||||
|
recalculateTableSize();
|
||||||
|
|
||||||
|
emit changed();
|
||||||
|
}
|
||||||
|
|
||||||
void QgsComposerTableV2::setHeaderFont( const QFont &font )
|
void QgsComposerTableV2::setHeaderFont( const QFont &font )
|
||||||
{
|
{
|
||||||
if ( font == mHeaderFont )
|
if ( font == mHeaderFont )
|
||||||
@ -683,7 +752,7 @@ 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 int numberRows, const bool hasHeader ) const
|
void QgsComposerTableV2::drawVerticalGridLines( QPainter *painter, const QMap<int, double> &maxWidthMap, const int numberRows, const bool hasHeader, const bool mergeCells ) const
|
||||||
{
|
{
|
||||||
//vertical lines
|
//vertical lines
|
||||||
if ( numberRows < 1 && !hasHeader )
|
if ( numberRows < 1 && !hasHeader )
|
||||||
@ -697,20 +766,30 @@ void QgsComposerTableV2::drawVerticalGridLines( QPainter *painter, const QMap<in
|
|||||||
{
|
{
|
||||||
tableHeight += ( mShowGrid ? mGridStrokeWidth : 0 ) + mCellMargin * 2 + QgsComposerUtils::fontAscentMM( mHeaderFont );
|
tableHeight += ( mShowGrid ? mGridStrokeWidth : 0 ) + mCellMargin * 2 + QgsComposerUtils::fontAscentMM( mHeaderFont );
|
||||||
}
|
}
|
||||||
|
|
||||||
tableHeight += numberRows * (( mShowGrid ? mGridStrokeWidth : 0 ) + mCellMargin * 2 + QgsComposerUtils::fontAscentMM( mContentFont ) );
|
|
||||||
tableHeight += ( mShowGrid ? mGridStrokeWidth : 0 );
|
tableHeight += ( mShowGrid ? mGridStrokeWidth : 0 );
|
||||||
|
double headerHeight = tableHeight;
|
||||||
|
tableHeight += numberRows * (( mShowGrid ? mGridStrokeWidth : 0 ) + mCellMargin * 2 + QgsComposerUtils::fontAscentMM( mContentFont ) );
|
||||||
|
|
||||||
double halfGridStrokeWidth = ( mShowGrid ? mGridStrokeWidth : 0 ) / 2.0;
|
double halfGridStrokeWidth = ( mShowGrid ? mGridStrokeWidth : 0 ) / 2.0;
|
||||||
double currentX = halfGridStrokeWidth;
|
double currentX = halfGridStrokeWidth;
|
||||||
painter->drawLine( QPointF( currentX, halfGridStrokeWidth ), QPointF( currentX, tableHeight - halfGridStrokeWidth ) );
|
painter->drawLine( QPointF( currentX, halfGridStrokeWidth ), QPointF( currentX, tableHeight - halfGridStrokeWidth ) );
|
||||||
currentX += ( mShowGrid ? mGridStrokeWidth : 0 );
|
currentX += ( mShowGrid ? mGridStrokeWidth : 0 );
|
||||||
QMap<int, double>::const_iterator maxColWidthIt = maxWidthMap.constBegin();
|
QMap<int, double>::const_iterator maxColWidthIt = maxWidthMap.constBegin();
|
||||||
|
int col = 1;
|
||||||
for ( ; maxColWidthIt != maxWidthMap.constEnd(); ++maxColWidthIt )
|
for ( ; maxColWidthIt != maxWidthMap.constEnd(); ++maxColWidthIt )
|
||||||
{
|
{
|
||||||
currentX += ( maxColWidthIt.value() + 2 * mCellMargin );
|
currentX += ( maxColWidthIt.value() + 2 * mCellMargin );
|
||||||
|
if ( col == maxWidthMap.size() || !mergeCells )
|
||||||
|
{
|
||||||
painter->drawLine( QPointF( currentX, halfGridStrokeWidth ), QPointF( currentX, tableHeight - halfGridStrokeWidth ) );
|
painter->drawLine( QPointF( currentX, halfGridStrokeWidth ), QPointF( currentX, tableHeight - halfGridStrokeWidth ) );
|
||||||
|
}
|
||||||
|
else if ( hasHeader )
|
||||||
|
{
|
||||||
|
painter->drawLine( QPointF( currentX, halfGridStrokeWidth ), QPointF( currentX, headerHeight - halfGridStrokeWidth ) );
|
||||||
|
}
|
||||||
|
|
||||||
currentX += ( mShowGrid ? mGridStrokeWidth : 0 );
|
currentX += ( mShowGrid ? mGridStrokeWidth : 0 );
|
||||||
|
col++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,6 +71,16 @@ class CORE_EXPORT QgsComposerTableV2: public QgsComposerMultiFrame
|
|||||||
NoHeaders /*!< no headers shown for table */
|
NoHeaders /*!< no headers shown for table */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*! Controls how empty tables are displayed
|
||||||
|
*/
|
||||||
|
enum EmptyTableMode
|
||||||
|
{
|
||||||
|
HeadersOnly = 0, /*!< show header rows only */
|
||||||
|
HideTable, /*!< hides entire table if empty */
|
||||||
|
DrawEmptyCells, /*!< draws empty cells */
|
||||||
|
ShowMessage /*!< shows preset message instead of table contents*/
|
||||||
|
};
|
||||||
|
|
||||||
QgsComposerTableV2( QgsComposition* composition, bool createUndoCommands );
|
QgsComposerTableV2( QgsComposition* composition, bool createUndoCommands );
|
||||||
QgsComposerTableV2();
|
QgsComposerTableV2();
|
||||||
|
|
||||||
@ -88,6 +98,37 @@ class CORE_EXPORT QgsComposerTableV2: public QgsComposerMultiFrame
|
|||||||
*/
|
*/
|
||||||
double cellMargin() const { return mCellMargin; }
|
double cellMargin() const { return mCellMargin; }
|
||||||
|
|
||||||
|
/**Sets the behaviour for empty tables with no content rows.
|
||||||
|
* @param mode behaviour mode for empty tables
|
||||||
|
* @see emptyTableBehaviour
|
||||||
|
*/
|
||||||
|
void setEmptyTableBehaviour( const EmptyTableMode mode );
|
||||||
|
|
||||||
|
/**Returns the behaviour mode for empty tables. This property controls
|
||||||
|
* how the table is drawn if it contains no content rows.
|
||||||
|
* @returns behaviour mode for empty tables
|
||||||
|
* @see setEmptyTableBehaviour
|
||||||
|
*/
|
||||||
|
EmptyTableMode emptyTableBehaviour() const { return mEmptyTableMode; }
|
||||||
|
|
||||||
|
/**Sets the message for empty tables with no content rows. This message
|
||||||
|
* is displayed in the table body if the empty table behaviour is
|
||||||
|
* set to ShowMessage
|
||||||
|
* @param message message to show for empty tables
|
||||||
|
* @see emptyTableMessage
|
||||||
|
* @see setEmptyTableBehaviour
|
||||||
|
*/
|
||||||
|
void setEmptyTableMessage( const QString message );
|
||||||
|
|
||||||
|
/**Returns the message for empty tables with no content rows. This message
|
||||||
|
* is displayed in the table body if the empty table behaviour is
|
||||||
|
* set to ShowMessage
|
||||||
|
* @returns message to show for empty tables
|
||||||
|
* @see setEmptyTableMessage
|
||||||
|
* @see emptyTableBehaviour
|
||||||
|
*/
|
||||||
|
QString emptyTableMessage() const { return mEmptyTableMessage; }
|
||||||
|
|
||||||
/**Sets the font used to draw header text in the table.
|
/**Sets the font used to draw header text in the table.
|
||||||
* @param font font for header cells
|
* @param font font for header cells
|
||||||
* @see headerFont
|
* @see headerFont
|
||||||
@ -279,6 +320,12 @@ class CORE_EXPORT QgsComposerTableV2: public QgsComposerMultiFrame
|
|||||||
/**Margin between cell borders and cell text*/
|
/**Margin between cell borders and cell text*/
|
||||||
double mCellMargin;
|
double mCellMargin;
|
||||||
|
|
||||||
|
/**Behaviour for empty tables*/
|
||||||
|
EmptyTableMode mEmptyTableMode;
|
||||||
|
|
||||||
|
/**String to show in empty tables*/
|
||||||
|
QString mEmptyTableMessage;
|
||||||
|
|
||||||
/**Header font*/
|
/**Header font*/
|
||||||
QFont mHeaderFont;
|
QFont mHeaderFont;
|
||||||
|
|
||||||
@ -370,12 +417,13 @@ class CORE_EXPORT QgsComposerTableV2: public QgsComposerMultiFrame
|
|||||||
* 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 numberRows number of rows of content in table frame
|
||||||
* @param hasHeader set to true if table frame includes header cells
|
* @param hasHeader set to true if table frame includes header cells
|
||||||
|
* @param mergeCells set to true to merge table content cells
|
||||||
* @note not available in python bindings
|
* @note not available in python bindings
|
||||||
* @see drawVerticalGridLines
|
* @see drawVerticalGridLines
|
||||||
* @see calculateMaxColumnWidths
|
* @see calculateMaxColumnWidths
|
||||||
* @note not available in python bindings
|
* @note not available in python bindings
|
||||||
*/
|
*/
|
||||||
void drawVerticalGridLines( QPainter* painter, const QMap<int, double>& maxWidthMap, const int numberRows, const bool hasHeader ) const;
|
void drawVerticalGridLines( QPainter* painter, const QMap<int, double>& maxWidthMap, const int numberRows, const bool hasHeader, const bool mergeCells = false ) const;
|
||||||
|
|
||||||
/**Recalculates and updates the size of the table and all table frames.
|
/**Recalculates and updates the size of the table and all table frames.
|
||||||
*/
|
*/
|
||||||
|
@ -45,9 +45,9 @@
|
|||||||
<property name="geometry">
|
<property name="geometry">
|
||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>-195</y>
|
||||||
<width>392</width>
|
<width>392</width>
|
||||||
<height>918</height>
|
<height>1020</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="mainLayout">
|
<layout class="QVBoxLayout" name="mainLayout">
|
||||||
@ -99,6 +99,16 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item row="2" column="0">
|
||||||
|
<widget class="QLabel" name="mRelationLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>Relation</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="1">
|
||||||
|
<widget class="QComboBox" name="mRelationsComboBox"/>
|
||||||
|
</item>
|
||||||
<item row="4" column="0" colspan="2">
|
<item row="4" column="0" colspan="2">
|
||||||
<widget class="QPushButton" name="mRefreshPushButton">
|
<widget class="QPushButton" name="mRefreshPushButton">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
@ -113,36 +123,6 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="6" column="0">
|
|
||||||
<widget class="QLabel" name="mMarginLabel">
|
|
||||||
<property name="text">
|
|
||||||
<string>Margin</string>
|
|
||||||
</property>
|
|
||||||
<property name="wordWrap">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
<property name="buddy">
|
|
||||||
<cstring>mMarginSpinBox</cstring>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="6" column="1">
|
|
||||||
<widget class="QDoubleSpinBox" name="mMarginSpinBox">
|
|
||||||
<property name="suffix">
|
|
||||||
<string> mm</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="2" column="1">
|
|
||||||
<widget class="QComboBox" name="mRelationsComboBox"/>
|
|
||||||
</item>
|
|
||||||
<item row="2" column="0">
|
|
||||||
<widget class="QLabel" name="mRelationLabel">
|
|
||||||
<property name="text">
|
|
||||||
<string>Relation</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
@ -235,6 +215,87 @@
|
|||||||
<zorder>mMaxNumFeaturesLabel</zorder>
|
<zorder>mMaxNumFeaturesLabel</zorder>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QgsCollapsibleGroupBoxBasic" name="groupBox_6">
|
||||||
|
<property name="title">
|
||||||
|
<string>Appearance</string>
|
||||||
|
</property>
|
||||||
|
<property name="syncGroup" stdset="0">
|
||||||
|
<string notr="true">composeritem</string>
|
||||||
|
</property>
|
||||||
|
<property name="collapsed" stdset="0">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<layout class="QFormLayout" name="formLayout_4">
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel" name="mMarginLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>Cell margins</string>
|
||||||
|
</property>
|
||||||
|
<property name="wordWrap">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="buddy">
|
||||||
|
<cstring>mMarginSpinBox</cstring>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QDoubleSpinBox" name="mMarginSpinBox">
|
||||||
|
<property name="suffix">
|
||||||
|
<string> mm</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QLabel" name="label_7">
|
||||||
|
<property name="text">
|
||||||
|
<string>Display header</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="QComboBox" name="mHeaderModeComboBox">
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>On first frame</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>On all frames</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>No header</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0">
|
||||||
|
<widget class="QLabel" name="label_9">
|
||||||
|
<property name="text">
|
||||||
|
<string>Empty tables</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="1">
|
||||||
|
<widget class="QComboBox" name="mEmptyModeComboBox"/>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="0">
|
||||||
|
<widget class="QLabel" name="mEmptyMessageLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>Message to display</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="1">
|
||||||
|
<widget class="QLineEdit" name="mEmptyMessageLineEdit"/>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QgsCollapsibleGroupBoxBasic" name="mShowGridGroupCheckBox">
|
<widget class="QgsCollapsibleGroupBoxBasic" name="mShowGridGroupCheckBox">
|
||||||
<property name="title">
|
<property name="title">
|
||||||
@ -317,13 +378,6 @@
|
|||||||
<string>Table heading</string>
|
<string>Table heading</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QGridLayout" name="gridLayout">
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
<item row="1" column="0">
|
|
||||||
<widget class="QLabel" name="label_7">
|
|
||||||
<property name="text">
|
|
||||||
<string>Display</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="5" column="1" colspan="2">
|
<item row="5" column="1" colspan="2">
|
||||||
<widget class="QComboBox" name="mHeaderHAlignmentComboBox">
|
<widget class="QComboBox" name="mHeaderHAlignmentComboBox">
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
@ -401,25 +455,6 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="1" column="1" colspan="2">
|
|
||||||
<widget class="QComboBox" name="mHeaderModeComboBox">
|
|
||||||
<item>
|
|
||||||
<property name="text">
|
|
||||||
<string>On first frame</string>
|
|
||||||
</property>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<property name="text">
|
|
||||||
<string>On all frames</string>
|
|
||||||
</property>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<property name="text">
|
|
||||||
<string>No header</string>
|
|
||||||
</property>
|
|
||||||
</item>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
@ -49,12 +49,10 @@ class TestQgsComposerTableV2: public QObject
|
|||||||
void attributeTableSetAttributes(); //test subset of attributes in table
|
void attributeTableSetAttributes(); //test subset of attributes in table
|
||||||
void attributeTableVisibleOnly(); //test displaying only visible attributes
|
void attributeTableVisibleOnly(); //test displaying only visible attributes
|
||||||
void attributeTableRender(); //test rendering attribute table
|
void attributeTableRender(); //test rendering attribute table
|
||||||
|
|
||||||
void manualColumnWidth(); //test setting manual column widths
|
void manualColumnWidth(); //test setting manual column widths
|
||||||
|
void attributeTableEmpty(); //test empty modes for attribute table
|
||||||
void attributeTableExtend();
|
void attributeTableExtend();
|
||||||
void attributeTableRepeat();
|
void attributeTableRepeat();
|
||||||
|
|
||||||
void attributeTableAtlasSource(); //test attribute table in atlas feature mode
|
void attributeTableAtlasSource(); //test attribute table in atlas feature mode
|
||||||
void attributeTableRelationSource(); //test attribute table in relation mode
|
void attributeTableRelationSource(); //test attribute table in relation mode
|
||||||
|
|
||||||
@ -325,6 +323,33 @@ void TestQgsComposerTableV2::manualColumnWidth()
|
|||||||
QVERIFY( result );
|
QVERIFY( result );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TestQgsComposerTableV2::attributeTableEmpty()
|
||||||
|
{
|
||||||
|
mComposerAttributeTable->setMaximumNumberOfFeatures( 20 );
|
||||||
|
//hide all features from table
|
||||||
|
mComposerAttributeTable->setFeatureFilter( QString( "1=2" ) );
|
||||||
|
mComposerAttributeTable->setFilterFeatures( true );
|
||||||
|
|
||||||
|
mComposerAttributeTable->setEmptyTableBehaviour( QgsComposerTableV2::HeadersOnly );
|
||||||
|
QgsCompositionChecker checker( "composerattributetable_headersonly", mComposition );
|
||||||
|
QVERIFY( checker.testComposition( mReport, 0 ) );
|
||||||
|
|
||||||
|
mComposerAttributeTable->setEmptyTableBehaviour( QgsComposerTableV2::HideTable );
|
||||||
|
QgsCompositionChecker checker2( "composerattributetable_hidetable", mComposition );
|
||||||
|
QVERIFY( checker2.testComposition( mReport, 0 ) );
|
||||||
|
|
||||||
|
mComposerAttributeTable->setEmptyTableBehaviour( QgsComposerTableV2::DrawEmptyCells );
|
||||||
|
QgsCompositionChecker checker3( "composerattributetable_drawempty", mComposition );
|
||||||
|
QVERIFY( checker3.testComposition( mReport, 0 ) );
|
||||||
|
|
||||||
|
mComposerAttributeTable->setEmptyTableBehaviour( QgsComposerTableV2::ShowMessage );
|
||||||
|
mComposerAttributeTable->setEmptyTableMessage( "no rows" );
|
||||||
|
QgsCompositionChecker checker4( "composerattributetable_showmessage", mComposition );
|
||||||
|
QVERIFY( checker4.testComposition( mReport, 0 ) );
|
||||||
|
|
||||||
|
mComposerAttributeTable->setFilterFeatures( false );
|
||||||
|
}
|
||||||
|
|
||||||
void TestQgsComposerTableV2::attributeTableExtend()
|
void TestQgsComposerTableV2::attributeTableExtend()
|
||||||
{
|
{
|
||||||
//test that adding and removing frames automatically does not result in a crash
|
//test that adding and removing frames automatically does not result in a crash
|
||||||
|
Binary file not shown.
After Width: | Height: | Size: 16 KiB |
Binary file not shown.
After Width: | Height: | Size: 14 KiB |
Binary file not shown.
After Width: | Height: | Size: 5.5 KiB |
Binary file not shown.
After Width: | Height: | Size: 17 KiB |
Loading…
x
Reference in New Issue
Block a user