OSDN Git Service

Version: 0.4
authorTakumi ASAKI <takumi.asaki@gmail.com>
Tue, 17 Jan 2012 00:02:18 +0000 (09:02 +0900)
committerTakumi ASAKI <takumi.asaki@gmail.com>
Wed, 18 Jan 2012 14:52:04 +0000 (23:52 +0900)
* Support system's fonts.conf
* Re-new editing fonts.conf
* Add 'Create Recommended Settings' feature
* Remove embeddedbitmap and hinting support

26 files changed:
applicationcontroller.cpp
applicationcontroller.h
fontconfigdefs.h
fontconfigmanager.cpp
fontconfigmanager.h
fontmanager.pro
fontsconf.cpp [new file with mode: 0644]
fontsconf.h [new file with mode: 0644]
fontsconfeditorcontroller.cpp [new file with mode: 0644]
fontsconfeditorcontroller.h [new file with mode: 0644]
fontsconfelement.cpp [new file with mode: 0644]
fontsconfelement.h [new file with mode: 0644]
fontsconfigproperties.cpp
fontsconfigproperties.h
main.cpp
qml/fontmanager/EditFontsConfPage.qml [new file with mode: 0644]
qml/fontmanager/EditorHelper.js [new file with mode: 0644]
qml/fontmanager/FontsConfEditor.qml [new file with mode: 0644]
qml/fontmanager/FontsConfProperties.qml
qml/fontmanager/FontsConfViewPage.qml
qml/fontmanager/InstalledFontInfoPage.qml
qml/fontmanager/MainPage.qml
qml/fontmanager/main.qml
qtc_packaging/debian_harmattan/changelog
translations/fontmanager_ja.ts
translations/fontmanager_untranslated.ts

index e0fbbb1..818b92a 100644 (file)
 
 #include "applicationcontroller.h"
 
+#include "fontconfigdefs.h"
 #include "fontconfigmanager.h"
 #include "installedfontinfo.h"
+#include "fontsconfeditorcontroller.h"
+#include "fontsconf.h"
 
 #include <QtCore>
 
 ApplicationController::ApplicationController(QObject *parent) :
-    QObject(parent), mFontDirExists(false), mShowSystemFont(false), mNextJob(Nothing), mForceOverwrite(false), mWorking(false),
+    QObject(parent), mFontDirExists(false), mShowSystemFont(false), mNextJob(Nothing),
+    mUpdating(0),
+    mForceOverwrite(false), mWorking(false), mIgnoreUpdate(false),
     mFontConfig(0)
 {
 
@@ -63,17 +68,30 @@ void ApplicationController::init()
     mFontConfig->setCurrentLanguage(mLang);
 
     connect(mFontConfig, SIGNAL(fcCacheFinished()), mFontConfig, SLOT(readFcList()));
-    connect(mFontConfig, SIGNAL(familiesChanged()), SLOT(readFcListFinished()));
-    connect(mFontConfig, SIGNAL(familiesChanged()), SIGNAL(fontListChanged()));
-    connect(mFontConfig, SIGNAL(familiesChanged()), SLOT(syncInstalledFonts()));
-    connect(mFontConfig, SIGNAL(warning(QString)), SIGNAL(alertDialog(QString)));
+    connect(mFontConfig, SIGNAL(fontListUpdated()), SLOT(readFcListFinished()));
+    connect(mFontConfig, SIGNAL(fontListUpdated()), SLOT(syncInstalledFonts()));
+
     connect(mFontConfig, SIGNAL(localFontsConfPathChanged()), SIGNAL(localFontsConfPathChanged()));
-    connect(mFontConfig, SIGNAL(configHasUninstalledFontsChanged()), SIGNAL(configHasUninstalledFontsChanged()));
+    connect(mFontConfig, SIGNAL(localFontsConfExistsChanged()), SIGNAL(localFontsConfExistsChanged()));
+
+    connect(mFontConfig, SIGNAL(startUpdateFontsConfig()), SLOT(startUpdateLocalFontsConf()));
+    connect(mFontConfig, SIGNAL(fontsConfUpdated()), SLOT(localFontsConfUpdated()));
+    connect(mFontConfig, SIGNAL(endUpdateFontsConfig()), SLOT(endUpdateLocalFontsConf()));
+
+    connect(this, SIGNAL(localFontsConfChanged()), SLOT(updateAllEditorController()));
+    connect(this, SIGNAL(localFontsConfChanged()), SLOT(saveFontsConf()));
+
+    connect(mFontConfig, SIGNAL(warning(QString)), SIGNAL(alertDialog(QString)));
 
     mFontConfig->setLocalFontsConfPath(QDir::homePath() + QLatin1String("/.fonts.conf"));
 
     mFontConfig->readFontsConf();
     mFontConfig->readFcList();
+
+    foreach (const QString &f, FontsConf::genericFamilies()) {
+        updateEditorController(f);
+    }
+
 }
 
 QString ApplicationController::currentLanguage() const
@@ -120,17 +138,9 @@ void ApplicationController::setShowSystemFont(bool show)
     if (mShowSystemFont != show) {
         mShowSystemFont = show;
         emit showSystemFontChanged();
-        emit fontListChanged();
     }
 }
 
-QStringList ApplicationController::fontList() const
-{
-    if (mShowSystemFont)
-        return mFontConfig->families();
-    return mFontConfig->localFamilies();
-}
-
 FontInfo *ApplicationController::checkFontInfo(const QUrl &path)
 {
     FontInfo *fInfo = new FontInfo(path.toLocalFile(), mFontConfig, this);
@@ -147,6 +157,59 @@ QStringList ApplicationController::fontCount(const QString &fontpath) const
     return mFontConfig->fontCount(fontpath);
 }
 
+FontsConfEditorController *ApplicationController::editorController(const QString &family)
+{
+    FontsConfEditorController *controller = mEditorController.value(family, 0);
+    if (!controller) {
+        controller = new FontsConfEditorController(family, this);
+        mEditorController.insert(family, controller);
+        connect(controller, SIGNAL(appendFamilyToConfig(QString,QString,QString)), SLOT(appendFamilyToConfig(QString,QString,QString)));
+        connect(controller, SIGNAL(removeFamilyFromList(QString,QString,QString)), SLOT(removeFamilyFromConfig(QString,QString,QString)));
+        updateEditorController(family);
+    }
+    return controller;
+}
+
+void ApplicationController::updateEditorController(const QString &family)
+{
+    FontsConfEditorController *controller = editorController(family);
+
+    QStringList familyList;
+
+    controller->clear();
+
+    familyList = mFontConfig->prependFamilyFor(family);
+    foreach (const QString &f, familyList) {
+        InstalledFontInfo *info = fontInfo(f);
+        controller->appendFontsInfo(f, PREPEND_DEF, info);
+    }
+
+    familyList = mFontConfig->preferFamilyFor(family);
+    foreach (const QString &f, familyList) {
+        InstalledFontInfo *info = fontInfo(f);
+        controller->appendFontsInfo(f, PREFER_DEF, info);
+    }
+
+    familyList = mFontConfig->acceptFamilyFor(family);
+    foreach (const QString &f, familyList) {
+        InstalledFontInfo *info = fontInfo(f);
+        controller->appendFontsInfo(f, ACCEPT_DEF, info);
+    }
+
+    controller->syncFamilyList();
+}
+
+void ApplicationController::updateAllEditorController()
+{
+    if (!mFontConfig->fontsConfModified() || mIgnoreUpdate) {
+        mIgnoreUpdate = false;
+        return;
+    }
+    foreach (const QString &f, mEditorController.keys()) {
+        updateEditorController(f);
+    }
+}
+
 bool ApplicationController::localFontsConfExists() const
 {
     if (!mFontConfig)
@@ -154,6 +217,13 @@ bool ApplicationController::localFontsConfExists() const
     return QFile::exists(mFontConfig->localFontsConfPath());
 }
 
+QString ApplicationController::localFontsConfPath() const
+{
+    if (!mFontConfig)
+        return QString();
+    return mFontConfig->localFontsConfPath();
+}
+
 QString ApplicationController::localFontsConf() const
 {
     if (!mFontConfig)
@@ -161,11 +231,11 @@ QString ApplicationController::localFontsConf() const
     return mFontConfig->localFontsConf();
 }
 
-bool ApplicationController::configHasUninstalledFonts() const
+bool ApplicationController::isEmptyFontsConf() const
 {
-    if (!mFontConfig)
-        return false;
-    return mFontConfig->configHasUninstalledFonts();
+    if (!localFontsConfExists())
+        return true;
+    return !mFontConfig || mFontConfig->isEmptyLocalFontsConf();
 }
 
 bool ApplicationController::working() const
@@ -173,17 +243,47 @@ bool ApplicationController::working() const
     return mWorking;
 }
 
-void ApplicationController::removeUninstalledFontsFromConfig()
+
+void ApplicationController::startUpdateLocalFontsConf()
+{
+    mUpdating++;
+}
+
+void ApplicationController::endUpdateLocalFontsConf()
 {
+    mUpdating--;
+    Q_ASSERT(mUpdating >= 0);
+}
+
+void ApplicationController::localFontsConfUpdated()
+{
+    if (mUpdating == 0)
+        emit localFontsConfChanged();
+}
+
+void ApplicationController::resetLocalFontsConf()
+{
+    // TODO:
     if (!mFontConfig)
         return;
-    mFontConfig->removeUninstalledFontsFromConfig();
+    mFontConfig->resetFontsConf();
 }
 
-void ApplicationController::installFont()
+void ApplicationController::importSystemSettings(const QString &family)
+{
+    mFontConfig->importSystemSettings(family);
+    if (mFontConfig->fontsConfModified()) {
+        updateEditorController(family);
+    }
+}
+
+void ApplicationController::createRecommendedSettings()
 {
-//    qDebug() << "ApplicationController::installFont()" << mNextJob;
+    mFontConfig->createRecommendedSettings();
+}
 
