Skip to content

Commit

Permalink
Add QgsFontUtils class to handle system font queries and style changes
Browse files Browse the repository at this point in the history
  • Loading branch information
dakcarto committed Jun 10, 2013
1 parent b9b8513 commit 04c4db1
Show file tree
Hide file tree
Showing 3 changed files with 250 additions and 0 deletions.
2 changes: 2 additions & 0 deletions src/core/CMakeLists.txt
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
192 changes: 192 additions & 0 deletions src/core/qgsfontutils.cpp
@@ -0,0 +1,192 @@
/***************************************************************************
qgsfontutils.h
---------------------
begin : June 5, 2013
copyright : (C) 2013 by Larry Shaffer
email : larrys at dakotacarto dot com
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/

#include "qgsfontutils.h"

#include <QApplication>
#include <QFont>
#include <QFontDatabase>
#include <QFontInfo>
#include <QStringList>


bool QgsFontUtils::fontMatchOnSystem( const QFont& f )
{
QFontInfo fi = QFontInfo( f );
return fi.exactMatch();
}

bool QgsFontUtils::fontFamilyOnSystem( const QString& family )
{
QFont tmpFont = QFont( family );
// compare just beginning of family string in case 'family [foundry]' differs
return family.startsWith( tmpFont.family(), Qt::CaseInsensitive );
}

bool QgsFontUtils::fontFamilyMatchOnSystem( const QString& family, QString* chosen, bool* match )
{
QFontDatabase fontDB;
QStringList fontFamilies = fontDB.families();
bool found = false;

QList<QString>::const_iterator it = fontFamilies.constBegin();
for ( ; it != fontFamilies.constEnd(); ++it )
{
// first compare just beginning of 'family [foundry]' string
if ( it->startsWith( family, Qt::CaseInsensitive ) )
{
found = true;
// keep looking if match info is requested
if ( match )
{
// full 'family [foundry]' strings have to match
*match = ( *it == family );
if ( match ) { break; }
}
else
{
break;
}
}
}

if ( found )
{
if ( chosen )
{
// retrieve the family actually assigned by matching algorithm
QFont f = QFont( family );
*chosen = f.family();
}
}
else
{
if ( chosen )
{
*chosen = QString();
}

if ( match )
{
*match = false;
}
}

return found;
}

bool QgsFontUtils::updateFontViaStyle( QFont& f, const QString& fontstyle, bool fallback )
{
if ( fontstyle.isEmpty() )
{
return false;
}

QFontDatabase fontDB;

if ( !fallback )
{
// does the font even have the requested style?
bool hasstyle = false;
foreach ( const QString &style, fontDB.styles( f.family() ) )
{
if ( style == fontstyle )
{
hasstyle = true;
break;
}
}

if ( !hasstyle )
{
return false;
}
}

// is the font's style already the same as requested?
if ( fontstyle == fontDB.styleString( f ) )
{
return true;
}

int defaultSize = QApplication::font().pointSize(); // QFontDatabase::font() needs an integer for size

QFont styledfont;
bool foundmatch = false;

styledfont = fontDB.font( f.family(), fontstyle, defaultSize );
if ( QApplication::font() != styledfont )
{
foundmatch = true;
}

// default to first found style if requested style is unavailable
// this helps in the situations where the passed-in font has to have a named style applied
if ( fallback && !foundmatch )
{
QFont testFont = QFont( f );
testFont.setPointSize( defaultSize );

// prefer a style that mostly matches the passed-in font
foreach ( const QString &style, fontDB.styles( f.family() ) )
{
styledfont = fontDB.font( f.family(), style, defaultSize );
styledfont = styledfont.resolve( f );
if ( testFont.toString() == styledfont.toString() )
{
foundmatch = true;
break;
}
}

// fallback to first style found that works
if ( !foundmatch )
{
foreach ( const QString &style, fontDB.styles( f.family() ) )
{
styledfont = fontDB.font( f.family(), style, defaultSize );
if ( QApplication::font() != styledfont )
{
foundmatch = true;
break;
}
}
}
}

// similar to QFont::resolve, but font may already have pixel size set
// and we want to make sure that's preserved
if ( foundmatch )
{
if ( f.pointSizeF() != -1 )
{
styledfont.setPointSizeF( f.pointSizeF() );
}
else if ( f.pixelSize() != -1 )
{
styledfont.setPixelSize( f.pixelSize() );
}
styledfont.setCapitalization( f.capitalization() );
styledfont.setUnderline( f.underline() );
styledfont.setStrikeOut( f.strikeOut() );
styledfont.setWordSpacing( f.wordSpacing() );
styledfont.setLetterSpacing( QFont::AbsoluteSpacing, f.letterSpacing() );
f = styledfont;

return true;
}

return false;
}
56 changes: 56 additions & 0 deletions src/core/qgsfontutils.h
@@ -0,0 +1,56 @@
/***************************************************************************
qgsfontutils.h
---------------------
begin : June 5, 2013
copyright : (C) 2013 by Larry Shaffer
email : larrys at dakotacarto dot com
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/

#ifndef QGSFONTUTILS_H
#define QGSFONTUTILS_H

#include <QFont>
#include <QString>

class CORE_EXPORT QgsFontUtils
{
public:
/** Check whether exact font is on system
* @param font The font to test for match
*/
static bool fontMatchOnSystem( const QFont& f );

/** Check whether font family is on system in a quick manner, which does not compare [foundry]
* @param family The family to test
* @returns Whether family was found on system
* @note This is good for use in loops of large lists, e.g. registering many features for labeling
*/
static bool fontFamilyOnSystem( const QString& family );

/** Check whether font family is on system
* @param family The family to test
* @param chosen The actual family (possibly from different foundry) returned by system
* @param match Whether the family [foundry] returned by system is a match
* @returns Whether family was found on system
*/
static bool fontFamilyMatchOnSystem( const QString& family, QString* chosen = 0, bool* match = 0 );

/** Updates font with named style and retain all font properties
* @param font The font to update
* @param fontstyle The style to try and switch the font to
* @param fallback If no matching fontstyle found for font, assign most similar or first style found to font
* @returns Whether the font was updated (also returns true if the requested style matches font's current style)
* @note This is a more featured replacement for a Qt 4.8+ function: void QFont::setStyleName ( const QString & styleName )
*/
static bool updateFontViaStyle( QFont& f, const QString& fontstyle, bool fallback = false );

};

#endif // QGSFONTUTILS_H

0 comments on commit 04c4db1

Please sign in to comment.