Skip to content

Commit 04c4db1

Browse files
committed
Add QgsFontUtils class to handle system font queries and style changes
1 parent b9b8513 commit 04c4db1

File tree

3 files changed

+250
-0
lines changed

3 files changed

+250
-0
lines changed

src/core/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ SET(QGIS_CORE_SRCS
7171
qgsfeaturerequest.cpp
7272
qgsfeaturestore.cpp
7373
qgsfield.cpp
74+
qgsfontutils.cpp
7475
qgsgeometry.cpp
7576
qgsgeometrycache.cpp
7677
qgsgeometryvalidator.cpp
@@ -395,6 +396,7 @@ SET(QGIS_CORE_HDRS
395396
qgsfeaturerequest.h
396397
qgsfeaturestore.h
397398
qgsfield.h
399+
qgsfontutils.h
398400
qgsgeometry.h
399401
qgsgml.h
400402
qgsgmlschema.h

src/core/qgsfontutils.cpp

Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
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 <QApplication>
19+
#include <QFont>
20+
#include <QFontDatabase>
21+
#include <QFontInfo>
22+
#include <QStringList>
23+
24+
25+
bool QgsFontUtils::fontMatchOnSystem( const QFont& f )
26+
{
27+
QFontInfo fi = QFontInfo( f );
28+
return fi.exactMatch();
29+
}
30+
31+
bool QgsFontUtils::fontFamilyOnSystem( const QString& family )
32+
{
33+
QFont tmpFont = QFont( family );
34+
// compare just beginning of family string in case 'family [foundry]' differs
35+
return family.startsWith( tmpFont.family(), Qt::CaseInsensitive );
36+
}
37+
38+
bool QgsFontUtils::fontFamilyMatchOnSystem( const QString& family, QString* chosen, bool* match )
39+
{
40+
QFontDatabase fontDB;
41+
QStringList fontFamilies = fontDB.families();
42+
bool found = false;
43+
44+
QList<QString>::const_iterator it = fontFamilies.constBegin();
45+
for ( ; it != fontFamilies.constEnd(); ++it )
46+
{
47+
// first compare just beginning of 'family [foundry]' string
48+
if ( it->startsWith( family, Qt::CaseInsensitive ) )
49+
{
50+
found = true;
51+
// keep looking if match info is requested
52+
if ( match )
53+
{
54+
// full 'family [foundry]' strings have to match
55+
*match = ( *it == family );
56+
if ( match ) { break; }
57+
}
58+
else
59+
{
60+
break;
61+
}
62+
}
63+
}
64+
65+
if ( found )
66+
{
67+
if ( chosen )
68+
{
69+
// retrieve the family actually assigned by matching algorithm
70+
QFont f = QFont( family );
71+
*chosen = f.family();
72+
}
73+
}
74+
else
75+
{
76+
if ( chosen )
77+
{
78+
*chosen = QString();
79+
}
80+
81+
if ( match )
82+
{
83+
*match = false;
84+
}
85+
}
86+
87+
return found;
88+
}
89+
90+
bool QgsFontUtils::updateFontViaStyle( QFont& f, const QString& fontstyle, bool fallback )
91+
{
92+
if ( fontstyle.isEmpty() )
93+
{
94+
return false;
95+
}
96+
97+
QFontDatabase fontDB;
98+
99+
if ( !fallback )
100+
{
101+
// does the font even have the requested style?
102+
bool hasstyle = false;
103+
foreach ( const QString &style, fontDB.styles( f.family() ) )
104+
{
105+
if ( style == fontstyle )
106+
{
107+
hasstyle = true;
108+
break;
109+
}
110+
}
111+
112+
if ( !hasstyle )
113+
{
114+
return false;
115+
}
116+
}
117+
118+
// is the font's style already the same as requested?
119+
if ( fontstyle == fontDB.styleString( f ) )
120+
{
121+
return true;
122+
}
123+
124+
int defaultSize = QApplication::font().pointSize(); // QFontDatabase::font() needs an integer for size
125+
126+
QFont styledfont;
127+
bool foundmatch = false;
128+
129+
styledfont = fontDB.font( f.family(), fontstyle, defaultSize );
130+
if ( QApplication::font() != styledfont )
131+
{
132+
foundmatch = true;
133+
}
134+
135+
// default to first found style if requested style is unavailable
136+
// this helps in the situations where the passed-in font has to have a named style applied
137+
if ( fallback && !foundmatch )
138+
{
139+
QFont testFont = QFont( f );
140+
testFont.setPointSize( defaultSize );
141+
142+
// prefer a style that mostly matches the passed-in font
143+
foreach ( const QString &style, fontDB.styles( f.family() ) )
144+
{
145+
styledfont = fontDB.font( f.family(), style, defaultSize );
146+
styledfont = styledfont.resolve( f );
147+
if ( testFont.toString() == styledfont.toString() )
148+
{
149+
foundmatch = true;
150+
break;
151+
}
152+
}
153+
154+
// fallback to first style found that works
155+
if ( !foundmatch )
156+
{
157+
foreach ( const QString &style, fontDB.styles( f.family() ) )
158+
{
159+
styledfont = fontDB.font( f.family(), style, defaultSize );
160+
if ( QApplication::font() != styledfont )
161+
{
162+
foundmatch = true;
163+
break;
164+
}
165+
}
166+
}
167+
}
168+
169+
// similar to QFont::resolve, but font may already have pixel size set
170+
// and we want to make sure that's preserved
171+
if ( foundmatch )
172+
{
173+
if ( f.pointSizeF() != -1 )
174+
{
175+
styledfont.setPointSizeF( f.pointSizeF() );
176+
}
177+
else if ( f.pixelSize() != -1 )
178+
{
179+
styledfont.setPixelSize( f.pixelSize() );
180+
}
181+
styledfont.setCapitalization( f.capitalization() );
182+
styledfont.setUnderline( f.underline() );
183+
styledfont.setStrikeOut( f.strikeOut() );
184+
styledfont.setWordSpacing( f.wordSpacing() );
185+
styledfont.setLetterSpacing( QFont::AbsoluteSpacing, f.letterSpacing() );
186+
f = styledfont;
187+
188+
return true;
189+
}
190+
191+
return false;
192+
}

src/core/qgsfontutils.h

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
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+
#ifndef QGSFONTUTILS_H
17+
#define QGSFONTUTILS_H
18+
19+
#include <QFont>
20+
#include <QString>
21+
22+
class CORE_EXPORT QgsFontUtils
23+
{
24+
public:
25+
/** Check whether exact font is on system
26+
* @param font The font to test for match
27+
*/
28+
static bool fontMatchOnSystem( const QFont& f );
29+
30+
/** Check whether font family is on system in a quick manner, which does not compare [foundry]
31+
* @param family The family to test
32+
* @returns Whether family was found on system
33+
* @note This is good for use in loops of large lists, e.g. registering many features for labeling
34+
*/
35+
static bool fontFamilyOnSystem( const QString& family );
36+
37+
/** Check whether font family is on system
38+
* @param family The family to test
39+
* @param chosen The actual family (possibly from different foundry) returned by system
40+
* @param match Whether the family [foundry] returned by system is a match
41+
* @returns Whether family was found on system
42+
*/
43+
static bool fontFamilyMatchOnSystem( const QString& family, QString* chosen = 0, bool* match = 0 );
44+
45+
/** Updates font with named style and retain all font properties
46+
* @param font The font to update
47+
* @param fontstyle The style to try and switch the font to
48+
* @param fallback If no matching fontstyle found for font, assign most similar or first style found to font
49+
* @returns Whether the font was updated (also returns true if the requested style matches font's current style)
50+
* @note This is a more featured replacement for a Qt 4.8+ function: void QFont::setStyleName ( const QString & styleName )
51+
*/
52+
static bool updateFontViaStyle( QFont& f, const QString& fontstyle, bool fallback = false );
53+
54+
};
55+
56+
#endif // QGSFONTUTILS_H

0 commit comments

Comments
 (0)