OSDN Git Service

Version 0.4.9(0.5beta)
[fontmanager/fontmanager.git] / fontsconf.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 Takumi Asaki
4 ** All rights reserved.
5 ** Contact: Takumi Asaki (takumi.asaki@gmail.com)
6 **
7 ** This file is part of the fontmanager application.
8 **
9 ** You may use this file under the terms of the BSD license as follows:
10 **
11 ** "Redistribution and use in source and binary forms, with or without
12 ** modification, are permitted provided that the following conditions are
13 ** met:
14 **   * Redistributions of source code must retain the above copyright
15 **     notice, this list of conditions and the following disclaimer.
16 **   * Redistributions in binary form must reproduce the above copyright
17 **     notice, this list of conditions and the following disclaimer in
18 **     the documentation and/or other materials provided with the
19 **     distribution.
20 **   * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
21 **     the names of its contributors may be used to endorse or promote
22 **     products derived from this software without specific prior written
23 **     permission.
24 **
25 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28 ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31 ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35 ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
36 **
37 ****************************************************************************/
38
39 #include "fontsconf.h"
40
41 #include "fontconfigdefs.h"
42 #include "fontsconfelement.h"
43
44 #include <QFile>
45 #include <QTextStream>
46 #include <QXmlStreamReader>
47
48 enum FCState {
49     Initialized, Ready, InvalidConfig, UnknownState
50 };
51
52 static inline QString boolString(bool val)
53 {
54     return val ? TRUE_DEF : FALSE_DEF;
55 }
56
57 FontsConf::FontsConf(QObject *parent) :
58     QObject(parent), mModified(false), mValid(true), mHasUnknownConfig(false)
59 {
60     initFontsConf();
61 }
62
63 bool FontsConf::isEmpty() const
64 {
65     return !mElements || (mElements->count() == 0);
66 }
67
68 bool FontsConf::modified() const
69 {
70     return mModified;
71 }
72
73 void FontsConf::setModified(bool value)
74 {
75     mModified = value;
76 }
77
78 bool FontsConf::hasUnknownConfig() const
79 {
80     return mHasUnknownConfig;
81 }
82
83 bool FontsConf::isValid() const
84 {
85     return mValid;
86 }
87
88 void FontsConf::initFontsConf()
89 {
90     if (mElements)
91         mModified = true;
92     FontsConfElementPointer rootElem(new FontsConfElement(FONTCONFIG_DEF, this));
93     mElements = rootElem;
94 }
95
96 bool FontsConf::parse(const QByteArray &buf)
97 {
98     if (buf.isEmpty())
99         return true;
100
101     QXmlStreamReader xml(buf);
102
103     FCState state = Initialized;
104
105     bool hasUnknownConfig = false;
106
107     FontsConfElementPointer elem;
108     while (!xml.atEnd()) {
109         QXmlStreamReader::TokenType token = xml.readNext();
110         if (token == QXmlStreamReader::DTD) {
111             if (xml.dtdName() != FONTCONFIG_DEF || xml.dtdSystemId() != "fonts.dtd") {
112                 state = InvalidConfig;
113             }
114         } else if (token == QXmlStreamReader::StartElement) {
115             QString elemName(xml.name().toString());
116             switch (state) {
117             case Initialized:
118                 if (elemName == FONTCONFIG_DEF) {
119                     state = Ready;
120                     elem = FontsConfElementPointer(new FontsConfElement(elemName, this));
121                     bool check = elem->parse(xml);
122                     if (!check)
123                         state = UnknownState;
124                 } else
125                     state = InvalidConfig;
126                 break;
127
128             default:
129                 ;
130             }
131         } else if (token == QXmlStreamReader::EndElement) {
132             QString elemName(xml.name().toString());
133         }
134
135         if (state == InvalidConfig)
136             qDebug("Invalid Config!!!");
137
138         if (state == InvalidConfig)
139             break;
140         else if (state == UnknownState)
141             hasUnknownConfig = true;
142     }
143
144     if (xml.error() != QXmlStreamReader::NoError)
145         state = InvalidConfig;
146
147     if (state == Ready) {
148         mElements = elem;
149         mModified = false;
150         mHasUnknownConfig = hasUnknownConfig;
151     }
152
153     return !(state == InvalidConfig);
154 }
155
156 QStringList FontsConf::preferFamily() const
157 {
158     if (!mElements)
159         return QStringList();
160
161     QStringList familyList;
162
163     int index = 0;
164     while ((index = mElements->indexOf(ALIAS_DEF, index)) >= 0) {
165         FontsConfElementPointer aliasElem = mElements->childElementAt(index++);
166         FontsConfElementPointer familyElem = aliasElem->childElementOf(FAMILY_DEF);
167         if (!familyElem || familyElem->text().isEmpty())
168             continue;
169         familyList << familyElem->text();
170     }
171     //    familyList.removeDuplicates();
172     return familyList;
173 }
174
175 QStringList FontsConf::aliasFamilyFor(const QString &family, const QString &mode) const
176 {
177     int index = 0;
178     while ((index = mElements->indexOf(ALIAS_DEF, index)) >= 0) {
179         FontsConfElementPointer aliasElem = mElements->childElementAt(index++);
180         FontsConfElementPointer familyElem = aliasElem->childElementOf(FAMILY_DEF);
181         if (!familyElem)
182             continue;
183         if (familyElem->text() != family)
184             continue;
185         FontsConfElementPointer targetElem = aliasElem->childElementOf(mode);
186         if (!targetElem)
187             return QStringList();
188         QStringList familyList = textElementList(targetElem, FAMILY_DEF);
189         return familyList;
190     }
191
192     return QStringList();
193 }
194
195 void FontsConf::appendAliasFamilyFor(const QString &family, const QString &mode, const QString &value)
196 {
197     int index = 0;
198     while ((index = mElements->indexOf(ALIAS_DEF, index)) >= 0) {
199         FontsConfElementPointer aliasElem = mElements->childElementAt(index++);
200         bool check = appendFamilyToAlias(aliasElem, family, mode, value);
201         if (check)
202             return;
203     }
204
205     FontsConfElementPointer aliasElem = aliasElementFor(family);
206     mElements->addChildElement(aliasElem);
207     bool check = appendFamilyToAlias(aliasElem, family, mode, value);
208     Q_ASSERT(check);
209 }
210
211 void FontsConf::insertAliasFamilyFor(const QString &family, const QString &mode, const QString &value, int idx)
212 {
213     int index = 0;
214     while ((index = mElements->indexOf(ALIAS_DEF, index)) >= 0) {
215         FontsConfElementPointer aliasElem = mElements->childElementAt(index++);
216         bool check = insertFamilyToAlias(aliasElem, family, mode, value, idx);
217         if (check)
218             return;
219     }
220
221     FontsConfElementPointer aliasElem = aliasElementFor(family);
222     mElements->addChildElement(aliasElem);
223     bool check = appendFamilyToAlias(aliasElem, family, mode, value);
224     Q_ASSERT(check);
225 }
226
227 void FontsConf::removeAliasFamilyFor(const QString &family, const QString &mode, const QString &value)
228 {
229     int index = 0;
230     while ((index = mElements->indexOf(ALIAS_DEF, index)) >= 0) {
231         FontsConfElementPointer aliasElem = mElements->childElementAt(index++);
232
233         FontsConfElementPointer familyElem = aliasElem->childElementOf(FAMILY_DEF);
234         if (!familyElem || familyElem->text() != family)
235             continue;
236
237         FontsConfElementPointer targetElem = aliasElem->childElementOf(mode);
238         if (!targetElem || targetElem->count() == 0)
239             continue;
240
241         int findex = 0;
242         while ((findex = targetElem->indexOf(FAMILY_DEF, findex)) >= 0) {
243             if (targetElem->childElementAt(findex)->text() == value) {
244                 targetElem->removeAt(findex);
245                 mModified = true;
246                 continue;
247             }
248             findex++;
249         }
250
251         if (targetElem->count() == 0) {
252             aliasElem->removeOne(targetElem);
253             if (aliasElem->count() == 1) {
254                 mElements->removeOne(aliasElem);
255             }
256         }
257     }
258 }
259
260 QStringList FontsConf::preferFamilyFor(const QString &family) const
261 {
262     return aliasFamilyFor(family, PREFER_DEF);
263 }
264
265 void FontsConf::appendPreferFamilyFor(const QString &family, const QString &value)
266 {
267     appendAliasFamilyFor(family, PREFER_DEF, value);
268 }
269
270 void FontsConf::insertPreferFamilyFor(const QString &family, const QString &value, int index)
271 {
272     insertAliasFamilyFor(family, PREFER_DEF, value, index);
273 }
274
275 void FontsConf::removePreferFamilyFor(const QString &family, const QString &value)
276 {
277     removeAliasFamilyFor(family, PREFER_DEF, value);
278 }
279
280 QStringList FontsConf::acceptFamilyFor(const QString &family) const
281 {
282     return aliasFamilyFor(family, ACCEPT_DEF);
283 }
284
285 void FontsConf::appendAcceptFamilyFor(const QString &family, const QString &value)
286 {
287     appendAliasFamilyFor(family, ACCEPT_DEF, value);
288 }
289
290 void FontsConf::insertAcceptFamilyFor(const QString &family, const QString &value, int index)
291 {
292     insertAliasFamilyFor(family, ACCEPT_DEF, value, index);
293 }
294
295 void FontsConf::removeAcceptFamilyFor(const QString &family, const QString &value)
296 {
297     removeAliasFamilyFor(family, ACCEPT_DEF, value);
298 }
299
300 QStringList FontsConf::matchFamilyFor(const QString &config, bool val) const
301 {
302     int index = 0;
303     while ((index = mElements->indexOf(MATCH_DEF, index)) >= 0) {
304         FontsConfElementPointer matchElem = mElements->childElementAt(index++);
305
306         bool check = isMatchElementFor(matchElem, config, QString(), boolString(val));
307         if (!check)
308             continue;
309
310         FontsConfElementPointer testElem = matchElem->childElementOf(TEST_DEF);
311         if (!testElem)
312             continue;
313
314         QStringList familyList = textElementList(testElem, STRING_DEF);
315         return familyList;
316     }
317
318     return QStringList();
319 }
320
321 QString FontsConf::matchEditValueFor(const QString &config, const QString &family) const
322 {
323     int index = 0;
324     while ((index = mElements->indexOf(MATCH_DEF, index)) >= 0) {
325         FontsConfElementPointer matchElem = mElements->childElementAt(index++);
326
327         bool check = isMatchElementFor(matchElem, config, family);
328         if (!check)
329             continue;
330
331         FontsConfElementPointer editElem = matchElem->childElementOf(EDIT_DEF);
332         if (!editElem)
333             continue;
334
335         FontsConfElementPointer boolElem = editElem->childElementOf(BOOL_DEF);
336         if (!boolElem)
337             continue;
338
339         return boolElem->text();
340     }
341
342     return QString();
343 }
344
345 void FontsConf::setMatchEditValueFor(const QString &config, const QString &family, bool val)
346 {
347     FontsConfElementPointer matchElem;
348     int index = 0;
349     while ((index = mElements->indexOf(MATCH_DEF, index)) >= 0) {
350         FontsConfElementPointer elem = mElements->childElementAt(index++);
351         bool check = isMatchElementFor(elem, config, QString(), boolString(val));
352         if (check) {
353             matchElem = elem;
354             break;
355         }
356     }
357
358     if (!matchElem) {
359         matchElem = matchElementFor(config, val);
360         mElements->addChildElement(matchElem);
361         mModified = true;
362     }
363
364     FontsConfElementPointer testElem = matchElem->childElementOf(TEST_DEF);
365     QStringList familyList = textElementList(testElem, STRING_DEF);
366     if (familyList.contains(family))
367         return;
368
369     FontsConfElementPointer stringElem(new FontsConfElement(STRING_DEF));
370     stringElem->setText(family);
371     testElem->addChildElement(stringElem);
372     mModified = true;
373 }
374
375 void FontsConf::unsetMatchEditValueFor(const QString &config, const QString &family)
376 {
377     int index = 0;
378     while ((index = mElements->indexOf(MATCH_DEF, index)) >= 0) {
379         FontsConfElementPointer matchElem = mElements->childElementAt(index++);
380
381         bool check = isMatchElementFor(matchElem, config, family);
382         if (!check)
383             continue;
384
385         FontsConfElementPointer testElem = matchElem->childElementOf(TEST_DEF);
386         int sindex = 0;
387         while ((sindex = testElem->indexOf(STRING_DEF, sindex)) >= 0) {
388             FontsConfElementPointer stringElem = testElem->childElementAt(sindex++);
389             if (stringElem->text() == family) {
390                 testElem->removeAt(--sindex);
391                 mModified = true;
392             }
393         }
394
395         if (testElem->count() == 0) {
396             mElements->removeAt(--index);
397         }
398
399     }
400 }
401
402 QStringList FontsConf::patternFamilyFor(const QString &family, const QString &mode) const
403 {
404     int index = 0;
405     while ((index = mElements->indexOf(MATCH_DEF, index)) >= 0) {
406         FontsConfElementPointer matchElem = mElements->childElementAt(index++);
407         bool check = isPatternElementFor(matchElem, family, mode);
408         if (!check)
409             continue;
410         FontsConfElementPointer editElem = getEditPatternElementFor(matchElem, family, mode);
411         return textElementList(editElem, STRING_DEF);
412     }
413     return QStringList();
414 }
415
416 void FontsConf::appendPatternFamilyFor(const QString &family, const QString &mode, const QString &value)
417 {
418     insertPatternFamilyFor(family, mode, value, -1);
419 }
420
421 void FontsConf::insertPatternFamilyFor(const QString &family, const QString &mode, const QString &value, int idx)
422 {
423     FontsConfElementPointer matchElem;
424
425     int index = 0;
426     while ((index = mElements->indexOf(MATCH_DEF, index)) >= 0) {
427         FontsConfElementPointer elem = mElements->childElementAt(index++);
428         bool check = isPatternElementFor(elem, family, mode);
429         if (check) {
430             matchElem = elem;
431             break;
432         }
433     }
434
435     if (!matchElem) {
436         int index = 0;
437         while ((index = mElements->indexOf(MATCH_DEF, index)) >= 0) {
438             FontsConfElementPointer elem = mElements->childElementAt(index++);
439             bool check = isPatternElementFor(elem, family);
440             if (check) {
441                 matchElem = elem;
442                 break;
443             }
444         }
445     }
446
447     if (!matchElem) {
448         matchElem = patternElementFor(family);
449         mElements->addChildElement(matchElem);
450         mModified = true;
451     }
452
453     FontsConfElementPointer editElem = getEditPatternElementFor(matchElem, family, mode);
454     if (!editElem) {
455         editElem = FontsConfElementPointer(new FontsConfElement(EDIT_DEF));
456         editElem->setAttribute(NAME_DEF, FAMILY_DEF);
457         editElem->setAttribute(MODE_DEF, mode);
458         editElem->setAttribute(BINDING_DEF, STRONG_DEF);
459         matchElem->addChildElement(editElem);
460         mModified = true;
461     }
462
463     QStringList familyList = textElementList(editElem, STRING_DEF);
464     if (familyList.contains(value))
465         return;
466
467     FontsConfElementPointer stringElem(new FontsConfElement(STRING_DEF));
468     stringElem->setText(value);
469     if (idx < 0)
470         editElem->addChildElement(stringElem);
471     else
472         editElem->insertChildElement(stringElem, idx);
473     mModified = true;
474 }
475
476 void FontsConf::removePatternFamilyFor(const QString &family, const QString &mode, const QString &value)
477 {
478     FontsConfElementPointer matchElem;
479
480     int index = 0;
481     while ((index = mElements->indexOf(MATCH_DEF, index)) >= 0) {
482         FontsConfElementPointer elem = mElements->childElementAt(index++);
483         bool check = isPatternElementFor(elem, family, mode);
484         if (check) {
485             matchElem = elem;
486             break;
487         }
488     }
489
490     if (!matchElem)
491         return;
492
493     FontsConfElementPointer editElem = getEditPatternElementFor(matchElem, family, mode);
494     if (!editElem)
495         return;
496
497     int sindex = 0;
498     while ((sindex = editElem->indexOf(STRING_DEF, sindex)) >= 0) {
499         FontsConfElementPointer stringElem = editElem->childElementAt(sindex++);
500         if (stringElem->text() == value) {
501             editElem->removeAt(--sindex);
502             mModified = true;
503         }
504     }
505
506     if (editElem->count() == 0) {
507         mModified = true;
508         matchElem->removeOne(editElem);
509         FontsConfElementList editElemList = matchElem->findChildrenElements(EDIT_DEF);
510         if (editElemList.isEmpty())
511             mElements->removeOne(matchElem);
512     }
513
514 }
515
516 QStringList FontsConf::prependFamilyFor(const QString &family) const
517 {
518     return patternFamilyFor(family, PREPEND_DEF);
519 }
520
521 void FontsConf::appendPrependFamilyFor(const QString &family, const QString &value)
522 {
523     appendPatternFamilyFor(family, PREPEND_DEF, value);
524 }
525
526 void FontsConf::insertPrependFamilyFor(const QString &family, const QString &value, int index)
527 {
528     insertPatternFamilyFor(family, PREPEND_DEF, value, index);
529 }
530
531 void FontsConf::removePrependFamilyFor(const QString &family, const QString &value)
532 {
533     removePatternFamilyFor(family, PREPEND_DEF, value);
534 }
535
536 QStringList FontsConf::appendFamilyFor(const QString &family) const
537 {
538     return patternFamilyFor(family, APPEND_DEF);
539 }
540
541 void FontsConf::appendAppendFamilyFor(const QString &family, const QString &value)
542 {
543     appendPatternFamilyFor(family, APPEND_DEF, value);
544 }
545
546 void FontsConf::insertAppendFamilyFor(const QString &family, const QString &value, int index)
547 {
548     insertPatternFamilyFor(family, APPEND_DEF, value, index);
549 }
550
551 void FontsConf::removeAppendFamilyFor(const QString &family, const QString &value)
552 {
553     removePatternFamilyFor(family, APPEND_DEF, value);
554 }
555
556 void FontsConf::copy(FontsConf *src)
557 {
558     mModified = true;
559     mValid = src->mValid;
560     mHasUnknownConfig = src->mHasUnknownConfig;
561     mElements = src->mElements;
562 }
563
564 QStringList FontsConf::genericFamilies()
565 {
566     static QStringList families;
567     if (families.isEmpty())
568         families << SANSSERIF_DEF << SERIF_DEF << MONOSPACE_DEF << SYSTEM_DEF;
569     return families;
570 }
571
572 QStringList FontsConf::configKeys()
573 {
574     static QStringList keys;
575     if (keys.isEmpty())
576         keys << EMBEDDEDBITMAP_DEF << HINTING_DEF << ANTIALIAS_DEF << AUTOHINT_DEF;
577     return keys;
578 }
579
580 void FontsConf::load(const QString &path)
581 {
582     QFile fp(path);
583     if (!fp.exists())
584         return;
585
586     fp.open(QIODevice::ReadOnly);
587     if (!fp.isOpen() || fp.error() != QFile::NoError)
588         return;
589
590     QByteArray buf = fp.readAll();
591
592     fp.close();
593
594     mValid = parse(buf);
595 }
596
597 void FontsConf::save(const QString &path)
598 {
599 #if 0
600     if (!mElements && fp.exists()) {
601         fp.remove();
602         return;
603     }
604 #endif
605
606     QString buf;
607     QXmlStreamWriter xml(&buf);
608
609     xml.setAutoFormatting(true);
610     xml.setAutoFormattingIndent(8);
611
612     xml.writeStartDocument();
613
614     xml.writeDTD("<!DOCTYPE fontconfig SYSTEM 'fonts.dtd'>");
615
616     if (mElements)
617         mElements->save(xml);
618
619     xml.writeEndDocument();
620
621     QFile fp(path);
622     fp.open(QIODevice::WriteOnly);
623     if (!fp.isOpen())
624         return;
625
626     QTextStream ts(&fp);
627     ts.setCodec("UTF-8");
628     ts << buf;
629
630     mModified = false;
631
632     fp.close();
633 }
634
635 bool FontsConf::appendFamilyToAlias(FontsConfElementPointer aliasElem, const QString &family, const QString &mode, const QString &value)
636 {
637     return insertFamilyToAlias(aliasElem, family, mode, value, -1);
638 }
639
640 bool FontsConf::insertFamilyToAlias(FontsConfElementPointer aliasElem, const QString &family, const QString &mode, const QString &value, int index)
641 {
642     if (aliasElem->type() != ALIAS_DEF)
643         return false;
644
645     FontsConfElementPointer familyElem = aliasElem->childElementOf(FAMILY_DEF);
646     if (!familyElem || familyElem->text() != family)
647         return false;
648
649     FontsConfElementPointer targetElem = aliasElem->childElementOf(mode);
650     if (!targetElem) {
651         targetElem = FontsConfElementPointer(new FontsConfElement(mode));
652         aliasElem->addChildElement(targetElem);
653         mModified = true;
654     }
655
656     int findex = 0;
657     while ((findex = targetElem->indexOf(FAMILY_DEF, findex)) >= 0) {
658         if (targetElem->childElementAt(findex)->text() == value)
659             return true;
660         findex++;
661     }
662
663     FontsConfElementPointer valueElem(new FontsConfElement(FAMILY_DEF));
664     valueElem->setText(value);
665     if (index < 0)
666         targetElem->addChildElement(valueElem);
667     else
668         targetElem->insertChildElement(valueElem, index);
669     mModified = true;
670
671     return true;
672 }
673
674 bool FontsConf::isMatchElementFor(FontsConfElementPointer matchElem, const QString &config, const QString &family, const QString &val) const
675 {
676     if (!matchElem->hasAttribute(TARGET_DEF) || matchElem->value(TARGET_DEF) != FONT_DEF)
677         return false;
678
679     FontsConfElementList testElemList = matchElem->findChildrenElements(TEST_DEF);
680     if (testElemList.count() != 1)
681         return false;
682
683     FontsConfElementPointer testElem = testElemList.at(0);
684     if (!testElem->hasAttribute(NAME_DEF) || testElem->value(NAME_DEF) != FAMILY_DEF)
685         return false;
686     if ((testElem->hasAttribute(QUAL_DEF) && testElem->value(QUAL_DEF) != ANY_DEF) ||
687             (testElem->hasAttribute(COMPARE_DEF) && testElem->value(COMPARE_DEF) != EQ_DEF) ||
688             (testElem->hasAttribute(TARGET_DEF) && testElem->value(TARGET_DEF) != DEFAULT_DEF))
689         return false;
690
691     if (!family.isEmpty()) {
692         if (testElem->count() == 0 && testElem->text() != family)
693             return false;
694         QStringList familyList = textElementList(testElem, STRING_DEF);
695         if (!familyList.contains(family))
696             return false;
697     }
698
699     FontsConfElementList editElemList = matchElem->findChildrenElements(EDIT_DEF);
700     if (editElemList.count() != 1)
701         return false;
702
703     FontsConfElementPointer editElem = editElemList.at(0);
704     if ((!editElem->hasAttribute(NAME_DEF) || editElem->value(NAME_DEF) != config) ||
705             (editElem->hasAttribute(MODE_DEF) && editElem->value(MODE_DEF) != ASSIGN_DEF))
706         return false;
707
708     FontsConfElementList boolElemList = editElem->findChildrenElements(BOOL_DEF);
709     if (boolElemList.count() != 1) {
710         return false;
711     }
712
713     if (!val.isEmpty()) {
714         FontsConfElementPointer boolElem = boolElemList.at(0);
715         if (boolElem->text() != val)
716             return false;
717     }
718
719     return true;
720 }
721
722 bool FontsConf::isPatternElementFor(FontsConfElementPointer matchElem, const QString &family, const QString &mode) const
723 {
724     if (matchElem->hasAttribute(TARGET_DEF) && matchElem->value(TARGET_DEF) != PATTERN_DEF)
725         return false;
726
727     FontsConfElementList testElemList = matchElem->findChildrenElements(TEST_DEF);
728     if (testElemList.count() != 1)
729         return false;
730
731     FontsConfElementPointer testElem = testElemList.at(0);
732     if (testElem->hasAttribute(NAME_DEF) && testElem->value(NAME_DEF) != FAMILY_DEF)
733         return false;
734     if ((testElem->hasAttribute(COMPARE_DEF) && testElem->value(COMPARE_DEF) != EQ_DEF) ||
735             (testElem->hasAttribute(TARGET_DEF) && testElem->value(TARGET_DEF) != DEFAULT_DEF))
736         return false;
737
738     if (testElem->count() == 0) {
739         if (testElem->text().isEmpty() || testElem->text() != family)
740             return false;
741     } else {
742         QStringList familyList = textElementList(testElem, STRING_DEF);
743         if (familyList.count() != 1 || !familyList.contains(family))
744             return false;
745     }
746
747     if (mode.isEmpty())
748         return true;
749
750     int eindex = 0;
751     while ((eindex = matchElem->indexOf(EDIT_DEF, eindex)) >= 0) {
752         FontsConfElementPointer editElem = matchElem->childElementAt(eindex++);
753
754         if ((editElem->hasAttribute(NAME_DEF) && editElem->value(NAME_DEF) == FAMILY_DEF) &&
755                 (editElem->hasAttribute(MODE_DEF) && editElem->value(MODE_DEF) == mode))
756             return true;
757
758     }
759
760     return false;
761 }
762
763 FontsConfElementPointer FontsConf::getEditPatternElementFor(FontsConfElementPointer matchElem, const QString &family, const QString &mode) const
764 {
765     Q_UNUSED(family);
766     int eindex = 0;
767     while ((eindex = matchElem->indexOf(EDIT_DEF, eindex)) >= 0) {
768         FontsConfElementPointer editElem = matchElem->childElementAt(eindex++);
769
770         if ((editElem->hasAttribute(NAME_DEF) && editElem->value(NAME_DEF) == FAMILY_DEF) &&
771                 (editElem->hasAttribute(MODE_DEF) && editElem->value(MODE_DEF) == mode))
772             return editElem;
773     }
774     return FontsConfElementPointer();
775 }
776
777 bool FontsConf::containsTextElement(FontsConfElementPointer elem, const QString &tag, const QString &text) const
778 {
779     int index = 0;
780     while ((index = elem->indexOf(tag, index)) >= 0) {
781         FontsConfElementPointer e = elem->childElementAt(index++);
782         if (e->text() == text)
783             return true;
784     }
785     return false;
786 }
787
788 QStringList FontsConf::textElementList(FontsConfElementPointer elem, const QString &tag) const
789 {
790     if (!elem)
791         return QStringList();
792     QStringList list;
793     int index = 0;
794     while ((index = elem->indexOf(tag, index)) >= 0) {
795         FontsConfElementPointer e = elem->childElementAt(index++);
796         if (!e->text().isEmpty())
797             list << e->text();
798     }
799     return list;
800 }
801
802 FontsConfElementPointer FontsConf::aliasElementFor(const QString &family) const
803 {
804     FontsConfElementPointer aliasElem(new FontsConfElement(ALIAS_DEF));
805     FontsConfElementPointer familyElem(new FontsConfElement(FAMILY_DEF));
806     familyElem->setText(family);
807     aliasElem->addChildElement(familyElem);
808     return aliasElem;
809 }
810
811 FontsConfElementPointer FontsConf::matchElementFor(const QString &config, bool val) const
812 {
813     FontsConfElementPointer matchElem = FontsConfElementPointer(new FontsConfElement(MATCH_DEF));
814     matchElem->setAttribute(TARGET_DEF, FONT_DEF);
815
816     FontsConfElementPointer testElem(new FontsConfElement(TEST_DEF));
817     testElem->setAttribute(QUAL_DEF, ANY_DEF);
818     testElem->setAttribute(NAME_DEF, FAMILY_DEF);
819     matchElem->addChildElement(testElem);
820
821     FontsConfElementPointer editElem(new FontsConfElement(EDIT_DEF));
822     editElem->setAttribute(NAME_DEF, config);
823     editElem->setAttribute(MODE_DEF, ASSIGN_DEF);
824     matchElem->addChildElement(editElem);
825
826     FontsConfElementPointer boolElem(new FontsConfElement(BOOL_DEF));
827     boolElem->setText(boolString(val));
828     editElem->addChildElement(boolElem);
829
830     return matchElem;
831 }
832
833 FontsConfElementPointer FontsConf::patternElementFor(const QString &family) const
834 {
835     FontsConfElementPointer matchElem = FontsConfElementPointer(new FontsConfElement(MATCH_DEF));
836     matchElem->setAttribute(TARGET_DEF, PATTERN_DEF);
837
838     FontsConfElementPointer testElem(new FontsConfElement(TEST_DEF));
839     testElem->setAttribute(QUAL_DEF, ANY_DEF);
840     testElem->setAttribute(NAME_DEF, FAMILY_DEF);
841     matchElem->addChildElement(testElem);
842
843     FontsConfElementPointer stringElem(new FontsConfElement(STRING_DEF));
844     stringElem->setText(family);
845     testElem->addChildElement(stringElem);
846
847     return matchElem;
848 }