1 /************************************************************************
2 **
3 ** @file VVSTConverter.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 "vvstconverter.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 VVSTConverter::MeasurementMinVerStr = QStringLiteral("0.3.0");
57 const QString VVSTConverter::MeasurementMaxVerStr = QStringLiteral("0.5.1");
58 const QString VVSTConverter::CurrentSchema = QStringLiteral("://schema/multisize_measurements/v0.5.1.xsd");
59
60 //VVSTConverter::MeasurementMinVer; // <== DON'T FORGET TO UPDATE TOO!!!!
61 //VVSTConverter::MeasurementMaxVer; // <== DON'T FORGET TO UPDATE TOO!!!!
62
63 namespace
64 {
65 Q_GLOBAL_STATIC_WITH_ARGS(const QString, strTagRead_Only, (QLatin1String("read-only")))
66 }
67
68 //---------------------------------------------------------------------------------------------------------------------
VVSTConverter(const QString & fileName)69 VVSTConverter::VVSTConverter(const QString &fileName)
70 :VAbstractMConverter(fileName)
71 {
72 ValidateInputFile(CurrentSchema);
73 }
74
75 //---------------------------------------------------------------------------------------------------------------------
XSDSchema(int ver) const76 QString VVSTConverter::XSDSchema(int ver) const
77 {
78 QHash <int, QString> schemas =
79 {
80 std::make_pair(FORMAT_VERSION(0, 3, 0), QStringLiteral("://schema/multisize_measurements/v0.3.0.xsd")),
81 std::make_pair(FORMAT_VERSION(0, 4, 0), QStringLiteral("://schema/multisize_measurements/v0.4.0.xsd")),
82 std::make_pair(FORMAT_VERSION(0, 4, 1), QStringLiteral("://schema/multisize_measurements/v0.4.1.xsd")),
83 std::make_pair(FORMAT_VERSION(0, 4, 2), QStringLiteral("://schema/multisize_measurements/v0.4.2.xsd")),
84 std::make_pair(FORMAT_VERSION(0, 4, 3), QStringLiteral("://schema/multisize_measurements/v0.4.3.xsd")),
85 std::make_pair(FORMAT_VERSION(0, 4, 4), QStringLiteral("://schema/multisize_measurements/v0.4.4.xsd")),
86 std::make_pair(FORMAT_VERSION(0, 5, 0), QStringLiteral("://schema/multisize_measurements/v0.5.0.xsd")),
87 std::make_pair(FORMAT_VERSION(0, 5, 1), CurrentSchema),
88 };
89
90 if (schemas.contains(ver))
91 {
92 return schemas.value(ver);
93 }
94 else
95 {
96 InvalidVersion(ver);
97 }
98 }
99
100 //---------------------------------------------------------------------------------------------------------------------
ApplyPatches()101 void VVSTConverter::ApplyPatches()
102 {
103 switch (m_ver)
104 {
105 case (FORMAT_VERSION(0, 3, 0)):
106 ToV0_4_0();
107 ValidateXML(XSDSchema(FORMAT_VERSION(0, 4, 0)));
108 Q_FALLTHROUGH();
109 case (FORMAT_VERSION(0, 4, 0)):
110 ToV0_4_1();
111 ValidateXML(XSDSchema(FORMAT_VERSION(0, 4, 1)));
112 Q_FALLTHROUGH();
113 case (FORMAT_VERSION(0, 4, 1)):
114 ToV0_4_2();
115 ValidateXML(XSDSchema(FORMAT_VERSION(0, 4, 2)));
116 Q_FALLTHROUGH();
117 case (FORMAT_VERSION(0, 4, 2)):
118 ToV0_4_3();
119 ValidateXML(XSDSchema(FORMAT_VERSION(0, 4, 3)));
120 Q_FALLTHROUGH();
121 case (FORMAT_VERSION(0, 4, 3)):
122 ToV0_4_4();
123 ValidateXML(XSDSchema(FORMAT_VERSION(0, 4, 4)));
124 Q_FALLTHROUGH();
125 case (FORMAT_VERSION(0, 4, 4)):
126 ToV0_5_0();
127 ValidateXML(XSDSchema(FORMAT_VERSION(0, 5, 0)));
128 Q_FALLTHROUGH();
129 case (FORMAT_VERSION(0, 5, 0)):
130 ToV0_5_1();
131 ValidateXML(XSDSchema(FORMAT_VERSION(0, 5, 1)));
132 Q_FALLTHROUGH();
133 case (FORMAT_VERSION(0, 5, 1)):
134 break;
135 default:
136 InvalidVersion(m_ver);
137 break;
138 }
139 }
140
141 //---------------------------------------------------------------------------------------------------------------------
DowngradeToCurrentMaxVersion()142 void VVSTConverter::DowngradeToCurrentMaxVersion()
143 {
144 SetVersion(MeasurementMaxVerStr);
145 Save();
146 }
147
148 //---------------------------------------------------------------------------------------------------------------------
IsReadOnly() const149 bool VVSTConverter::IsReadOnly() const
150 {
151 // Check if attribute read-only was not changed in file format
152 Q_STATIC_ASSERT_X(VVSTConverter::MeasurementMaxVer == FORMAT_VERSION(0, 5, 1),
153 "Check attribute read-only.");
154
155 // Possibly in future attribute read-only will change position etc.
156 // For now position is the same for all supported format versions.
157 // But don't forget to keep all versions of attribute until we support that format versions
158
159 return UniqueTagText(*strTagRead_Only, falseStr) == trueStr;
160 }
161
162 //---------------------------------------------------------------------------------------------------------------------
AddNewTagsForV0_4_0()163 void VVSTConverter::AddNewTagsForV0_4_0()
164 {
165 // TODO. Delete if minimal supported version is 0.4.0
166 Q_STATIC_ASSERT_X(VVSTConverter::MeasurementMinVer < FORMAT_VERSION(0, 4, 0),
167 "Time to refactor the code.");
168
169 QDomElement rootElement = this->documentElement();
170 QDomNode refChild = rootElement.firstChildElement(QStringLiteral("version"));
171
172 refChild = rootElement.insertAfter(CreateElementWithText(QStringLiteral("read-only"), falseStr), refChild);
173
174 rootElement.insertAfter(CreateElementWithText(QStringLiteral("notes"),
175 UniqueTagText(QStringLiteral("description"))), refChild);
176 }
177
178 //---------------------------------------------------------------------------------------------------------------------
RemoveTagsForV0_4_0()179 void VVSTConverter::RemoveTagsForV0_4_0()
180 {
181 // TODO. Delete if minimal supported version is 0.4.0
182 Q_STATIC_ASSERT_X(VVSTConverter::MeasurementMinVer < FORMAT_VERSION(0, 4, 0),
183 "Time to refactor the code.");
184
185 QDomElement rootElement = this->documentElement();
186
187 {
188 const QDomNodeList nodeList = this->elementsByTagName(QStringLiteral("description"));
189 if (not nodeList.isEmpty())
190 {
191 rootElement.removeChild(nodeList.at(0));
192 }
193 }
194
195 {
196 const QDomNodeList nodeList = this->elementsByTagName(QStringLiteral("id"));
197 if (not nodeList.isEmpty())
198 {
199 rootElement.removeChild(nodeList.at(0));
200 }
201 }
202 }
203
204 //---------------------------------------------------------------------------------------------------------------------
ConvertMeasurementsToV0_4_0()205 void VVSTConverter::ConvertMeasurementsToV0_4_0()
206 {
207 // TODO. Delete if minimal supported version is 0.4.0
208 Q_STATIC_ASSERT_X(VVSTConverter::MeasurementMinVer < FORMAT_VERSION(0, 4, 0),
209 "Time to refactor the code.");
210
211 const QString tagBM = QStringLiteral("body-measurements");
212
213 QDomElement bm = createElement(tagBM);
214
215 const QMultiMap<QString, QString> names = OldNamesToNewNames_InV0_3_0();
216 const QList<QString> keys = names.uniqueKeys();
217 for (auto &key : keys)
218 {
219 qreal resValue = 0;
220 qreal resSizeIncrease = 0;
221 qreal resHeightIncrease = 0;
222
223 // This has the same effect as a .values(), just isn't as elegant
224 const QList<QString> list = names.values( key );
225 for(const auto &val : list)
226 {
227 const QDomNodeList nodeList = this->elementsByTagName(val);
228 if (nodeList.isEmpty())
229 {
230 continue;
231 }
232
233 QDomElement m = nodeList.at(0).toElement();
234 const qreal value = GetParametrDouble(m, QStringLiteral("value"), "0.0");
235 const qreal size_increase = GetParametrDouble(m, QStringLiteral("size_increase"), "0.0");
236 const qreal height_increase = GetParametrDouble(m, QStringLiteral("height_increase"), "0.0");
237
238 if (not qFuzzyIsNull(value))
239 {
240 resValue = value;
241 resSizeIncrease = size_increase;
242 resHeightIncrease = height_increase;
243 }
244 }
245
246 bm.appendChild(AddMV0_4_0(key, resValue, resSizeIncrease, resHeightIncrease));
247 }
248
249 QDomElement rootElement = this->documentElement();
250 const QDomNodeList listBM = elementsByTagName(tagBM);
251 rootElement.replaceChild(bm, listBM.at(0));
252 }
253
254 //---------------------------------------------------------------------------------------------------------------------
AddMV0_4_0(const QString & name,qreal value,qreal sizeIncrease,qreal heightIncrease)255 QDomElement VVSTConverter::AddMV0_4_0(const QString &name, qreal value, qreal sizeIncrease, qreal heightIncrease)
256 {
257 // TODO. Delete if minimal supported version is 0.4.0
258 Q_STATIC_ASSERT_X(VVSTConverter::MeasurementMinVer < FORMAT_VERSION(0, 4, 0),
259 "Time to refactor the code.");
260
261 QDomElement element = createElement(QStringLiteral("m"));
262
263 SetAttribute(element, QStringLiteral("name"), name);
264 SetAttribute(element, QStringLiteral("base"), QString().setNum(value));
265 SetAttribute(element, QStringLiteral("size_increase"), QString().setNum(sizeIncrease));
266 SetAttribute(element, QStringLiteral("height_increase"), QString().setNum(heightIncrease));
267 SetAttribute(element, QStringLiteral("description"),QString());
268 SetAttribute(element, QStringLiteral("full_name"), QString());
269
270 return element;
271 }
272
273 //---------------------------------------------------------------------------------------------------------------------
PM_SystemV0_4_1()274 void VVSTConverter::PM_SystemV0_4_1()
275 {
276 // TODO. Delete if minimal supported version is 0.4.1
277 Q_STATIC_ASSERT_X(VVSTConverter::MeasurementMinVer < FORMAT_VERSION(0, 4, 1),
278 "Time to refactor the code.");
279
280 const QDomNodeList nodeList = this->elementsByTagName(QStringLiteral("size"));
281 QDomElement personal = nodeList.at(0).toElement();
282
283 QDomElement parent = personal.parentNode().toElement();
284 parent.insertBefore(CreateElementWithText(QStringLiteral("pm_system"), QStringLiteral("998")), personal);
285 }
286
287 //---------------------------------------------------------------------------------------------------------------------
ConvertMeasurementsToV0_4_2()288 void VVSTConverter::ConvertMeasurementsToV0_4_2()
289 {
290 // TODO. Delete if minimal supported version is 0.4.2
291 Q_STATIC_ASSERT_X(VVSTConverter::MeasurementMinVer < FORMAT_VERSION(0, 4, 2),
292 "Time to refactor the code.");
293
294 const QMap<QString, QString> names = OldNamesToNewNames_InV0_3_3();
295 auto i = names.constBegin();
296 while (i != names.constEnd())
297 {
298 const QDomNodeList nodeList = this->elementsByTagName(QStringLiteral("m"));
299 if (nodeList.isEmpty())
300 {
301 ++i;
302 continue;
303 }
304
305 for (int ii = 0; ii < nodeList.size(); ++ii)
306 {
307 const QString attrName = QStringLiteral("name");
308 QDomElement element = nodeList.at(ii).toElement();
309 const QString name = GetParametrString(element, attrName);
310 if (name == i.value())
311 {
312 SetAttribute(element, attrName, i.key());
313 }
314 }
315
316 ++i;
317 }
318 }
319
320 //---------------------------------------------------------------------------------------------------------------------
AddNewTagsForV0_5_0()321 void VVSTConverter::AddNewTagsForV0_5_0()
322 {
323 // TODO. Delete if minimal supported version is 0.5.0
324 Q_STATIC_ASSERT_X(VVSTConverter::MeasurementMinVer < FORMAT_VERSION(0, 5, 0),
325 "Time to refactor the code.");
326
327 QDomElement root = documentElement();
328 const QDomElement pmSystemTag = root.firstChildElement(QStringLiteral("pm_system"));
329 if (pmSystemTag.isNull())
330 {
331 return;
332 }
333
334 QDomElement dimensionsTag = createElement(QStringLiteral("dimensions"));
335
336 auto Base = [this](const QString &base)
337 {
338 const QDomElement root = documentElement();
339 const QDomElement baseTag = root.firstChildElement(base);
340 if (baseTag.isNull())
341 {
342 return 0;
343 }
344
345 return GetParametrInt(baseTag, QStringLiteral("base"), QChar('0'));
346 };
347
348 const Unit units = Units();
349
350 {
351 const int step = static_cast<int>(UnitConvertor(6, Unit::Cm, units));
352 const int min = static_cast<int>(UnitConvertor(50, Unit::Cm, units));
353 const int max = static_cast<int>(UnitConvertor(200, Unit::Cm, units));
354
355 QDomElement dimensionX = createElement(QStringLiteral("dimension"));
356 SetAttribute(dimensionX, QStringLiteral("type"), QChar('x'));
357 SetAttribute(dimensionX, QStringLiteral("step"), step);
358 SetAttribute(dimensionX, QStringLiteral("min"), min);
359 SetAttribute(dimensionX, QStringLiteral("max"), max);
360 SetAttribute(dimensionX, QStringLiteral("base"), Base(QStringLiteral("height")));
361 dimensionsTag.appendChild(dimensionX);
362 }
363
364 {
365 const int step = static_cast<int>(UnitConvertor(2, Unit::Cm, units));
366 const int min = static_cast<int>(UnitConvertor(22, Unit::Cm, units));
367 const int max = static_cast<int>(UnitConvertor(72, Unit::Cm, units));
368
369 QDomElement dimensionY = createElement(QStringLiteral("dimension"));
370 SetAttribute(dimensionY, QStringLiteral("type"), QChar('y'));
371 SetAttribute(dimensionY, QStringLiteral("step"), step);
372 SetAttribute(dimensionY, QStringLiteral("min"), min);
373 SetAttribute(dimensionY, QStringLiteral("max"), max);
374 SetAttribute(dimensionY, QStringLiteral("base"), Base(QStringLiteral("size")));
375 SetAttribute(dimensionY, QStringLiteral("circumference"), true);
376 dimensionsTag.appendChild(dimensionY);
377 }
378
379 root.insertAfter(dimensionsTag, pmSystemTag);
380
381 root.insertAfter(createElement(QStringLiteral("restrictions")), dimensionsTag);
382 }
383
384 //---------------------------------------------------------------------------------------------------------------------
RemoveTagsForV0_5_0()385 void VVSTConverter::RemoveTagsForV0_5_0()
386 {
387 // TODO. Delete if minimal supported version is 0.5.0
388 Q_STATIC_ASSERT_X(VVSTConverter::MeasurementMinVer < FORMAT_VERSION(0, 5, 0),
389 "Time to refactor the code.");
390
391 QDomElement root = documentElement();
392
393 const QDomElement sizeTag = root.firstChildElement(QStringLiteral("size"));
394 if (not sizeTag.isNull())
395 {
396 root.removeChild(sizeTag);
397 }
398
399 const QDomElement heightTag = root.firstChildElement(QStringLiteral("height"));
400 if (not heightTag.isNull())
401 {
402 root.removeChild(heightTag);
403 }
404 }
405
406 //---------------------------------------------------------------------------------------------------------------------
ConvertMeasurementsToV0_5_0()407 void VVSTConverter::ConvertMeasurementsToV0_5_0()
408 {
409 // TODO. Delete if minimal supported version is 0.5.0
410 Q_STATIC_ASSERT_X(VVSTConverter::MeasurementMinVer < FORMAT_VERSION(0, 5, 0),
411 "Time to refactor the code.");
412
413 const QDomNodeList measurements = elementsByTagName(QStringLiteral("m"));
414 for (int i = 0; i < measurements.size(); ++i)
415 {
416 QDomElement m = measurements.at(i).toElement();
417
418 SetAttribute(m, QStringLiteral("shiftA"), GetParametrString(m, QStringLiteral("height_increase")));
419 m.removeAttribute(QStringLiteral("height_increase"));
420
421 SetAttribute(m, QStringLiteral("shiftB"), GetParametrString(m, QStringLiteral("size_increase")));
422 m.removeAttribute(QStringLiteral("size_increase"));
423 }
424 }
425
426 //---------------------------------------------------------------------------------------------------------------------
ToV0_4_0()427 void VVSTConverter::ToV0_4_0()
428 {
429 // TODO. Delete if minimal supported version is 0.4.0
430 Q_STATIC_ASSERT_X(VVSTConverter::MeasurementMinVer < FORMAT_VERSION(0, 4, 0),
431 "Time to refactor the code.");
432
433 AddRootComment();
434 SetVersion(QStringLiteral("0.4.0"));
435 AddNewTagsForV0_4_0();
436 RemoveTagsForV0_4_0();
437 ConvertMeasurementsToV0_4_0();
438 Save();
439 }
440
441 //---------------------------------------------------------------------------------------------------------------------
ToV0_4_1()442 void VVSTConverter::ToV0_4_1()
443 {
444 // TODO. Delete if minimal supported version is 0.4.1
445 Q_STATIC_ASSERT_X(VVSTConverter::MeasurementMinVer < FORMAT_VERSION(0, 4, 1),
446 "Time to refactor the code.");
447
448 SetVersion(QStringLiteral("0.4.1"));
449 PM_SystemV0_4_1();
450 Save();
451 }
452
453 //---------------------------------------------------------------------------------------------------------------------
ToV0_4_2()454 void VVSTConverter::ToV0_4_2()
455 {
456 // TODO. Delete if minimal supported version is 0.4.2
457 Q_STATIC_ASSERT_X(VVSTConverter::MeasurementMinVer < FORMAT_VERSION(0, 4, 2),
458 "Time to refactor the code.");
459
460 SetVersion(QStringLiteral("0.4.2"));
461 ConvertMeasurementsToV0_4_2();
462 Save();
463 }
464
465 //---------------------------------------------------------------------------------------------------------------------
ToV0_4_3()466 void VVSTConverter::ToV0_4_3()
467 {
468 // TODO. Delete if minimal supported version is 0.4.3
469 Q_STATIC_ASSERT_X(VVSTConverter::MeasurementMinVer < FORMAT_VERSION(0, 4, 3),
470 "Time to refactor the code.");
471
472 SetVersion(QStringLiteral("0.4.3"));
473 Save();
474 }
475
476 //---------------------------------------------------------------------------------------------------------------------
ToV0_4_4()477 void VVSTConverter::ToV0_4_4()
478 {
479 // TODO. Delete if minimal supported version is 0.4.4
480 Q_STATIC_ASSERT_X(VVSTConverter::MeasurementMinVer < FORMAT_VERSION(0, 4, 4),
481 "Time to refactor the code.");
482
483 SetVersion(QStringLiteral("0.4.4"));
484 Save();
485 }
486
487 //---------------------------------------------------------------------------------------------------------------------
ToV0_5_0()488 void VVSTConverter::ToV0_5_0()
489 {
490 // TODO. Delete if minimal supported version is 0.5.0
491 Q_STATIC_ASSERT_X(VVSTConverter::MeasurementMinVer < FORMAT_VERSION(0, 5, 0),
492 "Time to refactor the code.");
493
494 SetVersion(QStringLiteral("0.5.0"));
495 AddNewTagsForV0_5_0();
496 RemoveTagsForV0_5_0();
497 ConvertMeasurementsToV0_5_0();
498 Save();
499 }
500
501 //---------------------------------------------------------------------------------------------------------------------
ToV0_5_1()502 void VVSTConverter::ToV0_5_1()
503 {
504 // TODO. Delete if minimal supported version is 0.5.1
505 Q_STATIC_ASSERT_X(VVSTConverter::MeasurementMinVer < FORMAT_VERSION(0, 5, 1),
506 "Time to refactor the code.");
507
508 SetVersion(QStringLiteral("0.5.1"));
509 Save();
510 }
511