[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:
Nyall Dawson 2014-09-26 01:05:26 +10:00
parent b8bb4f0fe0
commit 272b79b6ca
20 changed files with 628 additions and 35 deletions

View File

@ -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;
};

View File

@ -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*/

View File

@ -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];

View File

@ -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 )

View File

@ -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 );

View File

@ -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 );

View File

@ -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();

View File

@ -780,7 +780,6 @@ void QgsComposerAttributeTableV2::addFrame( QgsComposerFrame *frame, bool recalc
if ( recalcFrameSizes )
{
recalculateFrameSizes();
}
}

View File

@ -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() )

View File

@ -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

View File

@ -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() );

View File

@ -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() )

View File

@ -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;
}
}
}

View File

@ -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

View File

@ -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>

View File

@ -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>

View File

@ -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)

View 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"

View 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"

View File

@ -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