Skip to content

Commit

Permalink
[FEATURE][composer] Add checkbox to frame items for preventing export
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
nyalldawson committed Sep 25, 2014
1 parent b8bb4f0 commit 272b79b
Show file tree
Hide file tree
Showing 20 changed files with 628 additions and 35 deletions.
21 changes: 21 additions & 0 deletions python/core/composer/qgscomposerframe.sip
Expand Up @@ -41,5 +41,26 @@ class QgsComposerFrame: QgsComposerItem
* @see setContentSection
*/
QRectF extent() const;

/**Returns whether the page should be hidden (ie, not included in composer exports) if this frame is empty
* @returns true if page should be hidden if frame is empty
* @note added in QGIS 2.5
* @see setHidePageIfEmpty
*/
bool hidePageIfEmpty() const;

/**Sets whether the page should be hidden (ie, not included in composer exports) if this frame is empty
* @param hidePageIfEmpty set to true if page should be hidden if frame is empty
* @note added in QGIS 2.5
* @see hidePageIfEmpty
*/
void setHidePageIfEmpty( const bool hidePageIfEmpty );

/**Returns whether the frame is empty
* @returns true if frame is empty
* @note added in QGIS 2.5
* @see hidePageIfEmpty
*/
bool isEmpty() const;

};
48 changes: 44 additions & 4 deletions python/core/composer/qgscomposition.sip
Expand Up @@ -56,22 +56,54 @@ class QgsComposition : QGraphicsScene

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

/**Returns height of paper item*/
/**Height of paper item
* @returns height in mm
* @see paperWidth
* @see setPaperSize
*/
double paperHeight() const;

/**Returns width of paper item*/
/**Width of paper item
* @returns width in mm
* @see paperHeight
* @see setPaperSize
*/
double paperWidth() const;

/**Returns the vertical space between pages in a composer view
* @returns space between pages in mm
*/
double spaceBetweenPages() const;

/**Note: added in version 1.9*/
/**Sets the number of pages for the composition.
* @param pages number of pages
* @note added in version 1.9
* @see numPages
*/
void setNumPages( const int pages );
/**Note: added in version 1.9*/

/**Returns the number of pages in the composition.
* @returns number of pages
* @note added in version 1.9
* @see setNumPages
*/
int numPages() const;

/**Returns whether a specified page number should be included in exports of the composition.
* @param page page number, starting with 1
* @returns true if page should be exported
* @note added in QGIS 2.5
* @see numPages
*/
bool shouldExportPage( const int page ) const;

/**Note: added in version 2.1*/
void setPageStyleSymbol( QgsFillSymbolV2* symbol /Transfer/ );
/**Note: added in version 2.1*/
Expand Down Expand Up @@ -220,6 +252,14 @@ class QgsComposition : QGraphicsScene
@note not available in python bindings
*/
// template<class T> void composerItems( QList<T*>& itemList );

/**Return composer items of a specific type on a specified page
* @param itemList list of item type to store matching items in
* @param pageNumber page number (0 based)
* @note not available in python bindings
* @note added in QGIS 2.5
*/
//template<class T> void composerItemsOnPage( QList<T*>& itemList, const int pageNumber );

/**Returns the composer map with specified id
@return QgsComposerMap or 0 pointer if the composer map item does not exist*/
Expand Down
16 changes: 16 additions & 0 deletions src/app/composer/qgscomposer.cpp
Expand Up @@ -1739,6 +1739,10 @@ void QgsComposer::exportCompositionAsImage( QgsComposer::OutputMode mode )

