1 /************************************************************************
2 **
3 ** @file vvitconverter.cpp
4 ** @author Roman Telezhynskyi <dismine(at)gmail.com>
5 ** @date 15 7, 2015
6 **
7 ** @brief
8 ** @copyright
9 ** This source code is part of the Valentina project, a pattern making
10 ** program, whose allow create and modeling patterns of clothing.
11 ** Copyright (C) 2015 Valentina project
12 ** <https://gitlab.com/smart-pattern/valentina> All Rights Reserved.
13 **
14 ** Valentina is free software: you can redistribute it and/or modify
15 ** it under the terms of the GNU General Public License as published by
16 ** the Free Software Foundation, either version 3 of the License, or
17 ** (at your option) any later version.
18 **
19 ** Valentina is distributed in the hope that it will be useful,
20 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
21 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 ** GNU General Public License for more details.
23 **
24 ** You should have received a copy of the GNU General Public License
25 ** along with Valentina. If not, see <http://www.gnu.org/licenses/>.
26 **
27 *************************************************************************/
28
29 #include "vvitconverter.h"
30
31 #include <QDomNode>
32 #include <QDomNodeList>
33 #include <QDomText>
34 #include <QFile>
35 #include <QLatin1String>
36 #include <QList>
37 #include <QMap>
38 #include <QMultiMap>
39 #include <QStaticStringData>
40 #include <QStringData>
41 #include <QStringDataPtr>
42 #include <QGlobalStatic>
43
44 #include "../exception/vexception.h"
45 #include "../vmisc/def.h"
46 #include "vabstractmconverter.h"
47
48 /*
49 * Version rules:
50 * 1. Version have three parts "major.minor.patch";
51 * 2. major part only for stable releases;
52 * 3. minor - 10 or more patch changes, or one big change;
53 * 4. patch - little change.
54 */
55
56 const QString VVITConverter::MeasurementMinVerStr = QStringLiteral("0.2.0");
57 const QString VVITConverter::MeasurementMaxVerStr = QStringLiteral("0.5.1");
58 const QString VVITConverter::CurrentSchema = QStringLiteral("://schema/individual_measurements/v0.5.1.xsd");
59
60 //VVITConverter::MeasurementMinVer; // <== DON'T FORGET TO UPDATE TOO!!!!
61 //VVITConverter::MeasurementMaxVer; // <== DON'T FORGET TO UPDATE TOO!!!!
62
63 namespace
64 {
65 // The list of all string we use for conversion
66 // Better to use global variables because repeating QStringLiteral blows up code size
67 Q_GLOBAL_STATIC_WITH_ARGS(const QString, strTagRead_Only, (QLatin1String("read-only")))
68 Q_GLOBAL_STATIC_WITH_ARGS(const QString, strGivenName, (QLatin1String("given-name")))
69 Q_GLOBAL_STATIC_WITH_ARGS(const QString, strFamilyName, (QLatin1String("family-name")))
70 Q_GLOBAL_STATIC_WITH_ARGS(const QString, strCustomer, (QLatin1String("customer")))
71 Q_GLOBAL_STATIC_WITH_ARGS(const QString, strPersonal, (QLatin1String("personal")))
72 }
73
74 //---------------------------------------------------------------------------------------------------------------------
VVITConverter(const QString & fileName)75 VVITConverter::VVITConverter(const QString &fileName)
76 :VAbstractMConverter(fileName)
77 {
78 ValidateInputFile(CurrentSchema);
79 }
80
81 //---------------------------------------------------------------------------------------------------------------------
XSDSchema(int ver) const82 QString VVITConverter::XSDSchema(int ver) const
83 {
84 QHash <int, QString> schemas =
85 {
86 std::make_pair(FORMAT_VERSION(0, 2, 0), QStringLiteral("://schema/individual_measurements/v0.2.0.xsd")),
87 std::make_pair(FORMAT_VERSION(0, 3, 0), QStringLiteral("://schema/individual_measurements/v0.3.0.xsd")),
88 std::make_pair(FORMAT_VERSION(0, 3, 1), QStringLiteral("://schema/individual_measurements/v0.3.1.xsd")),
89 std::make_pair(FORMAT_VERSION(0, 3, 2), QStringLiteral("://schema/individual_measurements/v0.3.2.xsd")),
90 std::make_pair(FORMAT_VERSION(0, 3, 3), QStringLiteral("://schema/individual_measurements/v0.3.3.xsd")),
91 std::make_pair(FORMAT_VERSION(0, 4, 0), QStringLiteral("://schema/individual_measurements/v0.4.0.xsd")),
92 std::make_pair(FORMAT_VERSION(0, 5, 0), QStringLiteral("://schema/individual_measurements/v0.5.0.xsd")),
93 std::make_pair(FORMAT_VERSION(0, 5, 1), CurrentSchema),
94 };
95
96 if (schemas.contains(ver))
97 {
98 return schemas.value(ver);
99 }
100 else
101 {
102 InvalidVersion(ver);
103 }
104 }
105
106 //---------------------------------------------------------------------------------------------------------------------
ApplyPatches()107 void VVITConverter::ApplyPatches()
108 {
109 switch (m_ver)
110 {
111 case (FORMAT_VERSION(0, 2, 0)):
112 ToV0_3_0();
113 ValidateXML(XSDSchema(FORMAT_VERSION(0, 3, 0)));
114 Q_FALLTHROUGH();
115 case (FORMAT_VERSION(0, 3, 0)):
116 ToV0_3_1();
117 ValidateXML(XSDSchema(FORMAT_VERSION(0, 3, 1)));
118 Q_FALLTHROUGH();
119 case (FORMAT_VERSION(0, 3, 1)):
120 ToV0_3_2();
121 ValidateXML(XSDSchema(FORMAT_VERSION(0, 3, 2)));
122 Q_FALLTHROUGH();
123 case (FORMAT_VERSION(0, 3, 2)):
124 ToV0_3_3();
125 ValidateXML(XSDSchema(FORMAT_VERSION(0, 3, 3)));
126 Q_FALLTHROUGH();
127 case (FORMAT_VERSION(0, 3, 3)):
128 ToV0_4_0();
129 ValidateXML(XSDSchema(FORMAT_VERSION(0, 4, 0)));
130 Q_FALLTHROUGH();
131 case (FORMAT_VERSION(0, 4, 0)):
132 ToV0_5_0();
133 ValidateXML(XSDSchema(FORMAT_VERSION(0, 5, 0)));
134 Q_FALLTHROUGH();
135 case (FORMAT_VERSION(0, 5, 0)):
136 ToV0_5_1();
137 ValidateXML(XSDSchema(FORMAT_VERSION(0, 5, 1)));
138 Q_FALLTHROUGH();
139 case (FORMAT_VERSION(0, 5, 1)):
140 break;
141 default:
142 InvalidVersion(m_ver);
143 break;
144 }
145 }
146
147 //---------------------------------------------------------------------------------------------------------------------
DowngradeToCurrentMaxVersion()148 void VVITConverter::DowngradeToCurrentMaxVersion()
149 {
150 SetVersion(MeasurementMaxVerStr);
151 Save();
152 }
153
154 //---------------------------------------------------------------------------------------------------------------------
IsReadOnly() const155 bool VVITConverter::IsReadOnly() const
156 {
157 // Check if attribute read-only was not changed in file format
158 Q_STATIC_ASSERT_X(VVITConverter::MeasurementMaxVer == FORMAT_VERSION(0, 5, 1),
159 "Check attribute read-only.");
160
161 // Possibly in future attribute read-only will change position etc.
162 // For now position is the same for all supported format versions.
163 // But don't forget to keep all versions of attribute until we support that format versions
164
165 return UniqueTagText(*strTagRead_Only, falseStr) == trueStr;
166 }
167
168 //---------------------------------------------------------------------------------------------------------------------
AddNewTagsForV0_3_0()169 void VVITConverter::AddNewTagsForV0_3_0()
170 {
171 // TODO. Delete if minimal supported version is 0.3.0
172 Q_STATIC_ASSERT_X(VVITConverter::MeasurementMinVer < FORMAT_VERSION(0, 3, 0),
173 "Time to refactor the code.");
174
175 QDomElement rootElement = this->documentElement();
176 QDomNode refChild = rootElement.firstChildElement(QStringLiteral("version"));
177
178 refChild = rootElement.insertAfter(CreateElementWithText(QStringLiteral("read-only"), falseStr), refChild);
179 refChild = rootElement.insertAfter(createElement(QStringLiteral("notes")), refChild);
180
181 rootElement.insertAfter(CreateElementWithText(QStringLiteral("unit"), MUnitV0_2_0()), refChild);
182 }
183
184 //---------------------------------------------------------------------------------------------------------------------
MUnitV0_2_0()185 QString VVITConverter::MUnitV0_2_0()
186 {
187 // TODO. Delete if minimal supported version is 0.3.0
188 Q_STATIC_ASSERT_X(VVITConverter::MeasurementMinVer < FORMAT_VERSION(0, 3, 0),
189 "Time to refactor the code.");
190
191 return UniqueTagText(QStringLiteral("unit"), QStringLiteral("cm"));
192 }
193
194 //---------------------------------------------------------------------------------------------------------------------
ConvertMeasurementsToV0_3_0()195 void VVITConverter::ConvertMeasurementsToV0_3_0()
196 {
197 // TODO. Delete if minimal supported version is 0.3.0
198 Q_STATIC_ASSERT_X(VVITConverter::MeasurementMinVer < FORMAT_VERSION(0, 3, 0),
199 "Time to refactor the code.");
200
201 const QString tagBM = QStringLiteral("body-measurements");
202
203 QDomElement bm = createElement(tagBM);
204
205 const QMultiMap<QString, QString> names = OldNamesToNewNames_InV0_3_0();
206 const QList<QString> keys = names.uniqueKeys();
207 for (auto &key : keys)
208 {
209 qreal resValue = 0;
210
211 // This has the same effect as a .values(), just isn't as elegant
212 const QList<QString> list = names.values( key );
213 for(const auto &val : list)
214 {
215 const QDomNodeList nodeList = this->elementsByTagName(val);
216 if (nodeList.isEmpty())
217 {
218 continue;
219 }
220
221 const qreal value = GetParametrDouble(nodeList.at(0).toElement(), QStringLiteral("value"), "0.0");
222
223 if (not qFuzzyIsNull(value))
224 {
225 resValue = value;
226 }
227 }
228
229 bm.appendChild(AddMV0_3_0(key, resValue));
230 }
231
232 QDomElement rootElement = this->documentElement();
233 const QDomNodeList listBM = elementsByTagName(tagBM);
234 rootElement.replaceChild(bm, listBM.at(0));
235 }
236
237 //---------------------------------------------------------------------------------------------------------------------
AddMV0_3_0(const QString & name,qreal value)238 QDomElement VVITConverter::AddMV0_3_0(const QString &name, qreal value)
239 {
240 // TODO. Delete if minimal supported version is 0.3.0
241 Q_STATIC_ASSERT_X(VVITConverter::MeasurementMinVer < FORMAT_VERSION(0, 3, 0),
242 "Time to refactor the code.");
243
244 QDomElement element = createElement(QStringLiteral("m"));
245
246 SetAttribute(element, QStringLiteral("name"), name);
247 SetAttribute(element, QStringLiteral("value"), QString().setNum(value));
248 SetAttribute(element, QStringLiteral("description"), QString());
249 SetAttribute(element, QStringLiteral("full_name"), QString());
250
251 return element;
252 }
253
254 //---------------------------------------------------------------------------------------------------------------------
GenderV0_3_1()255 void VVITConverter::GenderV0_3_1()
256 {
257 // TODO. Delete if minimal supported version is 0.3.1
258 Q_STATIC_ASSERT_X(VVITConverter::MeasurementMinVer < FORMAT_VERSION(0, 3, 1),
259 "Time to refactor the code.");
260
261 const QDomNodeList nodeList = this->elementsByTagName(QStringLiteral("sex"));
262 QDomElement sex = nodeList.at(0).toElement();
263 QDomElement parent = sex.parentNode().toElement();
264 parent.replaceChild(CreateElementWithText(QStringLiteral("gender"), sex.text()), sex);
265 }
266
267 //---------------------------------------------------------------------------------------------------------------------
PM_SystemV0_3_2()268 void VVITConverter::PM_SystemV0_3_2()
269 {
270 // TODO. Delete if minimal supported version is 0.3.2
271 Q_STATIC_ASSERT_X(VVITConverter::MeasurementMinVer < FORMAT_VERSION(0, 3, 2),
272 "Time to refactor the code.");
273
274 const QDomNodeList nodeList = this->elementsByTagName(QStringLiteral("personal"));
275 QDomElement personal = nodeList.at(0).toElement();
276
277 QDomElement parent = personal.parentNode().toElement();
278 parent.insertBefore(CreateElementWithText(QStringLiteral("pm_system"), QStringLiteral("998")), personal);
279 }
280
281 //---------------------------------------------------------------------------------------------------------------------
ConvertMeasurementsToV0_3_3()282 void VVITConverter::ConvertMeasurementsToV0_3_3()
283 {
284 // TODO. Delete if minimal supported version is 0.3.3
285 Q_STATIC_ASSERT_X(VVITConverter::MeasurementMinVer < FORMAT_VERSION(0, 3, 3),
286 "Time to refactor the code.");
287
288 const QMap<QString, QString> names = OldNamesToNewNames_InV0_3_3();
289 auto i = names.constBegin();
290 while (i != names.constEnd())
291 {
292 const QDomNodeList nodeList = this->elementsByTagName(QStringLiteral("m"));
293 if (nodeList.isEmpty())
294 {
295 ++i;
296 continue;
297 }
298
299 for (int ii = 0; ii < nodeList.size(); ++ii)
300 {
301 const QString attrName = QStringLiteral("name");
302 QDomElement element = nodeList.at(ii).toElement();
303 const QString name = GetParametrString(element, attrName);
304 if (name == i.value())
305 {
306 SetAttribute(element, attrName, i.key());
307 }
308 }
309
310 ++i;
311 }
312 }
313
314 //---------------------------------------------------------------------------------------------------------------------
ConverCustomerNameToV0_4_0()315 void VVITConverter::ConverCustomerNameToV0_4_0()
316 {
317 // Find root tag
318 const QDomNodeList personalList = this->elementsByTagName(*strPersonal);
319 if (personalList.isEmpty())
320 {
321 return;
322 }
323
324 QDomNode personal = personalList.at(0);
325
326 // Given name
327 QString givenName;
328 const QDomNodeList givenNameList = this->elementsByTagName(*strGivenName);
329 if (not givenNameList.isEmpty())
330 {
331 QDomNode givenNameNode = givenNameList.at(0);
332 givenName = givenNameNode.toElement().text();
333 personal.removeChild(givenNameNode);
334 }
335
336 // Family name
337 QString familyName;
338 const QDomNodeList familyNameList = this->elementsByTagName(*strFamilyName);
339 if (not familyNameList.isEmpty())
340 {
341 QDomNode familyNameNode = familyNameList.at(0);
342 familyName = familyNameNode.toElement().text();
343 personal.removeChild(familyNameNode);
344 }
345
346 QString customerName;
347 if (not givenName.isEmpty() && not familyName.isEmpty())
348 {
349 customerName = givenName + QLatin1Char(' ') + familyName;
350 }
351 else if (not givenName.isEmpty() && familyName.isEmpty())
352 {
353 customerName = givenName;
354 }
355 else if (givenName.isEmpty() && not familyName.isEmpty())
356 {
357 customerName = familyName;
358 }
359
360 personal.insertBefore(CreateElementWithText(*strCustomer, not customerName.isEmpty() ? customerName : QString()),
361 personal.firstChild());
362 }
363
364 //---------------------------------------------------------------------------------------------------------------------
ToV0_3_0()365 void VVITConverter::ToV0_3_0()
366 {
367 // TODO. Delete if minimal supported version is 0.3.0
368 Q_STATIC_ASSERT_X(VVITConverter::MeasurementMinVer < FORMAT_VERSION(0, 3, 0),
369 "Time to refactor the code.");
370
371 AddRootComment();
372 SetVersion(QStringLiteral("0.3.0"));
373 AddNewTagsForV0_3_0();
374 ConvertMeasurementsToV0_3_0();
375 Save();
376 }
377
378 //---------------------------------------------------------------------------------------------------------------------
ToV0_3_1()379 void VVITConverter::ToV0_3_1()
380 {
381 // TODO. Delete if minimal supported version is 0.3.1
382 Q_STATIC_ASSERT_X(VVITConverter::MeasurementMinVer < FORMAT_VERSION(0, 3, 1),
383 "Time to refactor the code.");
384
385 SetVersion(QStringLiteral("0.3.1"));
386 GenderV0_3_1();
387 Save();
388 }
389
390 //---------------------------------------------------------------------------------------------------------------------
ToV0_3_2()391 void VVITConverter::ToV0_3_2()
392 {
393 // TODO. Delete if minimal supported version is 0.3.2
394 Q_STATIC_ASSERT_X(VVITConverter::MeasurementMinVer < FORMAT_VERSION(0, 3, 2),
395 "Time to refactor the code.");
396
397 SetVersion(QStringLiteral("0.3.2"));
398 PM_SystemV0_3_2();
399 Save();
400 }
401
402 //---------------------------------------------------------------------------------------------------------------------
ToV0_3_3()403 void VVITConverter::ToV0_3_3()
404 {
405 // TODO. Delete if minimal supported version is 0.3.3
406 Q_STATIC_ASSERT_X(VVITConverter::MeasurementMinVer < FORMAT_VERSION(0, 3, 3),
407 "Time to refactor the code.");
408
409 SetVersion(QStringLiteral("0.3.3"));
410 ConvertMeasurementsToV0_3_3();
411 Save();
412 }
413
414 //---------------------------------------------------------------------------------------------------------------------
ToV0_4_0()415 void VVITConverter::ToV0_4_0()
416 {
417 // TODO. Delete if minimal supported version is 0.4.0
418 Q_STATIC_ASSERT_X(VVITConverter::MeasurementMinVer < FORMAT_VERSION(0, 4, 0),
419 "Time to refactor the code.");
420
421 SetVersion(QStringLiteral("0.4.0"));
422 ConverCustomerNameToV0_4_0();
423 Save();
424 }
425
426 //---------------------------------------------------------------------------------------------------------------------
ToV0_5_0()427 void VVITConverter::ToV0_5_0()
428 {
429 // TODO. Delete if minimal supported version is 0.5.0
430 Q_STATIC_ASSERT_X(VVITConverter::MeasurementMinVer < FORMAT_VERSION(0, 5, 0),
431 "Time to refactor the code.");
432
433 SetVersion(QStringLiteral("0.5.0"));
434 Save();
435 }
436
437 //---------------------------------------------------------------------------------------------------------------------
ToV0_5_1()438 void VVITConverter::ToV0_5_1()
439 {
440 // TODO. Delete if minimal supported version is 0.5.1
441 Q_STATIC_ASSERT_X(VVITConverter::MeasurementMinVer < FORMAT_VERSION(0, 5, 1),
442 "Time to refactor the code.");
443
444 SetVersion(QStringLiteral("0.5.1"));
445 Save();
446 }
447