2 changes: 2 additions & 0 deletions python/core/qgspallabeling.sip
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,9 @@ class QgsPalLayerSettings
QgsExpression* getLabelExpression();

QFont textFont;
//QString textFontFamily;
QString textNamedStyle;
//bool textFontFound;
bool fontSizeInMapUnits; //true if font size is in map units (otherwise in points)
QColor textColor;
int textTransp;
Expand Down
5 changes: 5 additions & 0 deletions python/core/qgsvectorlayer.sip
Original file line number Diff line number Diff line change
Expand Up @@ -1047,6 +1047,11 @@ class QgsVectorLayer : QgsMapLayer
void committedAttributeValuesChanges( const QString& layerId, const QgsChangedAttributesMap& changedAttributesValues );
void committedGeometriesChanges( const QString& layerId, const QgsGeometryMap& changedGeometries );

/** Emitted when the font family defined for labeling layer is not found on system
* @note added in 1.9
*/
void labelingFontNotFound( QgsVectorLayer* layer, const QString& fontfamily );

protected:
/** Set the extent */
void setExtent( const QgsRectangle &rect );
Expand Down
61 changes: 61 additions & 0 deletions src/app/qgisapp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4279,6 +4279,63 @@ void QgisApp::modifyAnnotation()
mMapCanvas->setMapTool( mMapTools.mAnnotation );
}

void QgisApp::labelingFontNotFound( QgsVectorLayer* vlayer, const QString& fontfamily )
{
// TODO: update when pref for how to resolve missing family (use matching algorithm or just default font) is implemented
QString substitute = tr( "Default system font substituted." );

QWidget* fontMsg = QgsMessageBar::createMessage(
tr( "Labeling" ),
tr( "Font for layer <b><u>%1</u></b> was not found (<i>%2</i>). %3" ).arg( vlayer->name() ).arg( fontfamily ).arg( substitute ),
QgsApplication::getThemeIcon( "/mIconWarn.png" ),
messageBar() );

QToolButton* btnOpenPrefs = new QToolButton( fontMsg );
btnOpenPrefs->setStyleSheet( "QToolButton{ background-color: rgba(255, 255, 255, 0); color: black; text-decoration: underline; }" );
btnOpenPrefs->setCursor( Qt::PointingHandCursor );
btnOpenPrefs->setSizePolicy( QSizePolicy::Maximum, QSizePolicy::Preferred );
btnOpenPrefs->setToolButtonStyle( Qt::ToolButtonTextOnly );

// store pointer to vlayer in data of QAction
QAction* act = new QAction( fontMsg );
act->setData( QVariant( QMetaType::QObjectStar, &vlayer ) );
act->setText( tr( "Open labeling dialog" ) );
btnOpenPrefs->addAction( act );
btnOpenPrefs->setDefaultAction( act );
btnOpenPrefs->setToolTip( "" );

connect( btnOpenPrefs, SIGNAL( triggered( QAction* ) ), this, SLOT( labelingDialogFontNotFound( QAction* ) ) );
fontMsg->layout()->addWidget( btnOpenPrefs );

// no timeout set, since notice needs attention and is only shown first time layer is labeled
messageBar()->pushWidget( fontMsg, QgsMessageBar::WARNING );
}

void QgisApp::labelingDialogFontNotFound( QAction* act )
{
if ( !act )
{
return;
}

// get base pointer to layer
QObject* obj = qvariant_cast<QObject*>( act->data() );

// remove calling messagebar widget
messageBar()->popWidget();

if ( !obj )
{
return;
}

QgsMapLayer* layer = qobject_cast<QgsMapLayer*>( obj );
if ( layer && setActiveLayer( layer ) )
{
labeling();
}
}

