You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

363 lines
11 KiB

/*
* KFontInst - KDE Font Installer
*
* Copyright 2003-2009 Craig Drummond <craig@kde.org>
*
* ----
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "Folder.h"
#include "FcConfig.h"
#include "KfiConstants.h"
#include "XmlStrings.h"
#include "config-fontinst.h"
#include <KShell>
#include <QCoreApplication>
#include <QDebug>
#include <QDir>
#include <QDomDocument>
#include <QDomElement>
#include <QDomNode>
#include <QFile>
#include <QProcess>
#include <QSaveFile>
#include <QStandardPaths>
#include <QTextStream>
#include <fontconfig/fontconfig.h>
#define DISABLED_FONTS "disabledfonts"
#define KFI_DBUG qDebug() << time(nullptr)
namespace KFI
{
bool Folder::CfgFile::modified()
{
return timestamp != Misc::getTimeStamp(name);
}
void Folder::CfgFile::updateTimeStamp()
{
timestamp = Misc::getTimeStamp(name);
}
Folder::~Folder()
{
saveDisabled();
}
void Folder::init(bool system, bool systemBus)
{
itsIsSystem = system;
if (!system) {
FcStrList *list = FcConfigGetFontDirs(FcInitLoadConfigAndFonts());
QStringList dirs;
FcChar8 *fcDir;
while ((fcDir = FcStrListNext(list)))
dirs.append(Misc::dirSyntax((const char *)fcDir));
itsLocation = Misc::getFolder(Misc::dirSyntax(QDir::homePath() + "/.fonts/"), Misc::dirSyntax(QDir::homePath()), dirs);
} else
itsLocation = KFI_DEFAULT_SYS_FONTS_FOLDER;
if ((!system && !systemBus) || (system && systemBus))
FcConfig::addDir(itsLocation, system);
itsDisabledCfg.dirty = false;
if (itsDisabledCfg.name.isEmpty()) {
QString fileName("/" DISABLED_FONTS ".xml");
if (system)
itsDisabledCfg.name = QString::fromLatin1(KFI_ROOT_CFG_DIR) + fileName;
else {
QString path = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + QLatin1Char('/');
if (!Misc::dExists(path))
Misc::createDir(path);
itsDisabledCfg.name = path + fileName;
}
itsDisabledCfg.timestamp = 0;
}
}
bool Folder::allowToggling() const
{
return Misc::fExists(itsDisabledCfg.name) ? Misc::fWritable(itsDisabledCfg.name) : Misc::dWritable(Misc::getDir(itsDisabledCfg.name));
}
void Folder::loadDisabled()
{
if (itsDisabledCfg.dirty)
saveDisabled();
QFile f(itsDisabledCfg.name);
KFI_DBUG << itsDisabledCfg.name;
itsDisabledCfg.dirty = false;
if (f.open(QIODevice::ReadOnly)) {
QDomDocument doc;
if (doc.setContent(&f))
for (QDomNode n = doc.documentElement().firstChild(); !n.isNull(); n = n.nextSibling()) {
QDomElement e = n.toElement();
if (FONT_TAG == e.tagName()) {
Family fam(e, false);
if (!fam.name().isEmpty()) {
Style style(e, false);
if (KFI_NO_STYLE_INFO != style.value()) {
QList<File> files;
if (e.hasAttribute(PATH_ATTR)) {
File file(e, true);
if (!file.path().isEmpty())
files.append(file);
else
itsDisabledCfg.dirty = true;
} else {
for (QDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling()) {
QDomElement ent = n.toElement();
if (FILE_TAG == ent.tagName()) {
File file(ent, true);
if (!file.path().isEmpty())
files.append(file);
else {
KFI_DBUG << "Set dirty from load";
itsDisabledCfg.dirty = true;
}
}
}
}
if (files.count() > 0) {
QList<File>::ConstIterator it(files.begin()), end(files.end());
FamilyCont::ConstIterator f(itsFonts.insert(fam));
StyleCont::ConstIterator s((*f).add(style));
for (; it != end; ++it)
(*s).add(*it);
}
}
}
}
}
f.close();
itsDisabledCfg.updateTimeStamp();
}
saveDisabled();
}
void Folder::saveDisabled()
{
if (itsDisabledCfg.dirty) {
if (!itsIsSystem || Misc::root()) {
KFI_DBUG << itsDisabledCfg.name;
QSaveFile file;
file.setFileName(itsDisabledCfg.name);
if (!file.open(QIODevice::WriteOnly)) {
KFI_DBUG << "Exit - cant open save file";
qApp->exit(0);
}
QTextStream str(&file);
str << "<" DISABLED_FONTS ">" << Qt::endl;
FamilyCont::ConstIterator it(itsFonts.begin()), end(itsFonts.end());
for (; it != end; ++it)
(*it).toXml(true, str);
str << "</" DISABLED_FONTS ">" << Qt::endl;
str.flush();
if (!file.commit()) {
KFI_DBUG << "Exit - cant finalize save file";
qApp->exit(0);
}
}
itsDisabledCfg.updateTimeStamp();
itsDisabledCfg.dirty = false;
}
}
QStringList Folder::toXml(int max)
{
QStringList rv;
FamilyCont::ConstIterator it(itsFonts.begin()), end(itsFonts.end());
QString string;
QTextStream str(&string);
for (int i = 0; it != end; ++it, ++i) {
if (0 == (i % max)) {
if (i) {
str << "</" FONTLIST_TAG ">" << Qt::endl;
rv.append(string);
string = QString();
}
str << "<" FONTLIST_TAG " " << SYSTEM_ATTR "=\"" << (itsIsSystem ? "true" : "false") << "\">" << Qt::endl;
}
(*it).toXml(false, str);
}
if (!string.isEmpty()) {
str << "</" FONTLIST_TAG ">" << Qt::endl;
rv.append(string);
}
return rv;
}
Families Folder::list()
{
Families fam(itsIsSystem);
FamilyCont::ConstIterator it(itsFonts.begin()), end(itsFonts.end());
for (int i = 0; it != end; ++it, ++i)
fam.items.insert(*it);
return fam;
}
bool Folder::contains(const QString &family, quint32 style)
{
FamilyCont::ConstIterator fam = itsFonts.find(Family(family));
if (fam == itsFonts.end())
return false;
StyleCont::ConstIterator st = (*fam).styles().find(Style(style));
return st != (*fam).styles().end();
}
void Folder::add(const Family &family)
{
FamilyCont::ConstIterator existingFamily = itsFonts.find(family);
if (existingFamily == itsFonts.end())
itsFonts.insert(family);
else {
StyleCont::ConstIterator it(family.styles().begin()), end(family.styles().end());
for (; it != end; ++it) {
StyleCont::ConstIterator existingStyle = (*existingFamily).styles().find(*it);
if (existingStyle == (*existingFamily).styles().end())
(*existingFamily).add(*it);
else {
FileCont::ConstIterator fit((*it).files().begin()), fend((*it).files().end());
for (; fit != fend; ++fit) {
FileCont::ConstIterator f = (*existingStyle).files().find(*fit);
if (f == (*existingStyle).files().end())
(*existingStyle).add(*fit);
}
(*existingStyle).setWritingSystems((*existingStyle).writingSystems() | (*it).writingSystems());
if (!(*existingStyle).scalable() && (*it).scalable())
(*existingStyle).setScalable(true);
}
}
}
}
void Folder::configure(bool force)
{
KFI_DBUG << "EMPTY MODIFIED " << itsModifiedDirs.isEmpty();
if (force || !itsModifiedDirs.isEmpty()) {
saveDisabled();
QSet<QString>::ConstIterator it(itsModifiedDirs.constBegin()), end(itsModifiedDirs.constEnd());
QSet<QString> dirs;
for (; it != end; ++it)
if (Misc::fExists((*it) + "fonts.dir"))
dirs.insert(KShell::quoteArg(*it));
if (!dirs.isEmpty())
QProcess::startDetached(QStringLiteral(KFONTINST_LIB_EXEC_DIR "/fontinst_x11"), dirs.values());
itsModifiedDirs.clear();
KFI_DBUG << "RUN FC";
Misc::doCmd("fc-cache");
KFI_DBUG << "DONE";
}
}
Folder::Flat Folder::flatten() const
{
FamilyCont::ConstIterator fam = itsFonts.begin(), famEnd = itsFonts.end();
Flat rv;
for (; fam != famEnd; ++fam) {
StyleCont::ConstIterator style((*fam).styles().begin()), styleEnd((*fam).styles().end());
for (; style != styleEnd; ++style) {
FileCont::ConstIterator file((*style).files().begin()), fileEnd((*style).files().end());
for (; file != fileEnd; ++file)
rv.insert(FlatFont(*fam, *style, *file));
}
}
return rv;
}
Families Folder::Flat::build(bool system) const
{
ConstIterator it(begin()), e(end());
Families families(system);
for (; it != e; ++it) {
Family f((*it).family);
Style s((*it).styleInfo, (*it).scalable, (*it).writingSystems);
FamilyCont::ConstIterator fam = families.items.constFind(f);
if (families.items.constEnd() == fam) {
s.add((*it).file);
f.add(s);
families.items.insert(f);
} else {
StyleCont::ConstIterator st = (*fam).styles().constFind(s);
if ((*fam).styles().constEnd() == st) {
s.add((*it).file);
(*fam).add(s);
} else
(*st).add((*it).file);
}
}
return families;
}
}