Skip to content
Permalink
Browse files
[FEATURE][composer] Allow specifying user stylesheets to apply to a H…
…TML item's content
  • Loading branch information
nyalldawson committed Jul 27, 2014
1 parent b3de1dd commit d0e9d8d
Show file tree
Hide file tree
Showing 13 changed files with 324 additions and 4 deletions.
@@ -144,6 +144,43 @@ class QgsComposerHtml: QgsComposerMultiFrame
* @see useSmartBreaks
*/
double maxBreakDistance() const;

/**Sets the user stylesheet CSS rules to use while rendering the HTML content. These
* allow for overriding the styles specified within the HTML source. Setting the stylesheet
* using this function does not automatically refresh the item's contents. Call loadHtml
* to trigger a refresh of the item after setting the stylesheet rules.
* @param stylesheet CSS rules for user stylesheet
* @see userStylesheet
* @see setUserStylesheetEnabled
* @see loadHtml
* @note added in 2.5
*/
void setUserStylesheet( const QString stylesheet );

/**Returns the user stylesheet CSS rules used while rendering the HTML content. These
* overriding the styles specified within the HTML source.
* @returns CSS rules for user stylesheet
* @see setUserStylesheet
* @see userStylesheetEnabled
* @note added in 2.5
*/
QString userStylesheet() const;

/**Sets whether user stylesheets are enabled for the HTML content.
* @param stylesheetEnabled set to true to enable user stylesheets
* @see userStylesheetEnabled
* @see setUserStylesheet
* @note added in 2.5
*/
void setUserStylesheetEnabled( const bool stylesheetEnabled );

/**Returns whether user stylesheets are enabled for the HTML content.
* @returns true if user stylesheets are enabled
* @see setUserStylesheetEnabled
* @see userStylesheet
* @note added in 2.5
*/
bool userStylesheetEnabled() const;

public slots:

@@ -30,6 +30,7 @@
%Include qgscodeeditorpython.sip
%Include qgscodeeditorsql.sip
%Include qgscodeeditorhtml.sip
%Include qgscodeeditorcss.sip
%End
%Include qgscolorbutton.sip
%Include qgscolordialog.sip
@@ -0,0 +1,10 @@
class QgsCodeEditorCSS: QgsCodeEditor
{
%TypeHeaderCode
#include <qgscodeeditorcss.h>
%End

public:
QgsCodeEditorCSS( QWidget *parent /TransferThis/ = 0 );
~QgsCodeEditorCSS();
};
@@ -20,6 +20,7 @@
#include "qgscomposition.h"
#include "qgsexpressionbuilderdialog.h"
#include "qgscodeeditorhtml.h"
#include "qgscodeeditorcss.h"
#include <QFileDialog>
#include <QSettings>

@@ -30,10 +31,14 @@ QgsComposerHtmlWidget::QgsComposerHtmlWidget( QgsComposerHtml* html, QgsComposer

//setup html editor
mHtmlEditor = new QgsCodeEditorHTML( this );

connect( mHtmlEditor, SIGNAL( textChanged() ), this, SLOT( htmlEditorChanged() ) );
htmlEditorLayout->addWidget( mHtmlEditor );

//setup stylesheet editor
mStylesheetEditor = new QgsCodeEditorCSS( this );
connect( mStylesheetEditor, SIGNAL( textChanged() ), this, SLOT( stylesheetEditorChanged() ) );
stylesheetEditorLayout->addWidget( mStylesheetEditor );

blockSignals( true );
mResizeModeComboBox->addItem( tr( "Use existing frames" ), QgsComposerMultiFrame::UseExistingFrames );
mResizeModeComboBox->addItem( tr( "Extend to next page" ), QgsComposerMultiFrame::ExtendToNextPage );
@@ -87,6 +92,8 @@ void QgsComposerHtmlWidget::blockSignals( bool block )
mUseSmartBreaksCheckBox->blockSignals( block );
mMaxDistanceSpinBox->blockSignals( block );
mHtmlEditor->blockSignals( block );
mStylesheetEditor->blockSignals( block );
mUserStylesheetCheckBox->blockSignals( block );
mRadioManualSource->blockSignals( block );
mRadioUrlSource->blockSignals( block );
mEvaluateExpressionsCheckbox->blockSignals( block );
@@ -219,6 +226,42 @@ void QgsComposerHtmlWidget::htmlEditorChanged()

}

void QgsComposerHtmlWidget::stylesheetEditorChanged()
{
if ( !mHtml )
{
return;
}

QgsComposition* composition = mHtml->composition();
if ( composition )
{
blockSignals( true );
composition->beginMultiFrameCommand( mHtml, tr( "User stylesheet changed" ) );
mHtml->setUserStylesheet( mStylesheetEditor->text() );
composition->endMultiFrameCommand();
blockSignals( false );
}
}

