Seamly2D
Code documentation
vmeasurements.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  * *
3  * Copyright (C) 2017 Seamly, LLC *
4  * *
5  * https://github.com/fashionfreedom/seamly2d *
6  * *
7  ***************************************************************************
8  **
9  ** Seamly2D is free software: you can redistribute it and/or modify
10  ** it under the terms of the GNU General Public License as published by
11  ** the Free Software Foundation, either version 3 of the License, or
12  ** (at your option) any later version.
13  **
14  ** Seamly2D is distributed in the hope that it will be useful,
15  ** but WITHOUT ANY WARRANTY; without even the implied warranty of
16  ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  ** GNU General Public License for more details.
18  **
19  ** You should have received a copy of the GNU General Public License
20  ** along with Seamly2D. If not, see <http://www.gnu.org/licenses/>.
21  **
22  **************************************************************************
23 
24  ************************************************************************
25  **
26  ** @file vmeasurements.cpp
27  ** @author Roman Telezhynskyi <dismine(at)gmail.com>
28  ** @date 14 7, 2015
29  **
30  ** @brief
31  ** @copyright
32  ** This source code is part of the Valentine project, a pattern making
33  ** program, whose allow create and modeling patterns of clothing.
34  ** Copyright (C) 2015 Seamly2D project
35  ** <https://github.com/fashionfreedom/seamly2d> All Rights Reserved.
36  **
37  ** Seamly2D is free software: you can redistribute it and/or modify
38  ** it under the terms of the GNU General Public License as published by
39  ** the Free Software Foundation, either version 3 of the License, or
40  ** (at your option) any later version.
41  **
42  ** Seamly2D is distributed in the hope that it will be useful,
43  ** but WITHOUT ANY WARRANTY; without even the implied warranty of
44  ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
45  ** GNU General Public License for more details.
46  **
47  ** You should have received a copy of the GNU General Public License
48  ** along with Seamly2D. If not, see <http://www.gnu.org/licenses/>.
49  **
50  *************************************************************************/
51 
52 #include "vmeasurements.h"
53 
54 #include <qnumeric.h>
55 #include <QDate>
56 #include <QDomNode>
57 #include <QDomNodeList>
58 #include <QDomText>
59 #include <QLatin1Char>
60 #include <QMessageLogger>
61 #include <QScopedPointer>
62 #include <QSet>
63 #include <QStaticStringData>
64 #include <QStringData>
65 #include <QStringDataPtr>
66 #include <QtDebug>
67 
68 #include "../ifc/exception/vexceptionemptyparameter.h"
69 #include "../ifc/xml/vvitconverter.h"
70 #include "../ifc/xml/vvstconverter.h"
71 #include "../ifc/ifcdef.h"
72 #include "../qmuparser/qmutokenparser.h"
73 #include "../qmuparser/qmuparsererror.h"
74 #include "../vpatterndb/calculator.h"
75 #include "../vpatterndb/variables/vmeasurement.h"
76 #include "../vpatterndb/vcontainer.h"
77 #include "../vpatterndb/measurements.h"
78 #include "../vpatterndb/pmsystems.h"
79 #include "../vmisc/projectversion.h"
80 
81 const QString VMeasurements::TagVST = QStringLiteral("vst");
82 const QString VMeasurements::TagVIT = QStringLiteral("vit");
83 const QString VMeasurements::TagBodyMeasurements = QStringLiteral("body-measurements");
84 const QString VMeasurements::TagNotes = QStringLiteral("notes");
85 const QString VMeasurements::TagSize = QStringLiteral("size");
86 const QString VMeasurements::TagHeight = QStringLiteral("height");
87 const QString VMeasurements::TagPersonal = QStringLiteral("personal");
88 const QString VMeasurements::TagFamilyName = QStringLiteral("family-name");
89 const QString VMeasurements::TagGivenName = QStringLiteral("given-name");
90 const QString VMeasurements::TagBirthDate = QStringLiteral("birth-date");
91 const QString VMeasurements::TagGender = QStringLiteral("gender");
92 const QString VMeasurements::TagPMSystem = QStringLiteral("pm_system");
93 const QString VMeasurements::TagEmail = QStringLiteral("email");
94 const QString VMeasurements::TagReadOnly = QStringLiteral("read-only");
95 const QString VMeasurements::TagMeasurement = QStringLiteral("m");
96 
97 const QString VMeasurements::AttrBase = QStringLiteral("base");
98 const QString VMeasurements::AttrValue = QStringLiteral("value");
99 const QString VMeasurements::AttrSizeIncrease = QStringLiteral("size_increase");
100 const QString VMeasurements::AttrHeightIncrease = QStringLiteral("height_increase");
101 const QString VMeasurements::AttrDescription = QStringLiteral("description");
102 const QString VMeasurements::AttrName = QStringLiteral("name");
103 const QString VMeasurements::AttrFullName = QStringLiteral("full_name");
104 
105 const QString VMeasurements::GenderMale = QStringLiteral("male");
106 const QString VMeasurements::GenderFemale = QStringLiteral("female");
107 const QString VMeasurements::GenderUnknown = QStringLiteral("unknown");
108 
109 const QString defBirthDate = QStringLiteral("1800-01-01");
110 
111 namespace
112 {
113 //---------------------------------------------------------------------------------------------------------------------
114 QString FileComment()
115 {
116  return QString("Measurements created with Seamly2D v%1 (http://seamly.net/).").arg(APP_VERSION_STR);
117 }
118 }
119 
120 //---------------------------------------------------------------------------------------------------------------------
122  :VDomDocument(),
123  data(data),
124  type(MeasurementsType::Unknown),
125  m_currentSize(nullptr),
126  m_currentHeight(nullptr)
127 {
128  SCASSERT(data != nullptr)
129 }
130 
131 //---------------------------------------------------------------------------------------------------------------------
133  :VDomDocument(),
134  data(data),
136  m_currentSize(nullptr),
137  m_currentHeight(nullptr)
138 {
139  SCASSERT(data != nullptr)
140 
142 }
143 
144 //---------------------------------------------------------------------------------------------------------------------
145 VMeasurements::VMeasurements(Unit unit, int baseSize, int baseHeight, VContainer *data)
146  :VDomDocument(),
147  data(data),
149  m_currentSize(nullptr),
150  m_currentHeight(nullptr)
151 {
152  SCASSERT(data != nullptr)
153 
154  CreateEmptyMultisizeFile(unit, baseSize, baseHeight);
155 }
156 
157 //---------------------------------------------------------------------------------------------------------------------
158 void VMeasurements::setXMLContent(const QString &fileName)
159 {
160  VDomDocument::setXMLContent(fileName);
161  type = ReadType();
162 }
163 
164 //---------------------------------------------------------------------------------------------------------------------
165 bool VMeasurements::SaveDocument(const QString &fileName, QString &error)
166 {
167  // Update comment with Seamly2D version
168  QDomNode commentNode = documentElement().firstChild();
169  if (commentNode.isComment())
170  {
171  QDomComment comment = commentNode.toComment();
172  comment.setData(FileComment());
173  }
174 
175  return VDomDocument::SaveDocument(fileName, error);
176 }
177 
178 //---------------------------------------------------------------------------------------------------------------------
179 void VMeasurements::addEmpty(const QString &name, const QString &formula)
180 {
181  const QDomElement element = MakeEmpty(name, formula);
182 
183  const QDomNodeList list = elementsByTagName(TagBodyMeasurements);
184  list.at(0).appendChild(element);
185 }
186 
187 //---------------------------------------------------------------------------------------------------------------------
188 void VMeasurements::AddEmptyAfter(const QString &after, const QString &name, const QString &formula)
189 {
190  const QDomElement element = MakeEmpty(name, formula);
191  const QDomElement sibling = FindM(after);
192 
193  const QDomNodeList list = elementsByTagName(TagBodyMeasurements);
194 
195  if (sibling.isNull())
196  {
197  list.at(0).appendChild(element);
198  }
199  else
200  {
201  list.at(0).insertAfter(element, sibling);
202  }
203 }
204 
205 //---------------------------------------------------------------------------------------------------------------------
206 void VMeasurements::Remove(const QString &name)
207 {
208  const QDomNodeList list = elementsByTagName(TagBodyMeasurements);
209  list.at(0).removeChild(FindM(name));
210 }
211 
212 //---------------------------------------------------------------------------------------------------------------------
213 void VMeasurements::MoveTop(const QString &name)
214 {
215  const QDomElement node = FindM(name);
216  if (not node.isNull())
217  {
218  const QDomNodeList mList = elementsByTagName(TagMeasurement);
219  if (mList.size() >= 2)
220  {
221  const QDomNode top = mList.at(0);
222  if (not top.isNull())
223  {
224  const QDomNodeList list = elementsByTagName(TagBodyMeasurements);
225  list.at(0).insertBefore(node, top);
226  }
227  }
228  }
229 }
230 
231 //---------------------------------------------------------------------------------------------------------------------
232 void VMeasurements::MoveUp(const QString &name)
233 {
234  const QDomElement node = FindM(name);
235  if (not node.isNull())
236  {
237  const QDomElement prSibling = node.previousSiblingElement(TagMeasurement);
238  if (not prSibling.isNull())
239  {
240  const QDomNodeList list = elementsByTagName(TagBodyMeasurements);
241  list.at(0).insertBefore(node, prSibling);
242  }
243  }
244 }
245 
246 //---------------------------------------------------------------------------------------------------------------------
247 void VMeasurements::MoveDown(const QString &name)
248 {
249  const QDomElement node = FindM(name);
250  if (not node.isNull())
251  {
252  const QDomElement nextSibling = node.nextSiblingElement(TagMeasurement);
253  if (not nextSibling.isNull())
254  {
255  const QDomNodeList list = elementsByTagName(TagBodyMeasurements);
256  list.at(0).insertAfter(node, nextSibling);
257  }
258  }
259 }
260 
261 //---------------------------------------------------------------------------------------------------------------------
262 void VMeasurements::MoveBottom(const QString &name)
263 {
264  const QDomElement node = FindM(name);
265  if (not node.isNull())
266  {
267  const QDomNodeList mList = elementsByTagName(TagMeasurement);
268  if (mList.size() >= 2)
269  {
270  const QDomNode bottom = mList.at(mList.size()-1);
271  if (not bottom.isNull())
272  {
273  const QDomNodeList list = elementsByTagName(TagBodyMeasurements);
274  list.at(0).insertAfter(node, bottom);
275  }
276  }
277  }
278 }
279 
280 //---------------------------------------------------------------------------------------------------------------------
282 {
283  // For conversion values we must first calculate all data in measurement file's unit.
284  // That's why we need two containers: one for converted values, second for real data.
285 
286  // Container for values in measurement file's unit
287  QScopedPointer<VContainer> tempData(new VContainer(data->GetTrVars(), data->GetPatternUnit()));
288 
289  const QDomNodeList list = elementsByTagName(TagMeasurement);
290  for (int i=0; i < list.size(); ++i)
291  {
292  const QDomElement dom = list.at(i).toElement();
293 
294  const QString name = GetParametrString(dom, AttrName);
295 
296  QString description;
297  try
298  {
299  description = GetParametrString(dom, AttrDescription);
300  }
301  catch (VExceptionEmptyParameter &e)
302  {
303  Q_UNUSED(e)
304  }
305 
306  QString fullName;
307  try
308  {
309  fullName = GetParametrString(dom, AttrFullName);
310  }
311  catch (VExceptionEmptyParameter &e)
312  {
313  Q_UNUSED(e)
314  }
315 
319  {
320  qreal base = GetParametrDouble(dom, AttrBase, "0");
321  qreal ksize = GetParametrDouble(dom, AttrSizeIncrease, "0");
322  qreal kheight = GetParametrDouble(dom, AttrHeightIncrease, "0");
323 
324  tempMeash = QSharedPointer<VMeasurement>(new VMeasurement(static_cast<quint32>(i), name, BaseSize(),
325  BaseHeight(), base, ksize, kheight));
326  tempMeash->SetSize(m_currentSize);
327  tempMeash->SetHeight(m_currentHeight);
328  tempMeash->SetUnit(data->GetPatternUnit());
329 
330  base = UnitConvertor(base, MUnit(), *data->GetPatternUnit());
331  ksize = UnitConvertor(ksize, MUnit(), *data->GetPatternUnit());
332  kheight = UnitConvertor(kheight, MUnit(), *data->GetPatternUnit());
333 
334  const qreal baseSize = UnitConvertor(BaseSize(), MUnit(), *data->GetPatternUnit());
335  const qreal baseHeight = UnitConvertor(BaseHeight(), MUnit(), *data->GetPatternUnit());
336 
337  meash = QSharedPointer<VMeasurement>(new VMeasurement(static_cast<quint32>(i), name, baseSize, baseHeight,
338  base, ksize, kheight, fullName, description));
339  meash->SetSize(m_currentSize);
340  meash->SetHeight(m_currentHeight);
341  meash->SetUnit(data->GetPatternUnit());
342  }
343  else
344  {
345  const QString formula = GetParametrString(dom, AttrValue, "0");
346  bool ok = false;
347  qreal value = EvalFormula(tempData.data(), formula, &ok);
348 
349  tempMeash = QSharedPointer<VMeasurement>(new VMeasurement(tempData.data(), static_cast<quint32>(i), name,
350  value, formula, ok));
351 
352  value = UnitConvertor(value, MUnit(), *data->GetPatternUnit());
353  meash = QSharedPointer<VMeasurement>(new VMeasurement(data, static_cast<quint32>(i), name, value, formula,
354  ok, fullName, description));
355  }
356  tempData->AddVariable(name, tempMeash);
357  data->AddVariable(name, meash);
358  }
359 }
360 
361 //---------------------------------------------------------------------------------------------------------------------
363 {
364  const QDomNodeList list = elementsByTagName(TagMeasurement);
365 
366  for (int i=0; i < list.size(); ++i)
367  {
368  QDomElement domElement = list.at(i).toElement();
369  if (domElement.isNull() == false)
370  {
371  if (qmu::QmuTokenParser::IsSingle(domElement.attribute(AttrValue)))
372  {
373  SetAttribute(domElement, AttrValue, QString("0"));
374  }
375  }
376  }
377 }
378 
379 //---------------------------------------------------------------------------------------------------------------------
381 {
382  return type;
383 }
384 
385 //---------------------------------------------------------------------------------------------------------------------
387 {
389  {
390  return static_cast<int>(UniqueTagAttr(TagSize, AttrBase, 50));
391  }
392  else
393  {
394  return 0;
395  }
396 }
397 
398 //---------------------------------------------------------------------------------------------------------------------
400 {
402  {
403  return static_cast<int>(UniqueTagAttr(TagHeight, AttrBase, 176));
404  }
405  else
406  {
407  return 0;
408  }
409 }
410 
411 //---------------------------------------------------------------------------------------------------------------------
412 QString VMeasurements::Notes() const
413 {
414  return UniqueTagText(TagNotes, "");
415 }
416 
417 //---------------------------------------------------------------------------------------------------------------------
418 void VMeasurements::SetNotes(const QString &text)
419 {
420  if (not IsReadOnly())
421  {
422  setTagText(TagNotes, text);
423  }
424 }
425 
426 //---------------------------------------------------------------------------------------------------------------------
428 {
429  return UniqueTagText(TagFamilyName, "");
430 }
431 
432 //---------------------------------------------------------------------------------------------------------------------
433 void VMeasurements::SetFamilyName(const QString &text)
434 {
435  if (not IsReadOnly())
436  {
437  setTagText(TagFamilyName, text);
438  }
439 }
440 
441 //---------------------------------------------------------------------------------------------------------------------
443 {
444  return UniqueTagText(TagGivenName, "");
445 }
446 
447 //---------------------------------------------------------------------------------------------------------------------
448 void VMeasurements::SetGivenName(const QString &text)
449 {
450  if (not IsReadOnly())
451  {
452  setTagText(TagGivenName, text);
453  }
454 }
455 
456 //---------------------------------------------------------------------------------------------------------------------
458 {
459  return QDate::fromString(UniqueTagText(TagBirthDate, defBirthDate), "yyyy-MM-dd");
460 }
461 
462 //---------------------------------------------------------------------------------------------------------------------
463 void VMeasurements::SetBirthDate(const QDate &date)
464 {
465  if (not IsReadOnly())
466  {
467  setTagText(TagBirthDate, date.toString("yyyy-MM-dd"));
468  }
469 }
470 
471 //---------------------------------------------------------------------------------------------------------------------
473 {
475 }
476 
477 //---------------------------------------------------------------------------------------------------------------------
479 {
480  if (not IsReadOnly())
481  {
482  setTagText(TagGender, GenderToStr(gender));
483  }
484 }
485 
486 //---------------------------------------------------------------------------------------------------------------------
487 QString VMeasurements::PMSystem() const
488 {
490 }
491 
492 //---------------------------------------------------------------------------------------------------------------------
493 void VMeasurements::SetPMSystem(const QString &system)
494 {
495  if (not IsReadOnly())
496  {
498  }
499 }
500 
501 //---------------------------------------------------------------------------------------------------------------------
502 QString VMeasurements::Email() const
503 {
504  return UniqueTagText(TagEmail, "");
505 }
506 
507 //---------------------------------------------------------------------------------------------------------------------
508 void VMeasurements::SetEmail(const QString &text)
509 {
510  if (not IsReadOnly())
511  {
512  setTagText(TagEmail, text);
513  }
514 }
515 
516 //---------------------------------------------------------------------------------------------------------------------
518 {
520 }
521 
522 //---------------------------------------------------------------------------------------------------------------------
524 {
525  if (ro)
526  {
528  }
529  else
530  {
532  }
533 }
534 
535 //---------------------------------------------------------------------------------------------------------------------
536 void VMeasurements::SetSize(qreal *size)
537 {
538  m_currentSize = size;
539 }
540 
541 //---------------------------------------------------------------------------------------------------------------------
542 void VMeasurements::SetHeight(qreal *height)
543 {
544  m_currentHeight = height;
545 }
546 
547 //---------------------------------------------------------------------------------------------------------------------
548 void VMeasurements::SetMName(const QString &name, const QString &text)
549 {
550  QDomElement node = FindM(name);
551  if (not node.isNull())
552  {
553  SetAttribute(node, AttrName, text);
554  }
555  else
556  {
557  qWarning() << tr("Can't find measurement '%1'").arg(name);
558  }
559 }
560 
561 //---------------------------------------------------------------------------------------------------------------------
562 void VMeasurements::SetMValue(const QString &name, const QString &text)
563 {
564  QDomElement node = FindM(name);
565  if (not node.isNull())
566  {
567  SetAttribute(node, AttrValue, text);
568  }
569  else
570  {
571  qWarning() << tr("Can't find measurement '%1'").arg(name);
572  }
573 }
574 
575 //---------------------------------------------------------------------------------------------------------------------
576 void VMeasurements::SetMBaseValue(const QString &name, double value)
577 {
578  QDomElement node = FindM(name);
579  if (not node.isNull())
580  {
581  SetAttribute(node, AttrBase, value);
582  }
583  else
584  {
585  qWarning() << tr("Can't find measurement '%1'").arg(name);
586  }
587 }
588 
589 //---------------------------------------------------------------------------------------------------------------------
590 void VMeasurements::SetMSizeIncrease(const QString &name, double value)
591 {
592  QDomElement node = FindM(name);
593  if (not node.isNull())
594  {
595  SetAttribute(node, AttrSizeIncrease, value);
596  }
597  else
598  {
599  qWarning() << tr("Can't find measurement '%1'").arg(name);
600  }
601 }
602 
603 //---------------------------------------------------------------------------------------------------------------------
604 void VMeasurements::SetMHeightIncrease(const QString &name, double value)
605 {
606  QDomElement node = FindM(name);
607  if (not node.isNull())
608  {
609  SetAttribute(node, AttrHeightIncrease, value);
610  }
611  else
612  {
613  qWarning() << tr("Can't find measurement '%1'").arg(name);
614  }
615 }
616 
617 //---------------------------------------------------------------------------------------------------------------------
618 void VMeasurements::SetMDescription(const QString &name, const QString &text)
619 {
620  QDomElement node = FindM(name);
621  if (not node.isNull())
622  {
623  SetAttribute(node, AttrDescription, text);
624  }
625  else
626  {
627  qWarning() << tr("Can't find measurement '%1'").arg(name);
628  }
629 }
630 
631 //---------------------------------------------------------------------------------------------------------------------
632 void VMeasurements::SetMFullName(const QString &name, const QString &text)
633 {
634  QDomElement node = FindM(name);
635  if (not node.isNull())
636  {
637  SetAttribute(node, AttrFullName, text);
638  }
639  else
640  {
641  qWarning() << tr("Can't find measurement '%1'").arg(name);
642  }
643 }
644 
645 //---------------------------------------------------------------------------------------------------------------------
647 {
648  switch (sex)
649  {
650  case GenderType::Male:
651  return GenderMale;
652  case GenderType::Female:
653  return GenderFemale;
654  case GenderType::Unknown:
655  default:
656  return GenderUnknown;
657  }
658 }
659 
660 //---------------------------------------------------------------------------------------------------------------------
662 {
663  const QStringList genders = QStringList() << GenderMale << GenderFemale << GenderUnknown;
664  switch (genders.indexOf(sex))
665  {
666  case 0: // GenderMale
667  return GenderType::Male;
668  case 1: // GenderFemale
669  return GenderType::Female;
670  case 2: // GenderUnknown
671  default:
672  return GenderType::Unknown;
673  }
674 }
675 
676 //---------------------------------------------------------------------------------------------------------------------
677 QStringList VMeasurements::ListAll() const
678 {
679  QStringList listNames;
680  const QDomNodeList list = elementsByTagName(TagMeasurement);
681 
682  for (int i=0; i < list.size(); ++i)
683  {
684  const QDomElement domElement = list.at(i).toElement();
685  if (domElement.isNull() == false)
686  {
687  listNames.append(domElement.attribute(AttrName));
688  }
689  }
690 
691  return listNames;
692 }
693 
694 //---------------------------------------------------------------------------------------------------------------------
695 QStringList VMeasurements::listKnown() const
696 {
697  QStringList listNames;
698  const QStringList list = ListAll();
699  for (int i=0; i < list.size(); ++i)
700  {
701  if (list.at(i).indexOf(CustomMSign) != 0)
702  {
703  listNames.append(list.at(i));
704  }
705  }
706 
707  return listNames;
708 }
709 
710 //---------------------------------------------------------------------------------------------------------------------
712 {
713  QStringList names = AllGroupNames();
714 
715  QSet<QString> set;
716  foreach (const QString &var, names)
717  {
718  set.insert(var);
719  }
720 
721  names = listKnown();
722  foreach (const QString &var, names)
723  {
724  if (not set.contains(var))
725  {
726  return false;
727  }
728  }
729 
730  return true;
731 }
732 
733 //---------------------------------------------------------------------------------------------------------------------
735 {
736  return data;
737 }
738 
739 //---------------------------------------------------------------------------------------------------------------------
740 void VMeasurements::CreateEmptyMultisizeFile(Unit unit, int baseSize, int baseHeight)
741 {
742  this->clear();
743  QDomElement mElement = this->createElement(TagVST);
744 
745  mElement.appendChild(createComment(FileComment()));
746 
747  QDomElement version = createElement(TagVersion);
748  const QDomText newNodeText = createTextNode(VVSTConverter::MeasurementMaxVerStr);
749  version.appendChild(newNodeText);
750  mElement.appendChild(version);
751 
752  QDomElement ro = createElement(TagReadOnly);
753  const QDomText roNodeText = createTextNode("false");
754  ro.appendChild(roNodeText);
755  mElement.appendChild(ro);
756 
757  mElement.appendChild(createElement(TagNotes));
758 
759  QDomElement mUnit = createElement(TagUnit);
760  const QDomText unitText = createTextNode(UnitsToStr(unit));
761  mUnit.appendChild(unitText);
762  mElement.appendChild(mUnit);
763 
764  QDomElement system = createElement(TagPMSystem);
765  system.appendChild(createTextNode(ClearPMCode(p998_S)));
766  mElement.appendChild(system);
767 
768  QDomElement size = createElement(TagSize);
769  SetAttribute(size, AttrBase, QString().setNum(baseSize));
770  mElement.appendChild(size);
771 
772  QDomElement height = createElement(TagHeight);
773  SetAttribute(height, AttrBase, QString().setNum(baseHeight));
774  mElement.appendChild(height);
775 
776  mElement.appendChild(createElement(TagBodyMeasurements));
777 
778  this->appendChild(mElement);
779  insertBefore(createProcessingInstruction("xml", "version=\"1.0\" encoding=\"UTF-8\""), this->firstChild());
780 }
781 
782 //---------------------------------------------------------------------------------------------------------------------
784 {
785  this->clear();
786  QDomElement mElement = this->createElement(TagVIT);
787 
788  mElement.appendChild(createComment(FileComment()));
789 
790  QDomElement version = createElement(TagVersion);
791  const QDomText newNodeText = createTextNode(VVITConverter::MeasurementMaxVerStr);
792  version.appendChild(newNodeText);
793  mElement.appendChild(version);
794 
795  QDomElement ro = createElement(TagReadOnly);
796  const QDomText roNodeText = createTextNode("false");
797  ro.appendChild(roNodeText);
798  mElement.appendChild(ro);
799 
800  mElement.appendChild(createElement(TagNotes));
801 
802  QDomElement mUnit = createElement(TagUnit);
803  mUnit.appendChild(createTextNode(UnitsToStr(unit)));
804  mElement.appendChild(mUnit);
805 
806  QDomElement system = createElement(TagPMSystem);
807  system.appendChild(createTextNode(ClearPMCode(p998_S)));
808  mElement.appendChild(system);
809 
810  QDomElement personal = createElement(TagPersonal);
811  personal.appendChild(createElement(TagFamilyName));
812  personal.appendChild(createElement(TagGivenName));
813 
814  QDomElement date = createElement(TagBirthDate);
815  date.appendChild(createTextNode(defBirthDate));
816  personal.appendChild(date);
817 
818  QDomElement gender = createElement(TagGender);
819  gender.appendChild(createTextNode(GenderToStr(GenderType::Unknown)));
820  personal.appendChild(gender);
821 
822  personal.appendChild(createElement(TagEmail));
823  mElement.appendChild(personal);
824 
825  mElement.appendChild(createElement(TagBodyMeasurements));
826 
827  this->appendChild(mElement);
828  insertBefore(createProcessingInstruction("xml", "version=\"1.0\" encoding=\"UTF-8\""), this->firstChild());
829 }
830 
831 //---------------------------------------------------------------------------------------------------------------------
832 qreal VMeasurements::UniqueTagAttr(const QString &tag, const QString &attr, qreal defValue) const
833 {
834  const qreal defVal = UnitConvertor(defValue, Unit::Cm, MUnit());
835 
836  const QDomNodeList nodeList = this->elementsByTagName(tag);
837  if (nodeList.isEmpty())
838  {
839  return defVal;
840  }
841  else
842  {
843  const QDomNode domNode = nodeList.at(0);
844  if (domNode.isNull() == false && domNode.isElement())
845  {
846  const QDomElement domElement = domNode.toElement();
847  if (domElement.isNull() == false)
848  {
849  return GetParametrDouble(domElement, attr, QString("%1").arg(defVal));
850  }
851  }
852  }
853  return defVal;
854 }
855 
856 //---------------------------------------------------------------------------------------------------------------------
857 QDomElement VMeasurements::MakeEmpty(const QString &name, const QString &formula)
858 {
859  QDomElement element = createElement(TagMeasurement);
860 
861  SetAttribute(element, AttrName, name);
862 
864  {
865  SetAttribute(element, AttrBase, QString("0"));
866  SetAttribute(element, AttrSizeIncrease, QString("0"));
867  SetAttribute(element, AttrHeightIncrease, QString("0"));
868  }
869  else
870  {
871  if (formula.isEmpty())
872  {
873  SetAttribute(element, AttrValue, QString("0"));
874  }
875  else
876  {
877  SetAttribute(element, AttrValue, formula);
878  }
879  }
880 
881  return element;
882 }
883 
884 //---------------------------------------------------------------------------------------------------------------------
885 QDomElement VMeasurements::FindM(const QString &name) const
886 {
887  if (name.isEmpty())
888  {
889  qWarning() << tr("The measurement name is empty!");
890  return QDomElement();
891  }
892 
893  QDomNodeList list = elementsByTagName(TagMeasurement);
894 
895  for (int i=0; i < list.size(); ++i)
896  {
897  const QDomElement domElement = list.at(i).toElement();
898  if (domElement.isNull() == false)
899  {
900  const QString parameter = domElement.attribute(AttrName);
901  if (parameter == name)
902  {
903  return domElement;
904  }
905  }
906  }
907 
908  return QDomElement();
909 }
910 
911 //---------------------------------------------------------------------------------------------------------------------
913 {
914  QDomElement root = documentElement();
915  if (root.tagName() == TagVST)
916  {
918  }
919  else if (root.tagName() == TagVIT)
920  {
922  }
923  else
924  {
926  }
927 }
928 
929 //---------------------------------------------------------------------------------------------------------------------
930 qreal VMeasurements::EvalFormula(VContainer *data, const QString &formula, bool *ok) const
931 {
932  if (formula.isEmpty())
933  {
934  *ok = true;
935  return 0;
936  }
937  else
938  {
939  try
940  {
941  // Replace line return character with spaces for calc if exist
942  QString f = formula;
943  f.replace("\n", " ");
944  QScopedPointer<Calculator> cal(new Calculator());
945  const qreal result = cal->EvalFormula(data->DataVariables(), f);
946 
947  (qIsInf(result) || qIsNaN(result)) ? *ok = false : *ok = true;
948  return result;
949  }
950  catch (qmu::QmuParserError &e)
951  {
952  Q_UNUSED(e)
953  *ok = false;
954  return 0;
955  }
956  }
957 }
958 
959 //---------------------------------------------------------------------------------------------------------------------
960 QString VMeasurements::ClearPMCode(const QString &code) const
961 {
962  QString clear = code;
963  const int index = clear.indexOf(QLatin1Char('p'));
964  if (index == 0)
965  {
966  clear.remove(0, 1);
967  }
968  return clear;
969 }
The Calculator class for calculation formula.
Definition: calculator.h:84
The VContainer class container of all variables.
Definition: vcontainer.h:141
void AddVariable(const QString &name, T *var)
Definition: vcontainer.h:327
const VTranslateVars * GetTrVars() const
Definition: vcontainer.cpp:605
const QHash< QString, QSharedPointer< VInternalVariable > > * DataVariables() const
Definition: vcontainer.cpp:718
const Unit * GetPatternUnit() const
Definition: vcontainer.cpp:599
The VDomDocument class represents a Seamly2D document (.val file).
Definition: vdomdocument.h:105
static QString GetParametrString(const QDomElement &domElement, const QString &name, const QString &defValue=QString())
Returns the string value of the given attribute. RENAME: see above.
Unit MUnit() const
bool setTagText(const QString &tag, const QString &text)
static qreal GetParametrDouble(const QDomElement &domElement, const QString &name, const QString &defValue)
Returns the double value of the given attribute.
static const QString TagVersion
Definition: vdomdocument.h:115
static const QString TagUnit
Definition: vdomdocument.h:116
QString UniqueTagText(const QString &tagName, const QString &defVal=QString()) const
void SetAttribute(QDomElement &domElement, const QString &name, const T &value) const
SetAttribute set attribute in pattern file. Replace "," by ".".
Definition: vdomdocument.h:185
virtual void setXMLContent(const QString &fileName)
virtual bool SaveDocument(const QString &fileName, QString &error)
The VExceptionEmptyParameter class for exception empty parameter.
The VMeasurement class keep data row of multisize table.
Definition: vmeasurement.h:74
void MoveUp(const QString &name)
MeasurementsType ReadType() const
void MoveTop(const QString &name)
static const QString TagSize
void SetMDescription(const QString &name, const QString &text)
void MoveDown(const QString &name)
static const QString AttrValue
static const QString TagNotes
qreal EvalFormula(VContainer *data, const QString &formula, bool *ok) const
static const QString AttrSizeIncrease
static const QString TagPMSystem
void addEmpty(const QString &name, const QString &formula=QString())
static GenderType StrToGender(const QString &sex)
static const QString TagGender
VMeasurements(VContainer *data)
QString PMSystem() const
void SetGender(const GenderType &gender)
void SetNotes(const QString &text)
static const QString AttrFullName
void SetMBaseValue(const QString &name, double value)
static const QString GenderFemale
void SetEmail(const QString &text)
QStringList ListAll() const
QStringList listKnown() const
static const QString TagBirthDate
static QString GenderToStr(const GenderType &sex)
MeasurementsType type
static const QString AttrBase
static const QString AttrName
QString ClearPMCode(const QString &code) const
void CreateEmptyMultisizeFile(Unit unit, int baseSize, int baseHeight)
void SetFamilyName(const QString &text)
static const QString TagHeight
void ReadMeasurements() const
static const QString TagReadOnly
static const QString TagFamilyName
qreal UniqueTagAttr(const QString &tag, const QString &attr, qreal defValue) const
static const QString TagPersonal
void SetSize(qreal *size)
void SetPMSystem(const QString &system)
QDomElement MakeEmpty(const QString &name, const QString &formula)
qreal * m_currentSize
void Remove(const QString &name)
VContainer * GetData() const
static const QString AttrDescription
void SetReadOnly(bool ro)
int BaseSize() const
void SetMFullName(const QString &name, const QString &text)
QDate BirthDate() const
QDomElement FindM(const QString &name) const
static const QString TagBodyMeasurements
void SetHeight(qreal *height)
void SetMValue(const QString &name, const QString &text)
MeasurementsType Type() const
void SetMSizeIncrease(const QString &name, double value)
void MoveBottom(const QString &name)
static const QString TagVIT
int BaseHeight() const
static const QString TagMeasurement
QString Email() const
void CreateEmptyIndividualFile(Unit unit)
static const QString TagGivenName
VContainer * data
data container with data.
void AddEmptyAfter(const QString &after, const QString &name, const QString &formula=QString())
static const QString GenderMale
bool IsReadOnly() const
static const QString TagVST
void SetGivenName(const QString &text)
void SetMHeightIncrease(const QString &name, double value)
QString FamilyName() const
virtual void setXMLContent(const QString &fileName) Q_DECL_OVERRIDE
static const QString GenderUnknown
qreal * m_currentHeight
GenderType Gender() const
static const QString TagEmail
virtual bool SaveDocument(const QString &fileName, QString &error) Q_DECL_OVERRIDE
static const QString AttrHeightIncrease
QString GivenName() const
QString Notes() const
bool IsDefinedKnownNamesValid() const
void SetMName(const QString &name, const QString &text)
void SetBirthDate(const QDate &date)
static const QString MeasurementMaxVerStr
Definition: vvitconverter.h:72
static const QString MeasurementMaxVerStr
Definition: vvstconverter.h:72
Error class of the parser.
static bool IsSingle(const QString &formula)
IsSingle test formula and return true if it contain only one number.
QString UnitsToStr(const Unit &unit, const bool translate)
UnitsToStr translate unit to string.
Definition: def.cpp:702
const QString trueStr
Definition: def.cpp:197
const QString falseStr
Definition: def.cpp:198
qreal UnitConvertor(qreal value, const Unit &from, const Unit &to)
Definition: def.cpp:269
#define SCASSERT(cond)
Definition: def.h:317
MeasurementsType
Definition: def.h:104
Unit
Definition: def.h:105
const QString CustomMSign
Definition: ifcdef.cpp:70
QStringList AllGroupNames()
const QString p998_S
Definition: pmsystems.cpp:114
const QString APP_VERSION_STR
const QString defBirthDate
GenderType
Definition: vmeasurements.h:66