+void ApplicationController::installFont()
+{
     FontInfo *info = qobject_cast<FontInfo *>(mJobOption.value<QObject*>());
     if (!info)
         return;
@@ -203,7 +303,7 @@ void ApplicationController::installFont()
     if (mNextJob == StartInstall) {
         if (!mFontDirExists) {
             mNextJob = CreateFontsDir;
-            emit confirmDialog(tr("Create it?"), tr("Local fonts dir '%1' does not exists!\nCreate it now?").arg(mFontDirPath));
+            emit confirmDialog(tr("Create it?"), tr("Local fonts directory '%1' does not exists!  Create it now?").arg(mFontDirPath));
             return;
         } else
             mNextJob = CheckDstFont;
@@ -219,7 +319,7 @@ void ApplicationController::installFont()
     if (mNextJob == CheckDstFont) {
         mNextJob = InstallFont;
         if (dstfont.exists()) {
-            emit confirmDialog(tr("Overwrite it?"), tr("Local font '%1' already exists!\nOverwrite it?").arg(dstfont.absoluteFilePath()));
+            emit confirmDialog(tr("Overwrite it?"), tr("Local font '%1' already exists!  Overwrite it?").arg(dstfont.absoluteFilePath()));
             return;
         }
     }
@@ -245,8 +345,6 @@ void ApplicationController::installFont()
 
 void ApplicationController::installFont(FontInfo *fontinfo)
 {
-//    qDebug() << "ApplicationController::installFont(" << fontinfo->families() << ")";
-
     mNextJob = Nothing;
     mJobOption = QVariant::fromValue<QObject *>(fontinfo);
 
@@ -255,7 +353,6 @@ void ApplicationController::installFont(FontInfo *fontinfo)
 
 void ApplicationController::postInstall()
 {
-    saveFontsConf();
 }
 
 void ApplicationController::updateFontsConf(InstalledFontInfo *fontInfo)
@@ -265,7 +362,6 @@ void ApplicationController::updateFontsConf(InstalledFontInfo *fontInfo)
 
 void ApplicationController::uninstallFont(const QString &fontpath)
 {
-//    qDebug() << "ApplicationController::uninstallFont(" << fontpath << ")";
     bool check = QFile::remove(fontpath);
     if (check) {
         emit uninstallFinished(fontpath);
@@ -280,7 +376,6 @@ void ApplicationController::uninstallFont(const QString &fontpath)
 
 void ApplicationController::confirm(bool ok)
 {
-//    qDebug() << "ApplicationController::confirm(" << ok << ")";
     if (!ok) {
         mNextJob = Nothing;
         mJobOption.clear();
@@ -306,6 +401,18 @@ void ApplicationController::syncInstalledFonts()
     }
 }
 
+void ApplicationController::syncInstallableFamilyFor(const QString &family)
+{
+    if (!mFontConfig)
+        return;
+    emit clearInstallableFamilyListFor(family);
+    QStringList familyList = mFontConfig->installableFamily(family);
+    foreach (const QString &f, familyList) {
+        InstalledFontInfo *info = mFontConfig->fontInfo(f);
+        emit appendInstallableFamily(info->enfamily(), info->localefamily(), info->systemFont());
+    }
+}
+
 void ApplicationController::saveFontsConf()
 {
     if (!mFontConfig->fontsConfModified())
@@ -317,6 +424,37 @@ void ApplicationController::saveFontsConf()
     }
     mFontConfig->saveFontsConf();
     mForceOverwrite = false;
+    emit localFontsConfPathChanged();
+}
+
+void ApplicationController::appendFamilyToConfig(const QString &family, const QString &value, const QString &priority)
+{
+    FontsConfEditorController *controller = qobject_cast<FontsConfEditorController*>(sender());
+    if (controller)
+        mIgnoreUpdate = true;
+    if (priority == PREPEND_DEF)
+        mFontConfig->addPrependFamily(family, value);
+    else if (priority == APPEND_DEF)
+        mFontConfig->addAppendFamily(family, value);
+    else if (priority == PREFER_DEF)
+        mFontConfig->addPreferFamily(family, value);
+    else if (priority == ACCEPT_DEF)
+        mFontConfig->addAcceptFamily(family, value);
+}
+
+void ApplicationController::removeFamilyFromConfig(const QString &family, const QString &value, const QString &priority)
+{
+    FontsConfEditorController *controller = qobject_cast<FontsConfEditorController*>(sender());
+    if (controller)
+        mIgnoreUpdate = true;
+    if (priority == PREPEND_DEF)
+        mFontConfig->removePrependFamily(family, value);
+    else if (priority == APPEND_DEF)
+        mFontConfig->removeAppendFamily(family, value);
+    else if (priority == PREFER_DEF)
+        mFontConfig->removePreferFamily(family, value);
+    else if (priority == ACCEPT_DEF)
+        mFontConfig->removeAcceptFamily(family, value);
 }
 
 void ApplicationController::readFcListFinished()
index d64efde..54f0f3f 100644 (file)
 #define APPLICATIONCONTROLLER_H
 
 #include <QObject>
-#include <QDir>
 #include <QStringList>
-#include <QUrl>
 #include <QVariant>
 
 #include "fontinfo.h"
 
+class QUrl;
+
 class FontConfigManager;
 class InstalledFontInfo;
+class FontsConfEditorController;
 
 class ApplicationController : public QObject
 {
     Q_OBJECT
     Q_PROPERTY(QString fontDir READ fontDir WRITE setFontDir NOTIFY fontDirChanged)
-    Q_PROPERTY(QStringList fontList READ fontList NOTIFY fontListChanged)
     Q_PROPERTY(bool fontDirExists READ fontDirExists)
-    Q_PROPERTY(bool showSystemFont READ showSystemFont WRITE setShowSystemFont NOTIFY showSystemFontChanged)
 
-    Q_PROPERTY(QString localFontsConf READ localFontsConf NOTIFY localFontsConfPathChanged)
-    Q_PROPERTY(bool localFontsConfExists READ localFontsConfExists NOTIFY localFontsConfPathChanged)
+    Q_PROPERTY(QString localFontsConfPath READ localFontsConfPath NOTIFY localFontsConfPathChanged)
+    Q_PROPERTY(bool localFontsConfExists READ localFontsConfExists NOTIFY localFontsConfExistsChanged)
+    Q_PROPERTY(bool isEmptyFontsConf READ isEmptyFontsConf NOTIFY localFontsConfChanged)
+    Q_PROPERTY(QString localFontsConf READ localFontsConf NOTIFY localFontsConfChanged)
 
-    Q_PROPERTY(bool configHasUninstalledFonts READ configHasUninstalledFonts NOTIFY configHasUninstalledFontsChanged)
+    Q_PROPERTY(bool showSystemFont READ showSystemFont WRITE setShowSystemFont NOTIFY showSystemFontChanged)
 
-    Q_PROPERTY(bool working READ working NOTIFY workingChanged())
+    Q_PROPERTY(bool working READ working NOTIFY workingChanged)
 public:
     explicit ApplicationController(QObject *parent = 0);
     
@@ -81,29 +82,38 @@ public:
     bool showSystemFont() const;
     void setShowSystemFont(bool show);
 
-    QStringList fontList() const;
-
     Q_INVOKABLE FontInfo *checkFontInfo(const QUrl &path);
     Q_INVOKABLE InstalledFontInfo *fontInfo(const QString &family, const QString &fullname = QString()) const;
     Q_INVOKABLE QStringList fontCount(const QString &fontpath) const;
 
+    Q_INVOKABLE FontsConfEditorController *editorController(const QString &family);
+    void updateEditorController(const QString &family);
+public slots:
+    void updateAllEditorController();
+
+public:
     bool localFontsConfExists() const;
+    QString localFontsConfPath() const;
     QString localFontsConf() const;
-
-    bool configHasUninstalledFonts() const;
+    bool isEmptyFontsConf() const;
 
     bool working() const;
 
 public slots:
-    void removeUninstalledFontsFromConfig();
+    void startUpdateLocalFontsConf();
+    void endUpdateLocalFontsConf();
+    void localFontsConfUpdated();
+
+    void resetLocalFontsConf();
+    void importSystemSettings(const QString &family);
+
+    void createRecommendedSettings();
 
 signals:
     void alertDialog(const QString &message);
-
     void confirmDialog(const QString &title, const QString &message);
 
     void fontDirChanged(const QString dirpath);
-    void fontListChanged();
 
     void showSystemFontChanged();
 
@@ -113,8 +123,12 @@ signals:
     void clearInstalledFontList();
     void appendInstalledFont(const QString &family, const QString &fullname);
 
+    void clearInstallableFamilyListFor(const QString &family);
+    void appendInstallableFamily(const QString &enfamily, const QString &family, bool systemFont);
+
     void localFontsConfPathChanged();
-    void configHasUninstalledFontsChanged();
+    void localFontsConfExistsChanged();
+    void localFontsConfChanged();
 
     void workingChanged();
 
@@ -133,9 +147,13 @@ public slots:
     void confirm(bool ok);
     
     void syncInstalledFonts();
+    void syncInstallableFamilyFor(const QString &family);
 
     void saveFontsConf();
 
+    void appendFamilyToConfig(const QString &family, const QString &value, const QString &priority);
+    void removeFamilyFromConfig(const QString &family, const QString &value, const QString &priority);
+
 private:
     enum FontJob { Nothing, StartInstall, CreateFontsDir, CheckDstFont, InstallFont, UninstallFont };
 
@@ -148,10 +166,13 @@ private:
     FontJob mNextJob;
     QVariant mJobOption;
 
+    int mUpdating;
     bool mForceOverwrite;
     bool mWorking;
+    bool mIgnoreUpdate;
 
     FontConfigManager *mFontConfig;
+    QMap<QString, FontsConfEditorController*> mEditorController;
 };
 
 #endif // APPLICATIONCONTROLLER_H
index ec997a0..e692950 100644 (file)
 #define ALIAS_DEF "alias"
 #define FAMILY_DEF "family"
 #define PREFER_DEF "prefer"
+#define ACCEPT_DEF "accept"
 #define MATCH_DEF "match"
 #define TEST_DEF "test"
 #define EDIT_DEF "edit"
 
 #define STRING_DEF "string"
 #define BOOL_DEF "bool"
+#define INT_DEF "int"
+#define DOUBLE_DEF "double"
 
 #define TARGET_DEF "target"
 #define COMPARE_DEF "compare"
 #define NAME_DEF "name"
 #define QUAL_DEF "qual"
 
+#define PATTERN_DEF "pattern"
 #define FONT_DEF "font"
+#define SCAN_DEF "scan"
+
+#define DEFAULT_DEF "default"
+#define PROPERTY_DEF "property"
+
 #define ANY_DEF "any"
+
 #define EQ_DEF "eq"
+
 #define ASSIGN_DEF "assign"
+#define PREPEND_DEF "prepend"
+#define APPEND_DEF "append"
+
+#define BINDING_DEF "binding"
+#define STRONG_DEF "strong"
 
 #define SANSSERIF_DEF "sans-serif"
 #define SERIF_DEF "serif"
index d1be27c..6fb4cad 100644 (file)
 #include "installedfontinfo.h"
 #include "fontsconfigproperties.h"
 
+#include "fontsconf.h"
+
 #include <QProcess>
 #include <QBuffer>
 #include <QFile>
 #include <QXmlStreamReader>
 #include <QVariant>
+#include <QFontInfo>
+#include <QFontMetrics>
 
 #include <QDebug>
 
 #define FCLIST_COMMAND "fc-list"
 #define FCLIST_OPTION "-v"
 
-enum FCState {
-    Initialized, Ready, WaitFamilyForAlias, WaitPreferForAlias, ReadingPrefer,
-    WaitTestForMatch, ReadingTest, WaitEditForMatch, WaitBoolForEdit, WaitEndMatch,
-    InvalidConfig,
-    UnknownState
-};
-
-static QStringList configKeys;
+//static QStringList configKeys;
 
 FontConfigManager::FontConfigManager(QObject *parent) :
-    QObject(parent), mLang("en"), mHasUnknownConfig(false), mFontsConfModified(false)
+    QObject(parent), mLang("en"), mLocalFontsConf(0)
 {
-    if (configKeys.isEmpty()) {
-        QStringList keys = FontsConfigProperties::configKeys();
-        foreach (const QString &key, keys) {
-            configKeys << key + ":" TRUE_DEF;
-            configKeys << key + ":" FALSE_DEF;
-        }
-    }
-    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
@@ -111,29 +112,28 @@ void FontConfigManager::setLocalFontsConfPath(const QString &path)
     }
 }
 
-bool FontConfigManager::hasUnknownConfig() const
-{
-    return mHasUnknownConfig;
-}
-
-bool FontConfigManager::fontsConfModified() const
+bool FontConfigManager::localFontsConfExists() const
 {
-    return mFontsConfModified;
+    return QFile::exists(mLocalFontsConfPath);
 }
 
-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
@@ -174,38 +174,42 @@ int FontConfigManager::count() const
 
 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();
+            mLocalFontsConf->appendPreferFamilyFor(family, prop->family());
             foreach (const QString &f, familyList) {
-                if (f != prop->family())
-                    preferList << f;
+                mLocalFontsConf->appendPreferFamilyFor(family, f);
             }
         } else {
-            preferList.removeOne(prop->family());
+            mLocalFontsConf->removePreferFamilyFor(family, prop->family());
             foreach (const QString &f, familyList) {
-                preferList.removeOne(f);
+                mLocalFontsConf->removePreferFamilyFor(family, f);
             }
         }
-        preferList.removeDuplicates();
-//        qDebug() << prop->family() << prop->preferFamilies() << origList << preferList;
-        if (preferList != origList) {
-            mFontsConfModified = true;
-            mPreferFontListMap.insert(family, preferList);
-        }
     }
 
-    QStringList keys = FontsConfigProperties::configKeys();
+    QStringList keys = FontsConf::configKeys();
     foreach (const QString &key, keys) {
-        appendFontPropertyBool(key, prop->configValue(key), prop, familyList);
+        if (prop->configValue(key) == FontsConfigProperties::Default) {
+            mLocalFontsConf->unsetMatchEditValueFor(key, prop->family());
+            foreach (const QString &f, familyList) {
+                mLocalFontsConf->unsetMatchEditValueFor(key, f);
+            }
+        } else {
+            mLocalFontsConf->setMatchEditValueFor(key, prop->family(), (prop->configValue(key) == FontsConfigProperties::True));
+            foreach (const QString &f, familyList) {
+                mLocalFontsConf->setMatchEditValueFor(key, f, (prop->configValue(key) == FontsConfigProperties::True));
+            }
+        }
     }
 
-    emit configHasUninstalledFontsChanged();
+    emit fontsConfUpdated();
 }
 
 void FontConfigManager::appendFontProperty(InstalledFontInfo *fontInfo)
@@ -217,9 +221,9 @@ FontsConfigProperties *FontConfigManager::fontProperty(const QString &family, co
 {
     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) {
@@ -228,12 +232,20 @@ FontsConfigProperties *FontConfigManager::fontProperty(const QString &family, co
         }
     }
 
-    QStringList keys = FontsConfigProperties::configKeys();
+    QStringList keys = FontsConf::configKeys();
     foreach (const QString &key, keys) {
-        if (fontPropertyBoolValue(key, true, family, familyList))
-            prop->setConfigValue(key, FontsConfigProperties::True);
-        if (fontPropertyBoolValue(key, false, family, familyList))
-            prop->setConfigValue(key, FontsConfigProperties::False);
+        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;
@@ -263,27 +275,51 @@ QString FontConfigManager::localFontsConf() const
     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;
             }
         }
     }
 
-    foreach (const QString &key, configKeys) {
-        QStringList families = mMatchFontListMap.value(key);
-        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;
             }
         }
@@ -292,83 +328,231 @@ bool FontConfigManager::configHasUninstalledFonts() const
     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();
 
-    foreach (const QString &key, configKeys) {
-        bool m = false;
-        QStringList families = mMatchFontListMap.value(key);
-        foreach (const QString &f, families) {
-            if (!localfamilies.contains(f)) {
-                families.removeOne(f);
-                modified = true;
-                m = true;
-            }
-        }
-        if (m)
-            mMatchFontListMap.insert(key, families);
+    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;
 
-    if (modified) {
-        mFontsConfModified = true;
-        emit configHasUninstalledFontsChanged();
+    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();
+
+#if 0
+    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());
+            addPreferFamily(MONOSPACE_DEF, info->localefamily());
+        }
+    else if (monospaceSansSerifFonts.count())
+        foreach (InstalledFontInfo *info, monospaceSansSerifFonts) {
+            addPreferFamily(MONOSPACE_DEF, info->enfamily());
+            addPreferFamily(MONOSPACE_DEF, info->localefamily());
+        }
+    else if (monospaceSerifFonts.count())
+        foreach (InstalledFontInfo *info, monospaceSerifFonts) {
+            addPreferFamily(MONOSPACE_DEF, info->enfamily());
+            addPreferFamily(MONOSPACE_DEF, info->localefamily());
+        }
+
+    if (sansSerifFonts.count())
+        foreach (InstalledFontInfo *info, sansSerifFonts) {
+            addPreferFamily(SANSSERIF_DEF, info->enfamily());
+            addPreferFamily(SANSSERIF_DEF, info->localefamily());
+        }
+    else if (monospaceSansSerifFonts.count())
+        foreach (InstalledFontInfo *info, monospaceSansSerifFonts) {
+            addPreferFamily(SANSSERIF_DEF, info->enfamily());
+            addPreferFamily(SANSSERIF_DEF, info->localefamily());
+        }
+    else if (unknownFonts.count())
+        foreach (InstalledFontInfo *info, unknownFonts) {
+            addPreferFamily(SANSSERIF_DEF, info->enfamily());
+            addPreferFamily(SANSSERIF_DEF, info->localefamily());
+        }
+    else if (monospaceFonts.count())
+        foreach (InstalledFontInfo *info, monospaceFonts) {
+            addPreferFamily(SANSSERIF_DEF, info->enfamily());
+            addPreferFamily(SANSSERIF_DEF, info->localefamily());
+        }
+
+    if (serifFonts.count())
+        foreach (InstalledFontInfo *info, serifFonts) {
+            addPreferFamily(SERIF_DEF, info->enfamily());
+            addPreferFamily(SERIF_DEF, info->localefamily());
+        }
+    else if (monospaceSerifFonts.count())
+        foreach (InstalledFontInfo *info, monospaceSerifFonts) {
+            addPreferFamily(SANSSERIF_DEF, info->enfamily());
+            addPreferFamily(SANSSERIF_DEF, info->localefamily());
+        }
+    else if (unknownFonts.count())
+        foreach (InstalledFontInfo *info, unknownFonts) {
+            addPreferFamily(SERIF_DEF, info->enfamily());
+            addPreferFamily(SERIF_DEF, info->localefamily());
+        }
+    else if (monospaceFonts.count())
+        foreach (InstalledFontInfo *info, monospaceFonts) {
+            addPreferFamily(SERIF_DEF, info->enfamily());
+            addPreferFamily(SERIF_DEF, info->localefamily());
+        }
+
+    foreach (const QString &f, FontsConf::genericFamilies())
+        importSystemSettings(f);
+    emit endUpdateFontsConfig();
+
+    emit fontsConfUpdated();
 }
 
-void FontConfigManager::appendFontPropertyBool(const QString &config, FontsConfigProperties::ConfigValue value, FontsConfigProperties *prop, const QStringList &familyList)
+QStringList FontConfigManager::installableFamily(const QString &family, bool localOnly)
 {
-    static const char *boolValues[] = { TRUE_DEF, FALSE_DEF, 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;
-            }
-        } else {
-            matchedList.removeOne(prop->family());
-            foreach (const QString &f, familyList) {
-                matchedList.removeOne(f);
+    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;
             }
         }
-        matchedList.removeDuplicates();
-        if (matchedList != origList) {
-            mFontsConfModified = true;
-            mMatchFontListMap.insert(key, matchedList);
-        }
+        if (!check)
+            familyList << info->localefamily();
+    }
+    familyList.sort();
+    familyList.removeDuplicates();
+
+    return familyList;
+}
+
+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;
 }
 
