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#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
487 QStringList words = namedStyle.split(
' ', QString::SkipEmptyParts );
489 QStringList words = namedStyle.split(
' ', Qt::SkipEmptyParts );
491 for (
int i = 0, n = words.length(); i < n; ++i )
493 words[i] = QCoreApplication::translate(
"QFontDatabase", words[i].toLocal8Bit().constData() );
495 return words.join( QLatin1Char(
' ' ) );
500 static const QMap<QString, QString> translatedStyleMap = createTranslatedStyleMap();
501#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
502 QStringList words = namedStyle.split(
' ', QString::SkipEmptyParts );
504 QStringList words = namedStyle.split(
' ', Qt::SkipEmptyParts );
507 for (
int i = 0, n = words.length(); i < n; ++i )
509 if ( translatedStyleMap.contains( words[i] ) )
511 words[i] = translatedStyleMap.value( words[i] );
515 QgsDebugMsgLevel( QStringLiteral(
"Warning: style map does not contain %1" ).arg( words[i] ), 2 );
518 return words.join( QLatin1Char(
' ' ) );
523 QString css = QStringLiteral(
"font-family: " ) + font.family() +
';';
526 css += QLatin1String(
"font-style: " );
527 switch ( font.style() )
529 case QFont::StyleNormal:
530 css += QLatin1String(
"normal" );
532 case QFont::StyleItalic:
533 css += QLatin1String(
"italic" );
535 case QFont::StyleOblique:
536 css += QLatin1String(
"oblique" );
543 switch ( font.weight() )
551 case QFont::DemiBold:
563 case QFont::ExtraLight:
569 case QFont::ExtraBold:
573 css += QStringLiteral(
"font-weight: %1;" ).arg( cssWeight );
576 css += QStringLiteral(
"font-size: %1px;" ).arg( font.pointSizeF() >= 0 ? font.pointSizeF() * pointToPixelScale : font.pixelSize() );
583 if ( family.isEmpty() )
589 QStringList recentFamilies = settings.
value( QStringLiteral(
"fonts/recent" ) ).toStringList();
592 recentFamilies.removeAll( family );
595 recentFamilies.prepend( family );
598 recentFamilies = recentFamilies.mid( 0, 10 );
600 settings.
setValue( QStringLiteral(
"fonts/recent" ), recentFamilies );
606 return settings.
value( QStringLiteral(
"fonts/recent" ) ).toStringList();
611 font.setFamily( family );
612 if ( !font.exactMatch() )
617 font.setFamilies( { family } );
623 QFont font( family, pointSize, weight, italic );
624 if ( !font.exactMatch() )
629 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)