Skip to content

Commit 272b79b

Browse files
committedSep 25, 2014
[FEATURE][composer] Add checkbox to frame items for preventing export
of page containing frame when frame is empty. This change allows users to create multiple pages containing extra frames for multiframe items (currently HTML and Attribute Table items), which are then only printed/exported if required. Sponsored by the City of Uster, Switzerland.
1 parent b8bb4f0 commit 272b79b

20 files changed

+628
-35
lines changed
 

‎python/core/composer/qgscomposerframe.sip

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,5 +41,26 @@ class QgsComposerFrame: QgsComposerItem
4141
* @see setContentSection
4242
*/
4343
QRectF extent() const;
44+
45+
/**Returns whether the page should be hidden (ie, not included in composer exports) if this frame is empty
46+
* @returns true if page should be hidden if frame is empty
47+
* @note added in QGIS 2.5
48+
* @see setHidePageIfEmpty
49+
*/
50+
bool hidePageIfEmpty() const;
51+
52+
/**Sets whether the page should be hidden (ie, not included in composer exports) if this frame is empty
53+
* @param hidePageIfEmpty set to true if page should be hidden if frame is empty
54+
* @note added in QGIS 2.5
55+
* @see hidePageIfEmpty
56+
*/
57+
void setHidePageIfEmpty( const bool hidePageIfEmpty );
58+
59+
/**Returns whether the frame is empty
60+
* @returns true if frame is empty
61+
* @note added in QGIS 2.5
62+
* @see hidePageIfEmpty
63+
*/
64+
bool isEmpty() const;
4465

4566
};

‎python/core/composer/qgscomposition.sip

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,22 +56,54 @@ class QgsComposition : QGraphicsScene
5656

5757
/**Changes size of paper item. Also moves all items so that they retain
5858
* their same relative position to the top left corner of their current page.
59+
* @param width page width in mm
60+
* @param height page height in mm
61+
* @see paperHeight
62+
* @see paperWidth
5963
*/
6064
void setPaperSize( const double width, const double height );
6165

62-
/**Returns height of paper item*/
66+
/**Height of paper item
67+
* @returns height in mm
68+
* @see paperWidth
69+
* @see setPaperSize
70+
*/
6371
double paperHeight() const;
6472

65-
/**Returns width of paper item*/
73+
/**Width of paper item
74+
* @returns width in mm
75+
* @see paperHeight
76+
* @see setPaperSize
77+
*/
6678
double paperWidth() const;
6779

80+
/**Returns the vertical space between pages in a composer view
81+
* @returns space between pages in mm
82+
*/
6883
double spaceBetweenPages() const;
6984

70-
/**Note: added in version 1.9*/
85+
/**Sets the number of pages for the composition.
86+
* @param pages number of pages
87+
* @note added in version 1.9
88+
* @see numPages
89+
*/
7190
void setNumPages( const int pages );
72-
/**Note: added in version 1.9*/
91+
92+
/**Returns the number of pages in the composition.
93+
* @returns number of pages
94+
* @note added in version 1.9
95+
* @see setNumPages
96+
*/
7397
int numPages() const;
7498

99+
/**Returns whether a specified page number should be included in exports of the composition.
100+
* @param page page number, starting with 1
101+
* @returns true if page should be exported
102+
* @note added in QGIS 2.5
103+
* @see numPages
104+
*/
105+
bool shouldExportPage( const int page ) const;
106+
75107
/**Note: added in version 2.1*/
76108
void setPageStyleSymbol( QgsFillSymbolV2* symbol /Transfer/ );
77109
/**Note: added in version 2.1*/
@@ -220,6 +252,14 @@ class QgsComposition : QGraphicsScene
220252
@note not available in python bindings
221253
*/
222254
// template<class T> void composerItems( QList<T*>& itemList );
255+
256+
/**Return composer items of a specific type on a specified page
257+
* @param itemList list of item type to store matching items in
258+
* @param pageNumber page number (0 based)
259+
* @note not available in python bindings
260+
* @note added in QGIS 2.5
261+
*/
262+
//template<class T> void composerItemsOnPage( QList<T*>& itemList, const int pageNumber );
223263

224264
/**Returns the composer map with specified id
225265
@return QgsComposerMap or 0 pointer if the composer map item does not exist*/

‎src/app/composer/qgscomposer.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1739,6 +1739,10 @@ void QgsComposer::exportCompositionAsImage( QgsComposer::OutputMode mode )
17391739

