Skip to content

Commit f696b0a

Browse files
author
Patrick Valsecchi
committedApr 4, 2016
Allow relative links in composer labels
Now labels and HTML boxes can contain relative URLs. If we don't have a base URL, the project file will be used as a base URL (closes #7236). Remove the exception for the labels where the images where not loaded (unless in in PDF or image mode). It was because of a crash. Qt didn't like having the HTML loading to be done synchronously during painting. Fix a leak when rendering labels.
1 parent 5414637 commit f696b0a

File tree

7 files changed

+90
-55
lines changed

7 files changed

+90
-55
lines changed
 

‎src/core/composer/qgscomposerhtml.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -184,8 +184,11 @@ void QgsComposerHtml::loadHtml( const bool useCache, const QgsExpressionContext
184184
//reset page size. otherwise viewport size increases but never decreases again
185185
mWebPage->setViewportSize( QSize( maxFrameWidth() * mHtmlUnitsToMM, 0 ) );
186186

187-
//set html, using the specified url as base if in Url mode
188-
mWebPage->mainFrame()->setHtml( loadedHtml, mContentMode == QgsComposerHtml::Url ? QUrl( mActualFetchedUrl ) : QUrl() );
187+
//set html, using the specified url as base if in Url mode or the project file if in manual mode
188+
const QUrl baseUrl = mContentMode == QgsComposerHtml::Url ?
189+
QUrl( mActualFetchedUrl ) :
190+
QUrl::fromLocalFile( QgsProject::instance()->fileInfo().absoluteFilePath() );
191+
mWebPage->mainFrame()->setHtml( loadedHtml, baseUrl );
189192

190193
//set user stylesheet
191194
QWebSettings* settings = mWebPage->settings();

‎src/core/composer/qgscomposerlabel.cpp

Lines changed: 61 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -79,11 +79,27 @@ QgsComposerLabel::QgsComposerLabel( QgsComposition *composition )
7979
//to update the expression context
8080
connect( &mComposition->atlasComposition(), SIGNAL( featureChanged( QgsFeature* ) ), this, SLOT( refreshExpressionContext() ) );
8181
}
82+
83+
mWebPage = new QWebPage( this );
84+
mWebPage->setNetworkAccessManager( QgsNetworkAccessManager::instance() );
85+
86+
//This makes the background transparent. Found on http://blog.qt.digia.com/blog/2009/06/30/transparent-qwebview-or-qwebpage/
87+
QPalette palette = mWebPage->palette();
88+
palette.setBrush( QPalette::Base, Qt::transparent );
89+
mWebPage->setPalette( palette );
90+
//webPage->setAttribute(Qt::WA_OpaquePaintEvent, false); //this does not compile, why ?
91+
92+
mWebPage->mainFrame()->setZoomFactor( 10.0 );
93+
mWebPage->mainFrame()->setScrollBarPolicy( Qt::Horizontal, Qt::ScrollBarAlwaysOff );
94+
mWebPage->mainFrame()->setScrollBarPolicy( Qt::Vertical, Qt::ScrollBarAlwaysOff );
95+
96+
connect( mWebPage, SIGNAL( loadFinished( bool ) ), SLOT( loadingHtmlFinished( bool ) ) );
8297
}
8398

8499
QgsComposerLabel::~QgsComposerLabel()
85100
{
86101
delete mDistanceArea;
102+
delete mWebPage;
87103
}
88104

