1 /*
2 * Copyright (C) 2010-2015 by Stephen Allewell
3 * steve.allewell@gmail.com
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 */
10
11
12 /**
13 @file
14 Implements the scheme parser to read an XML formatted scheme file.
15 */
16
17
18 #include "SchemeParser.h"
19
20 #include <KLocalizedString>
21
22 #include "FlossScheme.h"
23 #include "Floss.h"
24
25
26 /**
27 Valid tags that can exist in the file.
28 */
29 const QStringList validTags = {
30 QStringLiteral("flossScheme"), /**< The enclosing tags for the file */
31 QStringLiteral("title"), /**< The title of the scheme */
32 QStringLiteral("floss"), /**< Enclosing tags for a floss definition */
33 QStringLiteral("name"), /**< The name of the floss */
34 QStringLiteral("description"), /**< The descriptive text for the floss */
35 QStringLiteral("color"), /**< Enclosing tags for a color definition */
36 QStringLiteral("red"), /**< Red color value */
37 QStringLiteral("green"), /**< Green color value */
38 QStringLiteral("blue") /**< Blue color value */
39 };
40
41
42 /**
43 Error messages.
44 */
45 const char *errorMessages[] = {
46 I18N_NOOP("No error"),
47 I18N_NOOP("Floss not completely defined"),
48 I18N_NOOP("Unmatched element tags"),
49 I18N_NOOP("Unknown element tag"),
50 I18N_NOOP("Color value is invalid"),
51 I18N_NOOP("Unknown error code")
52 };
53
54
55 /**
56 Constructor. Initialises pointers to 0 and set the m_errorCode value to 0.
57 */
SchemeParser()58 SchemeParser::SchemeParser()
59 : m_errorCode(0),
60 m_scheme(nullptr)
61 {
62 }
63
64
65 /**
66 Get a pointer to the read FlossScheme.
67 @return pointer to FlossScheme class.
68 */
flossScheme()69 FlossScheme *SchemeParser::flossScheme()
70 {
71 return m_scheme;
72 }
73
74
75 /**
76 Start a new XML document, creating an instance of a FlossScheme.
77 @return true if the scheme is created, false otherwise.
78 */
startDocument()79 bool SchemeParser::startDocument()
80 {
81 m_scheme = new FlossScheme;
82 return (m_scheme) ? true : false;
83 }
84
85
86 /**
87 Start a new element. Reimplemented from QXmlDefaultHandler.
88 @param namespaceURI not used
89 @param localName not used
90 @param qName name of the tag.
91 @param qxmlAttributes not used
92 @return true if the tag is valid, false otherwise.
93 */
startElement(const QString & namespaceURI,const QString & localName,const QString & qName,const QXmlAttributes & qxmlAttributes)94 bool SchemeParser::startElement(const QString &namespaceURI, const QString &localName, const QString &qName, const QXmlAttributes &qxmlAttributes)
95 {
96 Q_UNUSED(namespaceURI);
97 Q_UNUSED(localName);
98 Q_UNUSED(qxmlAttributes);
99
100 QString name = qName.simplified();
101
102 if (validTags.contains(name)) {
103 m_elements.push(name);
104 return true;
105 }
106
107 // invalid tag found
108 m_errorCode = 3;
109 return false;
110 }
111
112
113 /**
114 Process a string of characters. Reimplemented from QXmlDefaultHandler.
115 @param d QString reference of the characters read from the file.
116 @return true if the data is acceptable, false otherwise.
117 */
characters(const QString & d)118 bool SchemeParser::characters(const QString &d)
119 {
120 QString data = d.simplified();
121
122 if (data.isEmpty()) {
123 return true;
124 }
125
126 if (m_elements.top() == QLatin1String("title")) {
127 m_scheme->setSchemeName(data);
128 } else {
129 m_flossMap.insert(m_elements.top(), data);
130 }
131
132 if (m_elements.top() == QLatin1String("red") || m_elements.top() == QLatin1String("green") || m_elements.top() == QLatin1String("blue")) {
133 if (data.toInt() > 255) {
134 // color value is not valid
135 m_errorCode = 4;
136 return false;
137 }
138 }
139
140 return true;
141 }
142
143
144 /**
145 End an element. Reimplemented from QXmlDefaultHandler.
146 @param namespaceURI not used
147 @param localName not used
148 @param qName name of the tag.
149 @return true if the tag is valid, false otherwise.
150 */
endElement(const QString & namespaceURI,const QString & localName,const QString & qName)151 bool SchemeParser::endElement(const QString &namespaceURI, const QString &localName, const QString &qName)
152 {
153 Q_UNUSED(namespaceURI);
154 Q_UNUSED(localName);
155
156 QString name = qName.simplified();
157 QString s = m_elements.pop();
158
159 if (s == name) {
160 if (name == QLatin1String("floss")) {
161 if (m_flossMap.contains(QLatin1String("name")) && m_flossMap.contains(QLatin1String("description")) && m_flossMap.contains(QLatin1String("red")) && m_flossMap.contains(QLatin1String("green")) && m_flossMap.contains(QLatin1String("blue"))) {
162 m_scheme->addFloss(new Floss(m_flossMap[QLatin1String("name")], m_flossMap[QLatin1String("description")], QColor(m_flossMap[QLatin1String("red")].toInt(), m_flossMap[QLatin1String("green")].toInt(), m_flossMap[QLatin1String("blue")].toInt())));
163 m_flossMap.clear();
164 } else {
165 // not all elements defined for a floss
166 m_errorCode = 1;
167 }
168 }
169 } else
170 // mismatched tags
171 {
172 m_errorCode = 2;
173 }
174
175 if (m_errorCode) {
176 return false;
177 } else {
178 return true;
179 }
180 }
181
182
183 /**
184 Return an error string related to the last error code encountered which is stored in m_errorCode.
185 @return QString containing the error message.
186 */
errorString() const187 QString SchemeParser::errorString() const
188 {
189 return i18n(errorMessages[m_errorCode]);
190 }
191