OSDN Git Service

Version 0.5
[fontmanager/fontmanager.git] / fontconfigmanager.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Takumi Asaki
4 ** All rights reserved.
5 ** Contact: Takumi Asaki (takumi.asaki@gmail.com)
6 **
7 ** This file is part of the fontmanager application.
8 **
9 ** You may use this file under the terms of the BSD license as follows:
10 **
11 ** "Redistribution and use in source and binary forms, with or without
12 ** modification, are permitted provided that the following conditions are
13 ** met:
14 **   * Redistributions of source code must retain the above copyright
15 **     notice, this list of conditions and the following disclaimer.
16 **   * Redistributions in binary form must reproduce the above copyright
17 **     notice, this list of conditions and the following disclaimer in
18 **     the documentation and/or other materials provided with the
19 **     distribution.
20 **   * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
21 **     the names of its contributors may be used to endorse or promote
22 **     products derived from this software without specific prior written
23 **     permission.
24 **
25 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28 ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31 ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35 ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
36 **
37 ****************************************************************************/
38
39 #include "fontconfigmanager.h"
40
41 #include "fontconfigdefs.h"
42 #include "installedfontinfo.h"
43 #include "fontsconfigproperties.h"
44
45 #include "fontsconf.h"
46
47 #include <QProcess>
48 #include <QBuffer>
49 #include <QFile>
50 #include <QXmlStreamReader>
51 #include <QVariant>
52 #include <QFontInfo>
53 #include <QFontMetrics>
54 #include <QFontDatabase>
55 #include <QUrl>
56 #include <QTextStream>
57
58 #undef FONTMANAGER_DEBUG_RECOMMENDED_SETTINGS
59
60 #ifdef FONTMANAGER_DEBUG_RECOMMENDED_SETTINGS
61 #include <QDebug>
62 #endif
63
64 #define FCBIN_PATH "/usr/bin/"
65 #define FCCACHE_COMMAND "fc-cache"
66 #define FCCACHE_OPTION "-v"
67 #define FCLIST_COMMAND "fc-list"
68 #define FCLIST_OPTION "-v"
69
70 FontConfigManager::FontConfigManager(QObject *parent) :
71     QObject(parent), mLang("en"), mLocalFontsConf(0)
72 {
73     connect(this, SIGNAL(localFontsConfPathChanged()), SIGNAL(localFontsConfExistsChanged()));
74     //    connect(this, SIGNAL(localFontsConfPathChanged()), SIGNAL(fontsConfUpdated()));
75
76     mLocalFontsConf = new FontsConf(this);
77     mSystemLocalConf = new FontsConf(this);
78
79     QStringList cjkConflicts;
80     cjkConflicts << "ja" << "ko" << "zh-cn" << "zh-hk" << "zh-mo" << "zh-sg" << "zh-tw";
81     mConflictFonts << cjkConflicts;
82
83     mSystemLocalConf->load("/etc/fonts/local.conf");
84
85 }
86
87 QString FontConfigManager::currentLanguage() const
88 {
89     return mLang;
90 }
91
92 void FontConfigManager::setCurrentLanguage(const QString &lang)
93 {
94     mLang = lang;
95 }
96
97 QString FontConfigManager::localFontPath() const
98 {
99     return mLocalFontPath;
100 }
101
102 void FontConfigManager::setLocalFontPath(const QString &path)
103 {
104     mLocalFontPath = path;
105 }
106
107 QString FontConfigManager::localFontsConfPath() const
108 {
109     return mLocalFontsConfPath;
110 }
111
112 void FontConfigManager::setLocalFontsConfPath(const QString &path)
113 {
114     if (mLocalFontsConfPath != path) {
115         mLocalFontsConfPath = path;
116         emit localFontsConfPathChanged();
117     }
118 }
119
120 bool FontConfigManager::localFontsConfExists() const
121 {
122     return QFile::exists(mLocalFontsConfPath);
123 }
124
125 bool FontConfigManager::hasUnknownConfig() const
126 {
127     if (!mLocalFontsConf)
128         return false;
129     return mLocalFontsConf->hasUnknownConfig();
130 }
131
132 bool FontConfigManager::fontsConfModified() const
133 {
134     if (!mLocalFontsConf)
135         return false;
136     return mLocalFontsConf->modified();
137 }
138
139 bool FontConfigManager::isEmptyLocalFontsConf() const
140 {
141     return !mLocalFontsConf || mLocalFontsConf->isEmpty();
142 }
143
144 QStringList FontConfigManager::fontCount(const QString &fontpath) const
145 {
146     QStringList fontList;
147     foreach (InstalledFontInfo *info, mFcListInfo) {
148         if (info->file() == fontpath)
149             fontList << info->localefamily();
150     }
151     return fontList;
152 }
153
154 InstalledFontInfo *FontConfigManager::fontInfo(const QString &family, const QString &fullname) const
155 {
156     InstalledFontInfo *info = 0;
157     foreach (info, mFcListInfo) {
158         if (info->family().contains(family)) {
159             if (fullname.isEmpty())
160                 return info;
161             if (info->fullname().contains(fullname))
162                 return info;
163         }
164     }
165     return 0;
166 }
167
168 InstalledFontInfo *FontConfigManager::fontInfo(int index) const
169 {
170     if (index >= 0 && index < mFcListInfo.count())
171         return mFcListInfo.at(index);
172     return 0;
173 }
174
175 int FontConfigManager::count() const
176 {
177     return mFcListInfo.count();
178 }
179
180 void FontConfigManager::appendFontProperty(FontsConfigProperties *prop, const QStringList &familyList)
181 {
182     if (!mLocalFontsConf)
183         return;
184
185     QStringList preferedFamilies(mLocalFontsConf->preferFamily());
186     preferedFamilies << prop->preferFamilies();
187     preferedFamilies.removeDuplicates();
188     foreach (const QString &family, preferedFamilies) {
189         if (prop->preferFamilies().contains(family)) {
190             if (familyList.isEmpty())
191                 mLocalFontsConf->appendPreferFamilyFor(family, prop->family());
192             else
193                 foreach (const QString &f, familyList)
194                     mLocalFontsConf->appendPreferFamilyFor(family, f);
195         } else {
196             if (familyList.isEmpty())
197                 mLocalFontsConf->removePreferFamilyFor(family, prop->family());
198             else
199                 foreach (const QString &f, familyList)
200                     mLocalFontsConf->removePreferFamilyFor(family, f);
201         }
202     }
203
204     QStringList keys = FontsConf::configKeys();
205     foreach (const QString &key, keys) {
206         if (prop->configValue(key) == FontsConfigProperties::Default) {
207             if (familyList.isEmpty())
208                 mLocalFontsConf->unsetMatchEditValueFor(key, prop->family());
209             else
210                 foreach (const QString &f, familyList)
211                     mLocalFontsConf->unsetMatchEditValueFor(key, f);
212         } else {
213             if (familyList.isEmpty())
214                 mLocalFontsConf->setMatchEditValueFor(key, prop->family(), (prop->configValue(key) == FontsConfigProperties::True));
215             else
216                 foreach (const QString &f, familyList)
217                     mLocalFontsConf->setMatchEditValueFor(key, f, (prop->configValue(key) == FontsConfigProperties::True));
218         }
219     }
220
221     emit fontsConfUpdated();
222 }
223
224 void FontConfigManager::appendFontProperty(InstalledFontInfo *fontInfo)
225 {
226     QStringList familyList;
227     familyList << fontInfo->enfamily();
228     appendFontProperty(fontInfo->fontProperty(), familyList);
229 }
230
231 FontsConfigProperties *FontConfigManager::fontProperty(const QString &family, const QStringList &familyList) const
232 {
233     FontsConfigProperties *prop = new FontsConfigProperties(family);
234     QStringList families;
235     QStringList preferedFamilies = mLocalFontsConf->preferFamily();
236     foreach (const QString &key, preferedFamilies) {
237         families = mLocalFontsConf->preferFamilyFor(key);
238         if (families.contains(family))
239             prop->addPreferFamily(key);
240         foreach (const QString &f, familyList) {
241             if (families.contains(f))
242                 prop->addPreferFamily(key);
243         }
244     }
245
246     QStringList keys = FontsConf::configKeys();
247     foreach (const QString &key, keys) {
248         QString val = mLocalFontsConf->matchEditValueFor(key, prop->family());
249         if (!val.isEmpty()) {
250             prop->setConfigValue(key, (QVariant(val).toBool() ? FontsConfigProperties::True : FontsConfigProperties::False));
251             continue;
252         }
253         foreach (const QString &f, familyList) {
254             mLocalFontsConf->matchEditValueFor(key, f);
255             if (!val.isEmpty()) {
256                 prop->setConfigValue(key, (QVariant(val).toBool() ? FontsConfigProperties::True : FontsConfigProperties::False));
257                 break;
258             }
259         }
260     }
261
262     return prop;
263 }
264
265 FontsConfigProperties *FontConfigManager::fontProperty(InstalledFontInfo *fontInfo) const
266 {
267     return fontProperty(fontInfo->enfamily(), fontInfo->family());
268 }
269
270 QString FontConfigManager::localFontsConf() const
271 {
272     QFile fp(mLocalFontsConfPath);
273
274     if (!fp.exists())
275         return QString();
276
277     if (!fp.open(QIODevice::ReadOnly))
278         return QString();
279
280     QTextStream ts(&fp);
281     ts.setCodec("UTF-8");
282     QString buf = ts.readAll();
283
284     fp.close();
285
286     return buf;
287 }
288
289 QStringList FontConfigManager::preferFamilyFor(const QString &family) const
290 {
291     return mLocalFontsConf->preferFamilyFor(family);
292 }
293
294 QStringList FontConfigManager::acceptFamilyFor(const QString &family) const
295 {
296     return mLocalFontsConf->acceptFamilyFor(family);
297 }
298
299 QStringList FontConfigManager::prependFamilyFor(const QString &family) const
300 {
301     return mLocalFontsConf->prependFamilyFor(family);
302 }
303
304 QStringList FontConfigManager::appendFamilyFor(const QString &family) const
305 {
306     return mLocalFontsConf->appendFamilyFor(family);
307 }
308
309 bool FontConfigManager::isConflict(const QString &family, const QStringList &lang) const
310 {
311     InstalledFontInfo *info = fontInfo(family);
312     if (!info)
313         return false;
314
315     QList<int> confListIndex;
316     for (int i = 0; i < mConflictFonts.count(); i++) {
317         const QStringList list(mConflictFonts.at(i));
318         foreach (const QString &f, list) {
319             if (lang.contains(f)) {
320                 if (!confListIndex.contains(i))
321                     confListIndex << i;
322                 break;
323             }
324         }
325     }
326
327     if (confListIndex.isEmpty())
328         return false;
329
330     foreach (int i, confListIndex) {
331         QStringList confList = mConflictFonts.at(confListIndex.at(i));
332         foreach (const QString &f, confList) {
333             if (info->lang().contains(f)) {
334                 return true;
335             }
336         }
337     }
338
339     return false;
340 }
341
342 QStringList FontConfigManager::systemPreferFamilyFor(const QString &family) const
343 {
344     return mSystemLocalConf->preferFamilyFor(family);
345 }
346
347 void FontConfigManager::importSystemSettings(const QString &family)
348 {
349     QStringList systemFamilyList = systemPreferFamilyFor(family);
350
351     QStringList installedFontLang;
352     foreach (InstalledFontInfo *info, mFcListInfo) {
353         if (info->systemFont())
354             continue;
355         installedFontLang << info->lang();
356     }
357     installedFontLang.sort();
358     installedFontLang.removeDuplicates();
359
360     emit startUpdateFontsConfig();
361     foreach (const QString &f, systemFamilyList) {
362         InstalledFontInfo *info = fontInfo(f);
363         if (!info)
364             continue;
365
366         if (isConflict(f, installedFontLang))
367             mLocalFontsConf->appendAcceptFamilyFor(family, f);
368         else
369             mLocalFontsConf->appendPrependFamilyFor(family, f);
370     }
371     emit endUpdateFontsConfig();
372
373     if (mLocalFontsConf->modified()) {
374         emit fontsConfUpdated();
375     }
376 }
377
378 void FontConfigManager::createRecommendedSettings()
379 {
380     QList<InstalledFontInfo*> sansSerifFonts;
381     QList<InstalledFontInfo*> serifFonts;
382     QList<InstalledFontInfo*> monospaceFonts;
383     QList<InstalledFontInfo*> monospaceSansSerifFonts;
384     QList<InstalledFontInfo*> monospaceSerifFonts;
385     QList<InstalledFontInfo*> unknownFonts;
386
387     foreach (InstalledFontInfo *info, mFcListInfo) {
388         if (info->systemFont())
389             continue;
390         if (maybeMonospaceFont(info)) {
391             if (maybeSansSerifFont(info))
392                 monospaceSansSerifFonts << info;
393             else if (maybeSerifFont(info))
394                 monospaceSerifFonts << info;
395             else
396                 monospaceFonts << info;
397         } else if (maybeSansSerifFont(info))
398             sansSerifFonts << info;
399         else if (maybeSerifFont(info))
400             serifFonts << info;
401         else
402             unknownFonts << info;
403     }
404
405     emit startUpdateFontsConfig();
406     resetFontsConf();
407
408 #ifdef FONTMANAGER_DEBUG_RECOMMENDED_SETTINGS
409     QStringList f;
410     foreach (InstalledFontInfo *info, monospaceFonts)
411         f << info->localefamily();
412     qDebug() << "Mono:" << f;
413     f.clear();
414     foreach (InstalledFontInfo *info, monospaceSansSerifFonts)
415         f << info->localefamily();
416     qDebug() << "Mono(Sans Serif):" << f;
417     f.clear();
418     foreach (InstalledFontInfo *info, monospaceSerifFonts)
419         f << info->localefamily();
420     qDebug() << "Mono(Serif):" << f;
421     f.clear();
422     foreach (InstalledFontInfo *info, sansSerifFonts)
423         f << info->localefamily();
424     qDebug() << "Sans Serif:" << f;
425     f.clear();
426     foreach (InstalledFontInfo *info, serifFonts)
427         f << info->localefamily();
428     qDebug() << "Serif:" << f;
429     f.clear();
430     foreach (InstalledFontInfo *info, unknownFonts)
431         f << info->localefamily();
432     qDebug() << "Unknown:" << f;
433 #endif
434
435     if (monospaceFonts.count())
436         foreach (InstalledFontInfo *info, monospaceFonts) {
437             addPreferFamily(MONOSPACE_DEF, info->enfamily());
438         }
439     else if (monospaceSansSerifFonts.count())
440         foreach (InstalledFontInfo *info, monospaceSansSerifFonts) {
441             addPreferFamily(MONOSPACE_DEF, info->enfamily());
442         }
443     else if (monospaceSerifFonts.count())
444         foreach (InstalledFontInfo *info, monospaceSerifFonts) {
445             addPreferFamily(MONOSPACE_DEF, info->enfamily());
446         }
447
448     if (sansSerifFonts.count())
449         foreach (InstalledFontInfo *info, sansSerifFonts) {
450             addPreferFamily(SANSSERIF_DEF, info->enfamily());
451             addPreferFamily(SYSTEM_DEF, info->enfamily());
452         }
453     else if (monospaceSansSerifFonts.count())
454         foreach (InstalledFontInfo *info, monospaceSansSerifFonts) {
455             addPreferFamily(SANSSERIF_DEF, info->enfamily());
456             addPreferFamily(SYSTEM_DEF, info->enfamily());
457         }
458     else if (unknownFonts.count())
459         foreach (InstalledFontInfo *info, unknownFonts) {
460             addPreferFamily(SANSSERIF_DEF, info->enfamily());
461             addPreferFamily(SYSTEM_DEF, info->enfamily());
462         }
463     else if (monospaceFonts.count())
464         foreach (InstalledFontInfo *info, monospaceFonts) {
465             addPreferFamily(SANSSERIF_DEF, info->enfamily());
466             addPreferFamily(SYSTEM_DEF, info->enfamily());
467         }
468
469     if (serifFonts.count())
470         foreach (InstalledFontInfo *info, serifFonts) {
471             addPreferFamily(SERIF_DEF, info->enfamily());
472         }
473     else if (monospaceSerifFonts.count())
474         foreach (InstalledFontInfo *info, monospaceSerifFonts) {
475             addPreferFamily(SANSSERIF_DEF, info->enfamily());
476         }
477     else if (unknownFonts.count())
478         foreach (InstalledFontInfo *info, unknownFonts) {
479             addPreferFamily(SERIF_DEF, info->enfamily());
480         }
481     else if (monospaceFonts.count())
482         foreach (InstalledFontInfo *info, monospaceFonts) {
483             addPreferFamily(SERIF_DEF, info->enfamily());
484         }
485
486     foreach (const QString &f, FontsConf::genericFamilies())
487         importSystemSettings(f);
488     emit endUpdateFontsConfig();
489
490     emit fontsConfUpdated();
491 }
492
493 QStringList FontConfigManager::installableFamily(const QString &family, bool localOnly)
494 {
495     QStringList installedFont;
496     installedFont << prependFamilyFor(family);
497     installedFont << appendFamilyFor(family);
498     installedFont << preferFamilyFor(family);
499     installedFont << acceptFamilyFor(family);
500
501     QStringList familyList;
502     foreach (InstalledFontInfo *info, mFcListInfo) {
503         if (localOnly && info->systemFont())
504             continue;
505         bool check = false;
506         foreach (const QString &f, info->family()) {
507             if (installedFont.contains(f)) {
508                 check = true;
509                 break;
510             }
511         }
512         if (!check)
513             familyList << info->localefamily();
514     }
515     familyList.sort();
516     familyList.removeDuplicates();
517
518     return familyList;
519 }
520
521 QString FontConfigManager::localeFamily(const QString &family) const
522 {
523     if (mEnLocaleFontMap.contains(family))
524         return mEnLocaleFontMap.value(family);
525     return family;
526 }
527
528 bool FontConfigManager::maybeSansSerifFont(InstalledFontInfo *info) const
529 {
530     foreach (const QString &f, info->family()) {
531         if (f.contains("gothic", Qt::CaseInsensitive) ||
532                 f.contains("arial", Qt::CaseInsensitive) ||
533                 f.contains("helvetica", Qt::CaseInsensitive) ||
534                 f.contains("verdana", Qt::CaseInsensitive) ||
535                 f.contains("sans", Qt::CaseInsensitive))
536             return true;
537     }
538     return false;
539 }
540
541 bool FontConfigManager::maybeSerifFont(InstalledFontInfo *info) const
542 {
543     foreach (const QString &f, info->family()) {
544         if (f.contains("mincho", Qt::CaseInsensitive) ||
545                 f.contains("times", Qt::CaseInsensitive) ||
546                 (f.contains("serif", Qt::CaseInsensitive) && !f.contains("sans", Qt::CaseInsensitive)))
547             return true;
548     }
549     return false;
550 }
551
552 #define DEFAULT_POINTSIZE 24
553
554 bool FontConfigManager::maybeMonospaceFont(InstalledFontInfo *info) const
555 {
556     int fontId = -1;
557     QFont font = font4info(info, DEFAULT_POINTSIZE);
558 #ifdef FONTMANAGER_DEBUG_RECOMMENDED_SETTINGS
559     qDebug() << "0 - FontConfigManager::maybeMonospaceFont(" << info->enfamily() << info->enstyle() << point << ")" << font.family() << font.exactMatch();
560 #endif
561     if (!font.exactMatch() || font.family() != info->enfamily()) {
562         fontId = QFontDatabase::addApplicationFont(info->file());
563 #ifdef FONTMANAGER_DEBUG_RECOMMENDED_SETTINGS
564         qDebug() << "\tfontId:" << fontId << info->file();
565 #endif
566         if (fontId >= 0) {
567             font = font4info(info, DEFAULT_POINTSIZE);
568 #ifdef FONTMANAGER_DEBUG_RECOMMENDED_SETTINGS
569             qDebug() << "1 - FontConfigManager::maybeMonospaceFont(" << info->enfamily() << info->enstyle() << point << ")" << font.family() << font.exactMatch();
570 #endif
571             if (!font.exactMatch() || font.family() != info->enfamily()) {
572                 font = QFont(info->enfamily());
573 #ifdef FONTMANAGER_DEBUG_RECOMMENDED_SETTINGS
574                 qDebug() << "2 - FontConfigManager::maybeMonospaceFont(" << info->enfamily() << info->enstyle() << point << ")" << font.family() << font.exactMatch();
575 #endif
576             }
577         }
578     }
579     bool isFixed = false;
580     if (font.exactMatch()) {
581         QFontInfo fi(font);
582 #ifdef FONTMANAGER_DEBUG_RECOMMENDED_SETTINGS
583         qDebug() << "\tfixedPitch:" << fi.fixedPitch();
584 #endif
585         if (fi.fixedPitch()) {
586             isFixed = true;
587         } else {
588             QFontMetrics fm(font);
589             int w = fm.width(QLatin1Char('A'));
590 #ifdef FONTMANAGER_DEBUG_RECOMMENDED_SETTINGS
591             qDebug() << "\twidth:" << w << fm.width(QLatin1Char('i')) << fm.width(QLatin1Char('X'));
592 #endif
593             if (fm.width(QLatin1Char('i')) == w && fm.width(QLatin1Char('X')) == w) {
594                 isFixed = true;
595             }
596         }
597     }
598     if (fontId >= 0)
599         QFontDatabase::removeApplicationFont(fontId);
600     if (isFixed)
601         return true;
602     foreach (const QString &f, info->family()) {
603         if (f.contains("courier", Qt::CaseInsensitive) ||
604                 f.contains("mono", Qt::CaseInsensitive))
605             return true;
606     }
607     return false;
608 }
609
610 QFont FontConfigManager::font4info(InstalledFontInfo *info, int pointSize) const
611 {
612     QFontDatabase fdb;
613     int point = pointSize;
614     if (!fdb.isScalable(info->enfamily(), info->enstyle())) {
615         QList<int> points = fdb.pointSizes(info->enfamily(), info->enstyle());
616         if (points.count() > 0)
617             point = points.first();
618     }
619     QFont font = fdb.font(info->enfamily(), info->enstyle(), point);
620     return font;
621 }
622
623 void FontConfigManager::runFcCache()
624 {
625     QProcess *proc = new QProcess(this);
626     connect(proc, SIGNAL(finished(int)), SIGNAL(fcCacheFinished()));
627     connect(proc, SIGNAL(finished(int)), proc, SLOT(deleteLater()));
628     proc->start(FCBIN_PATH FCCACHE_COMMAND, QStringList() << FCCACHE_OPTION);
629 }
630
631 void FontConfigManager::readFcList()
632 {
633     QProcess *proc = new QProcess(this);
634     proc->start(FCBIN_PATH FCLIST_COMMAND, QStringList() << FCLIST_OPTION);
635     if (!proc->waitForStarted())
636         return;
637
638     if (!proc->waitForFinished())
639         return;
640
641     qDeleteAll(mFcListInfo);
642     mFcListInfo.clear();
643     mEnLocaleFontMap.clear();
644
645     QByteArray buf = proc->readAllStandardOutput();
646     QByteArray errbuf = proc->readAllStandardError();
647     if (!errbuf.isEmpty())
648         qWarning("%s", errbuf.constData());
649     Q_ASSERT(errbuf.isEmpty());
650
651     static QByteArray emptyLine("\n");
652     QBuffer buffer(&buf);
653     QByteArray fibuf;
654     buffer.open(QIODevice::ReadOnly);
655     Q_ASSERT(buffer.isOpen());
656     while (!buffer.atEnd()) {
657         QByteArray linebuf = buffer.readLine();
658         if (linebuf.isEmpty() || linebuf == emptyLine) {
659             if (!fibuf.isEmpty()) {
660                 InstalledFontInfo *info = new InstalledFontInfo(fibuf, mLocalFontPath, this);
661                 info->setLocale(mLang);
662                 if (info->isValid()) {
663                     mFcListInfo.append(info);
664                     mEnLocaleFontMap.insert(info->enfamily(), info->localefamily());
665                     info->setFontProperty(fontProperty(info));
666                 } else
667                     delete info;
668                 fibuf.clear();
669             }
670         } else {
671             fibuf += linebuf;
672         }
673     }
674     Q_ASSERT(fibuf.isEmpty());
675     buffer.close();
676
677     qSort(mFcListInfo.begin(), mFcListInfo.end(), InstalledFontInfo::compare);
678
679     emit fontListUpdated();
680
681     delete proc;
682 }
683
684 void FontConfigManager::readFontsConf()
685 {
686     mLocalFontsConf->load(mLocalFontsConfPath);
687     emit fontsConfUpdated();
688 }
689
690 void FontConfigManager::saveFontsConf()
691 {
692     if (!mLocalFontsConf || mLocalFontsConfPath.isEmpty())
693         return;
694
695     bool check = localFontsConfExists();
696     if (isEmptyLocalFontsConf()) {
697         if (check) {
698             QFile::remove(mLocalFontsConfPath);
699             emit localFontsConfExistsChanged();
700         }
701     } else {
702         mLocalFontsConf->save(mLocalFontsConfPath);
703         if (!check)
704             emit localFontsConfExistsChanged();
705     }
706 }
707
708 void FontConfigManager::backupFontsConf(const QString &filepath)
709 {
710     if (filepath.isEmpty() || isEmptyLocalFontsConf())
711         return;
712     mLocalFontsConf->save(filepath);
713 }
714
715 void FontConfigManager::restoreFontsConf(const QString &filepath)
716 {
717     if (filepath.isEmpty() || !QFile::exists(filepath))
718         return;
719     FontsConf *restoredConf = new FontsConf(this);
720     restoredConf->load(filepath);
721     if (restoredConf->isValid()) {
722         mLocalFontsConf->copy(restoredConf);
723         emit fontsConfUpdated();
724         delete restoredConf;
725     }
726 }
727
728 void FontConfigManager::resetFontsConf()
729 {
730     if (!mLocalFontsConf)
731         return;
732     mLocalFontsConf->initFontsConf();
733     emit fontsConfUpdated();
734 }
735
736 void FontConfigManager::addPreferFamily(const QString &family, const QString &value)
737 {
738     mLocalFontsConf->appendPreferFamilyFor(family, value);
739     emit fontsConfUpdated();
740 }
741
742 void FontConfigManager::addAcceptFamily(const QString &family, const QString &value)
743 {
744     mLocalFontsConf->appendAcceptFamilyFor(family, value);
745     emit fontsConfUpdated();
746 }
747
748 void FontConfigManager::addPrependFamily(const QString &family, const QString &value)
749 {
750     mLocalFontsConf->appendPrependFamilyFor(family, value);
751     emit fontsConfUpdated();
752 }
753
754 void FontConfigManager::addAppendFamily(const QString &family, const QString &value)
755 {
756     mLocalFontsConf->appendAppendFamilyFor(family, value);
757     emit fontsConfUpdated();
758 }
759
760 void FontConfigManager::insertPreferFamily(const QString &family, const QString &value, int index)
761 {
762     mLocalFontsConf->insertPreferFamilyFor(family, value, index);
763     emit fontsConfUpdated();
764 }
765
766 void FontConfigManager::insertAcceptFamily(const QString &family, const QString &value, int index)
767 {
768     mLocalFontsConf->insertAcceptFamilyFor(family, value, index);
769     emit fontsConfUpdated();
770 }
771
772 void FontConfigManager::insertPrependFamily(const QString &family, const QString &value, int index)
773 {
774     mLocalFontsConf->insertPrependFamilyFor(family, value, index);
775     emit fontsConfUpdated();
776 }
777
778 void FontConfigManager::insertAppendFamily(const QString &family, const QString &value, int index)
779 {
780     mLocalFontsConf->insertAppendFamilyFor(family, value, index);
781     emit fontsConfUpdated();
782 }
783
784 void FontConfigManager::removePreferFamily(const QString &family, const QString &value)
785 {
786     mLocalFontsConf->removePreferFamilyFor(family, value);
787     emit fontsConfUpdated();
788 }
789
790 void FontConfigManager::removeAcceptFamily(const QString &family, const QString &value)
791 {
792     mLocalFontsConf->removeAcceptFamilyFor(family, value);
793     emit fontsConfUpdated();
794 }
795
796 void FontConfigManager::removePrependFamily(const QString &family, const QString &value)
797 {
798     mLocalFontsConf->removePrependFamilyFor(family, value);
799     emit fontsConfUpdated();
800 }
801
802 void FontConfigManager::removeAppendFamily(const QString &family, const QString &value)
803 {
804     mLocalFontsConf->removeAppendFamilyFor(family, value);
805     emit fontsConfUpdated();
806 }