89105
void QgsComposerLabel::paint( QPainter* painter, const QStyleOptionGraphicsItem* itemStyle, QWidget* pWidget )
@@ -110,79 +126,66 @@ void QgsComposerLabel::paint( QPainter* painter, const QStyleOptionGraphicsItem*
110126
double yPenAdjust = mMarginY < 0 ? -penWidth : penWidth;
111127
QRectF painterRect( xPenAdjust + mMarginX, yPenAdjust + mMarginY, rect().width() - 2 * xPenAdjust - 2 * mMarginX, rect().height() - 2 * yPenAdjust - 2 * mMarginY );
112128

113-
QString textToDraw = displayText();
114-
115129
if ( mHtmlState )
116130
{
117131
painter->scale( 1.0 / mHtmlUnitsToMM / 10.0, 1.0 / mHtmlUnitsToMM / 10.0 );
118-
QWebPage *webPage = new QWebPage();
119-
webPage->setNetworkAccessManager( QgsNetworkAccessManager::instance() );
120-
121-
//Setup event loop and timeout for rendering html
122-
QEventLoop loop;
123-
QTimer timeoutTimer;
124-
timeoutTimer.setSingleShot( true );
125-
126-
//This makes the background transparent. Found on http://blog.qt.digia.com/blog/2009/06/30/transparent-qwebview-or-qwebpage/
127-
QPalette palette = webPage->palette();
128-
palette.setBrush( QPalette::Base, Qt::transparent );
129-
webPage->setPalette( palette );
130-
//webPage->setAttribute(Qt::WA_OpaquePaintEvent, false); //this does not compile, why ?
131-
132-
webPage->setViewportSize( QSize( painterRect.width() * mHtmlUnitsToMM * 10.0, painterRect.height() * mHtmlUnitsToMM * 10.0 ) );
133-
webPage->mainFrame()->setZoomFactor( 10.0 );
134-
webPage->mainFrame()->setScrollBarPolicy( Qt::Horizontal, Qt::ScrollBarAlwaysOff );
135-
webPage->mainFrame()->setScrollBarPolicy( Qt::Vertical, Qt::ScrollBarAlwaysOff );
136-
webPage->settings()->setUserStyleSheetUrl( createStylesheetUrl() );
137-
138-
// QGIS segfaults when rendering web page while in composer if html
139-
// contains images. So if we are not printing the composition, then
140-
// disable image loading
141-
if ( mComposition->plotStyle() != QgsComposition::Print &&
142-
mComposition->plotStyle() != QgsComposition::Postscript )
143-
{
144-
webPage->settings()->setAttribute( QWebSettings::AutoLoadImages, false );
145-
}
132+
mWebPage->setViewportSize( QSize( painterRect.width() * mHtmlUnitsToMM * 10.0, painterRect.height() * mHtmlUnitsToMM * 10.0 ) );
133+
mWebPage->settings()->setUserStyleSheetUrl( createStylesheetUrl() );
134+
mWebPage->mainFrame()->render( painter );
135+
}
136+
else
137+
{
138+
const QString textToDraw = displayText();
139+
painter->setFont( mFont );
140+
//debug
141+
//painter->setPen( QColor( Qt::red ) );
142+
//painter->drawRect( painterRect );
143+
QgsComposerUtils::drawText( painter, painterRect, textToDraw, mFont, mFontColor, mHAlignment, mVAlignment, Qt::TextWordWrap );
144+
}
145+
146+
painter->restore();
147+
148+
drawFrame( painter );
149+
if ( isSelected() )
150+
{
151+
drawSelectionBoxes( painter );
152+
}
153+
}
146154

147-
//Connect timeout and webpage loadFinished signals to loop
148-
connect( &timeoutTimer, SIGNAL( timeout() ), &loop, SLOT( quit() ) );
149-
connect( webPage, SIGNAL( loadFinished( bool ) ), &loop, SLOT( quit() ) );
155+
void QgsComposerLabel::contentChanged()
156+
{
157+
if ( mHtmlState )
158+
{
159+
const QString textToDraw = displayText();
150160

151161
//mHtmlLoaded tracks whether the QWebPage has completed loading
152162
//its html contents, set it initially to false. The loadingHtmlFinished slot will
153163
//set this to true after html is loaded.
154164
mHtmlLoaded = false;
155-
connect( webPage, SIGNAL( loadFinished( bool ) ), SLOT( loadingHtmlFinished( bool ) ) );
156165

157-
webPage->mainFrame()->setHtml( textToDraw );
166+
const QUrl baseUrl = QUrl::fromLocalFile( QgsProject::instance()->fileInfo().absoluteFilePath() );
167+
mWebPage->mainFrame()->setHtml( textToDraw, baseUrl );
158168

159169
//For very basic html labels with no external assets, the html load will already be
160170
//complete before we even get a chance to start the QEventLoop. Make sure we check
161171
//this before starting the loop
162172
if ( !mHtmlLoaded )
163173
{
174+
//Setup event loop and timeout for rendering html
175+
QEventLoop loop;
176+
177+
//Connect timeout and webpage loadFinished signals to loop
178+
connect( mWebPage, SIGNAL( loadFinished( bool ) ), &loop, SLOT( quit() ) );
179+
164180
// Start a 20 second timeout in case html loading will never complete
181+
QTimer timeoutTimer;
182+
timeoutTimer.setSingleShot( true );
183+
connect( &timeoutTimer, SIGNAL( timeout() ), &loop, SLOT( quit() ) );
165184
timeoutTimer.start( 20000 );
185+
166186
// Pause until html is loaded
167187
loop.exec();
168188
}
169-
webPage->mainFrame()->render( painter );//DELETE WEBPAGE ?
170-
}
171-
else
172-
{
173-
painter->setFont( mFont );
174-
//debug
175-
//painter->setPen( QColor( Qt::red ) );
176-
//painter->drawRect( painterRect );
177-
QgsComposerUtils::drawText( painter, painterRect, textToDraw, mFont, mFontColor, mHAlignment, mVAlignment, Qt::TextWordWrap );
178-
}
179-
180-
painter->restore();
181-
182-
drawFrame( painter );
183-
if ( isSelected() )
184-
{
185-
drawSelectionBoxes( painter );
186189
}
187190
}
188191

@@ -209,6 +212,8 @@ void QgsComposerLabel::setText( const QString& text )
209212
mText = text;
210213
emit itemChanged();
211214

215+
contentChanged();
216+
212217
if ( mComposition && id().isEmpty() && !mHtmlState )
213218
{
214219
//notify the model that the display name has changed
@@ -224,6 +229,7 @@ void QgsComposerLabel::setHtmlState( int state )
224229
}
225230

