mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-18 00:03:05 -04:00
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.
This commit is contained in:
parent
541463718d
commit
f696b0a34d
@ -184,8 +184,11 @@ void QgsComposerHtml::loadHtml( const bool useCache, const QgsExpressionContext
|
||||
//reset page size. otherwise viewport size increases but never decreases again
|
||||
mWebPage->setViewportSize( QSize( maxFrameWidth() * mHtmlUnitsToMM, 0 ) );
|
||||
|
||||
//set html, using the specified url as base if in Url mode
|
||||
mWebPage->mainFrame()->setHtml( loadedHtml, mContentMode == QgsComposerHtml::Url ? QUrl( mActualFetchedUrl ) : QUrl() );
|
||||
//set html, using the specified url as base if in Url mode or the project file if in manual mode
|
||||
const QUrl baseUrl = mContentMode == QgsComposerHtml::Url ?
|
||||
QUrl( mActualFetchedUrl ) :
|
||||
QUrl::fromLocalFile( QgsProject::instance()->fileInfo().absoluteFilePath() );
|
||||
mWebPage->mainFrame()->setHtml( loadedHtml, baseUrl );
|
||||
|
||||
//set user stylesheet
|
||||
QWebSettings* settings = mWebPage->settings();
|
||||
|
@ -79,11 +79,27 @@ QgsComposerLabel::QgsComposerLabel( QgsComposition *composition )
|
||||
//to update the expression context
|
||||
connect( &mComposition->atlasComposition(), SIGNAL( featureChanged( QgsFeature* ) ), this, SLOT( refreshExpressionContext() ) );
|
||||
}
|
||||
|
||||
mWebPage = new QWebPage( this );
|
||||
mWebPage->setNetworkAccessManager( QgsNetworkAccessManager::instance() );
|
||||
|
||||
//This makes the background transparent. Found on http://blog.qt.digia.com/blog/2009/06/30/transparent-qwebview-or-qwebpage/
|
||||
QPalette palette = mWebPage->palette();
|
||||
palette.setBrush( QPalette::Base, Qt::transparent );
|
||||
mWebPage->setPalette( palette );
|
||||
//webPage->setAttribute(Qt::WA_OpaquePaintEvent, false); //this does not compile, why ?
|
||||
|
||||
mWebPage->mainFrame()->setZoomFactor( 10.0 );
|
||||
mWebPage->mainFrame()->setScrollBarPolicy( Qt::Horizontal, Qt::ScrollBarAlwaysOff );
|
||||
mWebPage->mainFrame()->setScrollBarPolicy( Qt::Vertical, Qt::ScrollBarAlwaysOff );
|
||||
|
||||
connect( mWebPage, SIGNAL( loadFinished( bool ) ), SLOT( loadingHtmlFinished( bool ) ) );
|
||||
}
|
||||
|
||||
QgsComposerLabel::~QgsComposerLabel()
|
||||
{
|
||||
delete mDistanceArea;
|
||||
delete mWebPage;
|
||||
}
|
||||
|
||||
void QgsComposerLabel::paint( QPainter* painter, const QStyleOptionGraphicsItem* itemStyle, QWidget* pWidget )
|
||||
@ -110,66 +126,16 @@ void QgsComposerLabel::paint( QPainter* painter, const QStyleOptionGraphicsItem*
|
||||
double yPenAdjust = mMarginY < 0 ? -penWidth : penWidth;
|
||||
QRectF painterRect( xPenAdjust + mMarginX, yPenAdjust + mMarginY, rect().width() - 2 * xPenAdjust - 2 * mMarginX, rect().height() - 2 * yPenAdjust - 2 * mMarginY );
|
||||
|
||||
QString textToDraw = displayText();
|
||||
|
||||
if ( mHtmlState )
|
||||
{
|
||||
painter->scale( 1.0 / mHtmlUnitsToMM / 10.0, 1.0 / mHtmlUnitsToMM / 10.0 );
|
||||
QWebPage *webPage = new QWebPage();
|
||||
webPage->setNetworkAccessManager( QgsNetworkAccessManager::instance() );
|
||||
|
||||
//Setup event loop and timeout for rendering html
|
||||
QEventLoop loop;
|
||||
QTimer timeoutTimer;
|
||||
timeoutTimer.setSingleShot( true );
|
||||
|
||||
//This makes the background transparent. Found on http://blog.qt.digia.com/blog/2009/06/30/transparent-qwebview-or-qwebpage/
|
||||
QPalette palette = webPage->palette();
|
||||
palette.setBrush( QPalette::Base, Qt::transparent );
|
||||
webPage->setPalette( palette );
|
||||
//webPage->setAttribute(Qt::WA_OpaquePaintEvent, false); //this does not compile, why ?
|
||||
|
||||
webPage->setViewportSize( QSize( painterRect.width() * mHtmlUnitsToMM * 10.0, painterRect.height() * mHtmlUnitsToMM * 10.0 ) );
|
||||
webPage->mainFrame()->setZoomFactor( 10.0 );
|
||||
webPage->mainFrame()->setScrollBarPolicy( Qt::Horizontal, Qt::ScrollBarAlwaysOff );
|
||||
webPage->mainFrame()->setScrollBarPolicy( Qt::Vertical, Qt::ScrollBarAlwaysOff );
|
||||
webPage->settings()->setUserStyleSheetUrl( createStylesheetUrl() );
|
||||
|
||||
// QGIS segfaults when rendering web page while in composer if html
|
||||
// contains images. So if we are not printing the composition, then
|
||||
// disable image loading
|
||||
if ( mComposition->plotStyle() != QgsComposition::Print &&
|
||||
mComposition->plotStyle() != QgsComposition::Postscript )
|
||||
{
|
||||
webPage->settings()->setAttribute( QWebSettings::AutoLoadImages, false );
|
||||
}
|
||||
|
||||
//Connect timeout and webpage loadFinished signals to loop
|
||||
connect( &timeoutTimer, SIGNAL( timeout() ), &loop, SLOT( quit() ) );
|
||||
connect( webPage, SIGNAL( loadFinished( bool ) ), &loop, SLOT( quit() ) );
|
||||
|
||||
//mHtmlLoaded tracks whether the QWebPage has completed loading
|
||||
//its html contents, set it initially to false. The loadingHtmlFinished slot will
|
||||
//set this to true after html is loaded.
|
||||
mHtmlLoaded = false;
|
||||
connect( webPage, SIGNAL( loadFinished( bool ) ), SLOT( loadingHtmlFinished( bool ) ) );
|
||||
|
||||
webPage->mainFrame()->setHtml( textToDraw );
|
||||
|
||||
//For very basic html labels with no external assets, the html load will already be
|
||||
//complete before we even get a chance to start the QEventLoop. Make sure we check
|
||||
//this before starting the loop
|
||||
if ( !mHtmlLoaded )
|
||||
{
|
||||
// Start a 20 second timeout in case html loading will never complete
|
||||
timeoutTimer.start( 20000 );
|
||||
// Pause until html is loaded
|
||||
loop.exec();
|
||||
}
|
||||
webPage->mainFrame()->render( painter );//DELETE WEBPAGE ?
|
||||
mWebPage->setViewportSize( QSize( painterRect.width() * mHtmlUnitsToMM * 10.0, painterRect.height() * mHtmlUnitsToMM * 10.0 ) );
|
||||
mWebPage->settings()->setUserStyleSheetUrl( createStylesheetUrl() );
|
||||
mWebPage->mainFrame()->render( painter );
|
||||
}
|
||||
else
|
||||
{
|
||||
const QString textToDraw = displayText();
|
||||
painter->setFont( mFont );
|
||||
//debug
|
||||
//painter->setPen( QColor( Qt::red ) );
|
||||
@ -186,6 +152,43 @@ void QgsComposerLabel::paint( QPainter* painter, const QStyleOptionGraphicsItem*
|
||||
}
|
||||
}
|
||||
|
||||
void QgsComposerLabel::contentChanged()
|
||||
{
|
||||
if ( mHtmlState )
|
||||
{
|
||||
const QString textToDraw = displayText();
|
||||
|
||||
//mHtmlLoaded tracks whether the QWebPage has completed loading
|
||||
//its html contents, set it initially to false. The loadingHtmlFinished slot will
|
||||
//set this to true after html is loaded.
|
||||
mHtmlLoaded = false;
|
||||
|
||||
const QUrl baseUrl = QUrl::fromLocalFile( QgsProject::instance()->fileInfo().absoluteFilePath() );
|
||||
mWebPage->mainFrame()->setHtml( textToDraw, baseUrl );
|
||||
|
||||
//For very basic html labels with no external assets, the html load will already be
|
||||
//complete before we even get a chance to start the QEventLoop. Make sure we check
|
||||
//this before starting the loop
|
||||
if ( !mHtmlLoaded )
|
||||
{
|
||||
//Setup event loop and timeout for rendering html
|
||||
QEventLoop loop;
|
||||
|
||||
//Connect timeout and webpage loadFinished signals to loop
|
||||
connect( mWebPage, SIGNAL( loadFinished( bool ) ), &loop, SLOT( quit() ) );
|
||||
|
||||
// Start a 20 second timeout in case html loading will never complete
|
||||
QTimer timeoutTimer;
|
||||
timeoutTimer.setSingleShot( true );
|
||||
connect( &timeoutTimer, SIGNAL( timeout() ), &loop, SLOT( quit() ) );
|
||||
timeoutTimer.start( 20000 );
|
||||
|
||||
// Pause until html is loaded
|
||||
loop.exec();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*Track when QWebPage has finished loading its html contents*/
|
||||
void QgsComposerLabel::loadingHtmlFinished( bool result )
|
||||
{
|
||||
@ -209,6 +212,8 @@ void QgsComposerLabel::setText( const QString& text )
|
||||
mText = text;
|
||||
emit itemChanged();
|
||||
|
||||
contentChanged();
|
||||
|
||||
if ( mComposition && id().isEmpty() && !mHtmlState )
|
||||
{
|
||||
//notify the model that the display name has changed
|
||||
@ -224,6 +229,7 @@ void QgsComposerLabel::setHtmlState( int state )
|
||||
}
|
||||
|
||||
mHtmlState = state;
|
||||
contentChanged();
|
||||
|
||||
if ( mComposition && id().isEmpty() )
|
||||
{
|
||||
@ -253,6 +259,7 @@ void QgsComposerLabel::setExpressionContext( QgsFeature *feature, QgsVectorLayer
|
||||
mDistanceArea->setEllipsoidalMode( mComposition->mapSettings().hasCrsTransformEnabled() );
|
||||
}
|
||||
mDistanceArea->setEllipsoid( QgsProject::instance()->readEntry( "Measure", "/Ellipsoid", GEO_NONE ) );
|
||||
contentChanged();
|
||||
|
||||
// Force label to redraw -- fixes label printing for labels with blend modes when used with atlas
|
||||
update();
|
||||
@ -289,6 +296,7 @@ void QgsComposerLabel::refreshExpressionContext()
|
||||
}
|
||||
mDistanceArea->setEllipsoidalMode( mComposition->mapSettings().hasCrsTransformEnabled() );
|
||||
mDistanceArea->setEllipsoid( QgsProject::instance()->readEntry( "Measure", "/Ellipsoid", GEO_NONE ) );
|
||||
contentChanged();
|
||||
|
||||
update();
|
||||
}
|
||||
@ -488,6 +496,7 @@ bool QgsComposerLabel::readXML( const QDomElement& itemElem, const QDomDocument&
|
||||
_readXML( composerItemElem, doc );
|
||||
}
|
||||
emit itemChanged();
|
||||
contentChanged();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -23,6 +23,7 @@
|
||||
class QgsVectorLayer;
|
||||
class QgsFeature;
|
||||
class QgsDistanceArea;
|
||||
class QWebPage;
|
||||
|
||||
/** \ingroup MapComposer
|
||||
* A label that can be placed onto a map composition.
|
||||
@ -184,6 +185,9 @@ class CORE_EXPORT QgsComposerLabel: public QgsComposerItem
|
||||
/** Helper function to calculate x/y shift for adjustSizeToText() depending on rotation, current size and alignment*/
|
||||
void itemShiftAdjustSize( double newWidth, double newHeight, double& xShift, double& yShift ) const;
|
||||
|
||||
/** Called when the content is changed to handle HTML loading */
|
||||
void contentChanged();
|
||||
|
||||
// Font
|
||||
QFont mFont;
|
||||
|
||||
@ -212,6 +216,7 @@ class CORE_EXPORT QgsComposerLabel: public QgsComposerItem
|
||||
QMap<QString, QVariant> mSubstitutions;
|
||||
QgsDistanceArea* mDistanceArea;
|
||||
|
||||
QWebPage* mWebPage;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -154,7 +154,7 @@ bool QgsCompositionChecker::testComposition( QString &theReport, int page, int p
|
||||
//QRectF targetArea( 0, 0, 3507, 2480 );
|
||||
mComposition->renderPage( &expectedPainter, page );
|
||||
expectedPainter.end();
|
||||
newImage.save( mExpectedImageFile, "PNG" );
|
||||
newImage.save( controlImagePath() + QDir::separator() + "expected_" + mTestName + ".png", "PNG" );
|
||||
return true;
|
||||
#endif //0
|
||||
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "qgsvectordataprovider.h"
|
||||
#include "qgsmultirenderchecker.h"
|
||||
#include "qgsfontutils.h"
|
||||
#include "qgsproject.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QtTest/QtTest>
|
||||
@ -55,6 +56,7 @@ class TestQgsComposerLabel : public QObject
|
||||
void marginMethods(); //tests getting/setting margins
|
||||
void render();
|
||||
void renderAsHtml();
|
||||
void renderAsHtmlRelative();
|
||||
|
||||
private:
|
||||
QgsComposition* mComposition;
|
||||
@ -265,5 +267,21 @@ void TestQgsComposerLabel::renderAsHtml()
|
||||
QVERIFY( checker.testComposition( mReport, 0, 0 ) );
|
||||
}
|
||||
|
||||
void TestQgsComposerLabel::renderAsHtmlRelative()
|
||||
{
|
||||
QgsProject::instance()->setFileName( QString( TEST_DATA_DIR ) + QDir::separator() + "test.qgs" );
|
||||
mComposerLabel->setFontColor( QColor( 200, 40, 60 ) );
|
||||
mComposerLabel->setText( "test <img src=\"small_sample_image.png\" />" );
|
||||
mComposerLabel->setFont( QgsFontUtils::getStandardTestFont( "Bold", 48 ) );
|
||||
mComposerLabel->setPos( 70, 70 );
|
||||
mComposerLabel->adjustSizeToText();
|
||||
mComposerLabel->setHtmlState( 1 );
|
||||
mComposerLabel->update();
|
||||
|
||||
QgsCompositionChecker checker( "composerlabel_renderhtmlrelative", mComposition );
|
||||
checker.setControlPathPrefix( "composer_label" );
|
||||
QVERIFY( checker.testComposition( mReport, 0, 0 ) );
|
||||
}
|
||||
|
||||
QTEST_MAIN( TestQgsComposerLabel )
|
||||
#include "testqgscomposerlabel.moc"
|
||||
|
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
Binary file not shown.
After Width: | Height: | Size: 7.1 KiB |
Loading…
x
Reference in New Issue
Block a user