kde-workspace/kcontrol/kfontinst/dbus/Folder.cpp
2014-11-13 19:30:51 +02:00

417 lines
12 KiB
C++

/*
* 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 <QtCore/QDir>
#include <QtCore/QFile>
#include <QtCore/QCoreApplication>
#include <QtCore/QTextStream>
#include <QtCore/QProcess>
#include <QtXml/QDomDocument>
#include <QtXml/QDomElement>
#include <QtXml/QDomNode>
#include <KDE/KStandardDirs>
#include <KDE/KSaveFile>
#include <KDE/KShell>
#include <KDE/KDebug>
#include <fontconfig/fontconfig.h>
#include "Folder.h"
#include "FcConfig.h"
#include "Misc.h"
#include "KfiConstants.h"
#include "XmlStrings.h"
#include "Style.h"
#include "File.h"
#include "config-fontinst.h"
#define DISABLED_FONTS "disabledfonts"
#define KFI_DBUG kDebug() << time(0L)
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=KGlobal::dirs()->localxdgconfdir();
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;
KSaveFile file;
file.setFileName(itsDisabledCfg.name);
if(!file.open())
{
KFI_DBUG << "Exit - cant open save file";
qApp->exit(0);
}
QTextStream str(&file);
str << "<"DISABLED_FONTS">" << endl;
FamilyCont::ConstIterator it(itsFonts.begin()),
end(itsFonts.end());
for(; it!=end; ++it)
(*it).toXml(true, str);
str << "</"DISABLED_FONTS">" << endl;
str.flush();
if(!file.finalize())
{
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">" << endl;
rv.append(string);
string=QString();
}
str << "<"FONTLIST_TAG" " << SYSTEM_ATTR"=\"" << (itsIsSystem ? "true" : "false") << "\">" << endl;
}
(*it).toXml(false, str);
}
if(!string.isEmpty())
{
str << "</"FONTLIST_TAG">" << 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(QLatin1String(KFONTINST_LIB_EXEC_DIR"/fontinst_x11"), dirs.toList());
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;
}
}