226231
mHtmlState = state;
232+
contentChanged();
227233

228234
if ( mComposition && id().isEmpty() )
229235
{
@@ -253,6 +259,7 @@ void QgsComposerLabel::setExpressionContext( QgsFeature *feature, QgsVectorLayer
253259
mDistanceArea->setEllipsoidalMode( mComposition->mapSettings().hasCrsTransformEnabled() );
254260
}
255261
mDistanceArea->setEllipsoid( QgsProject::instance()->readEntry( "Measure", "/Ellipsoid", GEO_NONE ) );
262+
contentChanged();
256263

257264
// Force label to redraw -- fixes label printing for labels with blend modes when used with atlas
258265
update();
@@ -289,6 +296,7 @@ void QgsComposerLabel::refreshExpressionContext()
289296
}
290297
mDistanceArea->setEllipsoidalMode( mComposition->mapSettings().hasCrsTransformEnabled() );
291298
mDistanceArea->setEllipsoid( QgsProject::instance()->readEntry( "Measure", "/Ellipsoid", GEO_NONE ) );
299+
contentChanged();
292300

293301
update();
294302
}
@@ -488,6 +496,7 @@ bool QgsComposerLabel::readXML( const QDomElement& itemElem, const QDomDocument&
488496
_readXML( composerItemElem, doc );
489497
}
490498
emit itemChanged();
499+
contentChanged();
491500
return true;
492501
}
493502

‎src/core/composer/qgscomposerlabel.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
class QgsVectorLayer;
2424
class QgsFeature;
2525
class QgsDistanceArea;
26+
class QWebPage;
2627

2728
/** \ingroup MapComposer
2829
* A label that can be placed onto a map composition.
@@ -184,6 +185,9 @@ class CORE_EXPORT QgsComposerLabel: public QgsComposerItem
184185
/** Helper function to calculate x/y shift for adjustSizeToText() depending on rotation, current size and alignment*/
185186
void itemShiftAdjustSize( double newWidth, double newHeight, double& xShift, double& yShift ) const;
186187

188+
/** Called when the content is changed to handle HTML loading */
189+
void contentChanged();
190+
187191
// Font
188192
QFont mFont;
189193

@@ -212,6 +216,7 @@ class CORE_EXPORT QgsComposerLabel: public QgsComposerItem
212216
QMap<QString, QVariant> mSubstitutions;
213217
QgsDistanceArea* mDistanceArea;
214218

219+
QWebPage* mWebPage;
215220
};
216221

217222
#endif

‎src/core/qgsmultirenderchecker.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ bool QgsCompositionChecker::testComposition( QString &theReport, int page, int p
154154
//QRectF targetArea( 0, 0, 3507, 2480 );
155155
mComposition->renderPage( &expectedPainter, page );
156156
expectedPainter.end();
157-
newImage.save( mExpectedImageFile, "PNG" );
157+
newImage.save( controlImagePath() + QDir::separator() + "expected_" + mTestName + ".png", "PNG" );
158158
return true;
159159
#endif //0
160160

‎tests/src/core/testqgscomposerlabel.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "qgsvectordataprovider.h"
2525
#include "qgsmultirenderchecker.h"
2626
#include "qgsfontutils.h"
27+
#include "qgsproject.h"
2728

2829
#include <QObject>
2930
#include <QtTest/QtTest>
@@ -55,6 +56,7 @@ class TestQgsComposerLabel : public QObject
5556
void marginMethods(); //tests getting/setting margins
5657
void render();
5758
void renderAsHtml();
59+
void renderAsHtmlRelative();
5860

5961
private:
6062
QgsComposition* mComposition;
@@ -265,5 +267,21 @@ void TestQgsComposerLabel::renderAsHtml()
265267
QVERIFY( checker.testComposition( mReport, 0, 0 ) );
266268
}
267269

270+
void TestQgsComposerLabel::renderAsHtmlRelative()
271+
{
272+
QgsProject::instance()->setFileName( QString( TEST_DATA_DIR ) + QDir::separator() + "test.qgs" );
273+
mComposerLabel->setFontColor( QColor( 200, 40, 60 ) );
274+
mComposerLabel->setText( "test <img src=\"small_sample_image.png\" />" );
275+
mComposerLabel->setFont( QgsFontUtils::getStandardTestFont( "Bold", 48 ) );
276+
mComposerLabel->setPos( 70, 70 );
277+
mComposerLabel->adjustSizeToText();
278+
mComposerLabel->setHtmlState( 1 );
279+
mComposerLabel->update();
280+
281+
QgsCompositionChecker checker( "composerlabel_renderhtmlrelative", mComposition );
282+
checker.setControlPathPrefix( "composer_label" );
283+
QVERIFY( checker.testComposition( mReport, 0, 0 ) );
284+
}
285+
268286
QTEST_MAIN( TestQgsComposerLabel )
269287
#include "testqgscomposerlabel.moc"

0 commit comments

Comments
 (0)
Please sign in to comment.