for ( int i = 0; i < mComposition->numPages(); ++i )
{
if ( !mComposition->shouldExportPage( i + 1 ) )
{
continue;
}
QImage image = mComposition->printPageAsRaster( i );
if ( image.isNull() )
{
Expand Down Expand Up @@ -1912,6 +1916,10 @@ void QgsComposer::exportCompositionAsImage( QgsComposer::OutputMode mode )

for ( int i = 0; i < mComposition->numPages(); ++i )
{
if ( !mComposition->shouldExportPage( i + 1 ) )
{
continue;
}
QImage image = mComposition->printPageAsRaster( i );
QString imageFilename = filename;

Expand Down Expand Up @@ -2187,6 +2195,10 @@ void QgsComposer::exportCompositionAsSVG( QgsComposer::OutputMode mode )
{
for ( int i = 0; i < mComposition->numPages(); ++i )
{
if ( !mComposition->shouldExportPage( i + 1 ) )
{
continue;
}
QSvgGenerator generator;
generator.setTitle( QgsProject::instance()->title() );
QString currentFileName = outputFileName;
Expand Down Expand Up @@ -2234,6 +2246,10 @@ void QgsComposer::exportCompositionAsSVG( QgsComposer::OutputMode mode )

for ( int i = 0; i < mComposition->numPages(); ++i )
{
if ( !mComposition->shouldExportPage( i + 1 ) )
{
continue;
}
QDomDocument svg;
QDomNode svgDocRoot;
QgsPaperItem * paperItem = paperItems[i];
Expand Down
29 changes: 25 additions & 4 deletions src/app/composer/qgscomposerattributetablewidget.cpp
Expand Up @@ -37,9 +37,6 @@ QgsComposerAttributeTableWidget::QgsComposerAttributeTableWidget( QgsComposerAtt
, mFrame( frame )
{
setupUi( this );
//add widget for general composer item properties
QgsComposerItemWidget* itemPropertiesWidget = new QgsComposerItemWidget( this, mFrame );
mainLayout->addWidget( itemPropertiesWidget );

blockAllSignals( true );

Expand Down Expand Up @@ -90,6 +87,14 @@ QgsComposerAttributeTableWidget::QgsComposerAttributeTableWidget( QgsComposerAtt
connect( atlas, SIGNAL( toggled( bool ) ), this, SLOT( atlasToggled() ) );
}
}

//embed widget for general options
if ( mFrame )
{
//add widget for general composer item properties
QgsComposerItemWidget* itemPropertiesWidget = new QgsComposerItemWidget( this, mFrame );
mainLayout->addWidget( itemPropertiesWidget );
}
}

QgsComposerAttributeTableWidget::~QgsComposerAttributeTableWidget()
Expand Down Expand Up @@ -509,6 +514,8 @@ void QgsComposerAttributeTableWidget::updateGuiElements()
mResizeModeComboBox->setCurrentIndex( mResizeModeComboBox->findData( mComposerTable->resizeMode() ) );
mAddFramePushButton->setEnabled( mComposerTable->resizeMode() == QgsComposerMultiFrame::UseExistingFrames );

mEmptyFrameCheckBox->setChecked( mFrame->hidePageIfEmpty() );

toggleSourceControls();

blockAllSignals( false );
Expand Down Expand Up @@ -539,7 +546,7 @@ void QgsComposerAttributeTableWidget::updateRelationsCombo()
if ( atlasLayer )
{
QList<QgsRelation> relations = QgsProject::instance()->relationManager()->referencedRelations( mComposerTable->composition()->atlasComposition().coverageLayer() );
Q_FOREACH( const QgsRelation& relation, relations )
Q_FOREACH ( const QgsRelation& relation, relations )
{
mRelationsComboBox->addItem( relation.name(), relation.id() );
}
Expand Down Expand Up @@ -608,6 +615,7 @@ void QgsComposerAttributeTableWidget::blockAllSignals( bool b )
mRelationsComboBox->blockSignals( b );
mEmptyModeComboBox->blockSignals( b );
mEmptyMessageLineEdit->blockSignals( b );
mEmptyFrameCheckBox->blockSignals( b );
}

void QgsComposerAttributeTableWidget::setMaximumNumberOfFeatures( int n )
Expand Down Expand Up @@ -662,6 +670,19 @@ void QgsComposerAttributeTableWidget::on_mUniqueOnlyCheckBox_stateChanged( int s
}
}


void QgsComposerAttributeTableWidget::on_mEmptyFrameCheckBox_toggled( bool checked )
{
if ( !mFrame )
{
return;
}

mFrame->beginCommand( tr( "Empty frame mode toggled" ) );
mFrame->setHidePageIfEmpty( checked );
mFrame->endCommand();
}

void QgsComposerAttributeTableWidget::on_mIntersectAtlasCheckBox_stateChanged( int state )
{
if ( !mComposerTable )
Expand Down
1 change: 1 addition & 0 deletions src/app/composer/qgscomposerattributetablewidget.h
Expand Up @@ -74,6 +74,7 @@ class QgsComposerAttributeTableWidget: public QgsComposerItemBaseWidget, private
void on_mEmptyMessageLineEdit_editingFinished();
void on_mIntersectAtlasCheckBox_stateChanged( int state );
void on_mUniqueOnlyCheckBox_stateChanged( int state );
void on_mEmptyFrameCheckBox_toggled( bool checked );

/**Inserts a new maximum number of features into the spin box (without the spinbox emitting a signal)*/
void setMaximumNumberOfFeatures( int n );
Expand Down
15 changes: 15 additions & 0 deletions src/app/composer/qgscomposerhtmlwidget.cpp
Expand Up @@ -100,6 +100,7 @@ void QgsComposerHtmlWidget::blockSignals( bool block )
mRadioManualSource->blockSignals( block );
mRadioUrlSource->blockSignals( block );
mEvaluateExpressionsCheckbox->blockSignals( block );
mEmptyFrameCheckBox->blockSignals( block );
}

void QgsComposerHtmlWidget::on_mUrlLineEdit_editingFinished()
Expand Down Expand Up @@ -265,6 +266,18 @@ void QgsComposerHtmlWidget::on_mUserStylesheetCheckBox_toggled( bool checked )
}
}

void QgsComposerHtmlWidget::on_mEmptyFrameCheckBox_toggled( bool checked )
{
if ( !mFrame )
{
return;
}

mFrame->beginCommand( tr( "Empty frame mode toggled" ) );
mFrame->setHidePageIfEmpty( checked );
mFrame->endCommand();
}

void QgsComposerHtmlWidget::on_mRadioManualSource_clicked( bool checked )
{
if ( !mHtml )
Expand Down Expand Up @@ -433,6 +446,8 @@ void QgsComposerHtmlWidget::setGuiElementValues()
mUserStylesheetCheckBox->setChecked( mHtml->userStylesheetEnabled() );
mStylesheetEditor->setText( mHtml->userStylesheet() );

mEmptyFrameCheckBox->setChecked( mFrame->hidePageIfEmpty() );

populateDataDefinedButtons();

blockSignals( false );
Expand Down
1 change: 1 addition & 0 deletions src/app/composer/qgscomposerhtmlwidget.h
Expand Up @@ -47,6 +47,7 @@ class QgsComposerHtmlWidget: public QgsComposerItemBaseWidget, private Ui::QgsCo
void on_mReloadPushButton_clicked();
void on_mReloadPushButton2_clicked();
void on_mAddFramePushButton_clicked();
void on_mEmptyFrameCheckBox_toggled( bool checked );

/**Sets the GUI elements to the values of mHtmlItem*/
void setGuiElementValues();
Expand Down
1 change: 0 additions & 1 deletion src/core/composer/qgscomposerattributetablev2.cpp
Expand Up @@ -780,7 +780,6 @@ void QgsComposerAttributeTableV2::addFrame( QgsComposerFrame *frame, bool recalc

if ( recalcFrameSizes )
{

recalculateFrameSizes();
}
}
Expand Down
28 changes: 28 additions & 0 deletions src/core/composer/qgscomposerframe.cpp
Expand Up @@ -20,6 +20,7 @@
QgsComposerFrame::QgsComposerFrame( QgsComposition* c, QgsComposerMultiFrame* mf, qreal x, qreal y, qreal width, qreal height )
: QgsComposerItem( x, y, width, height, c )
, mMultiFrame( mf )
, mHidePageIfEmpty( false )
{
//repaint frame when multiframe content changes
connect( mf, SIGNAL( contentsChanged() ), this, SLOT( repaint() ) );
Expand All @@ -33,6 +34,7 @@ QgsComposerFrame::QgsComposerFrame( QgsComposition* c, QgsComposerMultiFrame* mf
QgsComposerFrame::QgsComposerFrame()
: QgsComposerItem( 0, 0, 0, 0, 0 )
, mMultiFrame( 0 )
, mHidePageIfEmpty( false )
{
}

Expand All @@ -47,6 +49,8 @@ bool QgsComposerFrame::writeXML( QDomElement& elem, QDomDocument & doc ) const
frameElem.setAttribute( "sectionY", QString::number( mSection.y() ) );
frameElem.setAttribute( "sectionWidth", QString::number( mSection.width() ) );
frameElem.setAttribute( "sectionHeight", QString::number( mSection.height() ) );
frameElem.setAttribute( "hidePageIfEmpty", mHidePageIfEmpty );

elem.appendChild( frameElem );

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

void QgsComposerFrame::setHidePageIfEmpty( const bool hidePageIfEmpty )
{
mHidePageIfEmpty = hidePageIfEmpty;
}

bool QgsComposerFrame::isEmpty() const
{
if ( !mMultiFrame )
{
return true;
}

double multiFrameHeight = mMultiFrame->totalSize().height();
if ( multiFrameHeight <= mSection.top() )
{
//multiframe height is less than top of this frame's visible portion
return true;
}

return false;

}

QString QgsComposerFrame::displayName() const
{
if ( !id().isEmpty() )
Expand Down
24 changes: 24 additions & 0 deletions src/core/composer/qgscomposerframe.h
Expand Up @@ -64,10 +64,34 @@ class CORE_EXPORT QgsComposerFrame: public QgsComposerItem
*/
QRectF extent() const { return mSection; }

/**Returns whether the page should be hidden (ie, not included in composer exports) if this frame is empty
* @returns true if page should be hidden if frame is empty
* @note added in QGIS 2.5
* @see setHidePageIfEmpty
*/
bool hidePageIfEmpty() const { return mHidePageIfEmpty; }

/**Sets whether the page should be hidden (ie, not included in composer exports) if this frame is empty
* @param hidePageIfEmpty set to true if page should be hidden if frame is empty
* @note added in QGIS 2.5
* @see hidePageIfEmpty
*/
void setHidePageIfEmpty( const bool hidePageIfEmpty );

/**Returns whether the frame is empty
* @returns true if frame is empty
* @note added in QGIS 2.5
* @see hidePageIfEmpty
*/
bool isEmpty() const;

private:
QgsComposerFrame(); //forbidden
QgsComposerMultiFrame* mMultiFrame;
QRectF mSection;

/**if true, composition will not export page if this frame is empty*/
bool mHidePageIfEmpty;
};

#endif // QGSCOMPOSERFRAME_H
4 changes: 4 additions & 0 deletions src/core/composer/qgscomposerhtml.cpp
Expand Up @@ -173,6 +173,10 @@ void QgsComposerHtml::loadHtml()
}

mLoaded = false;

//reset page size. otherwise viewport size increases but never decreases again
mWebPage->setViewportSize( QSize( 0, 0 ) );

//set html, using the specified url as base if in Url mode
mWebPage->mainFrame()->setHtml( loadedHtml, mContentMode == QgsComposerHtml::Url ? QUrl( mActualFetchedUrl ) : QUrl() );

Expand Down
4 changes: 3 additions & 1 deletion src/core/composer/qgscomposertablev2.cpp
Expand Up @@ -684,8 +684,10 @@ double QgsComposerTableV2::totalHeight() const
double heightOfLastFrame = 0;
for ( int idx = 0; idx < numberExistingFrames; ++idx )
{
rowsVisibleInLastFrame = rowsVisible( idx );
bool hasHeader = (( mHeaderMode == QgsComposerTableV2::FirstFrame && idx == 0 )
|| ( mHeaderMode == QgsComposerTableV2::AllFrames ) );
heightOfLastFrame = frame( idx )->rect().height();
rowsVisibleInLastFrame = rowsVisible( heightOfLastFrame, hasHeader );
rowsAlreadyShown += rowsVisibleInLastFrame;
height += heightOfLastFrame;
if ( rowsAlreadyShown >= mTableContents.length() )
Expand Down

0 comments on commit 272b79b

Please sign in to comment.