17401740
for ( int i = 0; i < mComposition->numPages(); ++i )
17411741
{
1742+
if ( !mComposition->shouldExportPage( i + 1 ) )
1743+
{
1744+
continue;
1745+
}
17421746
QImage image = mComposition->printPageAsRaster( i );
17431747
if ( image.isNull() )
17441748
{
@@ -1912,6 +1916,10 @@ void QgsComposer::exportCompositionAsImage( QgsComposer::OutputMode mode )
19121916

19131917
for ( int i = 0; i < mComposition->numPages(); ++i )
19141918
{
1919+
if ( !mComposition->shouldExportPage( i + 1 ) )
1920+
{
1921+
continue;
1922+
}
19151923
QImage image = mComposition->printPageAsRaster( i );
19161924
QString imageFilename = filename;
19171925

@@ -2187,6 +2195,10 @@ void QgsComposer::exportCompositionAsSVG( QgsComposer::OutputMode mode )
21872195
{
21882196
for ( int i = 0; i < mComposition->numPages(); ++i )
21892197
{
2198+
if ( !mComposition->shouldExportPage( i + 1 ) )
2199+
{
2200+
continue;
2201+
}
21902202
QSvgGenerator generator;
21912203
generator.setTitle( QgsProject::instance()->title() );
21922204
QString currentFileName = outputFileName;
@@ -2234,6 +2246,10 @@ void QgsComposer::exportCompositionAsSVG( QgsComposer::OutputMode mode )
22342246

22352247
for ( int i = 0; i < mComposition->numPages(); ++i )
22362248
{
2249+
if ( !mComposition->shouldExportPage( i + 1 ) )
2250+
{
2251+
continue;
2252+
}
22372253
QDomDocument svg;
22382254
QDomNode svgDocRoot;
22392255
QgsPaperItem * paperItem = paperItems[i];

‎src/app/composer/qgscomposerattributetablewidget.cpp

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,6 @@ QgsComposerAttributeTableWidget::QgsComposerAttributeTableWidget( QgsComposerAtt
3737
, mFrame( frame )
3838
{
3939
setupUi( this );
40-
//add widget for general composer item properties
41-
QgsComposerItemWidget* itemPropertiesWidget = new QgsComposerItemWidget( this, mFrame );
42-
mainLayout->addWidget( itemPropertiesWidget );
4340

4441
blockAllSignals( true );
4542

@@ -90,6 +87,14 @@ QgsComposerAttributeTableWidget::QgsComposerAttributeTableWidget( QgsComposerAtt
9087
connect( atlas, SIGNAL( toggled( bool ) ), this, SLOT( atlasToggled() ) );
9188
}
9289
}
90+
91+
//embed widget for general options
92+
if ( mFrame )
93+
{
94+
//add widget for general composer item properties
95+
QgsComposerItemWidget* itemPropertiesWidget = new QgsComposerItemWidget( this, mFrame );
96+
mainLayout->addWidget( itemPropertiesWidget );
97+
}
9398
}
9499

95100
QgsComposerAttributeTableWidget::~QgsComposerAttributeTableWidget()
@@ -509,6 +514,8 @@ void QgsComposerAttributeTableWidget::updateGuiElements()
509514
mResizeModeComboBox->setCurrentIndex( mResizeModeComboBox->findData( mComposerTable->resizeMode() ) );
510515
mAddFramePushButton->setEnabled( mComposerTable->resizeMode() == QgsComposerMultiFrame::UseExistingFrames );
511516

517+
mEmptyFrameCheckBox->setChecked( mFrame->hidePageIfEmpty() );
518+
512519
toggleSourceControls();
513520

514521
blockAllSignals( false );
@@ -539,7 +546,7 @@ void QgsComposerAttributeTableWidget::updateRelationsCombo()
539546
if ( atlasLayer )
540547
{
541548
QList<QgsRelation> relations = QgsProject::instance()->relationManager()->referencedRelations( mComposerTable->composition()->atlasComposition().coverageLayer() );
542-
Q_FOREACH( const QgsRelation& relation, relations )
549+
Q_FOREACH ( const QgsRelation& relation, relations )
543550
{
544551
mRelationsComboBox->addItem( relation.name(), relation.id() );
545552
}
@@ -608,6 +615,7 @@ void QgsComposerAttributeTableWidget::blockAllSignals( bool b )
608615
mRelationsComboBox->blockSignals( b );
609616
mEmptyModeComboBox->blockSignals( b );
610617
mEmptyMessageLineEdit->blockSignals( b );
618+
mEmptyFrameCheckBox->blockSignals( b );
611619
}
612620

613621
void QgsComposerAttributeTableWidget::setMaximumNumberOfFeatures( int n )
@@ -662,6 +670,19 @@ void QgsComposerAttributeTableWidget::on_mUniqueOnlyCheckBox_stateChanged( int s
662670
}
663671
}
664672

673+
674+
void QgsComposerAttributeTableWidget::on_mEmptyFrameCheckBox_toggled( bool checked )
675+
{
676+
if ( !mFrame )
677+
{
678+
return;
679+
}
680+
681+
mFrame->beginCommand( tr( "Empty frame mode toggled" ) );
682+
mFrame->setHidePageIfEmpty( checked );
683+
mFrame->endCommand();
684+
}
685+
665686
void QgsComposerAttributeTableWidget::on_mIntersectAtlasCheckBox_stateChanged( int state )
666687
{
667688
if ( !mComposerTable )

‎src/app/composer/qgscomposerattributetablewidget.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ class QgsComposerAttributeTableWidget: public QgsComposerItemBaseWidget, private
7474
void on_mEmptyMessageLineEdit_editingFinished();
7575
void on_mIntersectAtlasCheckBox_stateChanged( int state );
7676
void on_mUniqueOnlyCheckBox_stateChanged( int state );
77+
void on_mEmptyFrameCheckBox_toggled( bool checked );
7778

7879
/**Inserts a new maximum number of features into the spin box (without the spinbox emitting a signal)*/
7980
void setMaximumNumberOfFeatures( int n );

‎src/app/composer/qgscomposerhtmlwidget.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ void QgsComposerHtmlWidget::blockSignals( bool block )
100100
mRadioManualSource->blockSignals( block );
101101
mRadioUrlSource->blockSignals( block );
102102
mEvaluateExpressionsCheckbox->blockSignals( block );
103+
mEmptyFrameCheckBox->blockSignals( block );
103104
}
104105

105106
void QgsComposerHtmlWidget::on_mUrlLineEdit_editingFinished()
@@ -265,6 +266,18 @@ void QgsComposerHtmlWidget::on_mUserStylesheetCheckBox_toggled( bool checked )
265266
}
266267
}
267268

269+
void QgsComposerHtmlWidget::on_mEmptyFrameCheckBox_toggled( bool checked )
270+
{
271+
if ( !mFrame )
272+
{
273+
return;
274+
}
275+
276+
mFrame->beginCommand( tr( "Empty frame mode toggled" ) );
277+
mFrame->setHidePageIfEmpty( checked );
278+
mFrame->endCommand();
279+
}
280+
268281
void QgsComposerHtmlWidget::on_mRadioManualSource_clicked( bool checked )
269282
{
270283
if ( !mHtml )
@@ -433,6 +446,8 @@ void QgsComposerHtmlWidget::setGuiElementValues()
433446
mUserStylesheetCheckBox->setChecked( mHtml->userStylesheetEnabled() );
434447
mStylesheetEditor->setText( mHtml->userStylesheet() );
435448

449+
mEmptyFrameCheckBox->setChecked( mFrame->hidePageIfEmpty() );
450+
436451
populateDataDefinedButtons();
437452

438453
blockSignals( false );

‎src/app/composer/qgscomposerhtmlwidget.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ class QgsComposerHtmlWidget: public QgsComposerItemBaseWidget, private Ui::QgsCo
4747
void on_mReloadPushButton_clicked();
4848
void on_mReloadPushButton2_clicked();
4949
void on_mAddFramePushButton_clicked();
50+
void on_mEmptyFrameCheckBox_toggled( bool checked );
5051

5152
/**Sets the GUI elements to the values of mHtmlItem*/
5253
void setGuiElementValues();

‎src/core/composer/qgscomposerattributetablev2.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -780,7 +780,6 @@ void QgsComposerAttributeTableV2::addFrame( QgsComposerFrame *frame, bool recalc
780780

781781
if ( recalcFrameSizes )
782782
{
783-
784783
recalculateFrameSizes();
785784
}
786785
}

‎src/core/composer/qgscomposerframe.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
QgsComposerFrame::QgsComposerFrame( QgsComposition* c, QgsComposerMultiFrame* mf, qreal x, qreal y, qreal width, qreal height )
2121
: QgsComposerItem( x, y, width, height, c )
2222
, mMultiFrame( mf )
23+
, mHidePageIfEmpty( false )
2324
{
2425
//repaint frame when multiframe content changes
2526
connect( mf, SIGNAL( contentsChanged() ), this, SLOT( repaint() ) );
@@ -33,6 +34,7 @@ QgsComposerFrame::QgsComposerFrame( QgsComposition* c, QgsComposerMultiFrame* mf
3334
QgsComposerFrame::QgsComposerFrame()
3435
: QgsComposerItem( 0, 0, 0, 0, 0 )
3536
, mMultiFrame( 0 )
37+
, mHidePageIfEmpty( false )
3638
{
3739
}
3840

@@ -47,6 +49,8 @@ bool QgsComposerFrame::writeXML( QDomElement& elem, QDomDocument & doc ) const
4749
frameElem.setAttribute( "sectionY", QString::number( mSection.y() ) );
4850
frameElem.setAttribute( "sectionWidth", QString::number( mSection.width() ) );
4951
frameElem.setAttribute( "sectionHeight", QString::number( mSection.height() ) );
52+
frameElem.setAttribute( "hidePageIfEmpty", mHidePageIfEmpty );
53+
5054
elem.appendChild( frameElem );
5155

5256
return _writeXML( frameElem, doc );
@@ -59,6 +63,7 @@ bool QgsComposerFrame::readXML( const QDomElement& itemElem, const QDomDocument&
5963
double width = itemElem.attribute( "sectionWidth" ).toDouble();
6064
double height = itemElem.attribute( "sectionHeight" ).toDouble();
6165
mSection = QRectF( x, y, width, height );
66+
mHidePageIfEmpty = itemElem.attribute( "hidePageIfEmpty", "0" ).toInt();
6267
QDomElement composerItem = itemElem.firstChildElement( "ComposerItem" );
6368
if ( composerItem.isNull() )
6469
{
@@ -67,6 +72,29 @@ bool QgsComposerFrame::readXML( const QDomElement& itemElem, const QDomDocument&
6772
return _readXML( composerItem, doc );
6873
}
6974

75+
void QgsComposerFrame::setHidePageIfEmpty( const bool hidePageIfEmpty )
76+
{
77+
mHidePageIfEmpty = hidePageIfEmpty;
78+
}
79+
80+
bool QgsComposerFrame::isEmpty() const
81+
{
82+
if ( !mMultiFrame )
83+
{
84+
return true;
85+
}
86+
87+
double multiFrameHeight = mMultiFrame->totalSize().height();
88+
if ( multiFrameHeight <= mSection.top() )
89+
{
90+
//multiframe height is less than top of this frame's visible portion
91+
return true;
92+
}
93+
94+
return false;
95+
96+
}
97+
7098
QString QgsComposerFrame::displayName() const
7199
{
72100
if ( !id().isEmpty() )

‎src/core/composer/qgscomposerframe.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,34 @@ class CORE_EXPORT QgsComposerFrame: public QgsComposerItem
6464
*/
6565
QRectF extent() const { return mSection; }
6666

67+
/**Returns whether the page should be hidden (ie, not included in composer exports) if this frame is empty
68+
* @returns true if page should be hidden if frame is empty
69+
* @note added in QGIS 2.5
70+
* @see setHidePageIfEmpty
71+
*/
72+
bool hidePageIfEmpty() const { return mHidePageIfEmpty; }
73+
74+
/**Sets whether the page should be hidden (ie, not included in composer exports) if this frame is empty
75+
* @param hidePageIfEmpty set to true if page should be hidden if frame is empty
76+
* @note added in QGIS 2.5
77+
* @see hidePageIfEmpty
78+
*/
79+
void setHidePageIfEmpty( const bool hidePageIfEmpty );
80+
81+
/**Returns whether the frame is empty
82+
* @returns true if frame is empty
83+
* @note added in QGIS 2.5
84+
* @see hidePageIfEmpty
85+
*/
86+
bool isEmpty() const;
87+
6788
private:
6889
QgsComposerFrame(); //forbidden
6990
QgsComposerMultiFrame* mMultiFrame;
7091
QRectF mSection;
92+
93+
/**if true, composition will not export page if this frame is empty*/
94+
bool mHidePageIfEmpty;
7195
};
7296

7397
#endif // QGSCOMPOSERFRAME_H

‎src/core/composer/qgscomposerhtml.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,10 @@ void QgsComposerHtml::loadHtml()
173173
}
174174

175175
mLoaded = false;
176+
177+
//reset page size. otherwise viewport size increases but never decreases again
178+
mWebPage->setViewportSize( QSize( 0, 0 ) );
179+
176180
//set html, using the specified url as base if in Url mode
177181
mWebPage->mainFrame()->setHtml( loadedHtml, mContentMode == QgsComposerHtml::Url ? QUrl( mActualFetchedUrl ) : QUrl() );
178182

‎src/core/composer/qgscomposertablev2.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -684,8 +684,10 @@ double QgsComposerTableV2::totalHeight() const
684684
double heightOfLastFrame = 0;
685685
for ( int idx = 0; idx < numberExistingFrames; ++idx )
686686
{
687-
rowsVisibleInLastFrame = rowsVisible( idx );
687+
bool hasHeader = (( mHeaderMode == QgsComposerTableV2::FirstFrame && idx == 0 )
688+
|| ( mHeaderMode == QgsComposerTableV2::AllFrames ) );
688689
heightOfLastFrame = frame( idx )->rect().height();
690+
rowsVisibleInLastFrame = rowsVisible( heightOfLastFrame, hasHeader );
689691
rowsAlreadyShown += rowsVisibleInLastFrame;
690692
height += heightOfLastFrame;
691693
if ( rowsAlreadyShown >= mTableContents.length() )

0 commit comments

Comments
 (0)
Please sign in to comment.