23#include <QApplication>
26#include <QFontDatabase>
34 const QFontInfo fi = QFontInfo( f );
35 return fi.exactMatch();
40 const QFont tmpFont = QFont( family );
42 return tmpFont.family().startsWith( family, Qt::CaseInsensitive );
47 const QFontDatabase fontDB;
51 if ( fontDB.styles( family ).contains( style ) )
55 QString modified( style );
56 if ( style ==
"Roman" )
58 if ( style ==
"Oblique" )
60 if ( style ==
"Bold Oblique" )
61 modified =
"Bold Italic";
62 if ( fontDB.styles( family ).contains( modified ) )
71 auto styleNameIsMatch = [&font](
const QString & candidate ) ->
bool
74 QFont testFont( font.family() );
75 testFont.setStyleName( candidate );
76 return testFont.italic() == font.italic() && testFont.weight() == font.weight();
80 const QFontInfo fontInfo( font );
81 QString styleName = fontInfo.styleName();
82 if ( !styleName.isEmpty() )
84 if ( styleNameIsMatch( styleName ) )
89 styleName = QFontDatabase().styleString( font );
90 if ( !styleName.isEmpty() )
92 if ( styleNameIsMatch( styleName ) )
102 const QFontDatabase fontDB;
103 const QStringList fontFamilies = fontDB.families();
106 QList<QString>::const_iterator it = fontFamilies.constBegin();
107 for ( ; it != fontFamilies.constEnd(); ++it )
110 if ( it->startsWith( family, Qt::CaseInsensitive ) )
117 *match = ( *it == family );
133 const QFont f = QFont( family );
134 *chosen = f.family();
155 if ( fontstyle.isEmpty() )
160 QFontDatabase fontDB;
173 if ( fontstyle == fontDB.styleString( f ) )
178 const QFont appfont = QApplication::font();
179 const int defaultSize = appfont.pointSize();
182 bool foundmatch =
false;
185 styledfont = fontDB.font( f.family(), fontstyle, defaultSize );
186 if ( appfont != styledfont || fontstyle != fontDB.styleString( f ) )
193 if ( fallback && !foundmatch )
195 QFont testFont = QFont( f );
196 testFont.setPointSize( defaultSize );
199 const auto constFamily = fontDB.styles( f.family() );
200 for (
const QString &style : constFamily )
202 styledfont = fontDB.font( f.family(), style, defaultSize );
203 styledfont = styledfont.resolve( f );
204 if ( testFont.toString() == styledfont.toString() )
214 for (
const QString &style : constFamily )
216 styledfont = fontDB.font( f.family(), style, defaultSize );
217 if ( QApplication::font() != styledfont )
232 styledfont.setPointSizeF( f.pointSizeF() );
234 else if ( f.pixelSize() != -1 )
236 styledfont.setPixelSize( f.pixelSize() );
238 styledfont.setCapitalization( f.capitalization() );
239 styledfont.setUnderline( f.underline() );
240 styledfont.setStrikeOut( f.strikeOut() );
241 styledfont.setWordSpacing( f.wordSpacing() );
242 styledfont.setLetterSpacing( QFont::AbsoluteSpacing, f.letterSpacing() );
253 return QStringLiteral(
"QGIS Vera Sans" );
259 bool fontsLoaded =
false;
262 QMap<QString, QString> fontStyles;
263 fontStyles.insert( QStringLiteral(
"Roman" ), QStringLiteral(
"QGIS-Vera/QGIS-Vera.ttf" ) );
264 fontStyles.insert( QStringLiteral(
"Oblique" ), QStringLiteral(
"QGIS-Vera/QGIS-VeraIt.ttf" ) );
265 fontStyles.insert( QStringLiteral(
"Bold" ), QStringLiteral(
"QGIS-Vera/QGIS-VeraBd.ttf" ) );
266 fontStyles.insert( QStringLiteral(
"Bold Oblique" ), QStringLiteral(
"QGIS-Vera/QGIS-VeraBI.ttf" ) );
268 QMap<QString, QString>::const_iterator f = fontStyles.constBegin();
269 for ( ; f != fontStyles.constEnd(); ++f )
271 const QString fontstyle( f.key() );
272 const QString fontpath( f.value() );
273 if ( !( loadstyles.contains( fontstyle ) || loadstyles.contains( QStringLiteral(
"All" ) ) ) )
280 QgsDebugMsgLevel( QStringLiteral(
"Test font '%1 %2' already available" ).arg( fontFamily, fontstyle ), 2 );
292 const int fontID = QFontDatabase::addApplicationFont( fontPath );
293 loaded = ( fontID != -1 );
294 fontsLoaded = ( fontsLoaded || loaded );
295 QgsDebugMsgLevel( QStringLiteral(
"Test font '%1 %2' %3 from filesystem [%4]" )
296 .arg( fontFamily, fontstyle, loaded ?
"loaded" :
"FAILED to load", fontPath ), 2 );
297 QgsDebugMsgLevel( QStringLiteral(
"font families in %1: %2" ).arg( fontID ).arg( QFontDatabase().applicationFontFamilies( fontID ).join(
"," ) ), 2 );
301 QFile fontResource(
":/testdata/font/" + fontpath );
302 if ( fontResource.open( QIODevice::ReadOnly ) )
304 const int fontID = QFontDatabase::addApplicationFontFromData( fontResource.readAll() );
305 loaded = ( fontID != -1 );
306 fontsLoaded = ( fontsLoaded || loaded );
308 QgsDebugMsgLevel( QStringLiteral(
"Test font '%1' (%2) %3 from testdata.qrc" )
309 .arg( fontFamily, fontstyle, loaded ?
"loaded" :
"FAILED to load" ), 2 );
324 const QFontDatabase fontDB;
327 if ( !f.exactMatch() )
330 if ( style ==
"Roman" )
332 else if ( style ==
"Oblique" )
334 else if ( style ==
"Bold Oblique" )
335 modified =
"Bold Italic";
336 if ( !modified.isEmpty() )
339 if ( !f.exactMatch() )
342 QgsDebugMsgLevel( QStringLiteral(
"Requested: %1" ).arg( f.toString() ), 2 );
344 QgsDebugMsgLevel( QStringLiteral(
"Replaced: %1,%2,%3,%4,%5,%6,%7,%8,%9" ).arg( fi.family() ).arg( fi.pointSizeF() ).arg( fi.pixelSize() ).arg( fi.styleHint() ).arg( fi.weight() ).arg( fi.style() ).arg( fi.underline() ).arg( fi.strikeOut() ).arg( fi.fixedPitch() ), 2 );
348 f.setBold( style.contains( QLatin1String(
"Bold" ) ) );
349 f.setItalic( style.contains( QLatin1String(
"Oblique" ) ) || style.contains( QLatin1String(
"Italic" ) ) );
356 QDomElement fontElem = document.createElement( elementName );
357 fontElem.setAttribute( QStringLiteral(
"description" ), font.toString() );
359 fontElem.setAttribute( QStringLiteral(
"bold" ), font.bold() ? QChar(
'1' ) : QChar(
'0' ) );
360 fontElem.setAttribute( QStringLiteral(
"italic" ), font.italic() ? QChar(
'1' ) : QChar(
'0' ) );
361 fontElem.setAttribute( QStringLiteral(
"underline" ), font.underline() ? QChar(
'1' ) : QChar(
'0' ) );
362 fontElem.setAttribute( QStringLiteral(
"strikethrough" ), font.strikeOut() ? QChar(
'1' ) : QChar(
'0' ) );
368 if ( element.isNull() )
373 font.fromString( element.attribute( QStringLiteral(
"description" ) ) );
375 if ( element.hasAttribute( QStringLiteral(
"bold" ) ) && element.attribute( QStringLiteral(
"bold" ) ) == QChar(
'1' ) )
377 font.setBold(
true );
379 if ( element.hasAttribute( QStringLiteral(
"italic" ) ) )
381 font.setItalic( element.attribute( QStringLiteral(
"italic" ) ) == QChar(
'1' ) );
383 if ( element.hasAttribute( QStringLiteral(
"underline" ) ) )
385 font.setUnderline( element.attribute( QStringLiteral(
"underline" ) ) == QChar(
'1' ) );
387 if ( element.hasAttribute( QStringLiteral(
"strikethrough" ) ) )
389 font.setStrikeOut( element.attribute( QStringLiteral(
"strikethrough" ) ) == QChar(
'1' ) );
392 if ( element.hasAttribute( QStringLiteral(
"style" ) ) )
402 if ( element.isNull() )
407 const QDomNodeList nodeList = element.elementsByTagName( childNode );
408 if ( !nodeList.isEmpty() )
410 const QDomElement fontElem = nodeList.at( 0 ).toElement();
421 std::unique_ptr< QMimeData >mimeData(
new QMimeData );
423 QDomDocument fontDoc;
424 const QDomElement fontElem =
toXmlElement( font, fontDoc, QStringLiteral(
"font" ) );
425 fontDoc.appendChild( fontElem );
426 mimeData->setText( fontDoc.toString() );
428 return mimeData.release();
440 const QString text = data->text();
441 if ( !text.isEmpty() )
446 if ( doc.setContent( text ) )
448 elem = doc.documentElement();
450 if ( elem.nodeName() != QLatin1String(
"font" ) )
451 elem = elem.firstChildElement( QStringLiteral(
"font" ) );
464static QMap<QString, QString> createTranslatedStyleMap()
466 QMap<QString, QString> translatedStyleMap;
467 const QStringList words = QStringList()
468 << QStringLiteral(
"Normal" )
469 << QStringLiteral(
"Regular" )
470 << QStringLiteral(
"Light" )
471 << QStringLiteral(
"Bold" )
472 << QStringLiteral(
"Black" )
473 << QStringLiteral(
"Demi" )
474 << QStringLiteral(
"Italic" )
475 << QStringLiteral(
"Oblique" );
476 const auto constWords = words;
477 for (
const QString &word : constWords )
479 translatedStyleMap.insert( QCoreApplication::translate(
"QFontDatabase", qPrintable( word ) ), word );
481 return translatedStyleMap;
486 QStringList words = namedStyle.split(
' ', Qt::SkipEmptyParts );
487 for (
int i = 0, n = words.length(); i < n; ++i )
489 words[i] = QCoreApplication::translate(
"QFontDatabase", words[i].toLocal8Bit().constData() );
491 return words.join( QLatin1Char(
' ' ) );
496 static const QMap<QString, QString> translatedStyleMap = createTranslatedStyleMap();
497 QStringList words = namedStyle.split(
' ', Qt::SkipEmptyParts );
499 for (
int i = 0, n = words.length(); i < n; ++i )
501 if ( translatedStyleMap.contains( words[i] ) )
503 words[i] = translatedStyleMap.value( words[i] );
507 QgsDebugMsgLevel( QStringLiteral(
"Warning: style map does not contain %1" ).arg( words[i] ), 2 );
510 return words.join( QLatin1Char(
' ' ) );
515 QString css = QStringLiteral(
"font-family: " ) + font.family() +
';';
518 css += QLatin1String(
"font-style: " );
519 switch ( font.style() )
521 case QFont::StyleNormal:
522 css += QLatin1String(
"normal" );
524 case QFont::StyleItalic:
525 css += QLatin1String(
"italic" );
527 case QFont::StyleOblique:
528 css += QLatin1String(
"oblique" );
535 switch ( font.weight() )
543 case QFont::DemiBold:
555 case QFont::ExtraLight:
561 case QFont::ExtraBold:
565 css += QStringLiteral(
"font-weight: %1;" ).arg( cssWeight );
568 css += QStringLiteral(
"font-size: %1px;" ).arg( font.pointSizeF() >= 0 ? font.pointSizeF() * pointToPixelScale : font.pixelSize() );
575 if ( family.isEmpty() )
581 QStringList recentFamilies = settings.
value( QStringLiteral(
"fonts/recent" ) ).toStringList();
584 recentFamilies.removeAll( family );
587 recentFamilies.prepend( family );
590 recentFamilies = recentFamilies.mid( 0, 10 );
592 settings.
setValue( QStringLiteral(
"fonts/recent" ), recentFamilies );
598 return settings.
value( QStringLiteral(
"fonts/recent" ) ).toStringList();
603 font.setFamily( family );
604 if ( !font.exactMatch() )
609 font.setFamilies( { family } );
615 QFont font( family, pointSize, weight, italic );
616 if ( !font.exactMatch() )
621 font.setFamilies( { family } );
static QString buildSourcePath()
Returns path to the source directory. Valid only when running from build directory.
static bool isRunningFromBuildDir()
Indicates whether running from build directory (not installed)
static QString resolveFontStyleName(const QFont &font)
Attempts to resolve the style name corresponding to the specified font object.
static QString asCSS(const QFont &font, double pointToPixelMultiplier=1.0)
Returns a CSS string representing the specified font as closely as possible.
static QString translateNamedStyle(const QString &namedStyle)
Returns the localized named style of a font, if such a translation is available.
static QString untranslateNamedStyle(const QString &namedStyle)
Returns the english named style of a font, if possible.
static bool setFromXmlElement(QFont &font, const QDomElement &element)
Sets the properties of a font to match the properties stored in an XML element.
static bool setFromXmlChildNode(QFont &font, const QDomElement &element, const QString &childNode)
Sets the properties of a font to match the properties stored in an XML child node.
static QFont createFont(const QString &family, int pointSize=-1, int weight=-1, bool italic=false)
Creates a font with the specified family.
static QMimeData * toMimeData(const QFont &font)
Returns new mime data representing the specified font settings.
static bool fontFamilyMatchOnSystem(const QString &family, QString *chosen=nullptr, bool *match=nullptr)
Check whether font family is on system.
static bool fontFamilyOnSystem(const QString &family)
Check whether font family is on system in a quick manner, which does not compare [foundry].
static bool updateFontViaStyle(QFont &f, const QString &fontstyle, bool fallback=false)
Updates font with named style and retain all font properties.
static bool fontMatchOnSystem(const QFont &f)
Check whether exact font is on system.
static bool loadStandardTestFonts(const QStringList &loadstyles)
Loads standard test fonts from filesystem or qrc resource.
static QFont getStandardTestFont(const QString &style="Roman", int pointsize=12)
Gets standard test font with specific style.
static void setFontFamily(QFont &font, const QString &family)
Sets the family for a font object.
static QDomElement toXmlElement(const QFont &font, QDomDocument &document, const QString &elementName)
Returns a DOM element containing the properties of the font.
static void addRecentFontFamily(const QString &family)
Adds a font family to the list of recently used font families.
static QString standardTestFontFamily()
Gets standard test font family.
static QFont fromMimeData(const QMimeData *data, bool *ok=nullptr)
Attempts to parse the provided mime data as a QFont.
static bool fontFamilyHasStyle(const QString &family, const QString &style)
Check whether font family on system has specific style.
static QStringList recentFontFamilies()
Returns a list of recently used font families.
This class is a composition of two QSettings instances:
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
#define QgsDebugMsgLevel(str, level)