void QgisApp::labeling()
{
QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer*>( activeLayer() );
Expand All @@ -4295,6 +4352,7 @@ void QgisApp::labeling()
QDialog *dlg = new QDialog( this );
dlg->setWindowTitle( tr( "Layer labeling settings" ) );
QgsLabelingGui *labelingGui = new QgsLabelingGui( mLBL, vlayer, mMapCanvas, dlg );
labelingGui->init(); // load QgsPalLayerSettings for layer
labelingGui->layout()->setContentsMargins( 0, 0, 0, 0 );
QVBoxLayout *layout = new QVBoxLayout( dlg );
layout->addWidget( labelingGui );
Expand Down Expand Up @@ -7657,6 +7715,9 @@ void QgisApp::layersWereAdded( QList<QgsMapLayer *> theLayers )
QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( layer );
if ( vlayer )
{
// notify user about any font family substitution, but only when rendering labels (i.e. not when opening settings dialog)
connect( vlayer, SIGNAL( labelingFontNotFound( QgsVectorLayer*, QString ) ), this, SLOT( labelingFontNotFound( QgsVectorLayer*, QString ) ) );

QgsVectorDataProvider* vProvider = vlayer->dataProvider();
if ( vProvider && vProvider->capabilities() & QgsVectorDataProvider::EditingCapabilities )
{
Expand Down
10 changes: 10 additions & 0 deletions src/app/qgisapp.h
Original file line number Diff line number Diff line change
Expand Up @@ -1020,6 +1020,16 @@ class QgisApp : public QMainWindow, private Ui::MainWindow
void addSvgAnnotation();
void modifyAnnotation();

/** Alerts user when labeling font for layer has not been found on system
* @note added in 1.9
*/
void labelingFontNotFound( QgsVectorLayer* vlayer, const QString& fontfamily );

/** Opens the labeling dialog for a layer when called from labelingFontNotFound alert
* @note added in 1.9
*/
void labelingDialogFontNotFound( QAction* act );

//! shows label settings dialog (for labeling-ng)
void labeling();

Expand Down
142 changes: 38 additions & 104 deletions src/app/qgslabelinggui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "qgslabelengineconfigdialog.h"
#include "qgsexpressionbuilderdialog.h"
#include "qgsexpression.h"
#include "qgsfontutils.h"
#include "qgisapp.h"
#include "qgsmaprenderer.h"
#include "qgsproject.h"
Expand Down Expand Up @@ -72,7 +73,6 @@ QgsLabelingGui::QgsLabelingGui( QgsPalLabeling* lbl, QgsVectorLayer* layer, QgsM

// preview and basic option connections
connect( btnTextColor, SIGNAL( colorChanged( const QColor& ) ), this, SLOT( changeTextColor( const QColor& ) ) );
connect( btnChangeFont, SIGNAL( clicked() ), this, SLOT( changeTextFont() ) );
connect( mFontTranspSpinBox, SIGNAL( valueChanged( int ) ), this, SLOT( updatePreview() ) );
connect( mBufferDrawChkBx, SIGNAL( toggled( bool ) ), this, SLOT( updatePreview() ) );
connect( btnBufferColor, SIGNAL( colorChanged( const QColor& ) ), this, SLOT( changeBufferColor( const QColor& ) ) );
Expand Down Expand Up @@ -184,9 +184,6 @@ QgsLabelingGui::QgsLabelingGui( QgsPalLabeling* lbl, QgsVectorLayer* layer, QgsM
// TODO: is this necessary? maybe just use the data defined-only rotation?
mPointAngleDDBtn->setVisible( false );

// load layer's current QgsPalLayerSettings
init();

// Global settings group for groupboxes' saved/retored collapsed state
// maintains state across different dialogs
foreach ( QgsCollapsibleGroupBox *grpbox, findChildren<QgsCollapsibleGroupBox*>() )
Expand Down Expand Up @@ -365,9 +362,25 @@ void QgsLabelingGui::init()
mFontWordSpacingSpinBox->setValue( lyr.textFont.wordSpacing() );
mFontLetterSpacingSpinBox->setValue( lyr.textFont.letterSpacing() );

updateFontViaStyle( lyr.textNamedStyle );
QgsFontUtils::updateFontViaStyle( mRefFont, lyr.textNamedStyle );
updateFont( mRefFont );

// show 'font not found' if substitution has occurred (should come after updateFont())
if ( !lyr.mTextFontFound )
{
mFontMissingLabel->setVisible( true );
QString missingTxt = tr( "%1 not found. Default substituted." );
QString txtPrepend = tr( "Chosen font" );
if ( !lyr.mTextFontFamily.isEmpty() )
{
txtPrepend = QString( "'%1'" ).arg( lyr.mTextFontFamily );
}
mFontMissingLabel->setText( missingTxt.arg( txtPrepend ) );

// ensure user is sent to 'Text style' section to see notice
mLabelingOptionsListWidget->setCurrentRow( 0 );
}

// shape background
mShapeDrawChkBx->setChecked( lyr.shapeDraw );
mShapeTypeCmbBx->blockSignals( true );
Expand Down Expand Up @@ -476,6 +489,7 @@ void QgsLabelingGui::collapseSample( bool collapse )
void QgsLabelingGui::apply()
{
writeSettingsToLayer();
mFontMissingLabel->setVisible( false );
QgisApp::instance()->markDirty();
// trigger refresh
if ( mMapCanvas )
Expand Down Expand Up @@ -1021,82 +1035,6 @@ void QgsLabelingGui::changeTextColor( const QColor &color )
updatePreview();
}

void QgsLabelingGui::changeTextFont()
{
// store properties of QFont that might be stripped by font dialog
QFont::Capitalization captials = mRefFont.capitalization();
double wordspacing = mRefFont.wordSpacing();
double letterspacing = mRefFont.letterSpacing();

bool ok;
#if defined(Q_WS_MAC) && QT_VERSION >= 0x040500 && defined(QT_MAC_USE_COCOA)
// Native Mac dialog works only for Qt Carbon
QFont font = QFontDialog::getFont( &ok, mRefFont, 0, QString(), QFontDialog::DontUseNativeDialog );
#else
QFont font = QFontDialog::getFont( &ok, mRefFont );
#endif
if ( ok )
{
if ( mFontSizeUnitComboBox->currentIndex() == 1 )
{
// don't override map units size with selected size from font dialog
font.setPointSizeF( mFontSizeSpinBox->value() );
}
else
{
mFontSizeSpinBox->setValue( font.pointSizeF() );
}

// reassign possibly stripped QFont properties
font.setCapitalization( captials );
font.setWordSpacing( wordspacing );
font.setLetterSpacing( QFont::AbsoluteSpacing, letterspacing );

updateFont( font );
}
}

void QgsLabelingGui::updateFontViaStyle( const QString & fontstyle )
{
QFont styledfont;
bool foundmatch = false;
int fontSize = 12; // QFontDatabase::font() needs an integer for size
if ( !fontstyle.isEmpty() )
{
styledfont = mFontDB.font( mRefFont.family(), fontstyle, fontSize );
styledfont.setPointSizeF( mRefFont.pointSizeF() );
if ( QApplication::font().toString() != styledfont.toString() )
{
foundmatch = true;
}
}
if ( !foundmatch )
{
foreach ( const QString &style, mFontDB.styles( mRefFont.family() ) )
{
styledfont = mFontDB.font( mRefFont.family(), style, fontSize );
styledfont.setPointSizeF( mRefFont.pointSizeF() );
styledfont = styledfont.resolve( mRefFont );
if ( mRefFont.toString() == styledfont.toString() )
{
foundmatch = true;
break;
}
}
}
if ( foundmatch )
{
// styledfont.setPointSizeF( mRefFont.pointSizeF() );
styledfont.setCapitalization( mRefFont.capitalization() );
styledfont.setUnderline( mRefFont.underline() );
styledfont.setStrikeOut( mRefFont.strikeOut() );
styledfont.setWordSpacing( mRefFont.wordSpacing() );
styledfont.setLetterSpacing( QFont::AbsoluteSpacing, mRefFont.letterSpacing() );
mRefFont = styledfont;
}
// if no match, style combobox will be left blank, which should not affect engine labeling
}

void QgsLabelingGui::updateFont( QFont font )
{
// update background reference font
Expand All @@ -1106,31 +1044,13 @@ void QgsLabelingGui::updateFont( QFont font )
}

// test if font is actually available
QString missingtxt = QString( "" );
bool missing = false;
if ( QApplication::font().toString() != mRefFont.toString() )
{
QFont testfont = mFontDB.font( mRefFont.family(), mFontDB.styleString( mRefFont ), 12 );
if ( QApplication::font().toString() == testfont.toString() )
{
missing = true;
}
}
if ( missing )
{
missingtxt = tr( " (not found!)" );
lblFontName->setStyleSheet( "color: #990000;" );
}
else
{
lblFontName->setStyleSheet( "color: #000000;" );
}
mFontMissingLabel->setVisible( QgsFontUtils::fontMatchOnSystem( mRefFont ) );

lblFontName->setText( QString( "%1%2" ).arg( mRefFont.family() ).arg( missingtxt ) );
mDirectSymbLeftLineEdit->setFont( mRefFont );
mDirectSymbRightLineEdit->setFont( mRefFont );

blockFontChangeSignals( true );
mFontFamilyCmbBx->setCurrentFont( mRefFont );
populateFontStyleComboBox();
int idx = mFontCapitalsComboBox->findData( QVariant(( unsigned int ) mRefFont.capitalization() ) );
mFontCapitalsComboBox->setCurrentIndex( idx == -1 ? 0 : idx );
Expand All @@ -1140,13 +1060,13 @@ void QgsLabelingGui::updateFont( QFont font )

// update font name with font face
// font.setPixelSize( 24 );
// lblFontName->setFont( QFont( font ) );

updatePreview();
}

void QgsLabelingGui::blockFontChangeSignals( bool blk )
{
mFontFamilyCmbBx->blockSignals( blk );
mFontStyleComboBox->blockSignals( blk );
mFontCapitalsComboBox->blockSignals( blk );
mFontUnderlineBtn->blockSignals( blk );
Expand Down Expand Up @@ -1376,7 +1296,15 @@ void QgsLabelingGui::populateFontStyleComboBox()
{
mFontStyleComboBox->addItem( style );
}
mFontStyleComboBox->setCurrentIndex( mFontStyleComboBox->findText( mFontDB.styleString( mRefFont ) ) );

int curIndx = 0;
int stylIndx = mFontStyleComboBox->findText( mFontDB.styleString( mRefFont ) );
if ( stylIndx > -1 )
{
curIndx = stylIndx;
}

mFontStyleComboBox->setCurrentIndex( curIndx );
}

void QgsLabelingGui::on_mPreviewSizeSlider_valueChanged( int i )
Expand All @@ -1398,9 +1326,15 @@ void QgsLabelingGui::on_mFontCapitalsComboBox_currentIndexChanged( int index )
updateFont( mRefFont );
}

void QgsLabelingGui::on_mFontFamilyCmbBx_currentFontChanged( const QFont& f )
{
mRefFont.setFamily( f.family() );
updateFont( mRefFont );
}

void QgsLabelingGui::on_mFontStyleComboBox_currentIndexChanged( const QString & text )
{
updateFontViaStyle( text );
QgsFontUtils::updateFontViaStyle( mRefFont, text );
updateFont( mRefFont );
}

Expand Down
3 changes: 1 addition & 2 deletions src/app/qgslabelinggui.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ class QgsLabelingGui : public QWidget, private Ui::QgsLabelingGuiBase
void collapseSample( bool collapse );
void apply();
void changeTextColor( const QColor &color );
void changeTextFont();
void showEngineConfigDialog();
void showExpressionDialog();
void changeBufferColor( const QColor &color );
Expand All @@ -58,6 +57,7 @@ class QgsLabelingGui : public QWidget, private Ui::QgsLabelingGuiBase
void on_mPreviewSizeSlider_valueChanged( int i );
void on_mFontSizeSpinBox_valueChanged( double d );
void on_mFontCapitalsComboBox_currentIndexChanged( int index );
void on_mFontFamilyCmbBx_currentFontChanged( const QFont& f );
void on_mFontStyleComboBox_currentIndexChanged( const QString & text );
void on_mFontUnderlineBtn_toggled( bool ckd );
void on_mFontStrikethroughBtn_toggled( bool ckd );
Expand Down Expand Up @@ -85,7 +85,6 @@ class QgsLabelingGui : public QWidget, private Ui::QgsLabelingGuiBase
void blockInitSignals( bool block );
void blockFontChangeSignals( bool blk );
void setPreviewBackground( QColor color );
void updateFontViaStyle( const QString & fontstyle );
void syncDefinedCheckboxFrame( QgsDataDefinedButton* ddBtn, QCheckBox* chkBx, QFrame* f );
void populateFontCapitalsComboBox();
void populateFontStyleComboBox();
Expand Down
2 changes: 2 additions & 0 deletions src/core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ SET(QGIS_CORE_SRCS
qgsfeaturerequest.cpp
qgsfeaturestore.cpp
qgsfield.cpp
qgsfontutils.cpp
qgsgeometry.cpp
qgsgeometrycache.cpp
qgsgeometryvalidator.cpp
Expand Down Expand Up @@ -395,6 +396,7 @@ SET(QGIS_CORE_HDRS
qgsfeaturerequest.h
qgsfeaturestore.h
qgsfield.h
qgsfontutils.h
qgsgeometry.h
qgsgml.h
qgsgmlschema.h
Expand Down
Loading