mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-15 00:04:00 -04:00
[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.
This commit is contained in:
parent
b8bb4f0fe0
commit
272b79b6ca
@ -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;
|
||||
|
||||
};
|
||||
|
@ -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*/
|
||||
@ -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*/
|
||||
|
@ -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() )
|
||||
{
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
@ -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];
|
||||
|
@ -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 );
|
||||
|
||||
@ -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()
|
||||
@ -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 );
|
||||
@ -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() );
|
||||
}
|
||||
@ -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 )
|
||||
@ -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 )
|
||||
|
@ -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 );
|
||||
|
@ -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()
|
||||
@ -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 )
|
||||
@ -433,6 +446,8 @@ void QgsComposerHtmlWidget::setGuiElementValues()
|
||||
mUserStylesheetCheckBox->setChecked( mHtml->userStylesheetEnabled() );
|
||||
mStylesheetEditor->setText( mHtml->userStylesheet() );
|
||||
|
||||
mEmptyFrameCheckBox->setChecked( mFrame->hidePageIfEmpty() );
|
||||
|
||||
populateDataDefinedButtons();
|
||||
|
||||
blockSignals( false );
|
||||
|
@ -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();
|
||||
|
@ -780,7 +780,6 @@ void QgsComposerAttributeTableV2::addFrame( QgsComposerFrame *frame, bool recalc
|
||||
|
||||
if ( recalcFrameSizes )
|
||||
{
|
||||
|
||||
recalculateFrameSizes();
|
||||
}
|
||||
}
|
||||
|
@ -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() ) );
|
||||
@ -33,6 +34,7 @@ QgsComposerFrame::QgsComposerFrame( QgsComposition* c, QgsComposerMultiFrame* mf
|
||||
QgsComposerFrame::QgsComposerFrame()
|
||||
: QgsComposerItem( 0, 0, 0, 0, 0 )
|
||||
, mMultiFrame( 0 )
|
||||
, mHidePageIfEmpty( false )
|
||||
{
|
||||
}
|
||||
|
||||
@ -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 );
|
||||
@ -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() )
|
||||
{
|
||||
@ -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() )
|
||||
|
@ -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
|
||||
|
@ -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() );
|
||||
|
||||
|
@ -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() )
|
||||
|
@ -416,6 +416,30 @@ int QgsComposition::numPages() const
|
||||
return mPages.size();
|
||||
}
|
||||
|
||||
bool QgsComposition::shouldExportPage( const int page ) const
|
||||
{
|
||||
if ( page > numPages() || page < 1 )
|
||||
{
|
||||
//page number out of range
|
||||
return false;
|
||||
}
|
||||
|
||||
//check all frame items on page
|
||||
QList<QgsComposerFrame*> frames;
|
||||
//composerItemsOnPage uses 0 based page numbering
|
||||
composerItemsOnPage( frames, page - 1 );
|
||||
QList<QgsComposerFrame*>::const_iterator frameIt = frames.constBegin();
|
||||
for ( ; frameIt != frames.constEnd(); ++frameIt )
|
||||
{
|
||||
if (( *frameIt )->hidePageIfEmpty() && ( *frameIt )->isEmpty() )
|
||||
{
|
||||
//frame is set to hide page if empty, and frame is empty, so we don't want to export this page
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void QgsComposition::setPageStyleSymbol( QgsFillSymbolV2* symbol )
|
||||
{
|
||||
delete mPageStyleSymbol;
|
||||
@ -2545,11 +2569,16 @@ void QgsComposition::doPrint( QPrinter& printer, QPainter& p, bool startNewPage
|
||||
int fromPage = ( printer.fromPage() < 1 ) ? 0 : printer.fromPage() - 1 ;
|
||||
int toPage = ( printer.toPage() < 1 ) ? numPages() - 1 : printer.toPage() - 1;
|
||||
|
||||
bool pageExported = false;
|
||||
if ( mPrintAsRaster )
|
||||
{
|
||||
for ( int i = fromPage; i <= toPage; ++i )
|
||||
{
|
||||
if ( i > fromPage || startNewPage )
|
||||
if ( !shouldExportPage( i + 1 ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (( pageExported && i > fromPage ) || startNewPage )
|
||||
{
|
||||
printer.newPage();
|
||||
}
|
||||
@ -2560,6 +2589,7 @@ void QgsComposition::doPrint( QPrinter& printer, QPainter& p, bool startNewPage
|
||||
QRectF targetArea( 0, 0, image.width(), image.height() );
|
||||
p.drawImage( targetArea, image, targetArea );
|
||||
}
|
||||
pageExported = true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2567,11 +2597,16 @@ void QgsComposition::doPrint( QPrinter& printer, QPainter& p, bool startNewPage
|
||||
{
|
||||
for ( int i = fromPage; i <= toPage; ++i )
|
||||
{
|
||||
if ( i > fromPage || startNewPage )
|
||||
if ( !shouldExportPage( i + 1 ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (( pageExported && i > fromPage ) || startNewPage )
|
||||
{
|
||||
printer.newPage();
|
||||
}
|
||||
renderPage( &p, i );
|
||||
pageExported = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -118,22 +118,54 @@ class CORE_EXPORT QgsComposition : public 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 { return mSpaceBetweenPages; }
|
||||
|
||||
/**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 );
|
||||
/**Note: added in version 2.1*/
|
||||
@ -277,10 +309,19 @@ class CORE_EXPORT QgsComposition : public QGraphicsScene
|
||||
QList<const QgsComposerMap*> composerMapItems() const;
|
||||
|
||||
/**Return composer items of a specific type
|
||||
@note not available in python bindings
|
||||
* @param itemList list of item type to store matching items in
|
||||
* @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 ) const;
|
||||
|
||||
/**Returns the composer map with specified id
|
||||
@return QgsComposerMap or 0 pointer if the composer map item does not exist*/
|
||||
const QgsComposerMap* getComposerMapById( const int id ) const;
|
||||
@ -823,6 +864,22 @@ template<class T> void QgsComposition::composerItems( QList<T*>& itemList )
|
||||
}
|
||||
}
|
||||
|
||||
template<class T> void QgsComposition::composerItemsOnPage( QList<T*>& itemList, const int pageNumber ) const
|
||||
{
|
||||
itemList.clear();
|
||||
QList<QGraphicsItem *> graphicsItemList = items();
|
||||
QList<QGraphicsItem *>::iterator itemIt = graphicsItemList.begin();
|
||||
for ( ; itemIt != graphicsItemList.end(); ++itemIt )
|
||||
{
|
||||
T* item = dynamic_cast<T*>( *itemIt );
|
||||
if ( item && itemPageNumber( item ) == pageNumber )
|
||||
{
|
||||
itemList.push_back( item );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -45,9 +45,9 @@
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<y>-312</y>
|
||||
<width>392</width>
|
||||
<height>1076</height>
|
||||
<height>1104</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="mainLayout">
|
||||
@ -541,6 +541,13 @@
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_3">
|
||||
<item row="1" column="0" colspan="2">
|
||||
<widget class="QPushButton" name="mAddFramePushButton">
|
||||
<property name="text">
|
||||
<string>Add Frame</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="mResizeModeLabel">
|
||||
<property name="text">
|
||||
@ -561,10 +568,10 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="2">
|
||||
<widget class="QPushButton" name="mAddFramePushButton">
|
||||
<item row="2" column="0" colspan="2">
|
||||
<widget class="QCheckBox" name="mEmptyFrameCheckBox">
|
||||
<property name="text">
|
||||
<string>Add Frame</string>
|
||||
<string>Don't export page if frame is empty</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -581,7 +588,7 @@
|
||||
<customwidget>
|
||||
<class>QgsCollapsibleGroupBoxBasic</class>
|
||||
<extends>QGroupBox</extends>
|
||||
<header location="global">qgscollapsiblegroupbox.h</header>
|
||||
<header>qgscollapsiblegroupbox.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
|
@ -45,9 +45,9 @@
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>-101</y>
|
||||
<y>-10</y>
|
||||
<width>391</width>
|
||||
<height>461</height>
|
||||
<height>489</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="mainLayout">
|
||||
@ -173,6 +173,13 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0" colspan="2">
|
||||
<widget class="QCheckBox" name="mEmptyFrameCheckBox">
|
||||
<property name="text">
|
||||
<string>Don't export page if frame is empty</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
|
@ -107,6 +107,8 @@ ADD_QGIS_TEST(ziplayertest testziplayer.cpp)
|
||||
ADD_QGIS_TEST(dataitemtest testqgsdataitem.cpp)
|
||||
ADD_QGIS_TEST(composerobject testqgscomposerobject.cpp)
|
||||
ADD_QGIS_TEST(composerutils testqgscomposerutils.cpp)
|
||||
ADD_QGIS_TEST(compositiontest testqgscomposition.cpp)
|
||||
ADD_QGIS_TEST(composermultiframetest testqgscomposermultiframe.cpp)
|
||||
ADD_QGIS_TEST(composerpapertest testqgscomposerpaper.cpp)
|
||||
ADD_QGIS_TEST(composermaptest testqgscomposermap.cpp)
|
||||
ADD_QGIS_TEST(composermapgridtest testqgscomposermapgrid.cpp)
|
||||
|
107
tests/src/core/testqgscomposermultiframe.cpp
Normal file
107
tests/src/core/testqgscomposermultiframe.cpp
Normal file
@ -0,0 +1,107 @@
|
||||
/***************************************************************************
|
||||
testqgscomposermultiframe.cpp
|
||||
-----------------------
|
||||
begin : September 2014
|
||||
copyright : (C) 2014 by Nyall Dawson
|
||||
email : nyall dot dawson at gmail dot com
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "qgscomposerhtml.h"
|
||||
#include "qgscomposerframe.h"
|
||||
#include "qgscomposition.h"
|
||||
#include "qgscompositionchecker.h"
|
||||
#include <QObject>
|
||||
#include <QtTest>
|
||||
|
||||
class TestQgsComposerMultiFrame: public QObject
|
||||
{
|
||||
Q_OBJECT;
|
||||
private slots:
|
||||
void initTestCase();// will be called before the first testfunction is executed.
|
||||
void cleanupTestCase();// will be called after the last testfunction was executed.
|
||||
void init();// will be called before each testfunction is executed.
|
||||
void cleanup();// will be called after every testfunction.
|
||||
void frameIsEmpty(); //test if frame is empty works
|
||||
|
||||
private:
|
||||
QgsComposition* mComposition;
|
||||
QgsMapSettings mMapSettings;
|
||||
QString mReport;
|
||||
};
|
||||
|
||||
void TestQgsComposerMultiFrame::initTestCase()
|
||||
{
|
||||
mComposition = new QgsComposition( mMapSettings );
|
||||
mComposition->setPaperSize( 297, 210 ); //A4 landscape
|
||||
|
||||
mReport = "<h1>Composer MultiFrame Tests</h1>\n";
|
||||
}
|
||||
|
||||
void TestQgsComposerMultiFrame::cleanupTestCase()
|
||||
{
|
||||
delete mComposition;
|
||||
|
||||
QString myReportFile = QDir::tempPath() + QDir::separator() + "qgistest.html";
|
||||
QFile myFile( myReportFile );
|
||||
if ( myFile.open( QIODevice::WriteOnly | QIODevice::Append ) )
|
||||
{
|
||||
QTextStream myQTextStream( &myFile );
|
||||
myQTextStream << mReport;
|
||||
myFile.close();
|
||||
}
|
||||
}
|
||||
|
||||
void TestQgsComposerMultiFrame::init()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void TestQgsComposerMultiFrame::cleanup()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void TestQgsComposerMultiFrame::frameIsEmpty()
|
||||
{
|
||||
QgsComposerHtml* htmlItem = new QgsComposerHtml( mComposition, false );
|
||||
QgsComposerFrame* frame1 = new QgsComposerFrame( mComposition, htmlItem, 0, 0, 100, 200 );
|
||||
QgsComposerFrame* frame2 = new QgsComposerFrame( mComposition, htmlItem, 0, 0, 100, 200 );
|
||||
htmlItem->addFrame( frame1 );
|
||||
htmlItem->addFrame( frame2 );
|
||||
htmlItem->setContentMode( QgsComposerHtml::ManualHtml );
|
||||
//short content, so frame 2 should be empty
|
||||
htmlItem->setHtml( QString( "<p><i>Test manual <b>html</b></i></p>" ) );
|
||||
htmlItem->loadHtml();
|
||||
|
||||
QCOMPARE( frame1->isEmpty(), false );
|
||||
QCOMPARE( frame2->isEmpty(), true );
|
||||
|
||||
//long content, so frame 2 should not be empty
|
||||
htmlItem->setHtml( QString( "<p style=\"height: 10000px\"><i>Test manual <b>html</b></i></p>" ) );
|
||||
htmlItem->loadHtml();
|
||||
|
||||
QCOMPARE( frame1->isEmpty(), false );
|
||||
QCOMPARE( frame2->isEmpty(), false );
|
||||
|
||||
//..and back again..
|
||||
htmlItem->setHtml( QString( "<p><i>Test manual <b>html</b></i></p>" ) );
|
||||
htmlItem->loadHtml();
|
||||
|
||||
QCOMPARE( frame1->isEmpty(), false );
|
||||
QCOMPARE( frame2->isEmpty(), true );
|
||||
|
||||
mComposition->removeMultiFrame( htmlItem );
|
||||
delete htmlItem;
|
||||
}
|
||||
|
||||
QTEST_MAIN( TestQgsComposerMultiFrame )
|
||||
#include "moc_testqgscomposermultiframe.cxx"
|
216
tests/src/core/testqgscomposition.cpp
Normal file
216
tests/src/core/testqgscomposition.cpp
Normal file
@ -0,0 +1,216 @@
|
||||
/***************************************************************************
|
||||
testqgscomposition.cpp
|
||||
----------------------
|
||||
begin : September 2014
|
||||
copyright : (C) 2014 by Nyall Dawson
|
||||
email : nyall dot dawson at gmail dot com
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "qgsapplication.h"
|
||||
#include "qgscomposition.h"
|
||||
#include "qgscomposerlabel.h"
|
||||
#include "qgscomposershape.h"
|
||||
#include "qgscomposerarrow.h"
|
||||
#include "qgscomposerhtml.h"
|
||||
#include "qgscomposerframe.h"
|
||||
#include "qgsmapsettings.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QtTest>
|
||||
|
||||
class TestQgsComposition: public QObject
|
||||
{
|
||||
Q_OBJECT;
|
||||
|
||||
private slots:
|
||||
void initTestCase();// will be called before the first testfunction is executed.
|
||||
void cleanupTestCase();// will be called after the last testfunction was executed.
|
||||
void init();// will be called before each testfunction is executed.
|
||||
void cleanup();// will be called after every testfunction.
|
||||
|
||||
void itemsOnPage(); //test fetching matching items on a set page
|
||||
void shouldExportPage(); //test the shouldExportPage method
|
||||
|
||||
private:
|
||||
QgsComposition* mComposition;
|
||||
QgsMapSettings mMapSettings;
|
||||
QString mReport;
|
||||
};
|
||||
|
||||
void TestQgsComposition::initTestCase()
|
||||
{
|
||||
QgsApplication::init();
|
||||
QgsApplication::initQgis();
|
||||
|
||||
//create composition
|
||||
mMapSettings.setCrsTransformEnabled( true );
|
||||
mMapSettings.setMapUnits( QGis::Meters );
|
||||
mComposition = new QgsComposition( mMapSettings );
|
||||
mComposition->setPaperSize( 297, 210 ); //A4 landscape
|
||||
mComposition->setNumPages( 3 );
|
||||
|
||||
mReport = "<h1>Composition Tests</h1>\n";
|
||||
|
||||
}
|
||||
|
||||
void TestQgsComposition::cleanupTestCase()
|
||||
{
|
||||
delete mComposition;
|
||||
|
||||
QString myReportFile = QDir::tempPath() + QDir::separator() + "qgistest.html";
|
||||
QFile myFile( myReportFile );
|
||||
if ( myFile.open( QIODevice::WriteOnly | QIODevice::Append ) )
|
||||
{
|
||||
QTextStream myQTextStream( &myFile );
|
||||
myQTextStream << mReport;
|
||||
myFile.close();
|
||||
}
|
||||
}
|
||||
|
||||
void TestQgsComposition::init()
|
||||
{
|
||||
}
|
||||
|
||||
void TestQgsComposition::cleanup()
|
||||
{
|
||||
}
|
||||
|
||||
void TestQgsComposition::itemsOnPage()
|
||||
{
|
||||
//add some items to the composition
|
||||
QgsComposerLabel* label1 = new QgsComposerLabel( mComposition );
|
||||
mComposition->addComposerLabel( label1 );
|
||||
label1->setItemPosition( 10, 10, 50, 50, QgsComposerItem::UpperLeft, false, 1 );
|
||||
QgsComposerLabel* label2 = new QgsComposerLabel( mComposition );
|
||||
mComposition->addComposerLabel( label2 );
|
||||
label2->setItemPosition( 10, 10, 50, 50, QgsComposerItem::UpperLeft, false, 1 );
|
||||
QgsComposerLabel* label3 = new QgsComposerLabel( mComposition );
|
||||
mComposition->addComposerLabel( label3 );
|
||||
label3->setItemPosition( 10, 10, 50, 50, QgsComposerItem::UpperLeft, false, 2 );
|
||||
QgsComposerShape* shape1 = new QgsComposerShape( mComposition );
|
||||
mComposition->addComposerShape( shape1 );
|
||||
shape1->setItemPosition( 10, 10, 50, 50, QgsComposerItem::UpperLeft, false, 1 );
|
||||
QgsComposerShape* shape2 = new QgsComposerShape( mComposition );
|
||||
mComposition->addComposerShape( shape2 );
|
||||
shape2->setItemPosition( 10, 10, 50, 50, QgsComposerItem::UpperLeft, false, 2 );
|
||||
QgsComposerArrow* arrow1 = new QgsComposerArrow( mComposition );
|
||||
mComposition->addComposerArrow( arrow1 );
|
||||
arrow1->setItemPosition( 10, 10, 50, 50, QgsComposerItem::UpperLeft, false, 3 );
|
||||
QgsComposerArrow* arrow2 = new QgsComposerArrow( mComposition );
|
||||
mComposition->addComposerArrow( arrow2 );
|
||||
arrow2->setItemPosition( 10, 10, 50, 50, QgsComposerItem::UpperLeft, false, 3 );
|
||||
|
||||
//fetch items - remember that these numbers include the paper item!
|
||||
QList<QgsComposerItem*> items;
|
||||
mComposition->composerItemsOnPage( items, 0 );
|
||||
//should be 4 items on page 1
|
||||
QCOMPARE( items.length(), 4 );
|
||||
mComposition->composerItemsOnPage( items, 1 );
|
||||
//should be 3 items on page 2
|
||||
QCOMPARE( items.length(), 3 );
|
||||
mComposition->composerItemsOnPage( items, 2 );
|
||||
//should be 3 items on page 3
|
||||
QCOMPARE( items.length(), 3 );
|
||||
|
||||
//check fetching specific item types
|
||||
QList<QgsComposerLabel*> labels;
|
||||
mComposition->composerItemsOnPage( labels, 0 );
|
||||
//should be 2 labels on page 1
|
||||
QCOMPARE( labels.length(), 2 );
|
||||
mComposition->composerItemsOnPage( labels, 1 );
|
||||
//should be 1 label on page 2
|
||||
QCOMPARE( labels.length(), 1 );
|
||||
mComposition->composerItemsOnPage( labels, 2 );
|
||||
//should be no label on page 3
|
||||
QCOMPARE( labels.length(), 0 );
|
||||
|
||||
QList<QgsComposerShape*> shapes;
|
||||
mComposition->composerItemsOnPage( shapes, 0 );
|
||||
//should be 1 shapes on page 1
|
||||
QCOMPARE( shapes.length(), 1 );
|
||||
mComposition->composerItemsOnPage( shapes, 1 );
|
||||
//should be 1 shapes on page 2
|
||||
QCOMPARE( shapes.length(), 1 );
|
||||
mComposition->composerItemsOnPage( shapes, 2 );
|
||||
//should be no shapes on page 3
|
||||
QCOMPARE( shapes.length(), 0 );
|
||||
|
||||
QList<QgsComposerArrow*> arrows;
|
||||
mComposition->composerItemsOnPage( arrows, 0 );
|
||||
//should be no arrows on page 1
|
||||
QCOMPARE( arrows.length(), 0 );
|
||||
mComposition->composerItemsOnPage( arrows, 1 );
|
||||
//should be no arrows on page 2
|
||||
QCOMPARE( arrows.length(), 0 );
|
||||
mComposition->composerItemsOnPage( arrows, 2 );
|
||||
//should be 2 arrows on page 3
|
||||
QCOMPARE( arrows.length(), 2 );
|
||||
|
||||
mComposition->removeComposerItem( label1 );
|
||||
mComposition->removeComposerItem( label2 );
|
||||
mComposition->removeComposerItem( label3 );
|
||||
mComposition->removeComposerItem( shape1 );
|
||||
mComposition->removeComposerItem( shape2 );
|
||||
mComposition->removeComposerItem( arrow1 );
|
||||
mComposition->removeComposerItem( arrow2 );
|
||||
|
||||
//check again with removed items
|
||||
mComposition->composerItemsOnPage( labels, 0 );
|
||||
QCOMPARE( labels.length(), 0 );
|
||||
mComposition->composerItemsOnPage( labels, 1 );
|
||||
QCOMPARE( labels.length(), 0 );
|
||||
mComposition->composerItemsOnPage( labels, 2 );
|
||||
QCOMPARE( labels.length(), 0 );
|
||||
}
|
||||
|
||||
void TestQgsComposition::shouldExportPage()
|
||||
{
|
||||
mComposition->setPaperSize( 297, 200 );
|
||||
mComposition->setNumPages( 2 );
|
||||
|
||||
QgsComposerHtml* htmlItem = new QgsComposerHtml( mComposition, false );
|
||||
//frame on page 1
|
||||
QgsComposerFrame* frame1 = new QgsComposerFrame( mComposition, htmlItem, 0, 0, 100, 100 );
|
||||
//frame on page 2
|
||||
QgsComposerFrame* frame2 = new QgsComposerFrame( mComposition, htmlItem, 0, 320, 100, 100 );
|
||||
frame2->setHidePageIfEmpty( true );
|
||||
htmlItem->addFrame( frame1 );
|
||||
htmlItem->addFrame( frame2 );
|
||||
htmlItem->setContentMode( QgsComposerHtml::ManualHtml );
|
||||
//short content, so frame 2 should be empty
|
||||
htmlItem->setHtml( QString( "<p><i>Test manual <b>html</b></i></p>" ) );
|
||||
htmlItem->loadHtml();
|
||||
|
||||
QCOMPARE( mComposition->shouldExportPage( 1 ), true );
|
||||
QCOMPARE( mComposition->shouldExportPage( 2 ), false );
|
||||
|
||||
//long content, so frame 2 should not be empty
|
||||
htmlItem->setHtml( QString( "<p style=\"height: 10000px\"><i>Test manual <b>html</b></i></p>" ) );
|
||||
htmlItem->loadHtml();
|
||||
|
||||
QCOMPARE( mComposition->shouldExportPage( 1 ), true );
|
||||
QCOMPARE( mComposition->shouldExportPage( 2 ), true );
|
||||
|
||||
//...and back again...
|
||||
htmlItem->setHtml( QString( "<p><i>Test manual <b>html</b></i></p>" ) );
|
||||
htmlItem->loadHtml();
|
||||
|
||||
QCOMPARE( mComposition->shouldExportPage( 1 ), true );
|
||||
QCOMPARE( mComposition->shouldExportPage( 2 ), false );
|
||||
|
||||
mComposition->removeMultiFrame( htmlItem );
|
||||
delete htmlItem;
|
||||
}
|
||||
|
||||
QTEST_MAIN( TestQgsComposition )
|
||||
#include "moc_testqgscomposition.cxx"
|
||||
|
@ -93,11 +93,6 @@ class TestQgsComposerHtml(TestCase):
|
||||
myTestResult, myMessage = checker2.testComposition( myPage )
|
||||
assert myTestResult, myMessage
|
||||
|
||||
print "Checking page 3"
|
||||
myPage = 2
|
||||
checker3 = QgsCompositionChecker('composerhtml_multiframe3', self.mComposition)
|
||||
myTestResult, myMessage = checker3.testComposition( myPage )
|
||||
|
||||
self.mComposition.removeMultiFrame( composerHtml )
|
||||
composerHtml = None
|
||||
|
||||
@ -127,11 +122,6 @@ class TestQgsComposerHtml(TestCase):
|
||||
myTestResult, myMessage = checker2.testComposition( myPage )
|
||||
assert myTestResult, myMessage
|
||||
|
||||
print "Checking page 3"
|
||||
myPage = 2
|
||||
checker3 = QgsCompositionChecker('composerhtml_smartbreaks3', self.mComposition)
|
||||
myTestResult, myMessage = checker3.testComposition( myPage )
|
||||
|
||||
self.mComposition.removeMultiFrame( composerHtml )
|
||||
composerHtml = None
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user