/****************************************************************************
**
-** Copyright (C) 2011 Takumi Asaki
+** Copyright (C) 2012 Takumi Asaki
** All rights reserved.
** Contact: Takumi Asaki (takumi.asaki@gmail.com)
**
#include "fontconfigmanager.h"
+#include "fontconfigdefs.h"
#include "installedfontinfo.h"
#include "fontsconfigproperties.h"
+#include "fontsconf.h"
+
#include <QProcess>
#include <QBuffer>
#include <QFile>
#include <QXmlStreamReader>
#include <QVariant>
+#include <QFontInfo>
+#include <QFontMetrics>
+#include <QFontDatabase>
+#include <QUrl>
+#include <QTextStream>
+
+#undef FONTMANAGER_DEBUG_RECOMMENDED_SETTINGS
+#ifdef FONTMANAGER_DEBUG_RECOMMENDED_SETTINGS
#include <QDebug>
+#endif
#define FCBIN_PATH "/usr/bin/"
#define FCCACHE_COMMAND "fc-cache"
#define FCLIST_COMMAND "fc-list"
#define FCLIST_OPTION "-v"
-enum FCState {
- Initialized, Ready, WaitFamilyForAlias, WaitPreferForAlias, ReadingPrefer,
- WaitTestForMatch, ReadingTest, WaitEditForMatch, WaitBoolForEdit, WaitEndMatch,
- InvalidConfig,
- UnknownState
-};
-
-static const char *configKeys[] = { "embeddedbitmap:true", "embeddedbitmap:false", "hinting:true", "hinting:false", 0 };
-
FontConfigManager::FontConfigManager(QObject *parent) :
- QObject(parent), mLang("en"), mHasUnknownConfig(false), mFontsConfModified(false)
+ QObject(parent), mLang("en"), mLocalFontsConf(0)
{
- clearFontProperties();
+ connect(this, SIGNAL(localFontsConfPathChanged()), SIGNAL(localFontsConfExistsChanged()));
+ // connect(this, SIGNAL(localFontsConfPathChanged()), SIGNAL(fontsConfUpdated()));
+
+ mLocalFontsConf = new FontsConf(this);
+ mSystemLocalConf = new FontsConf(this);
+
+ QStringList cjkConflicts;
+ cjkConflicts << "ja" << "ko" << "zh-cn" << "zh-hk" << "zh-mo" << "zh-sg" << "zh-tw";
+ mConflictFonts << cjkConflicts;
+
+ mSystemLocalConf->load("/etc/fonts/local.conf");
+
}
QString FontConfigManager::currentLanguage() const
}
}
-bool FontConfigManager::hasUnknownConfig() const
+bool FontConfigManager::localFontsConfExists() const
{
- return mHasUnknownConfig;
+ return QFile::exists(mLocalFontsConfPath);
}
-bool FontConfigManager::fontsConfModified() const
-{
- return mFontsConfModified;
-}
-
-QStringList FontConfigManager::families() const
+bool FontConfigManager::hasUnknownConfig() const
{
- return mFamilies;
+ if (!mLocalFontsConf)
+ return false;
+ return mLocalFontsConf->hasUnknownConfig();
}
-QStringList FontConfigManager::systemFamilies() const
+bool FontConfigManager::fontsConfModified() const
{
- return mSystemFamilies;
+ if (!mLocalFontsConf)
+ return false;
+ return mLocalFontsConf->modified();
}
-QStringList FontConfigManager::localFamilies() const
+bool FontConfigManager::isEmptyLocalFontsConf() const
{
- return mLocalFamilies;
+ return !mLocalFontsConf || mLocalFontsConf->isEmpty();
}
QStringList FontConfigManager::fontCount(const QString &fontpath) const
return fontList;
}
-InstalledFontInfo *FontConfigManager::fontInfo(const QString &family) const
+InstalledFontInfo *FontConfigManager::fontInfo(const QString &family, const QString &fullname) const
{
InstalledFontInfo *info = 0;
foreach (info, mFcListInfo) {
- if (info->family().contains(family))
- return info;
+ if (info->family().contains(family)) {
+ if (fullname.isEmpty())
+ return info;
+ if (info->fullname().contains(fullname))
+ return info;
+ }
}
return 0;
}
void FontConfigManager::appendFontProperty(FontsConfigProperties *prop, const QStringList &familyList)
{
-// qDebug() << "appendFontProperty(" << prop->family() << "," << familyList << ")";
+ if (!mLocalFontsConf)
+ return;
- QStringList preferedFamilies(mPreferFontListMap.keys());
+ QStringList preferedFamilies(mLocalFontsConf->preferFamily());
+ preferedFamilies << prop->preferFamilies();
+ preferedFamilies.removeDuplicates();
foreach (const QString &family, preferedFamilies) {
- QStringList preferList(mPreferFontListMap.value(family, QStringList()));
- QStringList origList(preferList);
if (prop->preferFamilies().contains(family)) {
- preferList << prop->family();
- foreach (const QString &f, familyList) {
- if (f != prop->family())
- preferList << f;
- }
+ if (familyList.isEmpty())
+ mLocalFontsConf->appendPreferFamilyFor(family, prop->family());
+ else
+ foreach (const QString &f, familyList)
+ mLocalFontsConf->appendPreferFamilyFor(family, f);
} else {
- preferList.removeOne(prop->family());
- foreach (const QString &f, familyList) {
- preferList.removeOne(f);
- }
+ if (familyList.isEmpty())
+ mLocalFontsConf->removePreferFamilyFor(family, prop->family());
+ else
+ foreach (const QString &f, familyList)
+ mLocalFontsConf->removePreferFamilyFor(family, f);
}
- preferList.removeDuplicates();
-// qDebug() << prop->family() << prop->preferFamilies() << origList << preferList;
- if (preferList != origList) {
- mFontsConfModified = true;
- mPreferFontListMap.insert(family, preferList);
+ }
+
+ QStringList keys = FontsConf::configKeys();
+ foreach (const QString &key, keys) {
+ if (prop->configValue(key) == FontsConfigProperties::Default) {
+ if (familyList.isEmpty())
+ mLocalFontsConf->unsetMatchEditValueFor(key, prop->family());
+ else
+ foreach (const QString &f, familyList)
+ mLocalFontsConf->unsetMatchEditValueFor(key, f);
+ } else {
+ if (familyList.isEmpty())
+ mLocalFontsConf->setMatchEditValueFor(key, prop->family(), (prop->configValue(key) == FontsConfigProperties::True));
+ else
+ foreach (const QString &f, familyList)
+ mLocalFontsConf->setMatchEditValueFor(key, f, (prop->configValue(key) == FontsConfigProperties::True));
}
}
- appendFontPropertyBool("embeddedbitmap", prop->embeddedBitmap(), prop, familyList);
- appendFontPropertyBool("hinting", prop->embeddedBitmap(), prop, familyList);
- emit configHasUninstalledFontsChanged();
+ emit fontsConfUpdated();
}
void FontConfigManager::appendFontProperty(InstalledFontInfo *fontInfo)
{
- appendFontProperty(fontInfo->fontProperty(), fontInfo->family());
+ QStringList familyList;
+ familyList << fontInfo->enfamily();
+ appendFontProperty(fontInfo->fontProperty(), familyList);
}
FontsConfigProperties *FontConfigManager::fontProperty(const QString &family, const QStringList &familyList) const
{
FontsConfigProperties *prop = new FontsConfigProperties(family);
QStringList families;
- QStringList preferedFamilies = mPreferFontListMap.keys();
+ QStringList preferedFamilies = mLocalFontsConf->preferFamily();
foreach (const QString &key, preferedFamilies) {
- families = mPreferFontListMap.value(key);
+ families = mLocalFontsConf->preferFamilyFor(key);
if (families.contains(family))
prop->addPreferFamily(key);
foreach (const QString &f, familyList) {
}
}
- if (fontPropertyBoolValue("embeddedbitmap", true, family, familyList))
- prop->setEmbeddedBitmap(FontsConfigProperties::True);
- if (fontPropertyBoolValue("embeddedbitmap", false, family, familyList))
- prop->setEmbeddedBitmap(FontsConfigProperties::False);
-
- if (fontPropertyBoolValue("hinting", true, family, familyList))
- prop->setHinting(FontsConfigProperties::True);
- if (fontPropertyBoolValue("hinting", false, family, familyList))
- prop->setHinting(FontsConfigProperties::False);
+ QStringList keys = FontsConf::configKeys();
+ foreach (const QString &key, keys) {
+ QString val = mLocalFontsConf->matchEditValueFor(key, prop->family());
+ if (!val.isEmpty()) {
+ prop->setConfigValue(key, (QVariant(val).toBool() ? FontsConfigProperties::True : FontsConfigProperties::False));
+ continue;
+ }
+ foreach (const QString &f, familyList) {
+ mLocalFontsConf->matchEditValueFor(key, f);
+ if (!val.isEmpty()) {
+ prop->setConfigValue(key, (QVariant(val).toBool() ? FontsConfigProperties::True : FontsConfigProperties::False));
+ break;
+ }
+ }
+ }
return prop;
}
return buf;
}
-bool FontConfigManager::configHasUninstalledFonts() const
+QStringList FontConfigManager::preferFamilyFor(const QString &family) const
{
- QStringList localfamilies;
- foreach (InstalledFontInfo *info, mFcListInfo) {
- localfamilies << info->family();
- }
- localfamilies.removeDuplicates();
- QStringList preferedFamilies = mPreferFontListMap.keys();
- foreach (const QString &key, preferedFamilies) {
- QStringList families = mPreferFontListMap.value(key);
- foreach (const QString &f, families) {
- if (!localfamilies.contains(f)) {
- return true;
+ return mLocalFontsConf->preferFamilyFor(family);
+}
+
+QStringList FontConfigManager::acceptFamilyFor(const QString &family) const
+{
+ return mLocalFontsConf->acceptFamilyFor(family);
+}
+
+QStringList FontConfigManager::prependFamilyFor(const QString &family) const
+{
+ return mLocalFontsConf->prependFamilyFor(family);
+}
+
+QStringList FontConfigManager::appendFamilyFor(const QString &family) const
+{
+ return mLocalFontsConf->appendFamilyFor(family);
+}
+
+bool FontConfigManager::isConflict(const QString &family, const QStringList &lang) const
+{
+ InstalledFontInfo *info = fontInfo(family);
+ if (!info)
+ return false;
+
+ QList<int> confListIndex;
+ for (int i = 0; i < mConflictFonts.count(); i++) {
+ const QStringList list(mConflictFonts.at(i));
+ foreach (const QString &f, list) {
+ if (lang.contains(f)) {
+ if (!confListIndex.contains(i))
+ confListIndex << i;
+ break;
}
}
}
- for (int i = 0; configKeys[i]; i++) {
- QStringList families = mMatchFontListMap.value(configKeys[i]);
- foreach (const QString &f, families) {
- if (!localfamilies.contains(f)) {
+ if (confListIndex.isEmpty())
+ return false;
+
+ foreach (int i, confListIndex) {
+ QStringList confList = mConflictFonts.at(confListIndex.at(i));
+ foreach (const QString &f, confList) {
+ if (info->lang().contains(f)) {
return true;
}
}
return false;
}
-void FontConfigManager::removeUninstalledFontsFromConfig()
+QStringList FontConfigManager::systemPreferFamilyFor(const QString &family) const
+{
+ return mSystemLocalConf->preferFamilyFor(family);
+}
+
+void FontConfigManager::importSystemSettings(const QString &family)
{
- QStringList localfamilies;
+ QStringList systemFamilyList = systemPreferFamilyFor(family);
+
+ QStringList installedFontLang;
foreach (InstalledFontInfo *info, mFcListInfo) {
- localfamilies << info->family();
+ if (info->systemFont())
+ continue;
+ installedFontLang << info->lang();
}
- localfamilies.removeDuplicates();
- bool modified = false;
- QStringList preferedFamilies = mPreferFontListMap.keys();
- foreach (const QString &key, preferedFamilies) {
- bool m = false;
- QStringList families = mPreferFontListMap.value(key);
- foreach (const QString &f, families) {
- if (!localfamilies.contains(f)) {
- families.removeOne(f);
- modified = true;
- m = true;
- }
- }
- if (m)
- mPreferFontListMap.insert(key, families);
+ installedFontLang.sort();
+ installedFontLang.removeDuplicates();
+
+ emit startUpdateFontsConfig();
+ foreach (const QString &f, systemFamilyList) {
+ InstalledFontInfo *info = fontInfo(f);
+ if (!info)
+ continue;
+
+ if (isConflict(f, installedFontLang))
+ mLocalFontsConf->appendAcceptFamilyFor(family, f);
+ else
+ mLocalFontsConf->appendPrependFamilyFor(family, f);
+ }
+ emit endUpdateFontsConfig();
+
+ if (mLocalFontsConf->modified()) {
+ emit fontsConfUpdated();
}
+}
+
+void FontConfigManager::createRecommendedSettings()
+{
+ QList<InstalledFontInfo*> sansSerifFonts;
+ QList<InstalledFontInfo*> serifFonts;
+ QList<InstalledFontInfo*> monospaceFonts;
+ QList<InstalledFontInfo*> monospaceSansSerifFonts;
+ QList<InstalledFontInfo*> monospaceSerifFonts;
+ QList<InstalledFontInfo*> unknownFonts;
+
+ foreach (InstalledFontInfo *info, mFcListInfo) {
+ if (info->systemFont())
+ continue;
+ if (maybeMonospaceFont(info)) {
+ if (maybeSansSerifFont(info))
+ monospaceSansSerifFonts << info;
+ else if (maybeSerifFont(info))
+ monospaceSerifFonts << info;
+ else
+ monospaceFonts << info;
+ } else if (maybeSansSerifFont(info))
+ sansSerifFonts << info;
+ else if (maybeSerifFont(info))
+ serifFonts << info;
+ else
+ unknownFonts << info;
+ }
+
+ emit startUpdateFontsConfig();
+ resetFontsConf();
+
+#ifdef FONTMANAGER_DEBUG_RECOMMENDED_SETTINGS
+ QStringList f;
+ foreach (InstalledFontInfo *info, monospaceFonts)
+ f << info->localefamily();
+ qDebug() << "Mono:" << f;
+ f.clear();
+ foreach (InstalledFontInfo *info, monospaceSansSerifFonts)
+ f << info->localefamily();
+ qDebug() << "Mono(Sans Serif):" << f;
+ f.clear();
+ foreach (InstalledFontInfo *info, monospaceSerifFonts)
+ f << info->localefamily();
+ qDebug() << "Mono(Serif):" << f;
+ f.clear();
+ foreach (InstalledFontInfo *info, sansSerifFonts)
+ f << info->localefamily();
+ qDebug() << "Sans Serif:" << f;
+ f.clear();
+ foreach (InstalledFontInfo *info, serifFonts)
+ f << info->localefamily();
+ qDebug() << "Serif:" << f;
+ f.clear();
+ foreach (InstalledFontInfo *info, unknownFonts)
+ f << info->localefamily();
+ qDebug() << "Unknown:" << f;
+#endif
+
+ if (monospaceFonts.count())
+ foreach (InstalledFontInfo *info, monospaceFonts) {
+ addPreferFamily(MONOSPACE_DEF, info->enfamily());
+ }
+ else if (monospaceSansSerifFonts.count())
+ foreach (InstalledFontInfo *info, monospaceSansSerifFonts) {
+ addPreferFamily(MONOSPACE_DEF, info->enfamily());
+ }
+ else if (monospaceSerifFonts.count())
+ foreach (InstalledFontInfo *info, monospaceSerifFonts) {
+ addPreferFamily(MONOSPACE_DEF, info->enfamily());
+ }
+
+ if (sansSerifFonts.count())
+ foreach (InstalledFontInfo *info, sansSerifFonts) {
+ addPreferFamily(SANSSERIF_DEF, info->enfamily());
+ addPreferFamily(SYSTEM_DEF, info->enfamily());
+ }
+ else if (monospaceSansSerifFonts.count())
+ foreach (InstalledFontInfo *info, monospaceSansSerifFonts) {
+ addPreferFamily(SANSSERIF_DEF, info->enfamily());
+ addPreferFamily(SYSTEM_DEF, info->enfamily());
+ }
+ else if (unknownFonts.count())
+ foreach (InstalledFontInfo *info, unknownFonts) {
+ addPreferFamily(SANSSERIF_DEF, info->enfamily());
+ addPreferFamily(SYSTEM_DEF, info->enfamily());
+ }
+ else if (monospaceFonts.count())
+ foreach (InstalledFontInfo *info, monospaceFonts) {
+ addPreferFamily(SANSSERIF_DEF, info->enfamily());
+ addPreferFamily(SYSTEM_DEF, info->enfamily());
+ }
+
+ if (serifFonts.count())
+ foreach (InstalledFontInfo *info, serifFonts) {
+ addPreferFamily(SERIF_DEF, info->enfamily());
+ }
+ else if (monospaceSerifFonts.count())
+ foreach (InstalledFontInfo *info, monospaceSerifFonts) {
+ addPreferFamily(SANSSERIF_DEF, info->enfamily());
+ }
+ else if (unknownFonts.count())
+ foreach (InstalledFontInfo *info, unknownFonts) {
+ addPreferFamily(SERIF_DEF, info->enfamily());
+ }
+ else if (monospaceFonts.count())
+ foreach (InstalledFontInfo *info, monospaceFonts) {
+ addPreferFamily(SERIF_DEF, info->enfamily());
+ }
- for (int i = 0; configKeys[i]; i++) {
- bool m = false;
- QStringList families = mMatchFontListMap.value(configKeys[i]);
- foreach (const QString &f, families) {
- if (!localfamilies.contains(f)) {
- families.removeOne(f);
- modified = true;
- m = true;
+ foreach (const QString &f, FontsConf::genericFamilies())
+ importSystemSettings(f);
+ emit endUpdateFontsConfig();
+
+ emit fontsConfUpdated();
+}
+
+QStringList FontConfigManager::installableFamily(const QString &family, bool localOnly)
+{
+ QStringList installedFont;
+ installedFont << prependFamilyFor(family);
+ installedFont << appendFamilyFor(family);
+ installedFont << preferFamilyFor(family);
+ installedFont << acceptFamilyFor(family);
+
+ QStringList familyList;
+ foreach (InstalledFontInfo *info, mFcListInfo) {
+ if (localOnly && info->systemFont())
+ continue;
+ bool check = false;
+ foreach (const QString &f, info->family()) {
+ if (installedFont.contains(f)) {
+ check = true;
+ break;
}
}
- if (m)
- mMatchFontListMap.insert(configKeys[i], families);
+ if (!check)
+ familyList << info->localefamily();
+ }
+ familyList.sort();
+ familyList.removeDuplicates();
+
+ return familyList;
+}
+
+QString FontConfigManager::localeFamily(const QString &family) const
+{
+ if (mEnLocaleFontMap.contains(family))
+ return mEnLocaleFontMap.value(family);
+ return family;
+}
+
+bool FontConfigManager::maybeSansSerifFont(InstalledFontInfo *info) const
+{
+ foreach (const QString &f, info->family()) {
+ if (f.contains("gothic", Qt::CaseInsensitive) ||
+ f.contains("arial", Qt::CaseInsensitive) ||
+ f.contains("helvetica", Qt::CaseInsensitive) ||
+ f.contains("verdana", Qt::CaseInsensitive) ||
+ f.contains("sans", Qt::CaseInsensitive))
+ return true;
}
+ return false;
+}
- if (modified) {
- mFontsConfModified = true;
- emit configHasUninstalledFontsChanged();
+bool FontConfigManager::maybeSerifFont(InstalledFontInfo *info) const
+{
+ foreach (const QString &f, info->family()) {
+ if (f.contains("mincho", Qt::CaseInsensitive) ||
+ f.contains("times", Qt::CaseInsensitive) ||
+ (f.contains("serif", Qt::CaseInsensitive) && !f.contains("sans", Qt::CaseInsensitive)))
+ return true;
}
+ return false;
}
-void FontConfigManager::appendFontPropertyBool(const QString &config, FontsConfigProperties::ConfigValue value, FontsConfigProperties *prop, const QStringList &familyList)
+#define DEFAULT_POINTSIZE 24
+
+bool FontConfigManager::maybeMonospaceFont(InstalledFontInfo *info) const
{
- static const char *boolValues[] = { "true", "false", 0 };
- for (int i = 0; boolValues[i]; i++) {
- QString key = config + QLatin1String(":") + boolValues[i];
- QStringList matchedList(mMatchFontListMap.value(key, QStringList()));
- QStringList origList(matchedList);
- if ((value == FontsConfigProperties::True && i == 0) || (value == FontsConfigProperties::False && i == 1)) {
- matchedList << prop->family();
- foreach (const QString &f, familyList) {
- if (f != prop->family())
- matchedList << f;
+ int fontId = -1;
+ QFont font = font4info(info, DEFAULT_POINTSIZE);
+#ifdef FONTMANAGER_DEBUG_RECOMMENDED_SETTINGS
+ qDebug() << "0 - FontConfigManager::maybeMonospaceFont(" << info->enfamily() << info->enstyle() << point << ")" << font.family() << font.exactMatch();
+#endif
+ if (!font.exactMatch() || font.family() != info->enfamily()) {
+ fontId = QFontDatabase::addApplicationFont(info->file());
+#ifdef FONTMANAGER_DEBUG_RECOMMENDED_SETTINGS
+ qDebug() << "\tfontId:" << fontId << info->file();
+#endif
+ if (fontId >= 0) {
+ font = font4info(info, DEFAULT_POINTSIZE);
+#ifdef FONTMANAGER_DEBUG_RECOMMENDED_SETTINGS
+ qDebug() << "1 - FontConfigManager::maybeMonospaceFont(" << info->enfamily() << info->enstyle() << point << ")" << font.family() << font.exactMatch();
+#endif
+ if (!font.exactMatch() || font.family() != info->enfamily()) {
+ font = QFont(info->enfamily());
+#ifdef FONTMANAGER_DEBUG_RECOMMENDED_SETTINGS
+ qDebug() << "2 - FontConfigManager::maybeMonospaceFont(" << info->enfamily() << info->enstyle() << point << ")" << font.family() << font.exactMatch();
+#endif
}
+ }
+ }
+ bool isFixed = false;
+ if (font.exactMatch()) {
+ QFontInfo fi(font);
+#ifdef FONTMANAGER_DEBUG_RECOMMENDED_SETTINGS
+ qDebug() << "\tfixedPitch:" << fi.fixedPitch();
+#endif
+ if (fi.fixedPitch()) {
+ isFixed = true;
} else {
- matchedList.removeOne(prop->family());
- foreach (const QString &f, familyList) {
- matchedList.removeOne(f);
+ QFontMetrics fm(font);
+ int w = fm.width(QLatin1Char('A'));
+#ifdef FONTMANAGER_DEBUG_RECOMMENDED_SETTINGS
+ qDebug() << "\twidth:" << w << fm.width(QLatin1Char('i')) << fm.width(QLatin1Char('X'));
+#endif
+ if (fm.width(QLatin1Char('i')) == w && fm.width(QLatin1Char('X')) == w) {
+ isFixed = true;
}
}
- matchedList.removeDuplicates();
- if (matchedList != origList) {
- mFontsConfModified = true;
- mMatchFontListMap.insert(key, matchedList);
- }
}
-}
-
-bool FontConfigManager::fontPropertyBoolValue(const QString &config, bool value, const QString &family, const QStringList &familyList) const
-{
- QStringList families = mMatchFontListMap.value(config + (value ? ":true" : ":false"));
- if (families.contains(family))
+ if (fontId >= 0)
+ QFontDatabase::removeApplicationFont(fontId);
+ if (isFixed)
return true;
- foreach (const QString &f, familyList) {
- if (families.contains(f))
+ foreach (const QString &f, info->family()) {
+ if (f.contains("courier", Qt::CaseInsensitive) ||
+ f.contains("mono", Qt::CaseInsensitive))
return true;
}
return false;
}
+QFont FontConfigManager::font4info(InstalledFontInfo *info, int pointSize) const
+{
+ QFontDatabase fdb;
+ int point = pointSize;
+ if (!fdb.isScalable(info->enfamily(), info->enstyle())) {
+ QList<int> points = fdb.pointSizes(info->enfamily(), info->enstyle());
+ if (points.count() > 0)
+ point = points.first();
+ }
+ QFont font = fdb.font(info->enfamily(), info->enstyle(), point);
+ return font;
+}
+
void FontConfigManager::runFcCache()
{
-// qDebug("runFcCache()");
QProcess *proc = new QProcess(this);
connect(proc, SIGNAL(finished(int)), SIGNAL(fcCacheFinished()));
connect(proc, SIGNAL(finished(int)), proc, SLOT(deleteLater()));
void FontConfigManager::readFcList()
{
-// qDebug("FontConfigManager::readFcList()");
QProcess *proc = new QProcess(this);
proc->start(FCBIN_PATH FCLIST_COMMAND, QStringList() << FCLIST_OPTION);
if (!proc->waitForStarted())
qDeleteAll(mFcListInfo);
mFcListInfo.clear();
+ mEnLocaleFontMap.clear();
QByteArray buf = proc->readAllStandardOutput();
QByteArray errbuf = proc->readAllStandardError();
+ if (!errbuf.isEmpty())
+ qWarning("%s", errbuf.constData());
Q_ASSERT(errbuf.isEmpty());
static QByteArray emptyLine("\n");
if (!fibuf.isEmpty()) {
InstalledFontInfo *info = new InstalledFontInfo(fibuf, mLocalFontPath, this);
info->setLocale(mLang);
- if (info->isValid())
+ if (info->isValid()) {
mFcListInfo.append(info);
- else
+ mEnLocaleFontMap.insert(info->enfamily(), info->localefamily());
+ info->setFontProperty(fontProperty(info));
+ } else
delete info;
- info->setFontProperty(fontProperty(info));
fibuf.clear();
}
} else {
Q_ASSERT(fibuf.isEmpty());
buffer.close();
- QStringList f;
- QStringList sf;
- QStringList lf;
- foreach (InstalledFontInfo *info, mFcListInfo) {
- QString family(info->localefamily());
- f << family;
- if (info->systemFont()) {
- sf << family;
- } else {
- lf << family;
- }
- }
- f.sort();
- sf.sort();
- lf.sort();
- if (f != mFamilies) {
- mFamilies = f;
- emit familiesChanged();
- }
- if (sf != mSystemFamilies) {
- mSystemFamilies = sf;
- emit systemFamiliesChanged();
- }
- if (lf != mLocalFamilies) {
- mLocalFamilies = lf;
- emit localFamiliesChanged();
- }
+ qSort(mFcListInfo.begin(), mFcListInfo.end(), InstalledFontInfo::compare);
- emit configHasUninstalledFontsChanged();
+ emit fontListUpdated();
delete proc;
}
void FontConfigManager::readFontsConf()
{
- QFile fp(mLocalFontsConfPath);
- if (!fp.exists())
- return;
- fp.open(QIODevice::ReadOnly);
- if (!fp.isOpen())
- return;
-
- clearFontProperties();
-
- QXmlStreamReader xml(&fp);
-
- FCState state = Initialized;
-
- QString currentConig;
- int depth = 0;
- bool hasUnknownConfig = false;
- QString aliasFamily;
- QString matchTarget;
- QStringList familyList;
- while (!xml.atEnd()) {
- QXmlStreamReader::TokenType token = xml.readNext();
- if (token == QXmlStreamReader::DTD) {
- if (xml.dtdName() != "fontconfig" || xml.dtdSystemId() != "fonts.dtd") {
- state = InvalidConfig;
- }
- } else if (token == QXmlStreamReader::StartElement) {
- depth++;
- QString elemName(xml.name().toString());
- switch (state) {
- case Initialized:
- if (elemName == "fontconfig")
- state = Ready;
- else
- state = InvalidConfig;
- break;
-
- case Ready:
- currentConig = elemName;
- if (elemName == "alias")
- state = WaitFamilyForAlias;
- else if (elemName == "match" && xml.attributes().value("target") == "font")
- state = WaitTestForMatch;
- else
- state = UnknownState;
- break;
-
- case WaitFamilyForAlias:
- if (elemName == "family") {
- QXmlStreamReader::TokenType t = xml.readNext();
- Q_ASSERT(t == QXmlStreamReader::Characters);
- aliasFamily = xml.text().toString();
- QStringList preferList(mPreferFontListMap.value(aliasFamily, QStringList()));
- preferList.clear();
- mPreferFontListMap.insert(aliasFamily, preferList);
- state = WaitPreferForAlias;
- } else
- state = UnknownState;
- break;
-
- case WaitPreferForAlias:
- if (elemName == "prefer")
- state = ReadingPrefer;
- else
- state = UnknownState;
- break;
-
- case ReadingPrefer:
- if (elemName == "family") {
- QXmlStreamReader::TokenType t = xml.readNext();
- Q_ASSERT(t == QXmlStreamReader::Characters);
- QString family(xml.text().toString());
-
- QStringList preferList(mPreferFontListMap.value(aliasFamily, QStringList()));
- preferList << family;
- mPreferFontListMap.insert(aliasFamily, preferList);
- } else
- state = UnknownState;
- break;
-
- case WaitTestForMatch:
- if (elemName == "test" && xml.attributes().value("name") == "family" && xml.attributes().value("compare") == "eq") {
- familyList.clear();
- state = ReadingTest;
- } else
- state = UnknownState;
- break;
-
- case ReadingTest:
- if (elemName == "string") {
- QXmlStreamReader::TokenType t = xml.readNext();
- Q_ASSERT(t == QXmlStreamReader::Characters);
- QString family(xml.text().toString());
- familyList << family;
- } else
- state = UnknownState;
- break;
-
- case WaitEditForMatch:
- state = UnknownState;
- if (elemName == "edit" && xml.attributes().hasAttribute("name") && xml.attributes().value("mode") == "assign") {
- matchTarget = xml.attributes().value("name").toString();
- if (matchTarget == "embeddedbitmap" || matchTarget == "hinting")
- state = WaitBoolForEdit;
- }
- break;
-
- case WaitBoolForEdit:
- if (elemName == "bool") {
- QXmlStreamReader::TokenType t = xml.readNext();
- Q_ASSERT(t == QXmlStreamReader::Characters);
- QString boolVal(xml.text().toString());
- QString key(matchTarget + ":" + boolVal);
- mMatchFontListMap.insert(key, familyList);
- state = WaitEndMatch;
- } else
- state = UnknownState;
- break;
-
- default:
- ;
- }
-
- } else if (token == QXmlStreamReader::EndElement) {
- depth--;
- QString elemName(xml.name().toString());
-
- switch (state) {
- case ReadingPrefer:
- if (elemName == "alias")
- state = Ready;
- break;
-
- case ReadingTest:
- if (elemName == "test")
- state = WaitEditForMatch;
- break;
-
- case WaitEndMatch:
- if (elemName == "match")
- state = Ready;
- break;
+ mLocalFontsConf->load(mLocalFontsConfPath);
+ emit fontsConfUpdated();
+}
- case UnknownState:
- if (elemName == currentConig && depth == 1)
- state = Ready;
- break;
+void FontConfigManager::saveFontsConf()
+{
+ if (!mLocalFontsConf || mLocalFontsConfPath.isEmpty())
+ return;
- default:
- ;
- }
+ bool check = localFontsConfExists();
+ if (isEmptyLocalFontsConf()) {
+ if (check) {
+ QFile::remove(mLocalFontsConfPath);
+ emit localFontsConfExistsChanged();
}
- if (state == InvalidConfig)
- break;
- else if (state == UnknownState)
- hasUnknownConfig = true;
+ } else {
+ mLocalFontsConf->save(mLocalFontsConfPath);
+ if (!check)
+ emit localFontsConfExistsChanged();
}
-
- if (state == InvalidConfig)
- emit warning(tr("%1 is invali.! Could not parse it.").arg(mLocalFontsConfPath));
- else if (hasUnknownConfig)
- emit warning(tr("%1 contains unsupported config(s). It will be overwritten.\nAre you sure?").arg(mLocalFontsConfPath));
-
- mHasUnknownConfig = hasUnknownConfig;
- mFontsConfModified = false;
- emit configHasUninstalledFontsChanged();
}
-static void writeBoolConfig(QXmlStreamWriter &xml, const QString &configName, bool configValue, const QStringList &families)
+void FontConfigManager::backupFontsConf(const QString &filepath)
{
- if (families.isEmpty())
+ if (filepath.isEmpty() || isEmptyLocalFontsConf())
return;
+ mLocalFontsConf->save(filepath);
+}
- xml.writeStartElement("match");
- xml.writeAttribute("target", "font");
- xml.writeStartElement("test");
- xml.writeAttribute("name", "family");
- xml.writeAttribute("compare", "eq");
- foreach (const QString &family, families) {
- xml.writeTextElement("string", family);
+void FontConfigManager::restoreFontsConf(const QString &filepath)
+{
+ if (filepath.isEmpty() || !QFile::exists(filepath))
+ return;
+ FontsConf *restoredConf = new FontsConf(this);
+ restoredConf->load(filepath);
+ if (restoredConf->isValid()) {
+ mLocalFontsConf->copy(restoredConf);
+ emit fontsConfUpdated();
+ delete restoredConf;
}
- xml.writeEndElement();
- xml.writeStartElement("edit");
- xml.writeAttribute("name", configName);
- xml.writeAttribute("mode", "assign");
- xml.writeTextElement("bool", configValue ? "true" : "false");
- xml.writeEndElement();
- xml.writeEndElement();
-
}
-void FontConfigManager::saveFontsConf()
+void FontConfigManager::resetFontsConf()
{
- QByteArray buf;
-
- if (!mFontsConfModified)
+ if (!mLocalFontsConf)
return;
+ mLocalFontsConf->initFontsConf();
+ emit fontsConfUpdated();
+}
- QXmlStreamWriter xml(&buf);
- xml.setAutoFormatting(true);
+void FontConfigManager::addPreferFamily(const QString &family, const QString &value)
+{
+ mLocalFontsConf->appendPreferFamilyFor(family, value);
+ emit fontsConfUpdated();
+}
- xml.writeStartDocument();
+void FontConfigManager::addAcceptFamily(const QString &family, const QString &value)
+{
+ mLocalFontsConf->appendAcceptFamilyFor(family, value);
+ emit fontsConfUpdated();
+}
- xml.writeDTD("<!DOCTYPE fontconfig SYSTEM 'fonts.dtd'>");
+void FontConfigManager::addPrependFamily(const QString &family, const QString &value)
+{
+ mLocalFontsConf->appendPrependFamilyFor(family, value);
+ emit fontsConfUpdated();
+}
- xml.writeStartElement("fontconfig");
+void FontConfigManager::addAppendFamily(const QString &family, const QString &value)
+{
+ mLocalFontsConf->appendAppendFamilyFor(family, value);
+ emit fontsConfUpdated();
+}
- QStringList preferedFamilies = mPreferFontListMap.keys();
- foreach (const QString &family, preferedFamilies) {
- QStringList preferFamilies = mPreferFontListMap.value(family);
-
- if (!preferFamilies.isEmpty()) {
- xml.writeStartElement("alias");
- xml.writeTextElement("family", family);
- xml.writeStartElement("prefer");
- foreach (const QString &family, preferFamilies) {
- xml.writeTextElement("family", family);
- }
- xml.writeEndElement();
- xml.writeEndElement();
- }
- }
+void FontConfigManager::insertPreferFamily(const QString &family, const QString &value, int index)
+{
+ mLocalFontsConf->insertPreferFamilyFor(family, value, index);
+ emit fontsConfUpdated();
+}
- QStringList familyList;
+void FontConfigManager::insertAcceptFamily(const QString &family, const QString &value, int index)
+{
+ mLocalFontsConf->insertAcceptFamilyFor(family, value, index);
+ emit fontsConfUpdated();
+}
- familyList = mMatchFontListMap.value("embeddedbitmap:true");
- writeBoolConfig(xml, "embeddedbitmap", true, familyList);
- familyList = mMatchFontListMap.value("embeddedbitmap:false");
- writeBoolConfig(xml, "embeddedbitmap", false, familyList);
+void FontConfigManager::insertPrependFamily(const QString &family, const QString &value, int index)
+{
+ mLocalFontsConf->insertPrependFamilyFor(family, value, index);
+ emit fontsConfUpdated();
+}
- familyList = mMatchFontListMap.value("hinting:true");
- writeBoolConfig(xml, "hinting", true, familyList);
- familyList = mMatchFontListMap.value("hinting:false");
- writeBoolConfig(xml, "hinting", false, familyList);
+void FontConfigManager::insertAppendFamily(const QString &family, const QString &value, int index)
+{
+ mLocalFontsConf->insertAppendFamilyFor(family, value, index);
+ emit fontsConfUpdated();
+}
- xml.writeEndElement();
+void FontConfigManager::removePreferFamily(const QString &family, const QString &value)
+{
+ mLocalFontsConf->removePreferFamilyFor(family, value);
+ emit fontsConfUpdated();
+}
- QFile fp(mLocalFontsConfPath);
- if (!fp.open(QIODevice::WriteOnly)) {
- emit warning(tr("Could not write to %1").arg(mLocalFontsConfPath));
- return;
- }
- fp.write(buf);
- fp.close();
- mHasUnknownConfig = false;
- mFontsConfModified = false;
+void FontConfigManager::removeAcceptFamily(const QString &family, const QString &value)
+{
+ mLocalFontsConf->removeAcceptFamilyFor(family, value);
+ emit fontsConfUpdated();
}
-void FontConfigManager::clearFontProperties()
+void FontConfigManager::removePrependFamily(const QString &family, const QString &value)
{
- static const char *genericFamilies[] = { "sans-serif", "serif", "monospace", 0 };
- mPreferFontListMap.clear();
- for (int i = 0; genericFamilies[i]; i++) {
- mPreferFontListMap.insert(genericFamilies[i], QStringList());
- }
- mMatchFontListMap.clear();
+ mLocalFontsConf->removePrependFamilyFor(family, value);
+ emit fontsConfUpdated();
}
+void FontConfigManager::removeAppendFamily(const QString &family, const QString &value)
+{
+ mLocalFontsConf->removeAppendFamilyFor(family, value);
+ emit fontsConfUpdated();
+}