void QgsComposerHtmlWidget::on_mUserStylesheetCheckBox_toggled( bool checked )
{
if ( !mHtml )
{
return;
}

QgsComposition* composition = mHtml->composition();
if ( composition )
{
blockSignals( true );
composition->beginMultiFrameCommand( mHtml, tr( "User stylesheet toggled" ) );
mHtml->setUserStylesheetEnabled( checked );
composition->endMultiFrameCommand();
blockSignals( false );
}
}

void QgsComposerHtmlWidget::on_mRadioManualSource_clicked( bool checked )
{
if ( !mHtml )
@@ -327,6 +370,16 @@ void QgsComposerHtmlWidget::on_mReloadPushButton_clicked()
mHtml->loadHtml();
}

void QgsComposerHtmlWidget::on_mReloadPushButton2_clicked()
{
if ( !mHtml )
{
return;
}

mHtml->loadHtml();
}

void QgsComposerHtmlWidget::on_mAddFramePushButton_clicked()
{
if ( !mHtml || !mFrame )
@@ -374,6 +427,9 @@ void QgsComposerHtmlWidget::setGuiElementValues()
mHtmlEditor->setEnabled( mHtml->contentMode() == QgsComposerHtml::ManualHtml );
mInsertExpressionButton->setEnabled( mHtml->contentMode() == QgsComposerHtml::ManualHtml );

mUserStylesheetCheckBox->setChecked( mHtml->userStylesheetEnabled() );
mStylesheetEditor->setText( mHtml->userStylesheet() );

populateDataDefinedButtons();

blockSignals( false );
@@ -21,6 +21,7 @@
class QgsComposerHtml;
class QgsComposerFrame;
class QgsCodeEditorHTML;
class QgsCodeEditorCSS;

class QgsComposerHtmlWidget: public QgsComposerItemBaseWidget, private Ui::QgsComposerHtmlWidgetBase
{
@@ -37,11 +38,14 @@ class QgsComposerHtmlWidget: public QgsComposerItemBaseWidget, private Ui::QgsCo
void on_mUseSmartBreaksCheckBox_toggled( bool checked );
void on_mMaxDistanceSpinBox_valueChanged( double val );
void htmlEditorChanged();
void stylesheetEditorChanged();
void on_mUserStylesheetCheckBox_toggled( bool checked );
void on_mRadioManualSource_clicked( bool checked );
void on_mRadioUrlSource_clicked( bool checked );
void on_mInsertExpressionButton_clicked();

void on_mReloadPushButton_clicked();
void on_mReloadPushButton2_clicked();
void on_mAddFramePushButton_clicked();

/**Sets the GUI elements to the values of mHtmlItem*/
@@ -61,6 +65,7 @@ class QgsComposerHtmlWidget: public QgsComposerItemBaseWidget, private Ui::QgsCo
QgsComposerHtml* mHtml;
QgsComposerFrame* mFrame;
QgsCodeEditorHTML *mHtmlEditor;
QgsCodeEditorCSS *mStylesheetEditor;
};

#endif // QGSCOMPOSERHTMLWIDGET_H
@@ -39,7 +39,8 @@ QgsComposerHtml::QgsComposerHtml( QgsComposition* c, bool createUndoCommands ):
mUseSmartBreaks( true ),
mMaxBreakDistance( 10 ),
mExpressionFeature( 0 ),
mExpressionLayer( 0 )
mExpressionLayer( 0 ),
mEnableUserStylesheet( false )
{
mHtmlUnitsToMM = htmlUnitsToMM();
mWebPage = new QWebPage();
@@ -211,6 +212,20 @@ void QgsComposerHtml::loadHtml()
//set html, using the specified url as base if in Url mode
mWebPage->mainFrame()->setHtml( loadedHtml, mContentMode == QgsComposerHtml::Url ? QUrl( mLastFetchedUrl ) : QUrl() );

//set user stylesheet
QWebSettings* settings = mWebPage->settings();
if ( mEnableUserStylesheet && ! mUserStylesheet.isEmpty() )
{
QByteArray ba;
ba.append( mUserStylesheet.toUtf8() );
QUrl cssFileURL = QUrl( "data:text/css;charset=utf-8;base64," + ba.toBase64() );
settings->setUserStyleSheetUrl( cssFileURL );
}
else
{
settings->setUserStyleSheetUrl( QUrl() );
}

while ( !mLoaded )
{
qApp->processEvents();
@@ -412,6 +427,20 @@ void QgsComposerHtml::setMaxBreakDistance( double maxBreakDistance )
emit changed();
}

void QgsComposerHtml::setUserStylesheet( const QString stylesheet )
{
mUserStylesheet = stylesheet;
}

void QgsComposerHtml::setUserStylesheetEnabled( const bool stylesheetEnabled )
{
if ( mEnableUserStylesheet != stylesheetEnabled )
{
mEnableUserStylesheet = stylesheetEnabled;
loadHtml();
}
}

bool QgsComposerHtml::writeXML( QDomElement& elem, QDomDocument & doc, bool ignoreFrames ) const
{
QDomElement htmlElem = doc.createElement( "ComposerHtml" );
@@ -421,6 +450,8 @@ bool QgsComposerHtml::writeXML( QDomElement& elem, QDomDocument & doc, bool igno
htmlElem.setAttribute( "evaluateExpressions", mEvaluateExpressions ? "true" : "false" );
htmlElem.setAttribute( "useSmartBreaks", mUseSmartBreaks ? "true" : "false" );
htmlElem.setAttribute( "maxBreakDistance", QString::number( mMaxBreakDistance ) );
htmlElem.setAttribute( "stylesheet", mUserStylesheet );
htmlElem.setAttribute( "stylesheetEnabled", mEnableUserStylesheet ? "true" : "false" );

bool state = _writeXML( htmlElem, doc, ignoreFrames );
elem.appendChild( htmlElem );
@@ -447,6 +478,9 @@ bool QgsComposerHtml::readXML( const QDomElement& itemElem, const QDomDocument&
mUseSmartBreaks = itemElem.attribute( "useSmartBreaks", "true" ) == "true" ? true : false;
mMaxBreakDistance = itemElem.attribute( "maxBreakDistance", "10" ).toDouble();
mHtml = itemElem.attribute( "html" );
mUserStylesheet = itemElem.attribute( "stylesheet" );
mEnableUserStylesheet = itemElem.attribute( "stylesheetEnabled", "false" ) == "true" ? true : false;

//finally load the set url
QString urlString = itemElem.attribute( "url" );
if ( !urlString.isEmpty() )
@@ -168,6 +168,43 @@ class CORE_EXPORT QgsComposerHtml: public QgsComposerMultiFrame
*/
double maxBreakDistance() const { return mMaxBreakDistance; }

/**Sets the user stylesheet CSS rules to use while rendering the HTML content. These
* allow for overriding the styles specified within the HTML source. Setting the stylesheet
* using this function does not automatically refresh the item's contents. Call loadHtml
* to trigger a refresh of the item after setting the stylesheet rules.
* @param stylesheet CSS rules for user stylesheet
* @see userStylesheet
* @see setUserStylesheetEnabled
* @see loadHtml
* @note added in 2.5
*/
void setUserStylesheet( const QString stylesheet );

/**Returns the user stylesheet CSS rules used while rendering the HTML content. These
* overriding the styles specified within the HTML source.
* @returns CSS rules for user stylesheet
* @see setUserStylesheet
* @see userStylesheetEnabled
* @note added in 2.5
*/
QString userStylesheet() const { return mUserStylesheet; }

/**Sets whether user stylesheets are enabled for the HTML content.
* @param stylesheetEnabled set to true to enable user stylesheets
* @see userStylesheetEnabled
* @see setUserStylesheet
* @note added in 2.5
*/
void setUserStylesheetEnabled( const bool stylesheetEnabled );

/**Returns whether user stylesheets are enabled for the HTML content.
* @returns true if user stylesheets are enabled
* @see setUserStylesheetEnabled
* @see userStylesheet
* @note added in 2.5
*/
bool userStylesheetEnabled() const { return mEnableUserStylesheet; }

public slots:

/**Reloads the html source from the url and redraws the item.
@@ -200,6 +237,8 @@ class CORE_EXPORT QgsComposerHtml: public QgsComposerMultiFrame

QgsFeature* mExpressionFeature;
QgsVectorLayer* mExpressionLayer;
QString mUserStylesheet;
bool mEnableUserStylesheet;

double htmlUnitsToMM(); //calculate scale factor

@@ -130,6 +130,7 @@ qgscodeeditor.cpp
qgscodeeditorpython.cpp
qgscodeeditorsql.cpp
qgscodeeditorhtml.cpp
qgscodeeditorcss.cpp
qgscomposerruler.cpp
qgscomposerview.cpp
qgsprevieweffect.cpp
@@ -324,6 +325,7 @@ qgscodeeditor.h
qgscodeeditorpython.h
qgscodeeditorsql.h
qgscodeeditorhtml.h
qgscodeeditorcss.h
qgscolordialog.h
qgsprevieweffect.h
qgscomposerruler.h
@@ -0,0 +1,47 @@
/***************************************************************************
qgscodeeditorcss.cpp - A CSS editor based on QScintilla
--------------------------------------
Date : 27-Jul-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 "qgscodeeditorcss.h"

#include <QWidget>
#include <QString>
#include <QFont>
#include <Qsci/qscilexercss.h>


QgsCodeEditorCSS::QgsCodeEditorCSS( QWidget *parent )
: QgsCodeEditor( parent )
{
if ( !parent )
{
setTitle( tr( "CSS Editor" ) );
}
setMarginVisible( false );
setFoldingVisible( true );
setSciLexerCSS();
}

QgsCodeEditorCSS::~QgsCodeEditorCSS()
{
}

void QgsCodeEditorCSS::setSciLexerCSS()
{
QsciLexerCSS* lexer = new QsciLexerCSS();
lexer->setDefaultFont( QFont( "Sans", 10 ) );

setLexer( lexer );
}

0 comments on commit d0e9d8d

Please sign in to comment.