-bool FontConfigManager::fontPropertyBoolValue(const QString &config, bool value, const QString &family, const QStringList &familyList) const
+bool FontConfigManager::maybeSerifFont(InstalledFontInfo *info) const
 {
-    QStringList families = mMatchFontListMap.value(config + (value ? ":" TRUE_DEF : ":" FALSE_DEF));
-    if (families.contains(family))
-        return true;
-    foreach (const QString &f, familyList) {
-        if (families.contains(f))
+    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;
+}
+
+bool FontConfigManager::maybeMonospaceFont(InstalledFontInfo *info) const
+{
+    QFont font(info->enfamily());
+    if (font.exactMatch()) {
+        QFontInfo fi(font);
+        if (fi.fixedPitch())
+            return true;
+        QFontMetrics fm(font);
+        int w = fm.width(QLatin1Char('A'));
+        if (fm.width(QLatin1Char('i')) == w && fm.width(QLatin1Char('X')) == w)
+            return true;
+    }
+    foreach (const QString &f, info->family()) {
+        if (f.contains("courier", Qt::CaseInsensitive) ||
+                f.contains("mono", Qt::CaseInsensitive))
             return true;
     }
     return false;
@@ -376,7 +560,6 @@ bool FontConfigManager::fontPropertyBoolValue(const QString &config, bool value,
 
 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()));
@@ -385,7 +568,6 @@ void FontConfigManager::runFcCache()
 
 void FontConfigManager::readFcList()
 {
-//    qDebug("FontConfigManager::readFcList()");
     QProcess *proc = new QProcess(this);
     proc->start(FCBIN_PATH FCLIST_COMMAND, QStringList() << FCLIST_OPTION);
     if (!proc->waitForStarted())
@@ -399,6 +581,8 @@ void FontConfigManager::readFcList()
 
     QByteArray buf = proc->readAllStandardOutput();
     QByteArray errbuf = proc->readAllStandardError();
+    if (!errbuf.isEmpty())
+        qWarning() << errbuf;
     Q_ASSERT(errbuf.isEmpty());
 
     static QByteArray emptyLine("\n");
@@ -428,299 +612,88 @@ void FontConfigManager::readFcList()
 
     qSort(mFcListInfo.begin(), mFcListInfo.end(), InstalledFontInfo::compare);
 
-    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();
-    }
-
-    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_DEF || xml.dtdSystemId() != "fonts.dtd") {
-                state = InvalidConfig;
-            }
-        } else if (token == QXmlStreamReader::StartElement) {
-            depth++;
-            QString elemName(xml.name().toString());
-            switch (state) {
-            case Initialized:
-                if (elemName == FONTCONFIG_DEF)
-                    state = Ready;
-                else
-                    state = InvalidConfig;
-                break;
-
-            case Ready:
-                currentConig = elemName;
-                if (elemName == ALIAS_DEF)
-                    state = WaitFamilyForAlias;
-                else if (elemName == MATCH_DEF && xml.attributes().value(TARGET_DEF) == FONT_DEF)
-                    state = WaitTestForMatch;
-                else
-                    state = UnknownState;
-                break;
-
-            case WaitFamilyForAlias:
-                if (elemName == FAMILY_DEF) {
-                    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_DEF)
-                    state = ReadingPrefer;
-                else
-                    state = UnknownState;
-                break;
-
-            case ReadingPrefer:
-                if (elemName == FAMILY_DEF) {
-                    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:
-                state = UnknownState;
-                if (elemName == TEST_DEF && xml.attributes().value(NAME_DEF) == FAMILY_DEF) {
-                    QXmlStreamAttributes attrs(xml.attributes());
-                    QString qual = attrs.hasAttribute(QUAL_DEF) ? attrs.value(QUAL_DEF).toString() : ANY_DEF;
-                    QString compare = attrs.hasAttribute(COMPARE_DEF) ? attrs.value(COMPARE_DEF).toString() : EQ_DEF;
-                    if (qual == ANY_DEF && compare == EQ_DEF) {
-                        familyList.clear();
-                        state = ReadingTest;
-                    }
-                }
-                break;
-
-            case ReadingTest:
-                if (elemName == STRING_DEF) {
-                    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_DEF && xml.attributes().hasAttribute(NAME_DEF) && xml.attributes().value(MODE_DEF) == ASSIGN_DEF) {
-                    matchTarget = xml.attributes().value(NAME_DEF).toString();
-                    if (FontsConfigProperties::configKeys().contains(matchTarget))
-                        state = WaitBoolForEdit;
-                }
-                break;
-
-            case WaitBoolForEdit:
-                if (elemName == BOOL_DEF) {
-                    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_DEF)
-                    state = Ready;
-                break;
-
-            case ReadingTest:
-                if (elemName == TEST_DEF)
-                    state = WaitEditForMatch;
-                break;
-
-            case WaitEndMatch:
-                if (elemName == MATCH_DEF)
-                    state = Ready;
-                break;
-
-            case UnknownState:
-                if (elemName == currentConig && depth == 1)
-                    state = Ready;
-                break;
-
-            default:
-                ;
-            }
-        }
-        if (state == InvalidConfig)
-            break;
-        else if (state == UnknownState)
-            hasUnknownConfig = true;
-    }
-
-    if (state == InvalidConfig)
-        emit warning(tr("%1 is invalid!  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();
+    mLocalFontsConf->load(mLocalFontsConfPath);
+    emit fontsConfUpdated();
 }
 
-static void writeBoolConfig(QXmlStreamWriter &xml, const QString &configName, bool configValue, const QStringList &families)
+void FontConfigManager::saveFontsConf()
 {
-    if (families.isEmpty())
+    if (!mLocalFontsConf || mLocalFontsConfPath.isEmpty())
         return;
 
-    xml.writeStartElement(MATCH_DEF);
-    xml.writeAttribute(TARGET_DEF, FONT_DEF);
-    xml.writeStartElement(TEST_DEF);
-    xml.writeAttribute(NAME_DEF, FAMILY_DEF);
-    xml.writeAttribute(COMPARE_DEF, EQ_DEF);
-    xml.writeAttribute(QUAL_DEF, ANY_DEF);
-    foreach (const QString &family, families) {
-        xml.writeTextElement(STRING_DEF, family);
+    bool check = localFontsConfExists();
+    if (isEmptyLocalFontsConf()) {
+        if (check) {
+            QFile::remove(mLocalFontsConfPath);
+            emit localFontsConfExistsChanged();
+        }
+    } else {
+        mLocalFontsConf->save(mLocalFontsConfPath);
+        if (!check) {
+            emit localFontsConfExistsChanged();
+        }
     }
-    xml.writeEndElement();
-    xml.writeStartElement(EDIT_DEF);
-    xml.writeAttribute(NAME_DEF, configName);
-    xml.writeAttribute(MODE_DEF, ASSIGN_DEF);
-    xml.writeTextElement(BOOL_DEF, configValue ? TRUE_DEF : FALSE_DEF);
-    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);
-
-    xml.writeStartDocument();
-
-    xml.writeDTD("<!DOCTYPE fontconfig SYSTEM 'fonts.dtd'>");
-
-    xml.writeStartElement(FONTCONFIG_DEF);
+void FontConfigManager::addPreferFamily(const QString &family, const QString &value)
+{
+    mLocalFontsConf->appendPreferFamilyFor(family, value);
+    emit fontsConfUpdated();
+}
 
-    QStringList preferedFamilies = mPreferFontListMap.keys();
-    foreach (const QString &family, preferedFamilies) {
-        QStringList preferFamilies = mPreferFontListMap.value(family);
-
-        if (!preferFamilies.isEmpty()) {
-            xml.writeStartElement(ALIAS_DEF);
-            xml.writeTextElement(FAMILY_DEF, family);
-            xml.writeStartElement(PREFER_DEF);
-            foreach (const QString &family, preferFamilies) {
-                xml.writeTextElement(FAMILY_DEF, family);
-            }
-            xml.writeEndElement();
-            xml.writeEndElement();
-        }
-    }
+void FontConfigManager::addAcceptFamily(const QString &family, const QString &value)
+{
+    mLocalFontsConf->appendAcceptFamilyFor(family, value);
+    emit fontsConfUpdated();
+}
 
-    QStringList familyList;
+void FontConfigManager::addPrependFamily(const QString &family, const QString &value)
+{
+    mLocalFontsConf->appendPrependFamilyFor(family, value);
+    emit fontsConfUpdated();
+}
 
-    QStringList keys = FontsConfigProperties::configKeys();
-    foreach (const QString &key, keys) {
-        familyList = mMatchFontListMap.value(key + ":" TRUE_DEF);
-        writeBoolConfig(xml, key, true, familyList);
-        familyList = mMatchFontListMap.value(key + ":" FALSE_DEF);
-        writeBoolConfig(xml, key, false, familyList);
-    }
+void FontConfigManager::addAppendFamily(const QString &family, const QString &value)
+{
+    mLocalFontsConf->appendAppendFamilyFor(family, value);
+    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[] = { SANSSERIF_DEF, SERIF_DEF, MONOSPACE_DEF, 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();
+}
index 4e06999..af8b5e7 100644 (file)
 #include "fontsconfigproperties.h"
 
 class InstalledFontInfo;
+class FontsConf;
 
 class FontConfigManager : public QObject
 {
     Q_OBJECT
-    Q_PROPERTY(QStringList families READ families NOTIFY familiesChanged)
-    Q_PROPERTY(QStringList systemFamilies READ systemFamilies NOTIFY systemFamiliesChanged)
-    Q_PROPERTY(QStringList localFamilies READ localFamilies NOTIFY localFamiliesChanged)
 public:
     explicit FontConfigManager(QObject *parent = 0);
 
@@ -66,16 +64,15 @@ public:
     QString localFontsConfPath() const;
     void setLocalFontsConfPath(const QString &path);
 
+    bool localFontsConfExists() const;
+
     bool hasUnknownConfig() const;
     bool fontsConfModified() const;
-
-    QStringList families() const;
-    QStringList systemFamilies() const;
-    QStringList localFamilies() const;
+    bool isEmptyLocalFontsConf() const;
 
     QStringList fontCount(const QString &fontpath) const;
 
-    InstalledFontInfo *fontInfo(const QString &family, const QString &fullname) const;
+    InstalledFontInfo *fontInfo(const QString &family, const QString &fullname = QString()) const;
     InstalledFontInfo *fontInfo(int index) const;
     int count() const;
 
@@ -86,27 +83,47 @@ public:
 
     QString localFontsConf() const;
 
-    bool configHasUninstalledFonts() const;
-    void removeUninstalledFontsFromConfig();
+    QStringList preferFamilyFor(const QString &family) const;
+    QStringList acceptFamilyFor(const QString &family) const;
+    QStringList prependFamilyFor(const QString &family) const;
+    QStringList appendFamilyFor(const QString &family) const;
+
+    void addPreferFamily(const QString &family, const QString &value);
+    void addAcceptFamily(const QString &family, const QString &value);
+    void addPrependFamily(const QString &family, const QString &value);
+    void addAppendFamily(const QString &family, const QString &value);
+
+    void removePreferFamily(const QString &family, const QString &value);
+    void removeAcceptFamily(const QString &family, const QString &value);
+    void removePrependFamily(const QString &family, const QString &value);
+    void removeAppendFamily(const QString &family, const QString &value);
+
+    bool isConflict(const QString &family, const QStringList &lang) const;
+    QStringList systemPreferFamilyFor(const QString &family) const;
+
+    void importSystemSettings(const QString &family);
+
+    void createRecommendedSettings();
+
+    QStringList installableFamily(const QString &family, bool localOnly = false);
 
 private:
-    void appendFontPropertyBool(const QString &config, FontsConfigProperties::ConfigValue value, FontsConfigProperties *prop, const QStringList &familyList = QStringList());
-    bool fontPropertyBoolValue(const QString &config, bool value, const QString &family, const QStringList &familyList) const;
+    bool maybeSansSerifFont(InstalledFontInfo *info) const;
+    bool maybeSerifFont(InstalledFontInfo *info) const;
+    bool maybeMonospaceFont(InstalledFontInfo *info) const;
 
 signals:
     void fcCacheFinished();
 
-    void familiesChanged();
-    void systemFamiliesChanged();
-    void localFamiliesChanged();
-
+    void localFontsConfExistsChanged();
     void localFontsConfPathChanged();
-    void configHasUninstalledFontsChanged();
 
-    void warning(const QString &message);
+    void startUpdateFontsConfig();
+    void endUpdateFontsConfig();
+    void fontListUpdated();
+    void fontsConfUpdated();
 
-private slots:
-    void clearFontProperties();
+    void warning(const QString &message);
 
 public slots:
     void runFcCache();
@@ -114,19 +131,18 @@ public slots:
     void readFontsConf();
     void saveFontsConf();
 
+    void resetFontsConf();
+
 private:
     QString mLang;
     QString mLocalFontPath;
     QString mLocalFontsConfPath;
     QList<InstalledFontInfo *> mFcListInfo;
-    QStringList mFamilies;
-    QStringList mSystemFamilies;
-    QStringList mLocalFamilies;
-    bool mHasUnknownConfig;
-    bool mFontsConfModified;
-
-    QMap<QString, QStringList> mPreferFontListMap;
-    QMap<QString, QStringList> mMatchFontListMap;
+
+    FontsConf *mLocalFontsConf;
+    FontsConf *mSystemLocalConf;
+
+    QList<QStringList> mConflictFonts;
 };
 
 #endif // FONTCONFIGMANAGER_H
index 431c04f..77d649e 100644 (file)
@@ -56,7 +56,10 @@ SOURCES += main.cpp \
     fontinfo.cpp \
     fontconfigmanager.cpp \
     installedfontinfo.cpp \
-    fontsconfigproperties.cpp
+    fontsconfigproperties.cpp \
+    fontsconfelement.cpp \
+    fontsconf.cpp \
+    fontsconfeditorcontroller.cpp
 
 # Please do not modify the following two lines. Required for deployment.
 include(qmlapplicationviewer/qmlapplicationviewer.pri)
@@ -78,7 +81,10 @@ HEADERS += \
     fontconfigmanager.h \
     installedfontinfo.h \
     fontsconfigproperties.h \
-    fontconfigdefs.h
+    fontconfigdefs.h \
+    fontsconfelement.h \
+    fontsconf.h \
+    fontsconfeditorcontroller.h
 
 include(translations/translations.pri)
 
diff --git a/fontsconf.cpp b/fontsconf.cpp
new file mode 100644 (file)
index 0000000..29d3f67
--- /dev/null
@@ -0,0 +1,780 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Takumi Asaki
+** All rights reserved.
+** Contact: Takumi Asaki (takumi.asaki@gmail.com)
+**
+** This file is part of the fontmanager application.
+**
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+**   * Redistributions of source code must retain the above copyright
+**     notice, this list of conditions and the following disclaimer.
+**   * Redistributions in binary form must reproduce the above copyright
+**     notice, this list of conditions and the following disclaimer in
+**     the documentation and/or other materials provided with the
+**     distribution.
+**   * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+**     the names of its contributors may be used to endorse or promote
+**     products derived from this software without specific prior written
+**     permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+****************************************************************************/
+
+#include "fontsconf.h"
+
+#include "fontconfigdefs.h"
+#include "fontsconfelement.h"
+
+#include <QFile>
+#include <QXmlStreamReader>
+
+#include <QDebug>
+
+enum FCState {
+    Initialized, Ready, InvalidConfig, UnknownState
+};
+
+static inline QString boolString(bool val)
+{
+    return val ? TRUE_DEF : FALSE_DEF;
+}
+
+FontsConf::FontsConf(QObject *parent) :
+    QObject(parent), mModified(false), mHasUnknownConfig(false)
+{
+    initFontsConf();
+}
+
+bool FontsConf::isEmpty() const
+{
+    return !mElements || (mElements->count() == 0);
+}
+
+bool FontsConf::modified() const
+{
+    return mModified;
+}
+
+bool FontsConf::hasUnknownConfig() const
+{
+    return mHasUnknownConfig;
+}
+
+void FontsConf::initFontsConf()
+{
+    if (mElements)
+        mModified = true;
+    FontsConfElementPointer rootElem(new FontsConfElement(FONTCONFIG_DEF, this));
+    mElements = rootElem;
+}
+
+bool FontsConf::parse(const QByteArray &buf)
+{
+    if (buf.isEmpty())
+        return true;
+
+    QXmlStreamReader xml(buf);
+
+    FCState state = Initialized;
+
+    bool hasUnknownConfig = false;
+
+    FontsConfElementPointer elem;
+    while (!xml.atEnd()) {
+        QXmlStreamReader::TokenType token = xml.readNext();
+        if (token == QXmlStreamReader::DTD) {
+            if (xml.dtdName() != FONTCONFIG_DEF || xml.dtdSystemId() != "fonts.dtd") {
+                state = InvalidConfig;
+            }
+        } else if (token == QXmlStreamReader::StartElement) {
+            QString elemName(xml.name().toString());
+            switch (state) {
+            case Initialized:
+                if (elemName == FONTCONFIG_DEF) {
+                    state = Ready;
+                    elem = FontsConfElementPointer(new FontsConfElement(elemName, this));
+                    bool check = elem->parse(xml);
+                    if (!check)
+                        state = UnknownState;
+                } else
+                    state = InvalidConfig;
+                break;
+
+            default:
+                ;
+            }
+        } else if (token == QXmlStreamReader::EndElement) {
+            QString elemName(xml.name().toString());
+        }
+
+        if (state == InvalidConfig)
+            qDebug("Invalid Config!!!");
+
+        if (state == InvalidConfig)
+            break;
+        else if (state == UnknownState)
+            hasUnknownConfig = true;
+    }
+
+    if (xml.error() != QXmlStreamReader::NoError)
+        state = InvalidConfig;
+
+    if (state == Ready) {
+        mElements = elem;
+        mModified = false;
+        mHasUnknownConfig = hasUnknownConfig;
+    }
+
+    return !(state == InvalidConfig);
+}
+
+QStringList FontsConf::preferFamily() const
+{
+    if (!mElements)
+        return QStringList();
+
+    QStringList familyList;
+
+    int index = 0;
+    while ((index = mElements->indexOf(ALIAS_DEF, index)) >= 0) {
+        FontsConfElementPointer aliasElem = mElements->childElementAt(index++);
+        FontsConfElementPointer familyElem = aliasElem->childElementOf(FAMILY_DEF);
+        if (!familyElem || familyElem->text().isEmpty())
+            continue;
+        familyList << familyElem->text();
+    }
+    //    familyList.removeDuplicates();
+    return familyList;
+}
+
+QStringList FontsConf::aliasFamilyFor(const QString &family, const QString &mode) const
+{
+    int index = 0;
+    while ((index = mElements->indexOf(ALIAS_DEF, index)) >= 0) {
+        FontsConfElementPointer aliasElem = mElements->childElementAt(index++);
+        FontsConfElementPointer familyElem = aliasElem->childElementOf(FAMILY_DEF);
+        if (!familyElem)
+            continue;
+        if (familyElem->text() != family)
+            continue;
+        FontsConfElementPointer targetElem = aliasElem->childElementOf(mode);
+        if (!targetElem)
+            return QStringList();
+        QStringList familyList = textElementList(targetElem, FAMILY_DEF);
+        return familyList;
+    }
+
+    return QStringList();
+}
+
+void FontsConf::appendAliasFamilyFor(const QString &family, const QString &mode, const QString &value)
+{
+    int index = 0;
+    while ((index = mElements->indexOf(ALIAS_DEF, index)) >= 0) {
+        FontsConfElementPointer aliasElem = mElements->childElementAt(index++);
+        bool check = appendFamilyToAlias(aliasElem, family, mode, value);
+        if (check)
+            return;
+    }
+
+    FontsConfElementPointer aliasElem = aliasElementFor(family);
+    mElements->addChildElement(aliasElem);
+    bool check = appendFamilyToAlias(aliasElem, family, mode, value);
+    Q_ASSERT(check);
+}
+
+void FontsConf::removeAliasFamilyFor(const QString &family, const QString &mode, const QString &value)
+{
+    int index = 0;
+    while ((index = mElements->indexOf(ALIAS_DEF, index)) >= 0) {
+        FontsConfElementPointer aliasElem = mElements->childElementAt(index++);
+
+        FontsConfElementPointer familyElem = aliasElem->childElementOf(FAMILY_DEF);
+        if (!familyElem || familyElem->text() != family)
+            continue;
+
+        FontsConfElementPointer targetElem = aliasElem->childElementOf(mode);
+        if (!targetElem || targetElem->count() == 0)
+            continue;
+
+        int findex = 0;
+        while ((findex = targetElem->indexOf(FAMILY_DEF, findex)) >= 0) {
+            if (targetElem->childElementAt(findex)->text() == value) {
+                targetElem->removeAt(findex);
+                mModified = true;
+                continue;
+            }
+            findex++;
+        }
+
+        if (targetElem->count() == 0) {
+            aliasElem->removeOne(targetElem);
+            if (aliasElem->count() == 1) {
+                mElements->removeOne(aliasElem);
+            }
+        }
+    }
+}
+
+QStringList FontsConf::preferFamilyFor(const QString &family) const
+{
+    return aliasFamilyFor(family, PREFER_DEF);
+}
+
+void FontsConf::appendPreferFamilyFor(const QString &family, const QString &value)
+{
+    appendAliasFamilyFor(family, PREFER_DEF, value);
+}
+
+void FontsConf::removePreferFamilyFor(const QString &family, const QString &value)
+{
+    removeAliasFamilyFor(family, PREFER_DEF, value);
+}
+
+QStringList FontsConf::acceptFamilyFor(const QString &family) const
+{
+    return aliasFamilyFor(family, ACCEPT_DEF);
+}
+
+void FontsConf::appendAcceptFamilyFor(const QString &family, const QString &value)
+{
+    appendAliasFamilyFor(family, ACCEPT_DEF, value);
+}
+
+void FontsConf::removeAcceptFamilyFor(const QString &family, const QString &value)
+{
+    removeAliasFamilyFor(family, ACCEPT_DEF, value);
+}
+
+QStringList FontsConf::matchFamilyFor(const QString &config, bool val) const
+{
+    int index = 0;
+    while ((index = mElements->indexOf(MATCH_DEF, index)) >= 0) {
+        FontsConfElementPointer matchElem = mElements->childElementAt(index++);
+
+        bool check = isMatchElementFor(matchElem, config, QString(), boolString(val));
+        if (!check)
+            continue;
+
+        FontsConfElementPointer testElem = matchElem->childElementOf(TEST_DEF);
+        if (!testElem)
+            continue;
+
+        QStringList familyList = textElementList(testElem, STRING_DEF);
+        return familyList;
+    }
+
+    return QStringList();
+}
+
+QString FontsConf::matchEditValueFor(const QString &config, const QString &family) const
+{
+    int index = 0;
+    while ((index = mElements->indexOf(MATCH_DEF, index)) >= 0) {
+        FontsConfElementPointer matchElem = mElements->childElementAt(index++);
+
+        bool check = isMatchElementFor(matchElem, config, family);
+        if (!check)
+            continue;
+
+        FontsConfElementPointer editElem = matchElem->childElementOf(EDIT_DEF);
+        if (!editElem)
+            continue;
+
+        FontsConfElementPointer boolElem = editElem->childElementOf(BOOL_DEF);
+        if (!boolElem)
+            continue;
+
+        return boolElem->text();
+    }
+
+    return QString();
+}
+
+void FontsConf::setMatchEditValueFor(const QString &config, const QString &family, bool val)
+{
+    FontsConfElementPointer matchElem;
+    int index = 0;
+    while ((index = mElements->indexOf(MATCH_DEF, index)) >= 0) {
+        FontsConfElementPointer elem = mElements->childElementAt(index++);
+        bool check = isMatchElementFor(elem, config, QString(), boolString(val));
+        if (check) {
+            matchElem = elem;
+            break;
+        }
+    }
+
+    if (!matchElem) {
+        matchElem = matchElementFor(config, val);
+        mElements->addChildElement(matchElem);
+        mModified = true;
+    }
+
+    FontsConfElementPointer testElem = matchElem->childElementOf(TEST_DEF);
+    QStringList familyList = textElementList(testElem, STRING_DEF);
+    if (familyList.contains(family))
+        return;
+
+    FontsConfElementPointer stringElem(new FontsConfElement(STRING_DEF));
+    stringElem->setText(family);
+    testElem->addChildElement(stringElem);
+    mModified = true;
+}
+
+void FontsConf::unsetMatchEditValueFor(const QString &config, const QString &family)
+{
+    int index = 0;
+    while ((index = mElements->indexOf(MATCH_DEF, index)) >= 0) {
+        FontsConfElementPointer matchElem = mElements->childElementAt(index++);
+
+        bool check = isMatchElementFor(matchElem, config, family);
+        if (!check)
+            continue;
+
+        FontsConfElementPointer testElem = matchElem->childElementOf(TEST_DEF);
+        int sindex = 0;
+        while ((sindex = testElem->indexOf(STRING_DEF, sindex)) >= 0) {
+            FontsConfElementPointer stringElem = testElem->childElementAt(sindex++);
+            if (stringElem->text() == family) {
+                testElem->removeAt(--sindex);
+                mModified = true;
+            }
+        }
+
+        if (testElem->count() == 0) {
+            mElements->removeAt(--index);
+        }
+
+    }
+}
+
+QStringList FontsConf::patternFamilyFor(const QString &family, const QString &mode) const
+{
+    int index = 0;
+    while ((index = mElements->indexOf(MATCH_DEF, index)) >= 0) {
+        FontsConfElementPointer matchElem = mElements->childElementAt(index++);
+        bool check = isPatternElementFor(matchElem, family, mode);
+        if (!check)
+            continue;
+        FontsConfElementPointer editElem = getEditPatternElementFor(matchElem, family, mode);
+        return textElementList(editElem, STRING_DEF);
+    }
+    return QStringList();
+}
+
+void FontsConf::appendPatternFamilyFor(const QString &family, const QString &mode, const QString &value)
+{
+    FontsConfElementPointer matchElem;
+
+    int index = 0;
+    while ((index = mElements->indexOf(MATCH_DEF, index)) >= 0) {
+        FontsConfElementPointer elem = mElements->childElementAt(index++);
+        bool check = isPatternElementFor(elem, family, mode);
+        if (check) {
+            matchElem = elem;
+            break;
+        }
+    }
+
+    if (!matchElem) {
+        int index = 0;
+        while ((index = mElements->indexOf(MATCH_DEF, index)) >= 0) {
+            FontsConfElementPointer elem = mElements->childElementAt(index++);
+            bool check = isPatternElementFor(elem, family);
+            if (check) {
+                matchElem = elem;
+                break;
+            }
+        }
+    }
+
+    if (!matchElem) {
+        matchElem = patternElementFor(family);
+        mElements->addChildElement(matchElem);
+        mModified = true;
+    }
+
+    FontsConfElementPointer editElem = getEditPatternElementFor(matchElem, family, mode);
+    if (!editElem) {
+        editElem = FontsConfElementPointer(new FontsConfElement(EDIT_DEF));
+        editElem->setAttribute(NAME_DEF, FAMILY_DEF);
+        editElem->setAttribute(MODE_DEF, mode);
+        editElem->setAttribute(BINDING_DEF, STRONG_DEF);
+        matchElem->addChildElement(editElem);
+        mModified = true;
+    }
+
+    QStringList familyList = textElementList(editElem, STRING_DEF);
+    if (familyList.contains(value))
+        return;
+
+    FontsConfElementPointer stringElem(new FontsConfElement(STRING_DEF));
+    stringElem->setText(value);
+    editElem->addChildElement(stringElem);
+    mModified = true;
+}
+
+void FontsConf::removePatternFamilyFor(const QString &family, const QString &mode, const QString &value)
+{
+    FontsConfElementPointer matchElem;
+
+    int index = 0;
+    while ((index = mElements->indexOf(MATCH_DEF, index)) >= 0) {
+        FontsConfElementPointer elem = mElements->childElementAt(index++);
+        bool check = isPatternElementFor(elem, family, mode);
+        if (check) {
+            matchElem = elem;
+            break;
+        }
+    }
+
+    if (!matchElem)
+        return;
+
+    FontsConfElementPointer editElem = getEditPatternElementFor(matchElem, family, mode);
+    if (!editElem)
+        return;
+
+    int sindex = 0;
+    while ((sindex = editElem->indexOf(STRING_DEF, sindex)) >= 0) {
+        FontsConfElementPointer stringElem = editElem->childElementAt(sindex++);
+        if (stringElem->text() == value) {
+            editElem->removeAt(--sindex);
+            mModified = true;
+        }
+    }
+
+    if (editElem->count() == 0) {
+        mModified = true;
+        matchElem->removeOne(editElem);
+        FontsConfElementList editElemList = matchElem->findChildrenElements(EDIT_DEF);
+        if (editElemList.isEmpty())
+            mElements->removeOne(matchElem);
+    }
+
+}
+
+QStringList FontsConf::prependFamilyFor(const QString &family) const
+{
+    return patternFamilyFor(family, PREPEND_DEF);
+}
+
+void FontsConf::appendPrependFamilyFor(const QString &family, const QString &value)
+{
+    appendPatternFamilyFor(family, PREPEND_DEF, value);
+}
+
+void FontsConf::removePrependFamilyFor(const QString &family, const QString &value)
+{
+    removePatternFamilyFor(family, PREPEND_DEF, value);
+}
+
+QStringList FontsConf::appendFamilyFor(const QString &family) const
+{
+    return patternFamilyFor(family, APPEND_DEF);
+}
+
+void FontsConf::appendAppendFamilyFor(const QString &family, const QString &value)
+{
+    appendPatternFamilyFor(family, APPEND_DEF, value);
+}
+
+void FontsConf::removeAppendFamilyFor(const QString &family, const QString &value)
+{
+    removePatternFamilyFor(family, APPEND_DEF, value);
+}
+
+QStringList FontsConf::genericFamilies()
+{
+    static QStringList families;
+    if (families.isEmpty())
+        families << SANSSERIF_DEF << SERIF_DEF << MONOSPACE_DEF;
+    return families;
+}
+
+QStringList FontsConf::configKeys()
+{
+    static QStringList keys;
+    if (keys.isEmpty())
+        keys << EMBEDDEDBITMAP_DEF << HINTING_DEF << ANTIALIAS_DEF << AUTOHINT_DEF;
+    return keys;
+}
+
+void FontsConf::load(const QString &path)
+{
+    QFile fp(path);
+    if (!fp.exists())
+        return;
+
+    fp.open(QIODevice::ReadOnly);
+    if (!fp.isOpen() || fp.error() != QFile::NoError)
+        return;
+
+    QByteArray buf = fp.readAll();
+
+    fp.close();
+
+    bool check = parse(buf);
+    Q_UNUSED(check);
+
+}
+
+void FontsConf::save(const QString &path)
+{
+#if 0
+    if (!mElements && fp.exists()) {
+        fp.remove();
+        return;
+    }
+#endif
+
+    QString buf;
+    QXmlStreamWriter xml(&buf);
+
+    xml.setAutoFormatting(true);
+
+    xml.writeStartDocument();
+
+    xml.writeDTD("<!DOCTYPE fontconfig SYSTEM 'fonts.dtd'>");
+
+    if (mElements)
+        mElements->save(xml);
+
+    xml.writeEndDocument();
+
+    QFile fp(path);
+    fp.open(QIODevice::WriteOnly);
+    if (!fp.isOpen())
+        return;
+
+    QTextStream ts(&fp);
+    ts.setCodec("UTF-8");
+    ts << buf;
+
+    mModified = false;
+
+    fp.close();
+}
+
+bool FontsConf::appendFamilyToAlias(FontsConfElementPointer aliasElem, const QString &family, const QString &mode, const QString &value)
+{
+    if (aliasElem->type() != ALIAS_DEF)
+        return false;
+
+    FontsConfElementPointer familyElem = aliasElem->childElementOf(FAMILY_DEF);
+    if (!familyElem || familyElem->text() != family)
+        return false;
+
+    FontsConfElementPointer targetElem = aliasElem->childElementOf(mode);
+    if (!targetElem) {
+        targetElem = FontsConfElementPointer(new FontsConfElement(mode));
+        aliasElem->addChildElement(targetElem);
+        mModified = true;
+    }
+
+    int findex = 0;
+    while ((findex = targetElem->indexOf(FAMILY_DEF, findex)) >= 0) {
+        if (targetElem->childElementAt(findex)->text() == value)
+            return true;
+        findex++;
+    }
+
+    FontsConfElementPointer valueElem(new FontsConfElement(FAMILY_DEF));
+    valueElem->setText(value);
+    targetElem->addChildElement(valueElem);
+    mModified = true;
+
+    return true;
+}
+
+bool FontsConf::isMatchElementFor(FontsConfElementPointer matchElem, const QString &config, const QString &family, const QString &val) const
+{
+    if (!matchElem->hasAttribute(TARGET_DEF) || matchElem->value(TARGET_DEF) != FONT_DEF)
+        return false;
+
+    FontsConfElementList testElemList = matchElem->findChildrenElements(TEST_DEF);
+    if (testElemList.count() != 1)
+        return false;
+
+    FontsConfElementPointer testElem = testElemList.at(0);
+    if (!testElem->hasAttribute(NAME_DEF) || testElem->value(NAME_DEF) != FAMILY_DEF)
+        return false;
+    if ((testElem->hasAttribute(QUAL_DEF) && testElem->value(QUAL_DEF) != ANY_DEF) ||
+            (testElem->hasAttribute(COMPARE_DEF) && testElem->value(COMPARE_DEF) != EQ_DEF) ||
+            (testElem->hasAttribute(TARGET_DEF) && testElem->value(TARGET_DEF) != DEFAULT_DEF))
+        return false;
+
+    if (!family.isEmpty()) {
+        if (testElem->count() == 0 && testElem->text() != family)
+            return false;
+        QStringList familyList = textElementList(testElem, STRING_DEF);
+        if (!familyList.contains(family))
+            return false;
+    }
+
+    FontsConfElementList editElemList = matchElem->findChildrenElements(EDIT_DEF);
+    if (editElemList.count() != 1)
+        return false;
+
+    FontsConfElementPointer editElem = editElemList.at(0);
+    if ((!editElem->hasAttribute(NAME_DEF) || editElem->value(NAME_DEF) != config) ||
+            (editElem->hasAttribute(MODE_DEF) && editElem->value(MODE_DEF) != ASSIGN_DEF))
+        return false;
+
+    FontsConfElementList boolElemList = editElem->findChildrenElements(BOOL_DEF);
+    if (boolElemList.count() != 1) {
+        return false;
+    }
+
+    if (!val.isEmpty()) {
+        FontsConfElementPointer boolElem = boolElemList.at(0);
+        if (boolElem->text() != val)
+            return false;
+    }
+
+    return true;
+}
+
+bool FontsConf::isPatternElementFor(FontsConfElementPointer matchElem, const QString &family, const QString &mode) const
+{
+    if (matchElem->hasAttribute(TARGET_DEF) && matchElem->value(TARGET_DEF) != PATTERN_DEF)
+        return false;
+
+    FontsConfElementList testElemList = matchElem->findChildrenElements(TEST_DEF);
+    if (testElemList.count() != 1)
+        return false;
+
+    FontsConfElementPointer testElem = testElemList.at(0);
+    if (testElem->hasAttribute(NAME_DEF) && testElem->value(NAME_DEF) != FAMILY_DEF)
+        return false;
+    if ((testElem->hasAttribute(COMPARE_DEF) && testElem->value(COMPARE_DEF) != EQ_DEF) ||
+            (testElem->hasAttribute(TARGET_DEF) && testElem->value(TARGET_DEF) != DEFAULT_DEF))
+        return false;
+
+    if (testElem->count() == 0) {
+        if (testElem->text().isEmpty() || testElem->text() != family)
+            return false;
+    } else {
+        QStringList familyList = textElementList(testElem, STRING_DEF);
+        if (familyList.count() != 1 || !familyList.contains(family))
+            return false;
+    }
+
+    if (mode.isEmpty())
+        return true;
+
+    int eindex = 0;
+    while ((eindex = matchElem->indexOf(EDIT_DEF, eindex)) >= 0) {
+        FontsConfElementPointer editElem = matchElem->childElementAt(eindex++);
+
+        if ((editElem->hasAttribute(NAME_DEF) && editElem->value(NAME_DEF) == FAMILY_DEF) &&
+                (editElem->hasAttribute(MODE_DEF) && editElem->value(MODE_DEF) == mode))
+            return true;
+
+    }
+
+    return false;
+}
+
+FontsConfElementPointer FontsConf::getEditPatternElementFor(FontsConfElementPointer matchElem, const QString &family, const QString &mode) const
+{
+    Q_UNUSED(family);
+    int eindex = 0;
+    while ((eindex = matchElem->indexOf(EDIT_DEF, eindex)) >= 0) {
+        FontsConfElementPointer editElem = matchElem->childElementAt(eindex++);
+
+        if ((editElem->hasAttribute(NAME_DEF) && editElem->value(NAME_DEF) == FAMILY_DEF) &&
+                (editElem->hasAttribute(MODE_DEF) && editElem->value(MODE_DEF) == mode))
+            return editElem;
+    }
+    return FontsConfElementPointer();
+}
+
+bool FontsConf::containsTextElement(FontsConfElementPointer elem, const QString &tag, const QString &text) const
+{
+    int index = 0;
+    while ((index = elem->indexOf(tag, index)) >= 0) {
+        FontsConfElementPointer e = elem->childElementAt(index++);
+        if (e->text() == text)
+            return true;
+    }
+    return false;
+}
+
+QStringList FontsConf::textElementList(FontsConfElementPointer elem, const QString &tag) const
+{
+    if (!elem)
+        return QStringList();
+    QStringList list;
+    int index = 0;
+    while ((index = elem->indexOf(tag, index)) >= 0) {
+        FontsConfElementPointer e = elem->childElementAt(index++);
+        if (!e->text().isEmpty())
+            list << e->text();
+    }
+    return list;
+}
+
+FontsConfElementPointer FontsConf::aliasElementFor(const QString &family) const
+{
+    FontsConfElementPointer aliasElem(new FontsConfElement(ALIAS_DEF));
+    FontsConfElementPointer familyElem(new FontsConfElement(FAMILY_DEF));
+    familyElem->setText(family);
+    aliasElem->addChildElement(familyElem);
+    return aliasElem;
+}
+
+FontsConfElementPointer FontsConf::matchElementFor(const QString &config, bool val) const
+{
+    FontsConfElementPointer matchElem = FontsConfElementPointer(new FontsConfElement(MATCH_DEF));
+    matchElem->setAttribute(TARGET_DEF, FONT_DEF);
+
+    FontsConfElementPointer testElem(new FontsConfElement(TEST_DEF));
+    testElem->setAttribute(QUAL_DEF, ANY_DEF);
+    testElem->setAttribute(NAME_DEF, FAMILY_DEF);
+    matchElem->addChildElement(testElem);
+
+    FontsConfElementPointer editElem(new FontsConfElement(EDIT_DEF));
+    editElem->setAttribute(NAME_DEF, config);
+    editElem->setAttribute(MODE_DEF, ASSIGN_DEF);
+    matchElem->addChildElement(editElem);
+
+    FontsConfElementPointer boolElem(new FontsConfElement(BOOL_DEF));
+    boolElem->setText(boolString(val));
+    editElem->addChildElement(boolElem);
+
+    return matchElem;
+}
+
+FontsConfElementPointer FontsConf::patternElementFor(const QString &family) const
+{
+    FontsConfElementPointer matchElem = FontsConfElementPointer(new FontsConfElement(MATCH_DEF));
+    matchElem->setAttribute(TARGET_DEF, PATTERN_DEF);
+
+    FontsConfElementPointer testElem(new FontsConfElement(TEST_DEF));
+    testElem->setAttribute(QUAL_DEF, ANY_DEF);
+    testElem->setAttribute(NAME_DEF, FAMILY_DEF);
+    matchElem->addChildElement(testElem);
+
+    FontsConfElementPointer stringElem(new FontsConfElement(STRING_DEF));
+    stringElem->setText(family);
+    testElem->addChildElement(stringElem);
+
+    return matchElem;
+}
diff --git a/fontsconf.h b/fontsconf.h
new file mode 100644 (file)
index 0000000..4bb9358
--- /dev/null
@@ -0,0 +1,120 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Takumi Asaki
+** All rights reserved.
+** Contact: Takumi Asaki (takumi.asaki@gmail.com)
+**
+** This file is part of the fontmanager application.
+**
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+**   * Redistributions of source code must retain the above copyright
+**     notice, this list of conditions and the following disclaimer.
+**   * Redistributions in binary form must reproduce the above copyright
+**     notice, this list of conditions and the following disclaimer in
+**     the documentation and/or other materials provided with the
+**     distribution.
+**   * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+**     the names of its contributors may be used to endorse or promote
+**     products derived from this software without specific prior written
+**     permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+****************************************************************************/
+
+#ifndef FONTSCONF_H
+#define FONTSCONF_H
+
+#include <QObject>
+#include <QStringList>
+
+#include "fontsconfelement.h"
+
+class FontsConf : public QObject
+{
+    Q_OBJECT
+public:
+    explicit FontsConf(QObject *parent = 0);
+
+    bool isEmpty() const;
+    bool modified() const;
+    bool hasUnknownConfig() const;
+
+    void initFontsConf();
+
+    bool parse(const QByteArray &buf);
+
+    QStringList preferFamily() const;
+
+    QStringList aliasFamilyFor(const QString &family, const QString &mode) const;
+    void appendAliasFamilyFor(const QString &family, const QString &mode, const QString &value);
+    void removeAliasFamilyFor(const QString &family, const QString &mode, const QString &value);
+
+    QStringList preferFamilyFor(const QString &family) const;
+    void appendPreferFamilyFor(const QString &family, const QString &value);
+    void removePreferFamilyFor(const QString &family, const QString &value);
+
+    QStringList acceptFamilyFor(const QString &family) const;
+    void appendAcceptFamilyFor(const QString &family, const QString &value);
+    void removeAcceptFamilyFor(const QString &family, const QString &value);
+
+    QStringList matchFamilyFor(const QString &config, bool val) const;
+    QString matchEditValueFor(const QString &config, const QString &family) const;
+    void setMatchEditValueFor(const QString &config, const QString &family, bool val);
+    void unsetMatchEditValueFor(const QString &config, const QString &family);
+
+    QStringList patternFamilyFor(const QString &family, const QString &mode) const;
+    void appendPatternFamilyFor(const QString &family, const QString &mode, const QString &value);
+    void removePatternFamilyFor(const QString &family, const QString &mode, const QString &value);
+
+    QStringList prependFamilyFor(const QString &family) const;
+    void appendPrependFamilyFor(const QString &family, const QString &value);
+    void removePrependFamilyFor(const QString &family, const QString &value);
+
+    QStringList appendFamilyFor(const QString &family) const;
+    void appendAppendFamilyFor(const QString &family, const QString &value);
+    void removeAppendFamilyFor(const QString &family, const QString &value);
+
+    static QStringList genericFamilies();
+    static QStringList configKeys();
+
+private:
+    FontsConfElementPointer aliasElementFor(const QString &family) const;
+    FontsConfElementPointer matchElementFor(const QString &config, bool val) const;
+    FontsConfElementPointer patternElementFor(const QString &family) const;
+
+    bool appendFamilyToAlias(FontsConfElementPointer aliasElem, const QString &family, const QString &mode, const QString &value);
+    bool isMatchElementFor(FontsConfElementPointer matchElem, const QString &config, const QString &family, const QString &val = QString()) const;
+    bool isPatternElementFor(FontsConfElementPointer matchElem, const QString &family, const QString &mode = QString()) const;
+    FontsConfElementPointer getEditPatternElementFor(FontsConfElementPointer matchElem, const QString &family, const QString &mode = QString()) const;
+
+    bool containsTextElement(FontsConfElementPointer elem, const QString &tag, const QString &text) const;
+    QStringList textElementList(FontsConfElementPointer elem, const QString &tag) const;
+
+signals:
+    
+public slots:
+    void load(const QString &path);
+    void save(const QString &path);
+    
+private:
+    bool mModified;
+    bool mHasUnknownConfig;
+    FontsConfElementPointer mElements;
+};
+
+#endif // FONTSCONF_H
diff --git a/fontsconfeditorcontroller.cpp b/fontsconfeditorcontroller.cpp
new file mode 100644 (file)
index 0000000..67b3a95
--- /dev/null
@@ -0,0 +1,120 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Takumi Asaki
+** All rights reserved.
+** Contact: Takumi Asaki (takumi.asaki@gmail.com)
+**
+** This file is part of the fontmanager application.
+**
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+**   * Redistributions of source code must retain the above copyright
+**     notice, this list of conditions and the following disclaimer.
+**   * Redistributions in binary form must reproduce the above copyright
+**     notice, this list of conditions and the following disclaimer in
+**     the documentation and/or other materials provided with the
+**     distribution.
+**   * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+**     the names of its contributors may be used to endorse or promote
+**     products derived from this software without specific prior written
+**     permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+****************************************************************************/
+
+#include "fontsconfeditorcontroller.h"
+
+#include "fontconfigdefs.h"
+#include "installedfontinfo.h"
+
+FontsConfEditorController::FontsConfEditorController(const QString &family, QObject *parent) :
+    QObject(parent), mFamily(family)
+{
+}
+
+int FontsConfEditorController::count() const
+{
+    return mPrependFamily.count() + mPreferFamily.count() + mAcceptFamily.count();
+}
+
+void FontsConfEditorController::syncFamilyList()
+{
+    // TODO:
+    emit clearFamilyList();
+    emit startSection(PREPEND_DEF, tr("High"));
+    foreach (const QString &f, mPrependFamily) {
+        InstalledFontInfo *info = mFontInfoMap.value(f);
+        bool systemFont = info ? info->systemFont() : true;
+        emit appendFamilyToList(mFamily, f, PREPEND_DEF, systemFont);
+    }
+    emit startSection(PREFER_DEF, tr("Normal"));
+    foreach (const QString &f, mPreferFamily) {
+        InstalledFontInfo *info = mFontInfoMap.value(f);
+        bool systemFont = info ? info->systemFont() : true;
+        emit appendFamilyToList(mFamily, f, PREFER_DEF, systemFont);
+    }
+    emit startSection(ACCEPT_DEF, tr("Low"));
+    foreach (const QString &f, mAcceptFamily) {
+        InstalledFontInfo *info = mFontInfoMap.value(f);
+        bool systemFont = info ? info->systemFont() : true;
+        emit appendFamilyToList(mFamily, f, ACCEPT_DEF, systemFont);
+    }
+}
+
+void FontsConfEditorController::appendFontsInfo(const QString &family, const QString &priority, InstalledFontInfo *info)
+{
+    mFontInfoMap.insert(family, info);
+    if (priority == PREPEND_DEF)
+        mPrependFamily.append(family);
+    else if (priority == PREFER_DEF)
+        mPreferFamily.append(family);
+    else if (priority == ACCEPT_DEF)
+        mAcceptFamily.append(family);
+    emit countChanged();
+}
+
+void FontsConfEditorController::appendFamily(const QString &family, const QString &priority)
+{
+    emit appendFamilyToConfig(mFamily, family, priority);
+}
+
+void FontsConfEditorController::removeFamily(const QString &family, const QString &priority)
+{
+    if (priority.isEmpty() || priority == PREPEND_DEF) {
+        mPrependFamily.removeOne(family);
+        emit removeFamilyFromList(mFamily, family, PREPEND_DEF);
+    }
+    if (priority.isEmpty() || priority == PREFER_DEF) {
+        mPreferFamily.removeOne(family);
+        emit removeFamilyFromList(mFamily, family, PREFER_DEF);
+    }
+    if (priority.isEmpty() || priority == ACCEPT_DEF) {
+        mAcceptFamily.removeOne(family);
+        emit removeFamilyFromList(mFamily, family, ACCEPT_DEF);
+    }
+    if (!mPrependFamily.contains(family) && !mPreferFamily.contains(family) && !mAcceptFamily.contains(family))
+        mFontInfoMap.remove(family);
+}
+
+void FontsConfEditorController::clear()
+{
+    mFontInfoMap.clear();
+    mPrependFamily.clear();
+    mPreferFamily.clear();
+    mAcceptFamily.clear();
+    emit clearFamilyList();
+}
diff --git a/fontsconfeditorcontroller.h b/fontsconfeditorcontroller.h
new file mode 100644 (file)
index 0000000..f411f30
--- /dev/null
@@ -0,0 +1,84 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Takumi Asaki
+** All rights reserved.
+** Contact: Takumi Asaki (takumi.asaki@gmail.com)
+**
+** This file is part of the fontmanager application.
+**
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+**   * Redistributions of source code must retain the above copyright
+**     notice, this list of conditions and the following disclaimer.
+**   * Redistributions in binary form must reproduce the above copyright
+**     notice, this list of conditions and the following disclaimer in
+**     the documentation and/or other materials provided with the
+**     distribution.
+**   * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+**     the names of its contributors may be used to endorse or promote
+**     products derived from this software without specific prior written
+**     permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+****************************************************************************/
+
+#ifndef FONTSCONFEDITORCONTROLLER_H
+#define FONTSCONFEDITORCONTROLLER_H
+
+#include <QObject>
+#include <QStringList>
+#include <QMap>
+
+class InstalledFontInfo;
+
+class FontsConfEditorController : public QObject
+{
+    Q_OBJECT
+    Q_PROPERTY(int count READ count NOTIFY countChanged)
+public:
+    explicit FontsConfEditorController(const QString &family, QObject *parent = 0);
+    
+    int count() const;
+
+signals:
+    void clearFamilyList();
+    void startSection(const QString &section, const QString &sectionName);
+    void appendFamilyToList(const QString &section, const QString &family, const QString &priority, bool systemFont);
+    void removeFamilyFromList(const QString &section, const QString &family, const QString &priority);
+
+    void countChanged();
+
+    void appendFamilyToConfig(const QString &family, const QString &value, const QString &priority);
+
+public slots:
+    void clear();
+    void syncFamilyList();
+
+    void appendFontsInfo(const QString &family, const QString &priority, InstalledFontInfo *info);
+    void appendFamily(const QString &family, const QString &priority);
+    void removeFamily(const QString &family, const QString &priority);
+
+private:
+    QString mFamily;
+
+    QStringList mPrependFamily;
+    QStringList mPreferFamily;
+    QStringList mAcceptFamily;
+    QMap<QString, InstalledFontInfo*> mFontInfoMap;
+};
+
+#endif // FONTSCONFEDITORCONTROLLER_H
diff --git a/fontsconfelement.cpp b/fontsconfelement.cpp
new file mode 100644 (file)
index 0000000..cbfb01a
--- /dev/null
@@ -0,0 +1,243 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Takumi Asaki
+** All rights reserved.
+** Contact: Takumi Asaki (takumi.asaki@gmail.com)
+**
+** This file is part of the fontmanager application.
+**
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+**   * Redistributions of source code must retain the above copyright
+**     notice, this list of conditions and the following disclaimer.
+**   * Redistributions in binary form must reproduce the above copyright
+**     notice, this list of conditions and the following disclaimer in
+**     the documentation and/or other materials provided with the
+**     distribution.
+**   * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+**     the names of its contributors may be used to endorse or promote
+**     products derived from this software without specific prior written
+**     permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+****************************************************************************/
+
+#include "fontsconfelement.h"
+
+#include "fontconfigdefs.h"
+
+#include <QXmlStreamReader>
+
+FontsConfElement::FontsConfElement(const QString &type, QObject *parent) :
+    QObject(parent), mType(type)
+{
+}
+
+QString FontsConfElement::type() const
+{
+    return mType;
+}
+
+void FontsConfElement::clear()
+{
+    mAttributes.clear();
+    mChildElements.clear();
+}
+
+bool FontsConfElement::parse(QXmlStreamReader &xml)
+{
+    if (xml.atEnd() || xml.error() != QXmlStreamReader::NoError)
+        return false;
+
+    bool check = true;
+    if (!xml.isStartElement()) {
+        check = xml.readNextStartElement();
+        if (!check)
+            return false;
+    }
+
+    mAttributes = xml.attributes();
+
+    while (!xml.atEnd()) {
+        QXmlStreamReader::TokenType t = xml.readNext();
+        if (t == QXmlStreamReader::Characters) {
+            mText = xml.text().toString();
+        } else if (t == QXmlStreamReader::StartElement) {
+            FontsConfElementPointer elem(new FontsConfElement(xml.name().toString(), this));
+            check = elem->parse(xml);
+            if (!check)
+                return false;
+            addChildElement(elem);
+        } else if (t == QXmlStreamReader::EndElement)
+            return true;
+    }
+
+    return false;
+}
+
+void FontsConfElement::save(QXmlStreamWriter &xml)
+{
+    if (mChildElements.count() == 0) {
+        if (!mText.isEmpty())
+            xml.writeTextElement(mType, mText);
+        else
+            xml.writeEmptyElement(mType);
+        xml.writeAttributes(mAttributes);
+    } else {
+        xml.writeStartElement(mType);
+        xml.writeAttributes(mAttributes);
+        if (!mText.isEmpty())
+            xml.writeCharacters(mText);
+        foreach (FontsConfElementPointer elem, mChildElements) {
+            elem->save(xml);
+        }
+        xml.writeEndElement();
+    }
+}
+
+QXmlStreamAttributes FontsConfElement::attributes() const
+{
+    return mAttributes;
+}
+
+bool FontsConfElement::hasAttribute(const QString &key) const
+{
+    return mAttributes.hasAttribute(key);
+}
+
+QString FontsConfElement::value(const QString &key) const
+{
+    return mAttributes.value(key).toString();
+}
+
+void FontsConfElement::setAttribute(const QString &key, const QString &val)
+{
+    mAttributes.append(key, val);
+}
+
+int FontsConfElement::count() const
+{
+    return mChildElements.count();
+}
+
+FontsConfElementPointer FontsConfElement::childElementAt(int index) const
+{
+    return mChildElements.at(index);
+}
+
+FontsConfElementList FontsConfElement::findChildrenElements(const QString &type) const
+{
+    FontsConfElementList list;
+    foreach (FontsConfElementPointer elem, mChildElements) {
+        if (elem->type() == type)
+            list << elem;
+    }
+    return list;
+}
+
+int FontsConfElement::indexOf(const QString &type, int from) const
+{
+    if (from < 0 || from >= mChildElements.count())
+        return -1;
+
+    int index = from;
+    while (index < mChildElements.count()) {
+        if (mChildElements.at(index)->type() == type)
+            return index;
+        index++;
+    }
+    return -1;
+}
+
+FontsConfElementPointer FontsConfElement::childElementOf(const QString &type, int from) const
+{
+    int index = indexOf(type, from);
+    if (index < 0)
+        return FontsConfElementPointer();
+    return childElementAt(index);
+}
+
+void FontsConfElement::addChildElement(FontsConfElementPointer elem)
+{
+    if (!elem || mChildElements.contains(elem))
+        return;
+    elem->setParent(this);
+    mChildElements.append(elem);
+}
+
+void FontsConfElement::removeAt(int index)
+{
+    mChildElements.removeAt(index);
+}
+
+void FontsConfElement::removeOne(FontsConfElementPointer elem)
+{
+    mChildElements.removeOne(elem);
+}
+
+QString FontsConfElement::text() const
+{
+    return mText;
+}
+
+void FontsConfElement::setText(const QString &str)
+{
+    mText = str;
+}
+
+QString FontsConfElement::readAttribute(QXmlStreamReader &xml, const QString &attr, const QString &defaultValue)
+{
+    if (xml.attributes().hasAttribute(attr))
+        return xml.attributes().value(attr).toString();
+    return defaultValue;
+}
+
+QVariant FontsConfElement::readValue(QXmlStreamReader &xml)
+{
+
+    bool check = false;
+    if (xml.isStartElement())
+        check = true;
+    else
+        check = xml.readNextStartElement();
+    if (!check)
+        return QVariant();
+    QString elemName(xml.name().toString());
+    if (elemName != BOOL_DEF || elemName != STRING_DEF || elemName != INT_DEF || elemName != DOUBLE_DEF) {
+        return QVariant();
+    }
+
+    QVariant value;
+    QXmlStreamReader::TokenType t = xml.tokenType();
+    while (t != QXmlStreamReader::Characters || t != QXmlStreamReader::EndElement)
+        t = xml.readNext();
+    if (t != QXmlStreamReader::Characters)
+        return value;
+    QString str = xml.text().toString();
+    if (elemName == BOOL_DEF) {
+        value = (str == TRUE_DEF);
+    } else if (elemName == STRING_DEF) {
+        value = str;
+    } else if (elemName == INT_DEF) {
+        value = str.toInt(&check);
+    } else if (elemName == DOUBLE_DEF) {
+        value = str.toDouble(&check);
+    }
+    if (!check)
+        return QVariant();
+    return value;
+}
diff --git a/fontsconfelement.h b/fontsconfelement.h
new file mode 100644 (file)
index 0000000..16fffe6
--- /dev/null
@@ -0,0 +1,106 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Takumi Asaki
+** All rights reserved.
+** Contact: Takumi Asaki (takumi.asaki@gmail.com)
+**
+** This file is part of the fontmanager application.
+**
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+**   * Redistributions of source code must retain the above copyright
+**     notice, this list of conditions and the following disclaimer.
+**   * Redistributions in binary form must reproduce the above copyright
+**     notice, this list of conditions and the following disclaimer in
+**     the documentation and/or other materials provided with the
+**     distribution.
+**   * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+**     the names of its contributors may be used to endorse or promote
+**     products derived from this software without specific prior written
+**     permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+****************************************************************************/
+
+#ifndef FONTSCONFELEMENT_H
+#define FONTSCONFELEMENT_H
+
+#include <QObject>
+
+#include <QVariant>
+#include <QSharedPointer>
+
+#include <QXmlStreamAttributes>
+#include <QList>
+
+class QXmlStreamReader;
+class QXmlStreamWriter;
+
+class FontsConfElement;
+
+typedef QSharedPointer<FontsConfElement> FontsConfElementPointer;
+typedef QList<FontsConfElementPointer> FontsConfElementList;
+
+class FontsConfElement : public QObject
+{
+    Q_OBJECT
+    Q_ENUMS(Type)
+    Q_PROPERTY(QString type READ type NOTIFY typeChanged)
+public:
+
+    explicit FontsConfElement(const QString &type, QObject *parent = 0);
+    
+    QString type() const;
+
+    virtual void clear();
+    virtual bool parse(QXmlStreamReader &xml);
+    virtual void save(QXmlStreamWriter &xml);
+
+    QXmlStreamAttributes attributes() const;
+    bool hasAttribute(const QString &key) const;
+    QString value(const QString &key) const;
+    void setAttribute(const QString &key, const QString &val);
+
+    int count() const;
+    FontsConfElementPointer childElementAt(int index) const;
+    FontsConfElementList findChildrenElements(const QString &type) const;
+    int indexOf(const QString &type, int from = 0) const;
+    FontsConfElementPointer childElementOf(const QString &type, int from = 0) const;
+    void addChildElement(FontsConfElementPointer elem);
+    void removeAt(int index);
+    void removeOne(FontsConfElementPointer elem);
+
+    QString text() const;
+    void setText(const QString &str);
+
+    static QString readAttribute(QXmlStreamReader &xml, const QString &attr, const QString &defaultValue = QString());
+    static QVariant readValue(QXmlStreamReader &xml);
+
+signals:
+    void typeChanged();
+    
+public slots:
+    
+protected:
+    bool mModified;
+    QString mType;
+    QXmlStreamAttributes mAttributes;
+    FontsConfElementList mChildElements;
+    QString mText;
+};
+
+#endif // FONTSCONFELEMENT_H
index 9861b73..f72a4b6 100644 (file)
@@ -130,14 +130,6 @@ void FontsConfigProperties::setAutohint(FontsConfigProperties::ConfigValue confi
     setConfigValue(AUTOHINT_DEF, config);
 }
 
-QStringList FontsConfigProperties::configKeys()
-{
-    static QStringList keys;
-    if (keys.isEmpty())
-        keys << EMBEDDEDBITMAP_DEF << HINTING_DEF << ANTIALIAS_DEF << AUTOHINT_DEF;
-    return keys;
-}
-
 void FontsConfigProperties::checkConfigValueChanged(const QString &key)
 {
     if (key == EMBEDDEDBITMAP_DEF)
index 97bca61..8ff641d 100644 (file)
@@ -82,7 +82,6 @@ public:
     ConfigValue autohint() const;
     void setAutohint(ConfigValue config);
 
-    static QStringList configKeys();
 signals:
     void preferFamiliesChanged();
 
index 9a50da0..91cc7c4 100644 (file)
--- a/main.cpp
+++ b/main.cpp
 #include <qdeclarative.h>
 #include <QDeclarativeContext>
 
+#include <QDir>
 #include <QLocale>
 #include <QTranslator>
 
 #include "fontinfo.h"
 #include "installedfontinfo.h"
 #include "fontsconfigproperties.h"
+#include "fontsconfeditorcontroller.h"
 
 Q_DECL_EXPORT int main(int argc, char *argv[])
 {
@@ -65,6 +67,7 @@ Q_DECL_EXPORT int main(int argc, char *argv[])
     qmlRegisterType<FontsConfigProperties>();
     qmlRegisterType<FontInfo>();
     qmlRegisterType<InstalledFontInfo>();
+    qmlRegisterType<FontsConfEditorController>();
 
     QmlApplicationViewer viewer;
     viewer.rootContext()->setContextProperty("controller", &appController);
diff --git a/qml/fontmanager/EditFontsConfPage.qml b/qml/fontmanager/EditFontsConfPage.qml
new file mode 100644 (file)
index 0000000..dc328de
--- /dev/null
@@ -0,0 +1,166 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Takumi Asaki
+** All rights reserved.
+** Contact: Takumi Asaki (takumi.asaki@gmail.com)
+**
+** This file is part of the fontmanager application.
+**
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+**   * Redistributions of source code must retain the above copyright
+**     notice, this list of conditions and the following disclaimer.
+**   * Redistributions in binary form must reproduce the above copyright
+**     notice, this list of conditions and the following disclaimer in
+**     the documentation and/or other materials provided with the
+**     distribution.
+**   * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+**     the names of its contributors may be used to endorse or promote
+**     products derived from this software without specific prior written
+**     permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+****************************************************************************/
+
+// import QtQuick 1.0 // to target S60 5th Edition or Maemo 5
+import QtQuick 1.1
+import com.nokia.meego 1.0
+import 'UIConstants.js' as UI
+
+Page {
+    id: editorTabPage
+    tools: editorTabTool
+
+    property string currentPriority
+
+    TabGroup {
+        id: editFontsConfTab
+
+        currentTab: sansSerifTab
+
+        FontsConfEditor {
+            id: sansSerifTab
+            family: "sans-serif"
+            familyName: qsTr("Sans Serif")
+            editorController: controller.editorController(family)
+        }
+
+        FontsConfEditor {
+            id: serifTab
+            family: "serif"
+            familyName: qsTr("Serif")
+            editorController: controller.editorController(family)
+        }
+
+        FontsConfEditor {
+            id: monospaceTab
+            family: "monospace"
+            familyName: qsTr("Monospace")
+            editorController: controller.editorController(family)
+        }
+
+    }
+
+    MultiSelectionDialog {
+        id: selectInstallFamily
+        model: installableFamilyListModel
+        acceptButtonText: qsTr("Add")
+        titleText: qsTr("Add Family for %1").arg(editFontsConfTab.currentTab.familyName)
+        onAccepted: {
+            for (var i = 0; i < selectedIndexes.length; i++) {
+                var idx = selectedIndexes[i]
+                var sItem = installableFamilyListModel.get(idx)
+                var tab = editFontsConfTab.currentTab
+                tab.editorController.appendFamily(sItem.enfamily, currentPriority)
+                tab.insertFamily(sItem.enfamily, currentPriority, sItem.systemFont)
+            }
+        }
+    }
+
+    ToolBarLayout {
+        id: editorTabTool
+        visible: true
+        ToolIcon {
+            platformIconId: "toolbar-back"
+            onClicked: {
+                if (editMenu.status !== DialogStatus.Closed)
+                    editMenu.close()
+                pageStack.pop()
+            }
+        }
+        ButtonRow {
+            style: TabButtonStyle { }
+            TabButton {
+                text: sansSerifTab.familyName
+                tab: sansSerifTab
+            }
+            TabButton {
+                text: serifTab.familyName
+                tab: serifTab
+            }
+            TabButton {
+                text: monospaceTab.familyName
+                tab: monospaceTab
+            }
+        }
+        ToolIcon {
+            platformIconId: "toolbar-view-menu"
+            anchors.right: (parent === undefined) ? undefined : parent.right
+            onClicked: {
+                if (!mainPage.enabled)
+                    return
+                if (editMenu.status === DialogStatus.Closed)
+                    editMenu.open()
+                else
+                    editMenu.close()
+            }
+        }
+    }
+
+    Menu {
+        id: editMenu
+        visualParent: pageStack
+        MenuLayout {
+            MenuItem {
+                text: qsTr("Remove current fonts config");
+                enabled: !controller.isEmptyFontsConf
+                onClicked: {
+                    editMenu.close()
+                    removeConfirmDialog.open()
+                }
+            }
+            MenuItem {
+                text: qsTr("View current fonts config");
+//                enabled: controller.localFontsConfExists
+                onClicked: {
+                    editMenu.close()
+                    pageStack.push(fontsConfViewPageComponent, { "text": controller.localFontsConf } )
+                }
+            }
+        }
+    }
+
+    QueryDialog {
+        id: removeConfirmDialog
+        titleText: qsTr("Remove it?")
+        message: qsTr("Existing fonts config %1 will be removed.  Are you sure?").arg(controller.localFontsConfPath)
+        acceptButtonText: qsTr("OK")
+        rejectButtonText: qsTr("Cancel")
+        onAccepted: controller.resetLocalFontsConf()
+    }
+
+}
diff --git a/qml/fontmanager/EditorHelper.js b/qml/fontmanager/EditorHelper.js
new file mode 100644 (file)
index 0000000..8478f33
--- /dev/null
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Takumi Asaki
+** All rights reserved.
+** Contact: Takumi Asaki (takumi.asaki@gmail.com)
+**
+** This file is part of the fontmanager application.
+**
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+**   * Redistributions of source code must retain the above copyright
+**     notice, this list of conditions and the following disclaimer.
+**   * Redistributions in binary form must reproduce the above copyright
+**     notice, this list of conditions and the following disclaimer in
+**     the documentation and/or other materials provided with the
+**     distribution.
+**   * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+**     the names of its contributors may be used to endorse or promote
+**     products derived from this software without specific prior written
+**     permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+****************************************************************************/
+
+var sectionIndexes;
+
+function init()
+{
+    sectionIndexes = {}
+}
+
+function setIndex(key, index)
+{
+    sectionIndexes[key] = index
+}
+
+function index(key)
+{
+    return sectionIndexes[key]
+}
+
+function updateInsertIndexes(index)
+{
+    for (var key in sectionIndexes) {
+        if (sectionIndexes[key] >= index)
+            sectionIndexes[key]++
+    }
+}
+
+function updateRemoveIndexes(index)
+{
+    for (var key in sectionIndexes) {
+        if (sectionIndexes[key] >= index)
+            sectionIndexes[key]--
+    }
+}
diff --git a/qml/fontmanager/FontsConfEditor.qml b/qml/fontmanager/FontsConfEditor.qml
new file mode 100644 (file)
index 0000000..d9c120d
--- /dev/null
@@ -0,0 +1,279 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Takumi Asaki
+** All rights reserved.
+** Contact: Takumi Asaki (takumi.asaki@gmail.com)
+**
+** This file is part of the fontmanager application.
+**
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+**   * Redistributions of source code must retain the above copyright
+**     notice, this list of conditions and the following disclaimer.
+**   * Redistributions in binary form must reproduce the above copyright
+**     notice, this list of conditions and the following disclaimer in
+**     the documentation and/or other materials provided with the
+**     distribution.
+**   * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+**     the names of its contributors may be used to endorse or promote
+**     products derived from this software without specific prior written
+**     permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+****************************************************************************/
+
+// import QtQuick 1.0 // to target S60 5th Edition or Maemo 5
+import QtQuick 1.1
+import com.nokia.meego 1.0
+import com.nokia.extras 1.1
+import 'UIConstants.js' as UI
+import 'EditorHelper.js' as Helper
+
+Page {
+    id: editorPage
+
+    property string family
+    property string familyName
+    property variant editorController
+
+    property string curSection
+    property string curSectionName
+
+
+    Label {
+        id: pageHeader
+        anchors.top: parent.top
+        anchors.horizontalCenter: parent.horizontalCenter
+        anchors.margins: UI.DEFAULT_MARGIN
+
+        horizontalAlignment: Text.AlignHCenter
+        font.pixelSize: UI.FONT_LARGE
+        font.bold: true
+        text: qsTr("Edit Fonts Config: %1").arg(familyName)
+    }
+
+    onEditorControllerChanged: {
+        if (editorController) {
+            modelSyncConnections.createObject(editorPage, {target: editorController})
+            editorController.syncFamilyList()
+        }
+    }
+
+    function addHeader(section, sectionName)
+    {
+        Helper.setIndex(curSection, preferFamilyList.count)
+        curSection = section
+        curSectionName = sectionName
+        preferFamilyList.append({
+                                    "title": qsTr("Priority: %1").arg(sectionName),
+                                    "subtitle": "",
+                                    "systemFont": false,
+                                    "header": true,
+                                    "priority": section
+                                })
+        Helper.setIndex(curSection, preferFamilyList.count)
+    }
+
+    function insertFamily(family, priority, systemFont)
+    {
+        var index = Helper.index(priority)
+        preferFamilyList.insert(index, {
+                                    "title": family,
+                                    "subtitle": (systemFont ? qsTr("System Font") : qsTr("User Font")),
+                                    "systemFont": systemFont,
+                                    "header": false,
+                                    "priority": priority,
+                                    "family": family,
+                                })
+        Helper.updateInsertIndexes(index)
+    }
+
+    function addFamily(section, family, priority, systemFont)
+    {
+        preferFamilyList.append({
+                                    "title": family,
+                                    "subtitle": (systemFont ? qsTr("System Font") : qsTr("User Font")),
+                                    "systemFont": systemFont,
+                                    "header": false,
+                                    "priority": curSection,
+                                    "family": family,
+                                })
+        Helper.setIndex(curSection, preferFamilyList.count)
+    }
+
+    function removeFamily(index)
+    {
+        var item = preferFamilyList.get(index)
+        editorController.removeFamily(item.family, item.priority)
+        preferFamilyList.remove(index)
+        Helper.updateRemoveIndexes(index)
+    }
+
+    Component {
+        id: modelSyncConnections
+        Connections {
+            onClearFamilyList: {
+                preferFamilyList.clear()
+                Helper.init()
+            }
+            onStartSection: addHeader(section, sectionName)
+            onAppendFamilyToList: addFamily(section, family, priority, systemFont)
+        }
+    }
+
+    ListModel {
+        id: preferFamilyList
+    }
+
+    Item {
+        anchors.top: pageHeader.bottom
+        anchors.bottom: importButton.top
+        anchors.left: parent.left
+        anchors.right: parent.right
+        anchors.topMargin: UI.DEFAULT_MARGIN
+        anchors.bottomMargin: UI.DEFAULT_MARGIN
+        clip: true
+
+        ListView {
+            id: preferFamilyListView
+            anchors.fill: parent
+            anchors.leftMargin: UI.DEFAULT_MARGIN
+            anchors.rightMargin: UI.DEFAULT_MARGIN
+
+            model: preferFamilyList
+            delegate: editorListDelegate
+        }
+
+        ScrollDecorator {
+            flickableItem: preferFamilyListView
+        }
+
+        //    SectionScroller {
+        //        listView: preferFamilyListView
+        //    }
+
+    }
+
+    Button {
+        id: importButton
+        anchors.horizontalCenter: parent.horizontalCenter
+        //        width: parent.width - UI.DEFAULT_MARGIN * 2
+        anchors.bottom: parent.bottom
+        anchors.bottomMargin: UI.DEFAULT_MARGIN
+        text: qsTr("Import System Settings")
+        onClicked: {
+            controller.importSystemSettings(family)
+        }
+    }
+
+    ButtonStyle {
+        id: buttonStyle
+    }
+
+    Component {
+        id: editorListDelegate
+
+        Item {
+            id: listItem
+
+            signal clicked
+            property bool pressed: false
+
+            property int titleSize: (model.header ? UI.FONT_XLARGE : UI.FONT_DEFAULT)
+            property int titleWeight: Font.Bold
+            property color titleColor: theme.inverted ? (model.header ? UI.COLOR_FOREGROUND : UI.COLOR_INVERTED_FOREGROUND) : (UI.COLOR_FOREGROUND)
+
+            property int subtitleSize: UI.FONT_XSMALL
+            property int subtitleWeight: Font.Light
+            property color subtitleColor: theme.inverted ? UI.COLOR_SECONDARY_FOREGROUND : UI.COLOR_INVERTED_SECONDARY_FOREGROUND
+
+            height: UI.LIST_ITEM_HEIGHT_SMALL
+            width: parent.width
+
+            Rectangle {
+                anchors.fill: parent
+                anchors.leftMargin: -UI.MARGIN_XLARGE
+                anchors.rightMargin: -UI.MARGIN_XLARGE
+                color: model.header ? UI.COLOR_SELECT : UI.COLOR_BACKGROUND
+            }
+
+            Row {
+                anchors.fill: parent
+                spacing: UI.DEFAULT_MARGIN
+
+                Item { width: UI.DEFAULT_MARGIN; height: 1; visible: !model.header }
+
+                Image {
+                    anchors.verticalCenter: parent.verticalCenter
+                    visible: model.iconSource ? true : false
+                    width: UI.SIZE_ICON_DEFAULT
+                    height: UI.SIZE_ICON_DEFAULT
+                    source: model.iconSource ? model.iconSource : ""
+                }
+
+                Column {
+                    anchors.verticalCenter: parent.verticalCenter
+
+
+                    Label {
+                        id: mainText
+                        text: model.title
+                        font.weight: listItem.titleWeight
+                        font.pixelSize: listItem.titleSize
+                        color: listItem.titleColor
+                    }
+
+                    Label {
+                        id: subText
+                        text: model.subtitle
+                        font.weight: listItem.subtitleWeight
+                        font.pixelSize: listItem.subtitleSize
+                        color: listItem.subtitleColor
+
+                        visible: text != ""
+                    }
+                }
+            }
+            //            MouseArea {
+            //                id: mouseArea;
+            //                anchors.fill: parent
+            //                onClicked: {
+            //                    listItem.clicked();
+            //                }
+            //            }
+
+            ListButton {
+                anchors.right: parent.right
+                anchors.verticalCenter: parent.verticalCenter
+                anchors.rightMargin: UI.DEFAULT_MARGIN
+                iconSource: (model.header ? "image://theme/icon-m-toolbar-add" : "image://theme/icon-m-toolbar-delete")
+                onClicked: {
+                    if (model.header) {
+                        controller.syncInstallableFamilyFor(editorPage.family)
+                        editorTabPage.currentPriority = model.priority
+                        selectInstallFamily.selectedIndexes = []
+                        selectInstallFamily.open()
+                    } else {
+                        removeFamily(model.index)
+                    }
+                }
+            }
+
+        }
+    }
+
+}
index 0041896..1648325 100644 (file)
@@ -43,11 +43,12 @@ import 'UIConstants.js' as UI
 
 Item {
     property variant fontconf
-    property bool modified: (sansSerifCheck.checked != fontconf.prefer("sans-serif")) ||
-                            (serifCheck.checked != fontconf.prefer("serif")) ||
-                            (monospaceCheck.checked != fontconf.prefer("monospace")) ||
-                            (embeddedBitmapCombo.selectedIndex != fontconf.embeddedBitmap) ||
-                            (hintingCombo.selectedIndex != fontconf.hinting)
+    property bool modified: (sansSerifCheck.checked !== fontconf.prefer("sans-serif")) ||
+                            (serifCheck.checked !== fontconf.prefer("serif")) ||
+                            (monospaceCheck.checked !== fontconf.prefer("monospace"))
+//                            ||
+//                            (embeddedBitmapCombo.selectedIndex !== fontconf.embeddedBitmap) ||
+//                            (hintingCombo.selectedIndex !== fontconf.hinting)
 
     height: childrenRect.height
 
@@ -62,8 +63,8 @@ Item {
         sansSerifCheck.checked = fontconf.prefer("sans-serif")
         serifCheck.checked = fontconf.prefer("serif")
         monospaceCheck.checked = fontconf.prefer("monospace")
-        embeddedBitmapCombo.selectedIndex = fontconf.embeddedBitmap
-        hintingCombo.selectedIndex = fontconf.hinting
+//        embeddedBitmapCombo.selectedIndex = fontconf.embeddedBitmap
+//        hintingCombo.selectedIndex = fontconf.hinting
     }
 
     function save()
@@ -84,8 +85,8 @@ Item {
             fontconf.addPreferFamily("monospace")
         else
             fontconf.removePreferFamily("monospace")
-        fontconf.embeddedBitmap = embeddedBitmapCombo.selectedIndex
-        fontconf.hinting = hintingCombo.selectedIndex
+//        fontconf.embeddedBitmap = embeddedBitmapCombo.selectedIndex
+//        fontconf.hinting = hintingCombo.selectedIndex
     }
 
     Column {
@@ -106,16 +107,16 @@ Item {
             width: parent.width
             text: qsTr("Use as Prefer Font for Monospace")
         }
-        ConfigValueComboBox {
-            id: embeddedBitmapCombo
-            width: parent.width
-            comboLabel: qsTr("Use Embedded Bitmap")
-        }
-        ConfigValueComboBox {
-            id: hintingCombo
-            width: parent.width
-            comboLabel: qsTr("Use Hinting")
-        }
+//        ConfigValueComboBox {
+//            id: embeddedBitmapCombo
+//            width: parent.width
+//            comboLabel: qsTr("Use Embedded Bitmap")
+//        }
+//        ConfigValueComboBox {
+//            id: hintingCombo
+//            width: parent.width
+//            comboLabel: qsTr("Use Hinting")
+//        }
     }
 
 }
index 0fddb30..d557064 100644 (file)
@@ -75,6 +75,7 @@ Page {
         Flickable {
             id: flickable
             anchors.fill: parent
+            visible: controller.localFontsConfExists
 
             clip: true
             boundsBehavior: Flickable.StopAtBounds
@@ -88,6 +89,20 @@ Page {
                 font.pixelSize: UI.FONT_DEFAULT_SIZE
             }
         }
+
+        Text {
+            id: emptyText
+            width: parent.width - UI.DEFAULT_MARGIN * 2
+            wrapMode: Text.WrapAtWordBoundaryOrAnywhere
+            anchors.centerIn: parent
+            text: qsTr("No such file or directory: %1").arg(controller.localFontsConfPath)
+            font.pixelSize: UI.FONT_XLARGE
+            font.bold: true
+            color: "gray"
+            visible: !controller.localFontsConfExists
+            horizontalAlignment: Text.AlignHCenter
+
+        }
     }
 
     ToolBarLayout {
index dacf091..691cbf9 100644 (file)
@@ -51,7 +51,7 @@ Page {
         if (fontProperty.modified) {
             fontProperty.save()
             controller.updateFontsConf(fontInfo)
-            controller.saveFontsConf()
+//            controller.saveFontsConf()
         }
     }
 
@@ -96,8 +96,8 @@ Page {
                 x: UI.DEFAULT_MARGIN
                 text: qsTr("The quick brown fox jumps over the lazy dog")
                 font.family: fontInfo.enfamily
-                font.bold: (fontInfo.enstyle.match(/bold/i) ? true : false)
-                font.italic: (fontInfo.enstyle.match(/italic/i) ? true : false)
+                font.bold: /*(fontInfo.enstyle.match(/bold/i) ? true : false) ||*/  (fontInfo.weight >= 200)
+                font.italic: /*(fontInfo.enstyle.match(/italic/i) ? true : false) ||*/ (fontInfo.slant !== 0)
             }
             Label {
                 width: parent.width
@@ -163,7 +163,7 @@ Page {
         property variant fontlist
         titleText: qsTr("Delete Font?")
         message: fontcount > 1 ?
-                     qsTr("This Font has %1 families(%2).\nDo you really want to remove these fonts now?").arg(fontcount).arg(fontlist.join(qsTr(', '))) :
+                     qsTr("This Font has %1 families(%2).  Do you really want to remove these fonts now?").arg(fontcount).arg(fontlist.join(qsTr(', '))) :
                      qsTr("Do you really want to remove this font now?")
         acceptButtonText: qsTr("OK")
         rejectButtonText: qsTr("Cancel")
index db8646c..a543ce3 100644 (file)
@@ -89,9 +89,9 @@ Page {
             onClicked: {
                 if (!mainPage.enabled)
                     return
-                if (mainMenu.status != DialogStatus.Closed)
+                if (mainMenu.status !== DialogStatus.Closed)
                     mainMenu.close()
-                pageStack.push(installedFontInfoPage, { "fontInfo": controller.fontInfo(title, subtitle) } );
+                pageStack.push(installedFontInfoPageComponent, { "fontInfo": controller.fontInfo(title, subtitle) } );
             }
         }
 
@@ -102,7 +102,7 @@ Page {
         width: parent.width - UI.DEFAULT_MARGIN * 2
         wrapMode: Text.WrapAtWordBoundaryOrAnywhere
         anchors.centerIn: parent
-        text: qsTr("No Fonts Found!")
+        text: qsTr("No Fonts Installed")
         font.pixelSize: UI.FONT_XLARGE
         font.bold: true
         color: "gray"
@@ -119,7 +119,7 @@ Page {
     }
 
     Component {
-        id: installedFontInfoPage
+        id: installedFontInfoPageComponent
         InstalledFontInfoPage { }
     }
 
@@ -128,6 +128,11 @@ Page {
         FontsConfViewPage { }
     }
 
+    Component {
+        id: editFontsConfPageComponent
+        EditFontsConfPage {}
+    }
+
     ToolBarLayout {
         id: mainTools
         visible: true
@@ -136,18 +141,34 @@ Page {
             onClicked: {
                 if (!mainPage.enabled)
                     return
-                if (mainMenu.status != DialogStatus.Closed)
+                if (mainMenu.status !== DialogStatus.Closed)
                     mainMenu.close()
                 pageStack.push(fontSelectPage)
             }
         }
         ToolIcon {
+            platformIconId: "toolbar-settings"
+            enabled: (installedFontList.count > 0)
+            opacity: enabled ? 1.0 : 0.5
+            onClicked: {
+                if (!mainPage.enabled)
+                    return
+                if (mainMenu.status !== DialogStatus.Closed)
+                    mainMenu.close()
+                pageStack.push(editFontsConfPageComponent)
+            }
+        }
+
+        ToolIcon {
             platformIconId: "toolbar-view-menu"
             anchors.right: (parent === undefined) ? undefined : parent.right
             onClicked: {
                 if (!mainPage.enabled)
                     return
-                (mainMenu.status == DialogStatus.Closed) ? mainMenu.open() : mainMenu.close()
+                if (mainMenu.status === DialogStatus.Closed)
+                    mainMenu.open()
+                else
+                    mainMenu.close()
             }
         }
     }
@@ -157,23 +178,27 @@ Page {
         visualParent: pageStack
         MenuLayout {
             MenuItem {
-                text: qsTr("View current fonts config");
-                enabled: controller.localFontsConfExists
-                onClicked: {
-                    mainMenu.close()
-                    pageStack.push(fontsConfViewPageComponent, { "text": controller.localFontsConf } )
-                }
-            }
-            MenuItem {
-                text: qsTr("Remove uninstalled fonts from config");
-                enabled: controller.configHasUninstalledFonts
+                text: qsTr("Create Recommended Settings");
+                enabled: (installedFontList.count > 0)
                 onClicked: {
-                    mainMenu.close()
-                    controller.removeUninstalledFontsFromConfig()
-                    controller.saveFontsConf()
+                    if (mainMenu.status !== DialogStatus.Closed)
+                        mainMenu.close()
+                    if (controller.localFontsConfExists)
+                        createConfirmDialog.open()
+                    else
+                        controller.createRecommendedSettings()
                 }
             }
         }
     }
 
+    QueryDialog {
+        id: createConfirmDialog
+        titleText: qsTr("Replace it?")
+        message: qsTr("Existing %1 will be replaced by recommended settings.  Are you sure?").arg(controller.localFontsConfPath)
+        acceptButtonText: qsTr("OK")
+        rejectButtonText: qsTr("Cancel")
+        onAccepted: controller.createRecommendedSettings()
+    }
+
 }
index 273ca12..9d44179 100644 (file)
@@ -67,6 +67,18 @@ PageStackWindow {
             uninstallFinishedDialog.fontpath = fontpath
             uninstallFinishedDialog.open()
         }
+        onClearInstallableFamilyListFor: {
+            installableFamilyListModel.clear()
+            installableFamilyListModel.family = family;
+        }
+        onAppendInstallableFamily: {
+            installableFamilyListModel.append( { "name": family, "enfamily": enfamily, "systemFont": systemFont } )
+        }
+    }
+
+    ListModel {
+        id: installableFamilyListModel
+        property string family
     }
 
     Component {
index e4012d2..250dec1 100644 (file)
@@ -1,7 +1,17 @@
+fontmanager (0.4) unstable; urgency=low
+
+  * Support system's fonts.conf
+  * Re-new editing fonts.conf
+  * Add 'Create Recommended Settings' feature
+  * Remove embeddedbitmap and hinting support
+
+ -- Takumi Asaki <takumi.asaki@gmail.com>  Wed, 18 Jan 2012 23:30:00 +0900
+
 fontmanager (0.3.3) unstable; urgency=low
 
   * Fix: Some messages width
   * Fix: Can select uninstalling fonts.
+  * Minor fixes.
 
  -- Takumi Asaki <takumi.asaki@gmail.com>  Fri, 13 Jan 2012 12:00:00 +0900
 
index b4d5c2e..4039723 100644 (file)
@@ -4,47 +4,55 @@
 <context>
     <name>ApplicationController</name>
     <message>
-        <location filename="../applicationcontroller.cpp" line="+99"/>
+        <location filename="../applicationcontroller.cpp" line="+118"/>
         <source>Font Dir: %1 is not found!</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location line="+94"/>
+        <location line="+181"/>
         <source>Font &apos;%1&apos; does not exists anymore.</source>
         <translation>フォント &apos;%1&apos; が見つかりません。</translation>
     </message>
     <message>
         <location line="+7"/>
         <source>Create it?</source>
-        <translation>ディレクトリ作成</translation>
+        <translation>作成しますか?</translation>
     </message>
     <message>
         <location line="+0"/>
+        <source>Local fonts directory &apos;%1&apos; does not exists!  Create it now?</source>
+        <translation>ローカルのフォントディレクトリ &apos;%1&apos; がありません。今すぐ作成しますか?</translation>
+    </message>
+    <message>
+        <location line="+16"/>
+        <source>Local font &apos;%1&apos; already exists!  Overwrite it?</source>
+        <translation>フォント &apos;%1&apos; はインストール済みです。上書きしますか?</translation>
+    </message>
+    <message>
         <source>Local fonts dir &apos;%1&apos; does not exists!
 Create it now?</source>
-        <translation>ローカルのフォントディレクトリ &apos;%1&apos; がありません!
+        <translation type="obsolete">ローカルのフォントディレクトリ &apos;%1&apos; がありません!
 今すぐ作成しますか?</translation>
     </message>
     <message>
-        <location line="+16"/>
-        <location line="+85"/>
+        <location line="+0"/>
+        <location line="+100"/>
         <source>Overwrite it?</source>
-        <translation>上書き確認</translation>
+        <translation>上書きしますか?</translation>
     </message>
     <message>
-        <location line="-85"/>
         <source>Local font &apos;%1&apos; already exists!
 Overwrite it?</source>
-        <translation>フォント &apos;%1&apos; はインストール済みです!
+        <translation type="obsolete">フォント &apos;%1&apos; はインストール済みです!
 上書きしますか?</translation>
     </message>
     <message>
-        <location line="+48"/>
+        <location line="-48"/>
         <source>Could not remove Font &apos;%1&apos;</source>
         <translation>フォント &apos;%1&apos; を削除できません</translation>
     </message>
     <message>
-        <location line="+37"/>
+        <location line="+48"/>
         <source>Current Config file %1 has unsupported configs(s).  It will be overwritten.  Overwrite it now?</source>
         <translation>現在の設定ファイル %1 には未サポートの項目があり、それらは削除されます。設定を上書きしますか?</translation>
     </message>
@@ -68,26 +76,81 @@ Overwrite it?</source>
     </message>
 </context>
 <context>
+    <name>EditFontsConfPage</name>
+    <message>
+        <location filename="../qml/fontmanager/EditFontsConfPage.qml" line="+58"/>
+        <source>Sans Serif</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location line="+7"/>
+        <source>Serif</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location line="+7"/>
+        <source>Monospace</source>
+        <translation>等幅</translation>
+    </message>
+    <message>
+        <location line="+9"/>
+        <source>Add</source>
+        <translation>追加</translation>
+    </message>
+    <message>
+        <location line="+1"/>
+        <source>Add Family for %1</source>
+        <translation>%1 に追加するフォントファミリー</translation>
+    </message>
+    <message>
+        <location line="+57"/>
+        <source>Remove current fonts config</source>
+        <translation>現在のフォント設定を削除</translation>
+    </message>
+    <message>
+        <location line="+8"/>
+        <source>View current fonts config</source>
+        <translation>現在のフォント設定を表示</translation>
+    </message>
+    <message>
+        <location line="+12"/>
+        <source>Remove it?</source>
+        <translation>削除しますか?</translation>
+    </message>
+    <message>
+        <location line="+1"/>
+        <source>Existing fonts config %1 will be removed.  Are you sure?</source>
+        <translation>既存のフォント設定 %1 は削除されます。よろしいですか?</translation>
+    </message>
+    <message>
+        <location line="+1"/>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+    <message>
+        <location line="+1"/>
+        <source>Cancel</source>
+        <translation>キャンセル</translation>
+    </message>
+</context>
+<context>
     <name>FontConfigManager</name>
     <message>
         <source>%1 is invali.!  Could not parse it.</source>
         <translation type="obsolete">%1 は不正な設定ファイルです。解析できません。</translation>
     </message>
     <message>
-        <location filename="../fontconfigmanager.cpp" line="+627"/>
         <source>%1 is invalid!  Could not parse it.</source>
-        <translation>%1 は不正な設定ファイルです。解析できません。</translation>
+        <translation type="obsolete">%1 は不正な設定ファイルです。解析できません。</translation>
     </message>
     <message>
-        <location line="+2"/>
         <source>%1 contains unsupported config(s).  It will be overwritten.
 Are you sure?</source>
-        <translation>設定ファイル %1 には未サポートの項目があり、それらは削除されます。よろしいですか?</translation>
+        <translation type="obsolete">設定ファイル %1 には未サポートの項目があり、それらは削除されます。よろしいですか?</translation>
     </message>
     <message>
-        <location line="+77"/>
         <source>Could not write to %1</source>
-        <translation>%1 へ書き込めません</translation>
+        <translation type="obsolete">%1 へ書き込めません</translation>
     </message>
 </context>
 <context>
@@ -135,9 +198,57 @@ Are you sure?</source>
     </message>
 </context>
 <context>
+    <name>FontsConfEditor</name>
+    <message>
+        <location filename="../qml/fontmanager/FontsConfEditor.qml" line="+66"/>
+        <source>Edit Fonts Config: %1</source>
+        <translation>フォント設定の編集: %1</translation>
+    </message>
+    <message>
+        <location line="+16"/>
+        <source>Priority: %1</source>
+        <translation>優先順位: %1</translation>
+    </message>
+    <message>
+        <location line="+14"/>
+        <location line="+13"/>
+        <source>System Font</source>
+        <translation>システムフォント</translation>
+    </message>
+    <message>
+        <location line="-13"/>
+        <location line="+13"/>
+        <source>User Font</source>
+        <translation>ユーザーフォント</translation>
+    </message>
+    <message>
+        <location line="+68"/>
+        <source>Import System Settings</source>
+        <translation>システム設定のインポート</translation>
+    </message>
+</context>
+<context>
+    <name>FontsConfEditorController</name>
+    <message>
+        <location filename="../fontsconfeditorcontroller.cpp" line="+58"/>
+        <source>High</source>
+        <translation>高</translation>
+    </message>
+    <message>
+        <location line="+6"/>
+        <source>Normal</source>
+        <translation>標準</translation>
+    </message>
+    <message>
+        <location line="+6"/>
+        <source>Low</source>
+        <translation>低</translation>
+    </message>
+</context>
+<context>
     <name>FontsConfProperties</name>
     <message>
-        <location filename="../qml/fontmanager/FontsConfProperties.qml" line="+97"/>
+        <location filename="../qml/fontmanager/FontsConfProperties.qml" line="+98"/>
         <source>Use as Prefer Font for Sans-Serif</source>
         <translation>Sans-Serif(ゴシック体)で使用</translation>
     </message>
@@ -152,14 +263,12 @@ Are you sure?</source>
         <translation>等幅フォントで使用</translation>
     </message>
     <message>
-        <location line="+5"/>
         <source>Use Embedded Bitmap</source>
-        <translation>埋め込みビットマップの使用</translation>
+        <translation type="obsolete">埋め込みビットマップの使用</translation>
     </message>
     <message>
-        <location line="+5"/>
         <source>Use Hinting</source>
-        <translation>ヒントの使用</translation>
+        <translation type="obsolete">ヒントの使用</translation>
     </message>
 </context>
 <context>
@@ -169,6 +278,11 @@ Are you sure?</source>
         <source>Current Fonts Config</source>
         <translation>現在のフォント設定</translation>
     </message>
+    <message>
+        <location line="+38"/>
+        <source>No such file or directory: %1</source>
+        <translation>ファイルがありません: %1</translation>
+    </message>
 </context>
 <context>
     <name>InstalledFontInfoPage</name>
@@ -258,18 +372,22 @@ Are you sure?</source>
         <translation>フォントを削除しますか?</translation>
     </message>
     <message>
-        <location line="+2"/>
         <source>This Font has %1 families(%2).
 Do you really want to remove these fonts now?</source>
-        <translation>このフォントには %1 個のファミリー(%2)があります。
+        <translation type="obsolete">このフォントには %1 個のファミリー(%2)があります。
 これら全てのフォントを削除しますか?</translation>
     </message>
     <message>
-        <location line="+0"/>
+        <location line="+2"/>
         <source>, </source>
         <translation>、</translation>
     </message>
     <message>
+        <location line="+0"/>
+        <source>This Font has %1 families(%2).  Do you really want to remove these fonts now?</source>
+        <translation>このフォントには %1 個のファミリー(%2)があります。これら全てのフォントを削除しますか?</translation>
+    </message>
+    <message>
         <location line="+1"/>
         <source>Do you really want to remove this font now?</source>
         <translation>このフォントを削除しますか?</translation>
@@ -288,30 +406,57 @@ Do you really want to remove these fonts now?</source>
 <context>
     <name>MainPage</name>
     <message>
-        <location filename="../qml/fontmanager/MainPage.qml" line="+56"/>
+        <location filename="../qml/fontmanager/MainPage.qml" line="+60"/>
         <source>Installed Fonts</source>
         <translation>インストール済みフォント</translation>
     </message>
     <message>
-        <location line="+41"/>
+        <location line="+45"/>
+        <source>No Fonts Installed</source>
+        <translation>フォントは未インストールです</translation>
+    </message>
+    <message>
+        <location line="+76"/>
+        <source>Create Recommended Settings</source>
+        <translation>推奨設定の作成</translation>
+    </message>
+    <message>
+        <location line="+16"/>
+        <source>Replace it?</source>
+        <translation>置き換えますか?</translation>
+    </message>
+    <message>
+        <location line="+1"/>
+        <source>Existing %1 will be replaced by recommended settings.  Are you sure?</source>
+        <translation>既存の設定 %1 を推奨設定で置き換えます。よろしいですか?</translation>
+    </message>
+    <message>
+        <location line="+1"/>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+    <message>
+        <location line="+1"/>
+        <source>Cancel</source>
+        <translation>キャンセル</translation>
+    </message>
+    <message>
         <source>No Fonts Found!</source>
-        <translation>フォントがインストールされていません!</translation>
+        <translation type="obsolete">フォントがインストールされていません!</translation>
     </message>
     <message>
-        <location line="+40"/>
         <source>View current fonts config</source>
-        <translation>現在のフォント設定を表示</translation>
+        <translation type="obsolete">現在のフォント設定を表示</translation>
     </message>
     <message>
-        <location line="+8"/>
         <source>Remove uninstalled fonts from config</source>
-        <translation>不要なフォントを設定から削除</translation>
+        <translation type="obsolete">不要なフォントを設定から削除</translation>
     </message>
 </context>
 <context>
     <name>main</name>
     <message>
-        <location filename="../qml/fontmanager/main.qml" line="+80"/>
+        <location filename="../qml/fontmanager/main.qml" line="+92"/>
         <source>Confirm</source>
         <translation>確認</translation>
     </message>
index e81d5a7..40974b4 100644 (file)
@@ -4,12 +4,12 @@
 <context>
     <name>ApplicationController</name>
     <message>
-        <location filename="../applicationcontroller.cpp" line="+99"/>
+        <location filename="../applicationcontroller.cpp" line="+118"/>
         <source>Font Dir: %1 is not found!</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location line="+94"/>
+        <location line="+181"/>
         <source>Font &apos;%1&apos; does not exists anymore.</source>
         <translation type="unfinished"></translation>
     </message>
     </message>
     <message>
         <location line="+0"/>
-        <source>Local fonts dir &apos;%1&apos; does not exists!
-Create it now?</source>
+        <source>Local fonts directory &apos;%1&apos; does not exists!  Create it now?</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
         <location line="+16"/>
-        <location line="+85"/>
-        <source>Overwrite it?</source>
+        <source>Local font &apos;%1&apos; already exists!  Overwrite it?</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location line="-85"/>
-        <source>Local font &apos;%1&apos; already exists!
-Overwrite it?</source>
+        <location line="+0"/>
+        <location line="+100"/>
+        <source>Overwrite it?</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location line="+48"/>
+        <location line="-48"/>
         <source>Could not remove Font &apos;%1&apos;</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location line="+37"/>
+        <location line="+48"/>
         <source>Current Config file %1 has unsupported configs(s).  It will be overwritten.  Overwrite it now?</source>
         <translation type="unfinished"></translation>
     </message>
@@ -66,21 +64,60 @@ Overwrite it?</source>
     </message>
 </context>
 <context>
-    <name>FontConfigManager</name>
+    <name>EditFontsConfPage</name>
     <message>
-        <location filename="../fontconfigmanager.cpp" line="+627"/>
-        <source>%1 is invalid!  Could not parse it.</source>
+        <location filename="../qml/fontmanager/EditFontsConfPage.qml" line="+58"/>
+        <source>Sans Serif</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location line="+2"/>
-        <source>%1 contains unsupported config(s).  It will be overwritten.
-Are you sure?</source>
+        <location line="+7"/>
+        <source>Serif</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location line="+77"/>
-        <source>Could not write to %1</source>
+        <location line="+7"/>
+        <source>Monospace</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location line="+9"/>
+        <source>Add</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location line="+1"/>
+        <source>Add Family for %1</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location line="+57"/>
+        <source>Remove current fonts config</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location line="+8"/>
+        <source>View current fonts config</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location line="+12"/>
+        <source>Remove it?</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location line="+1"/>
+        <source>Existing fonts config %1 will be removed.  Are you sure?</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location line="+1"/>
+        <source>OK</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location line="+1"/>
+        <source>Cancel</source>
         <translation type="unfinished"></translation>
     </message>
 </context>
@@ -121,30 +158,68 @@ Are you sure?</source>
     </message>
 </context>
 <context>
-    <name>FontsConfProperties</name>
+    <name>FontsConfEditor</name>
     <message>
-        <location filename="../qml/fontmanager/FontsConfProperties.qml" line="+97"/>
-        <source>Use as Prefer Font for Sans-Serif</source>
+        <location filename="../qml/fontmanager/FontsConfEditor.qml" line="+66"/>
+        <source>Edit Fonts Config: %1</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location line="+5"/>
-        <source>Use as Prefer Font for Serif</source>
+        <location line="+16"/>
+        <source>Priority: %1</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location line="+5"/>
-        <source>Use as Prefer Font for Monospace</source>
+        <location line="+14"/>
+        <location line="+13"/>
+        <source>System Font</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location line="-13"/>
+        <location line="+13"/>
+        <source>User Font</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location line="+68"/>
+        <source>Import System Settings</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>FontsConfEditorController</name>
+    <message>
+        <location filename="../fontsconfeditorcontroller.cpp" line="+58"/>
+        <source>High</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location line="+6"/>
+        <source>Normal</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location line="+6"/>
+        <source>Low</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>FontsConfProperties</name>
+    <message>
+        <location filename="../qml/fontmanager/FontsConfProperties.qml" line="+98"/>
+        <source>Use as Prefer Font for Sans-Serif</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
         <location line="+5"/>
-        <source>Use Embedded Bitmap</source>
+        <source>Use as Prefer Font for Serif</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
         <location line="+5"/>
-        <source>Use Hinting</source>
+        <source>Use as Prefer Font for Monospace</source>
         <translation type="unfinished"></translation>
     </message>
 </context>
@@ -155,6 +230,11 @@ Are you sure?</source>
         <source>Current Fonts Config</source>
         <translation type="unfinished"></translation>
     </message>
+    <message>
+        <location line="+38"/>
+        <source>No such file or directory: %1</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>InstalledFontInfoPage</name>
@@ -245,13 +325,12 @@ Are you sure?</source>
     </message>
     <message>
         <location line="+2"/>
-        <source>This Font has %1 families(%2).
-Do you really want to remove these fonts now?</source>
+        <source>, </source>
         <translation type="unfinished"></translation>
     </message>
     <message>
         <location line="+0"/>
-        <source></source>
+        <source>This Font has %1 families(%2).  Do you really want to remove these fonts now?</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
@@ -273,30 +352,45 @@ Do you really want to remove these fonts now?</source>
 <context>
     <name>MainPage</name>
     <message>
-        <location filename="../qml/fontmanager/MainPage.qml" line="+56"/>
+        <location filename="../qml/fontmanager/MainPage.qml" line="+60"/>
         <source>Installed Fonts</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location line="+41"/>
-        <source>No Fonts Found!</source>
+        <location line="+45"/>
+        <source>No Fonts Installed</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location line="+40"/>
-        <source>View current fonts config</source>
+        <location line="+76"/>
+        <source>Create Recommended Settings</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location line="+8"/>
-        <source>Remove uninstalled fonts from config</source>
+        <location line="+16"/>
+        <source>Replace it?</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location line="+1"/>
+        <source>Existing %1 will be replaced by recommended settings.  Are you sure?</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location line="+1"/>
+        <source>OK</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location line="+1"/>
+        <source>Cancel</source>
         <translation type="unfinished"></translation>
     </message>
 </context>
 <context>
     <name>main</name>
     <message>
-        <location filename="../qml/fontmanager/main.qml" line="+80"/>
+        <location filename="../qml/fontmanager/main.qml" line="+92"/>
         <source>Confirm</source>
         <translation type="unfinished"></translation>
     </message>