QGIS API Documentation 3.43.0-Master (0cdc48caa8d)
qgsfontutils.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsfontutils.h
3 ---------------------
4 begin : June 5, 2013
5 copyright : (C) 2013 by Larry Shaffer
6 email : larrys at dakotacarto dot com
7 ***************************************************************************
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 ***************************************************************************/
15
16#include "qgsfontutils.h"
17
18#include "qgsapplication.h"
19#include "qgslogger.h"
20#include "qgssettings.h"
21#include "qgis.h"
22
23#include <QApplication>
24#include <QFile>
25#include <QFont>
26#include <QFontDatabase>
27#include <QFontInfo>
28#include <QStringList>
29#include <QMimeData>
30#include <memory>
31
32bool QgsFontUtils::fontMatchOnSystem( const QFont &f )
33{
34 const QFontInfo fi = QFontInfo( f );
35 return fi.exactMatch();
36}
37
38bool QgsFontUtils::fontFamilyOnSystem( const QString &family )
39{
40 const QFont tmpFont = QFont( family );
41 // compare just beginning of family string in case 'family [foundry]' differs
42 return tmpFont.family().startsWith( family, Qt::CaseInsensitive );
43}
44
45bool QgsFontUtils::fontFamilyHasStyle( const QString &family, const QString &style )
46{
47 const QFontDatabase fontDB;
48 if ( !fontFamilyOnSystem( family ) )
49 return false;
50
51 if ( fontDB.styles( family ).contains( style ) )
52 return true;
53
54#ifdef Q_OS_WIN
55 QString modified( style );
56 if ( style == "Roman" )
57 modified = "Normal";
58 if ( style == "Oblique" )
59 modified = "Italic";
60 if ( style == "Bold Oblique" )
61 modified = "Bold Italic";
62 if ( fontDB.styles( family ).contains( modified ) )
63 return true;
64#endif
65
66 return false;
67}
68
69QString QgsFontUtils::resolveFontStyleName( const QFont &font )
70{
71 auto styleNameIsMatch = [&font]( const QString & candidate ) -> bool
72 {
73 // confirm that style name matches bold/italic flags
74 QFont testFont( font.family() );
75 testFont.setStyleName( candidate );
76 return testFont.italic() == font.italic() && testFont.weight() == font.weight();
77 };
78
79 // attempt 1
80 const QFontInfo fontInfo( font );
81 QString styleName = fontInfo.styleName();
82 if ( !styleName.isEmpty() )
83 {
84 if ( styleNameIsMatch( styleName ) )
85 return styleName;
86 }
87
88 // attempt 2
89 styleName = QFontDatabase().styleString( font );
90 if ( !styleName.isEmpty() )
91 {
92 if ( styleNameIsMatch( styleName ) )
93 return styleName;
94 }
95
96 // failed
97 return QString();
98}
99
100bool QgsFontUtils::fontFamilyMatchOnSystem( const QString &family, QString *chosen, bool *match )
101{
102 const QFontDatabase fontDB;
103 const QStringList fontFamilies = fontDB.families();
104 bool found = false;
105
106 QList<QString>::const_iterator it = fontFamilies.constBegin();
107 for ( ; it != fontFamilies.constEnd(); ++it )
108 {
109 // first compare just beginning of 'family [foundry]' string
110 if ( it->startsWith( family, Qt::CaseInsensitive ) )
111 {
112 found = true;
113 // keep looking if match info is requested
114 if ( match )
115 {
116 // full 'family [foundry]' strings have to match
117 *match = ( *it == family );
118 if ( *match )
119 break;
120 }
121 else
122 {
123 break;
124 }
125 }
126 }
127
128 if ( found )
129 {
130 if ( chosen )
131 {
132 // retrieve the family actually assigned by matching algorithm
133 const QFont f = QFont( family );
134 *chosen = f.family();
135 }
136 }
137 else
138 {
139 if ( chosen )
140 {
141 *chosen = QString();
142 }
143
144 if ( match )
145 {
146 *match = false;
147 }
148 }
149
150 return found;
151}
152
153bool QgsFontUtils::updateFontViaStyle( QFont &f, const QString &fontstyle, bool fallback )
154{
155 if ( fontstyle.isEmpty() )
156 {
157 return false;
158 }
159
160 QFontDatabase fontDB;
161 QString actualFontStyle = fontstyle;
162
163 if ( !fallback )
164 {
165 // does the font even have the requested style?
166 bool hasstyle = fontFamilyHasStyle( f.family(), actualFontStyle );
167 if ( !hasstyle )
168 {
169 actualFontStyle = untranslateNamedStyle( fontstyle );
170 hasstyle = fontFamilyHasStyle( f.family(), actualFontStyle );
171 }
172
173 if ( !hasstyle )
174 {
175 return false;
176 }
177 }
178
179 // is the font's style already the same as requested?
180 if ( actualFontStyle == fontDB.styleString( f ) )
181 {
182 return false;
183 }
184
185 const QFont appfont = QApplication::font();
186 const int defaultSize = appfont.pointSize(); // QFontDatabase::font() needs an integer for size
187
188 QFont styledfont;
189 bool foundmatch = false;
190
191 // if fontDB.font() fails, it returns the default app font; but, that may be the target style
192 styledfont = fontDB.font( f.family(), actualFontStyle, defaultSize );
193 if ( appfont != styledfont || actualFontStyle != fontDB.styleString( f ) )
194 {
195 foundmatch = true;
196 }
197
198 // default to first found style if requested style is unavailable
199 // this helps in the situations where the passed-in font has to have a named style applied
200 if ( fallback && !foundmatch )
201 {
202 QFont testFont = QFont( f );
203 testFont.setPointSize( defaultSize );
204
205 // prefer a style that mostly matches the passed-in font
206 const auto constFamily = fontDB.styles( f.family() );
207 for ( const QString &style : constFamily )
208 {
209 styledfont = fontDB.font( f.family(), style, defaultSize );
210 styledfont = styledfont.resolve( f );
211 if ( testFont.toString() == styledfont.toString() )
212 {
213 foundmatch = true;
214 break;
215 }
216 }
217
218 // fallback to first style found that works
219 if ( !foundmatch )
220 {
221 for ( const QString &style : constFamily )
222 {
223 styledfont = fontDB.font( f.family(), style, defaultSize );
224 if ( QApplication::font() != styledfont )
225 {
226 foundmatch = true;
227 break;
228 }
229 }
230 }
231 }
232
233 // similar to QFont::resolve, but font may already have pixel size set
234 // and we want to make sure that's preserved
235 if ( foundmatch )
236 {
237 if ( !qgsDoubleNear( f.pointSizeF(), -1 ) )
238 {
239 styledfont.setPointSizeF( f.pointSizeF() );
240 }
241 else if ( f.pixelSize() != -1 )
242 {
243 styledfont.setPixelSize( f.pixelSize() );
244 }
245 styledfont.setCapitalization( f.capitalization() );
246 styledfont.setUnderline( f.underline() );
247 styledfont.setStrikeOut( f.strikeOut() );
248 styledfont.setWordSpacing( f.wordSpacing() );
249 styledfont.setLetterSpacing( QFont::AbsoluteSpacing, f.letterSpacing() );
250 f = styledfont;
251
252 return true;
253 }
254
255 return false;
256}
257
259{
260 return QStringLiteral( "QGIS Vera Sans" );
261}
262
263bool QgsFontUtils::loadStandardTestFonts( const QStringList &loadstyles )
264{
265 // load standard test font from filesystem or testdata.qrc (for unit tests and general testing)
266 bool fontsLoaded = false;
267
268 QMap<QString, QString> fontStyles;
269 fontStyles.insert( QStringLiteral( "Roman" ), QStringLiteral( "QGIS-Vera/QGIS-Vera.ttf" ) );
270 fontStyles.insert( QStringLiteral( "Oblique" ), QStringLiteral( "QGIS-Vera/QGIS-VeraIt.ttf" ) );
271 fontStyles.insert( QStringLiteral( "Bold" ), QStringLiteral( "QGIS-Vera/QGIS-VeraBd.ttf" ) );
272 fontStyles.insert( QStringLiteral( "Bold Oblique" ), QStringLiteral( "QGIS-Vera/QGIS-VeraBI.ttf" ) );
273 fontStyles.insert( QStringLiteral( "Deja Bold" ), QStringLiteral( "QGIS-DejaVu/QGISDejaVuSans-Bold.ttf" ) );
274
275 QMap<QString, QString>::const_iterator f = fontStyles.constBegin();
276 for ( ; f != fontStyles.constEnd(); ++f )
277 {
278 const QString fontpath( f.value() );
279 if ( !( loadstyles.contains( f.key() ) || loadstyles.contains( QStringLiteral( "All" ) ) ) )
280 {
281 continue;
282 }
283
284 const QString fontFamily = !f.key().startsWith( QLatin1String( "Deja" ) ) ? standardTestFontFamily() : QStringLiteral( "QGIS DejaVu Sans" );
285 const QString fontstyle = !f.key().startsWith( QLatin1String( "Deja" ) ) ? f.key() : f.key().mid( 5 );
286
287 if ( fontFamilyHasStyle( fontFamily, fontstyle ) )
288 {
289 QgsDebugMsgLevel( QStringLiteral( "Test font '%1 %2' already available" ).arg( fontFamily, fontstyle ), 2 );
290 }
291 else
292 {
293 bool loaded = false;
295 {
296 // workaround for bugs with Qt 4.8.5 (other versions?) on Mac 10.9, where fonts
297 // from qrc resources load but fail to work and default font is substituted [LS]:
298 // https://bugreports.qt.io/browse/QTBUG-30917
299 // https://bugreports.qt.io/browse/QTBUG-32789
300 const QString fontPath( QgsApplication::buildSourcePath() + "/tests/testdata/font/" + fontpath );
301 const int fontID = QFontDatabase::addApplicationFont( fontPath );
302 loaded = ( fontID != -1 );
303 fontsLoaded = ( fontsLoaded || loaded );
304 QgsDebugMsgLevel( QStringLiteral( "Test font '%1 %2' %3 from filesystem [%4]" )
305 .arg( fontFamily, fontstyle, loaded ? "loaded" : "FAILED to load", fontPath ), 2 );
306 QgsDebugMsgLevel( QStringLiteral( "font families in %1: %2" ).arg( fontID ).arg( QFontDatabase().applicationFontFamilies( fontID ).join( "," ) ), 2 );
307 }
308 else
309 {
310 QFile fontResource( ":/testdata/font/" + fontpath );
311 if ( fontResource.open( QIODevice::ReadOnly ) )
312 {
313 const int fontID = QFontDatabase::addApplicationFontFromData( fontResource.readAll() );
314 loaded = ( fontID != -1 );
315 fontsLoaded = ( fontsLoaded || loaded );
316 }
317 QgsDebugMsgLevel( QStringLiteral( "Test font '%1' (%2) %3 from testdata.qrc" )
318 .arg( fontFamily, fontstyle, loaded ? "loaded" : "FAILED to load" ), 2 );
319 }
320 }
321 }
322
323 return fontsLoaded;
324}
325
326QFont QgsFontUtils::getStandardTestFont( const QString &style, int pointsize )
327{
328 const QString fontFamily = !style.startsWith( QLatin1String( "Deja" ) ) ? standardTestFontFamily() : QStringLiteral( "QGIS DejaVu Sans" );
329 const QString fontStyle = !style.startsWith( QLatin1String( "Deja" ) ) ? style : style.mid( 5 );
330
331 if ( ! fontFamilyHasStyle( fontFamily, fontStyle ) )
332 {
333 loadStandardTestFonts( QStringList() << style );
334 }
335
336 const QFontDatabase fontDB;
337 QFont f = fontDB.font( fontFamily, fontStyle, pointsize );
338#ifdef Q_OS_WIN
339 if ( !f.exactMatch() )
340 {
341 QString modified;
342 if ( fontStyle == "Roman" )
343 modified = "Normal";
344 else if ( fontStyle == "Oblique" )
345 modified = "Italic";
346 else if ( fontStyle == "Bold Oblique" )
347 modified = "Bold Italic";
348 if ( !modified.isEmpty() )
349 f = fontDB.font( fontFamily, modified, pointsize );
350 }
351 if ( !f.exactMatch() )
352 {
353 QgsDebugMsgLevel( QStringLiteral( "Inexact font match - consider installing the %1 font." ).arg( fontFamily ), 2 );
354 QgsDebugMsgLevel( QStringLiteral( "Requested: %1" ).arg( f.toString() ), 2 );
355 QFontInfo fi( f );
356 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 );
357 }
358#endif
359 // in case above statement fails to set style
360 f.setBold( fontStyle.contains( QLatin1String( "Bold" ) ) );
361 f.setItalic( fontStyle.contains( QLatin1String( "Oblique" ) ) || fontStyle.contains( QLatin1String( "Italic" ) ) );
362
363 return f;
364}
365
366QDomElement QgsFontUtils::toXmlElement( const QFont &font, QDomDocument &document, const QString &elementName )
367{
368 QDomElement fontElem = document.createElement( elementName );
369 fontElem.setAttribute( QStringLiteral( "description" ), font.toString() );
370 fontElem.setAttribute( QStringLiteral( "style" ), untranslateNamedStyle( font.styleName() ) );
371 fontElem.setAttribute( QStringLiteral( "bold" ), font.bold() ? QChar( '1' ) : QChar( '0' ) );
372 fontElem.setAttribute( QStringLiteral( "italic" ), font.italic() ? QChar( '1' ) : QChar( '0' ) );
373 fontElem.setAttribute( QStringLiteral( "underline" ), font.underline() ? QChar( '1' ) : QChar( '0' ) );
374 fontElem.setAttribute( QStringLiteral( "strikethrough" ), font.strikeOut() ? QChar( '1' ) : QChar( '0' ) );
375 return fontElem;
376}
377
378bool QgsFontUtils::setFromXmlElement( QFont &font, const QDomElement &element )
379{
380 if ( element.isNull() )
381 {
382 return false;
383 }
384
385 font.fromString( element.attribute( QStringLiteral( "description" ) ) );
386
387 if ( element.hasAttribute( QStringLiteral( "bold" ) ) && element.attribute( QStringLiteral( "bold" ) ) == QChar( '1' ) )
388 {
389 font.setBold( true );
390 }
391 if ( element.hasAttribute( QStringLiteral( "italic" ) ) )
392 {
393 font.setItalic( element.attribute( QStringLiteral( "italic" ) ) == QChar( '1' ) );
394 }
395 if ( element.hasAttribute( QStringLiteral( "underline" ) ) )
396 {
397 font.setUnderline( element.attribute( QStringLiteral( "underline" ) ) == QChar( '1' ) );
398 }
399 if ( element.hasAttribute( QStringLiteral( "strikethrough" ) ) )
400 {
401 font.setStrikeOut( element.attribute( QStringLiteral( "strikethrough" ) ) == QChar( '1' ) );
402 }
403
404 if ( element.hasAttribute( QStringLiteral( "style" ) ) )
405 {
406 ( void )updateFontViaStyle( font, translateNamedStyle( element.attribute( QStringLiteral( "style" ) ) ) );
407 }
408
409 return true;
410}
411
412bool QgsFontUtils::setFromXmlChildNode( QFont &font, const QDomElement &element, const QString &childNode )
413{
414 if ( element.isNull() )
415 {
416 return false;
417 }
418
419 const QDomNodeList nodeList = element.elementsByTagName( childNode );
420 if ( !nodeList.isEmpty() )
421 {
422 const QDomElement fontElem = nodeList.at( 0 ).toElement();
423 return setFromXmlElement( font, fontElem );
424 }
425 else
426 {
427 return false;
428 }
429}
430
431QMimeData *QgsFontUtils::toMimeData( const QFont &font )
432{
433 std::unique_ptr< QMimeData >mimeData( new QMimeData );
434
435 QDomDocument fontDoc;
436 const QDomElement fontElem = toXmlElement( font, fontDoc, QStringLiteral( "font" ) );
437 fontDoc.appendChild( fontElem );
438 mimeData->setText( fontDoc.toString() );
439
440 return mimeData.release();
441}
442
443QFont QgsFontUtils::fromMimeData( const QMimeData *data, bool *ok )
444{
445 QFont font;
446 if ( ok )
447 *ok = false;
448
449 if ( !data )
450 return font;
451
452 const QString text = data->text();
453 if ( !text.isEmpty() )
454 {
455 QDomDocument doc;
456 QDomElement elem;
457
458 if ( doc.setContent( text ) )
459 {
460 elem = doc.documentElement();
461
462 if ( elem.nodeName() != QLatin1String( "font" ) )
463 elem = elem.firstChildElement( QStringLiteral( "font" ) );
464
465 if ( setFromXmlElement( font, elem ) )
466 {
467 if ( ok )
468 *ok = true;
469 }
470 return font;
471 }
472 }
473 return font;
474}
475
476static QMap<QString, QString> createTranslatedStyleMap()
477{
478 QMap<QString, QString> translatedStyleMap;
479 const QStringList words = QStringList()
480 << QStringLiteral( "Normal" )
481 << QStringLiteral( "Regular" )
482 << QStringLiteral( "Light" )
483 << QStringLiteral( "Bold" )
484 << QStringLiteral( "Black" )
485 << QStringLiteral( "Demi" )
486 << QStringLiteral( "Italic" )
487 << QStringLiteral( "Oblique" );
488 const auto constWords = words;
489 for ( const QString &word : constWords )
490 {
491 translatedStyleMap.insert( QCoreApplication::translate( "QFontDatabase", qPrintable( word ) ), word );
492 }
493 return translatedStyleMap;
494}
495
496QString QgsFontUtils::translateNamedStyle( const QString &namedStyle )
497{
498 QStringList words = namedStyle.split( ' ', Qt::SkipEmptyParts );
499 for ( int i = 0, n = words.length(); i < n; ++i )
500 {
501 words[i] = QCoreApplication::translate( "QFontDatabase", words[i].toLocal8Bit().constData() );
502 }
503 return words.join( QLatin1Char( ' ' ) );
504}
505
506QString QgsFontUtils::untranslateNamedStyle( const QString &namedStyle )
507{
508 static const QMap<QString, QString> translatedStyleMap = createTranslatedStyleMap();
509 QStringList words = namedStyle.split( ' ', Qt::SkipEmptyParts );
510
511 for ( int i = 0, n = words.length(); i < n; ++i )
512 {
513 if ( translatedStyleMap.contains( words[i] ) )
514 {
515 words[i] = translatedStyleMap.value( words[i] );
516 }
517 else
518 {
519 QgsDebugMsgLevel( QStringLiteral( "Warning: style map does not contain %1" ).arg( words[i] ), 2 );
520 }
521 }
522 return words.join( QLatin1Char( ' ' ) );
523}
524
525QString QgsFontUtils::asCSS( const QFont &font, double pointToPixelScale )
526{
527 QString css = QStringLiteral( "font-family: " ) + font.family() + ';';
528
529 //style
530 css += QLatin1String( "font-style: " );
531 switch ( font.style() )
532 {
533 case QFont::StyleNormal:
534 css += QLatin1String( "normal" );
535 break;
536 case QFont::StyleItalic:
537 css += QLatin1String( "italic" );
538 break;
539 case QFont::StyleOblique:
540 css += QLatin1String( "oblique" );
541 break;
542 }
543 css += ';';
544
545 //weight
546 int cssWeight = 400;
547 switch ( font.weight() )
548 {
549 case QFont::Light:
550 cssWeight = 300;
551 break;
552 case QFont::Normal:
553 cssWeight = 400;
554 break;
555 case QFont::DemiBold:
556 cssWeight = 600;
557 break;
558 case QFont::Bold:
559 cssWeight = 700;
560 break;
561 case QFont::Black:
562 cssWeight = 900;
563 break;
564 case QFont::Thin:
565 cssWeight = 100;
566 break;
567 case QFont::ExtraLight:
568 cssWeight = 200;
569 break;
570 case QFont::Medium:
571 cssWeight = 500;
572 break;
573 case QFont::ExtraBold:
574 cssWeight = 800;
575 break;
576 }
577 css += QStringLiteral( "font-weight: %1;" ).arg( cssWeight );
578
579 //size
580 css += QStringLiteral( "font-size: %1px;" ).arg( font.pointSizeF() >= 0 ? font.pointSizeF() * pointToPixelScale : font.pixelSize() );
581
582 return css;
583}
584
585void QgsFontUtils::addRecentFontFamily( const QString &family )
586{
587 if ( family.isEmpty() )
588 {
589 return;
590 }
591
592 QgsSettings settings;
593 QStringList recentFamilies = settings.value( QStringLiteral( "fonts/recent" ) ).toStringList();
594
595 //remove matching families
596 recentFamilies.removeAll( family );
597
598 //then add to start of list
599 recentFamilies.prepend( family );
600
601 //trim to 10 fonts
602 recentFamilies = recentFamilies.mid( 0, 10 );
603
604 settings.setValue( QStringLiteral( "fonts/recent" ), recentFamilies );
605}
606
608{
609 const QgsSettings settings;
610 return settings.value( QStringLiteral( "fonts/recent" ) ).toStringList();
611}
612
613void QgsFontUtils::setFontFamily( QFont &font, const QString &family )
614{
615 font.setFamily( family );
616 if ( !font.exactMatch() )
617 {
618 // some Qt versions struggle with fonts with certain unusual characters
619 // in their names, eg "ESRI Oil, Gas, & Water". Calling "setFamilies"
620 // can workaround these issues... (in some cases!)
621 font.setFamilies( { family } );
622 }
623}
624
625QFont QgsFontUtils::createFont( const QString &family, int pointSize, int weight, bool italic )
626{
627 QFont font( family, pointSize, weight, italic );
628 if ( !font.exactMatch() )
629 {
630 // some Qt versions struggle with fonts with certain unusual characters
631 // in their names, eg "ESRI Oil, Gas, & Water". Calling "setFamilies"
632 // can workaround these issues... (in some cases!)
633 font.setFamilies( { family } );
634 }
635 return font;
636}
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.
Stores settings for use within QGIS.
Definition qgssettings.h:65
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)
Definition qgis.h:6302
#define QgsDebugMsgLevel(str, level)
Definition qgslogger.h:41