/* * KFontInst - KDE Font Installer * * Copyright 2003-2009 Craig Drummond * * ---- * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #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 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::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 << "" << 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 << "" << 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 << "" << 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::ConstIterator it(itsModifiedDirs.constBegin()), end(itsModifiedDirs.constEnd()); QSet 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; } }