1 /************************************************************************
2  **
3  **  @file   vabstractpattern.cpp
4  **  @author Roman Telezhynskyi <dismine(at)gmail.com>
5  **  @date   15 6, 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 "vabstractpattern.h"
30 
31 #include <QDomNode>
32 #include <QDomNodeList>
33 #include <QLatin1String>
34 #include <QList>
35 #include <QMessageLogger>
36 #include <QSet>
37 #include <QStaticStringData>
38 #include <QStringData>
39 #include <QStringDataPtr>
40 #include <QtDebug>
41 #include <QtConcurrentMap>
42 #include <QFuture>
43 #include <QtConcurrentRun>
44 
45 #include "../exception/vexceptionemptyparameter.h"
46 #include "../exception/vexceptionobjecterror.h"
47 #include "../exception/vexceptionconversionerror.h"
48 #include "../qmuparser/qmutokenparser.h"
49 #include "../ifc/exception/vexceptionbadid.h"
50 #include "../ifc/ifcdef.h"
51 #include "../vpatterndb/vcontainer.h"
52 #include "../vpatterndb/vpiecenode.h"
53 #include "../vtools/tools/vdatatool.h"
54 #include "vpatternconverter.h"
55 #include "vdomdocument.h"
56 #include "vtoolrecord.h"
57 #include "../vmisc/vabstractvalapplication.h"
58 #include "../vmisc/compatibility.h"
59 #include "../vlayout/vtextmanager.h"
60 
61 class QDomElement;
62 
63 const QString VAbstractPattern::TagPattern          = QStringLiteral("pattern");
64 const QString VAbstractPattern::TagCalculation      = QStringLiteral("calculation");
65 const QString VAbstractPattern::TagModeling         = QStringLiteral("modeling");
66 const QString VAbstractPattern::TagDetails          = QStringLiteral("details");
67 const QString VAbstractPattern::TagDetail           = QStringLiteral("detail");
68 const QString VAbstractPattern::TagDescription      = QStringLiteral("description");
69 const QString VAbstractPattern::TagNotes            = QStringLiteral("notes");
70 const QString VAbstractPattern::TagImage            = QStringLiteral("image");
71 const QString VAbstractPattern::TagMeasurements     = QStringLiteral("measurements");
72 const QString VAbstractPattern::TagIncrements       = QStringLiteral("increments");
73 const QString VAbstractPattern::TagPreviewCalculations = QStringLiteral("previewCalculations");
74 const QString VAbstractPattern::TagIncrement        = QStringLiteral("increment");
75 const QString VAbstractPattern::TagDraw             = QStringLiteral("draw");
76 const QString VAbstractPattern::TagGroups           = QStringLiteral("groups");
77 const QString VAbstractPattern::TagGroup            = QStringLiteral("group");
78 const QString VAbstractPattern::TagGroupItem        = QStringLiteral("item");
79 const QString VAbstractPattern::TagPoint            = QStringLiteral("point");
80 const QString VAbstractPattern::TagSpline           = QStringLiteral("spline");
81 const QString VAbstractPattern::TagArc              = QStringLiteral("arc");
82 const QString VAbstractPattern::TagElArc            = QStringLiteral("elArc");
83 const QString VAbstractPattern::TagTools            = QStringLiteral("tools");
84 const QString VAbstractPattern::TagOperation        = QStringLiteral("operation");
85 const QString VAbstractPattern::TagData             = QStringLiteral("data");
86 const QString VAbstractPattern::TagPatternInfo      = QStringLiteral("patternInfo");
87 const QString VAbstractPattern::TagPatternName      = QStringLiteral("patternName");
88 const QString VAbstractPattern::TagPatternNum       = QStringLiteral("patternNumber");
89 const QString VAbstractPattern::TagCustomerName     = QStringLiteral("customer");
90 const QString VAbstractPattern::TagCustomerBirthDate = QStringLiteral("birthDate");
91 const QString VAbstractPattern::TagCustomerEmail     = QStringLiteral("email");
92 const QString VAbstractPattern::TagCompanyName      = QStringLiteral("company");
93 const QString VAbstractPattern::TagPatternLabel     = QStringLiteral("patternLabel");
94 const QString VAbstractPattern::TagWatermark        = QStringLiteral("watermark");
95 const QString VAbstractPattern::TagPatternMaterials = QStringLiteral("patternMaterials");
96 const QString VAbstractPattern::TagFinalMeasurements= QStringLiteral("finalMeasurements");
97 const QString VAbstractPattern::TagMaterial         = QStringLiteral("material");
98 const QString VAbstractPattern::TagFMeasurement     = QStringLiteral("finalMeasurment");
99 const QString VAbstractPattern::TagGrainline        = QStringLiteral("grainline");
100 const QString VAbstractPattern::TagPath             = QStringLiteral("path");
101 const QString VAbstractPattern::TagNodes            = QStringLiteral("nodes");
102 const QString VAbstractPattern::TagNode             = QStringLiteral("node");
103 
104 const QString VAbstractPattern::AttrName              = QStringLiteral("name");
105 const QString VAbstractPattern::AttrVisible           = QStringLiteral("visible");
106 const QString VAbstractPattern::AttrObject            = QStringLiteral("object");
107 const QString VAbstractPattern::AttrTool              = QStringLiteral("tool");
108 const QString VAbstractPattern::AttrType              = QStringLiteral("type");
109 const QString VAbstractPattern::AttrLetter            = QStringLiteral("letter");
110 const QString VAbstractPattern::AttrAnnotation        = QStringLiteral("annotation");
111 const QString VAbstractPattern::AttrOrientation       = QStringLiteral("orientation");
112 const QString VAbstractPattern::AttrRotationWay       = QStringLiteral("rotationWay");
113 const QString VAbstractPattern::AttrTilt              = QStringLiteral("tilt");
114 const QString VAbstractPattern::AttrFoldPosition      = QStringLiteral("foldPosition");
115 const QString VAbstractPattern::AttrQuantity          = QStringLiteral("quantity");
116 const QString VAbstractPattern::AttrOnFold            = QStringLiteral("onFold");
117 const QString VAbstractPattern::AttrDateFormat        = QStringLiteral("dateFormat");
118 const QString VAbstractPattern::AttrTimeFormat        = QStringLiteral("timeFormat");
119 const QString VAbstractPattern::AttrArrows            = QStringLiteral("arrows");
120 const QString VAbstractPattern::AttrNodeReverse       = QStringLiteral("reverse");
121 const QString VAbstractPattern::AttrNodeExcluded      = QStringLiteral("excluded");
122 const QString VAbstractPattern::AttrNodePassmark      = QStringLiteral("passmark");
123 const QString VAbstractPattern::AttrNodePassmarkLine  = QStringLiteral("passmarkLine");
124 const QString VAbstractPattern::AttrNodePassmarkAngle = QStringLiteral("passmarkAngle");
125 const QString VAbstractPattern::AttrNodeShowSecondPassmark = QStringLiteral("showSecondPassmark");
126 const QString VAbstractPattern::AttrSABefore          = QStringLiteral("before");
127 const QString VAbstractPattern::AttrSAAfter           = QStringLiteral("after");
128 const QString VAbstractPattern::AttrStart             = QStringLiteral("start");
129 const QString VAbstractPattern::AttrPath              = QStringLiteral("path");
130 const QString VAbstractPattern::AttrEnd               = QStringLiteral("end");
131 const QString VAbstractPattern::AttrIncludeAs         = QStringLiteral("includeAs");
132 const QString VAbstractPattern::AttrRotation          = QStringLiteral("rotation");
133 const QString VAbstractPattern::AttrNumber            = QStringLiteral("number");
134 const QString VAbstractPattern::AttrCheckUniqueness   = QStringLiteral("checkUniqueness");
135 const QString VAbstractPattern::AttrManualPassmarkLength = QStringLiteral("manualPassmarkLength");
136 const QString VAbstractPattern::AttrPassmarkLength    = QStringLiteral("passmarkLength");
137 const QString VAbstractPattern::AttrOpacity           = QStringLiteral("opacity");
138 const QString VAbstractPattern::AttrTags              = QStringLiteral("tags");
139 
140 const QString VAbstractPattern::AttrExtension       = QStringLiteral("extension");
141 
142 const QString VAbstractPattern::AttrFormula     = QStringLiteral("formula");
143 const QString VAbstractPattern::AttrDescription = QStringLiteral("description");
144 
145 const QString VAbstractPattern::NodeArc        = QStringLiteral("NodeArc");
146 const QString VAbstractPattern::NodeElArc      = QStringLiteral("NodeElArc");
147 const QString VAbstractPattern::NodePoint      = QStringLiteral("NodePoint");
148 const QString VAbstractPattern::NodeSpline     = QStringLiteral("NodeSpline");
149 const QString VAbstractPattern::NodeSplinePath = QStringLiteral("NodeSplinePath");
150 
151 QHash<quint32, VDataTool*> VAbstractPattern::tools = QHash<quint32, VDataTool*>();
152 QVector<VLabelTemplateLine> VAbstractPattern::patternLabelLines = QVector<VLabelTemplateLine>();
153 QMap<int, QString> VAbstractPattern::patternMaterials = QMap<int, QString>();
154 bool VAbstractPattern::patternLabelWasChanged = false;
155 
156 namespace
157 {
ReadExpressionAttribute(QVector<VFormulaField> & expressions,const QDomElement & element,const QString & attribute)158 void ReadExpressionAttribute(QVector<VFormulaField> &expressions, const QDomElement &element, const QString &attribute)
159 {
160     VFormulaField formula;
161     formula.expression = VDomDocument::GetParametrEmptyString(element, attribute);
162 
163     if (formula.expression.isEmpty())
164     {
165         return;
166     }
167 
168     formula.element = element;
169     formula.attribute = attribute;
170 
171     expressions.append(formula);
172 }
173 
174 //---------------------------------------------------------------------------------------------------------------------
GetTokens(const VFormulaField & formula)175 QList<QString> GetTokens(const VFormulaField &formula)
176 {
177     try
178     {
179         QScopedPointer<qmu::QmuTokenParser> cal(new qmu::QmuTokenParser(formula.expression, false, false));
180         return cal->GetTokens().values();
181     }
182     catch (const qmu::QmuParserError &e)
183     {
184         qWarning() << QObject::tr("Cannot get tokens from formula '%1'. Parser error: %2.")
185                       .arg(formula.expression, e.GetMsg());
186         return QList<QString>();
187     }
188     catch (const qmu::QmuParserWarning &e)
189     {
190         qWarning() << QObject::tr("Cannot get tokens from formula '%1'. Formula error: %2.")
191                           .arg(formula.expression, e.GetMsg());
192         return QList<QString>();
193     }
194 }
195 
196 //---------------------------------------------------------------------------------------------------------------------
GatherTokens(QSet<QString> & tokens,const QList<QString> & tokenList)197 void GatherTokens(QSet<QString> &tokens, const QList<QString> &tokenList)
198 {
199     tokens = tokens.unite(ConvertToSet(tokenList));
200 }
201 
202 //---------------------------------------------------------------------------------------------------------------------
203 /**
204  * @brief AdjustMaterials help function that combine user materials from pattern and cli.
205  * @param materials materials from pattern
206  * @return combined list
207  */
AdjustMaterials(QMap<int,QString> materials)208 QMap<int, QString> AdjustMaterials(QMap<int, QString> materials)
209 {
210     const QMap<int, QString> cliMaterials = VAbstractValApplication::VApp()->GetUserMaterials();
211     QMap<int, QString>::const_iterator i = cliMaterials.constBegin();
212     while (i != cliMaterials.constEnd())
213     {
214         if (not materials.contains(i.key()))
215         {
216             qWarning() << QObject::tr("User material number %1 was not defined in this pattern.").arg(i.key());
217         }
218 
219         materials.insert(i.key(), i.value());
220         ++i;
221     }
222 
223     return materials;
224 }
225 
226 //---------------------------------------------------------------------------------------------------------------------
PrepareGroupTags(QStringList tags)227 QString PrepareGroupTags(QStringList tags)
228 {
229     for (auto &tag : tags)
230     {
231         tag = tag.simplified();
232     }
233 
234     return ConvertToList(ConvertToSet<QString>(tags)).join(',');
235 }
236 }
237 
238 //---------------------------------------------------------------------------------------------------------------------
VAbstractPattern(QObject * parent)239 VAbstractPattern::VAbstractPattern(QObject *parent)
240     : VDomDocument(parent),
241       nameActivPP(),
242       cursor(0),
243       toolsOnRemove(QVector<VDataTool*>()),
244       history(QVector<VToolRecord>()),
245       patternPieces(),
246       modified(false)
247 {}
248 
249 //---------------------------------------------------------------------------------------------------------------------
~VAbstractPattern()250 VAbstractPattern::~VAbstractPattern()
251 {
252     qDeleteAll(toolsOnRemove);
253     toolsOnRemove.clear();
254 }
255 
256 //---------------------------------------------------------------------------------------------------------------------
RequiresMeasurements() const257 bool VAbstractPattern::RequiresMeasurements() const
258 {
259     return not ListMeasurements().isEmpty();
260 }
261 
262 //---------------------------------------------------------------------------------------------------------------------
ListMeasurements() const263 QStringList VAbstractPattern::ListMeasurements() const
264 {
265     const QFuture<QStringList> futureIncrements = QtConcurrent::run(this, &VAbstractPattern::ListIncrements);
266     const QList<QString> tokens = ConvertToList(QtConcurrent::blockingMappedReduced(ListExpressions(), GetTokens,
267                                                                                     GatherTokens));
268 
269     QSet<QString> measurements;
270     QSet<QString> others = ConvertToSet<QString>(futureIncrements.result());
271 
272     for (const auto &token : tokens)
273     {
274         if (token == QChar('-') || measurements.contains(token) || others.contains(token))
275         {
276             continue;
277         }
278 
279         IsVariable(token) || IsFunction(token) ? others.insert(token) : measurements.insert(token);
280     }
281 
282     return QStringList(measurements.values());
283 }
284 
285 //---------------------------------------------------------------------------------------------------------------------
286 /**
287  * @brief ChangeActivPP set new active pattern piece name.
288  * @param name new name.
289  * @param parse parser file mode.
290  */
ChangeActivPP(const QString & name,const Document & parse)291 void VAbstractPattern::ChangeActivPP(const QString &name, const Document &parse)
292 {
293     Q_ASSERT_X(not name.isEmpty(), Q_FUNC_INFO, "name pattern piece is empty");
294     if (CheckExistNamePP(name))
295     {
296         this->nameActivPP = name;
297         if (parse == Document::FullParse)
298         {
299             emit ChangedActivPP(name);
300         }
301     }
302 }
303 
304 //---------------------------------------------------------------------------------------------------------------------
305 /**
306  * @brief GetActivDrawElement return draw tag for current pattern peace.
307  * @param element draw tag.
308  * @return true if found.
309  */
GetActivDrawElement(QDomElement & element) const310 bool VAbstractPattern::GetActivDrawElement(QDomElement &element) const
311 {
312     if (nameActivPP.isEmpty() == false)
313     {
314         const QDomNodeList elements = this->documentElement().elementsByTagName( TagDraw );
315         if (elements.size() == 0)
316         {
317             return false;
318         }
319         for ( qint32 i = 0; i < elements.count(); i++ )
320         {
321             element = elements.at( i ).toElement();
322             if (element.isNull() == false)
323             {
324                 const QString fieldName = element.attribute( AttrName );
325                 if ( fieldName == nameActivPP )
326                 {
327                     return true;
328                 }
329             }
330         }
331         element = QDomElement();
332     }
333     return false;
334 }
335 
336 //---------------------------------------------------------------------------------------------------------------------
getLocalHistory(const QString & draw) const337 QVector<VToolRecord> VAbstractPattern::getLocalHistory(const QString &draw) const
338 {
339     QVector<VToolRecord> historyPP;
340     for (qint32 i = 0; i< history.size(); ++i)
341     {
342         const VToolRecord &tool = history.at(i);
343         if (tool.getNameDraw() == draw)
344         {
345             historyPP.append(tool);
346         }
347     }
348     return historyPP;
349 }
350 
351 //---------------------------------------------------------------------------------------------------------------------
352 /**
353  * @brief CheckNameDraw check if exist pattern peace with this name.
354  * @param name pattern peace name.
355  * @return true if exist.
356  */
CheckExistNamePP(const QString & name) const357 bool VAbstractPattern::CheckExistNamePP(const QString &name) const
358 {
359     Q_ASSERT_X(not name.isEmpty(), Q_FUNC_INFO, "name draw is empty");
360     const QDomNodeList elements = this->documentElement().elementsByTagName( TagDraw );
361     if (elements.size() == 0)
362     {
363         return false;
364     }
365     for ( qint32 i = 0; i < elements.count(); i++ )
366     {
367         const QDomElement elem = elements.at( i ).toElement();
368         if (elem.isNull() == false)
369         {
370             if ( GetParametrString(elem, AttrName) == name )
371             {
372                 return true;
373             }
374         }
375     }
376     return false;
377 }
378 
379 //---------------------------------------------------------------------------------------------------------------------
380 /**
381  * @brief GetActivNodeElement find element in current pattern piece by name.
382  * @param name name tag.
383  * @param element element.
384  * @return true if found.
385  */
GetActivNodeElement(const QString & name,QDomElement & element) const386 bool VAbstractPattern::GetActivNodeElement(const QString &name, QDomElement &element) const
387 {
388     Q_ASSERT_X(not name.isEmpty(), Q_FUNC_INFO, "name draw is empty");
389     QDomElement drawElement;
390     if (GetActivDrawElement(drawElement))
391     {
392         const QDomNodeList listElement = drawElement.elementsByTagName(name);
393         if (listElement.size() != 1)
394         {
395             return false;
396         }
397         element = listElement.at( 0 ).toElement();
398         if (element.isNull() == false)
399         {
400             return true;
401         }
402         else
403         {
404             return false;
405         }
406     }
407     return false;
408 }
409 
410 //---------------------------------------------------------------------------------------------------------------------
ParseGroups(const QDomElement & domElement)411 void VAbstractPattern::ParseGroups(const QDomElement &domElement)
412 {
413     Q_ASSERT_X(not domElement.isNull(), Q_FUNC_INFO, "domElement is null");
414 
415     QMap<quint32, quint32> itemTool;
416     QMap<quint32, bool> itemVisibility;
417 
418     QDomNode domNode = domElement.firstChild();
419     while (domNode.isNull() == false)
420     {
421         if (domNode.isElement())
422         {
423             const QDomElement domElement = domNode.toElement();
424             if (domElement.isNull() == false)
425             {
426                 if (domElement.tagName() == TagGroup)
427                 {
428                     VContainer::UpdateId(GetParametrUInt(domElement, AttrId, NULL_ID_STR), valentinaNamespace);
429 
430                     const QPair<bool, QMap<quint32, quint32> > groupData = ParseItemElement(domElement);
431                     const QMap<quint32, quint32> group = groupData.second;
432                     auto i = group.constBegin();
433                     while (i != group.constEnd())
434                     {
435                         if (not itemTool.contains(i.key()))
436                         {
437                             itemTool.insert(i.key(), i.value());
438                         }
439 
440                         const bool previous = itemVisibility.value(i.key(), false);
441                         itemVisibility.insert(i.key(), previous || groupData.first);
442                         ++i;
443                     }
444                 }
445             }
446         }
447         domNode = domNode.nextSibling();
448     }
449 
450     auto i = itemTool.constBegin();
451     while (i != itemTool.constEnd())
452     {
453         if (tools.contains(i.value()))
454         {
455             VDataTool* tool = tools.value(i.value());
456             tool->GroupVisibility(i.key(), itemVisibility.value(i.key(), true));
457         }
458         ++i;
459     }
460 }
461 
462 //---------------------------------------------------------------------------------------------------------------------
CountPP() const463 int VAbstractPattern::CountPP() const
464 {
465     const QDomElement rootElement = this->documentElement();
466     if (rootElement.isNull())
467     {
468         return 0;
469     }
470 
471     return rootElement.elementsByTagName( TagDraw ).count();
472 }
473 
474 //---------------------------------------------------------------------------------------------------------------------
GetPPElement(const QString & name)475 QDomElement VAbstractPattern::GetPPElement(const QString &name)
476 {
477     if (name.isEmpty() == false)
478     {
479         const QDomNodeList elements = this->documentElement().elementsByTagName( TagDraw );
480         if (elements.size() == 0)
481         {
482             return QDomElement();
483         }
484         for ( qint32 i = 0; i < elements.count(); i++ )
485         {
486             QDomElement element = elements.at( i ).toElement();
487             if (element.isNull() == false)
488             {
489                 if ( element.attribute( AttrName ) == name )
490                 {
491                     return element;
492                 }
493             }
494         }
495     }
496     return QDomElement();
497 }
498 
499 //---------------------------------------------------------------------------------------------------------------------
500 /**
501  * @brief ChangeNamePP change pattern piece name.
502  * @param oldName old pattern piece name.
503  * @param newName new pattern piece name.
504  * @return true if success.
505  */
ChangeNamePP(const QString & oldName,const QString & newName)506 bool VAbstractPattern::ChangeNamePP(const QString &oldName, const QString &newName)
507 {
508     Q_ASSERT_X(not newName.isEmpty(), Q_FUNC_INFO, "new name pattern piece is empty");
509     Q_ASSERT_X(not oldName.isEmpty(), Q_FUNC_INFO, "old name pattern piece is empty");
510 
511     if (CheckExistNamePP(oldName) == false)
512     {
513         qDebug()<<"Do not exist pattern piece with name"<<oldName;
514         return false;
515     }
516 
517     if (CheckExistNamePP(newName))
518     {
519         qDebug()<<"Already exist pattern piece with name"<<newName;
520         return false;
521     }
522 
523     QDomElement ppElement = GetPPElement(oldName);
524     if (ppElement.isElement())
525     {
526         if (nameActivPP == oldName)
527         {
528             nameActivPP = newName;
529         }
530         ppElement.setAttribute(AttrName, newName);
531         emit patternChanged(false);//For situation when we change name directly, without undocommands.
532         emit ChangedNameDraw(oldName, newName);
533         return true;
534     }
535     else
536     {
537         qDebug()<<"Can't find pattern piece node with name"<<oldName<<Q_FUNC_INFO;
538         return false;
539     }
540 }
541 
542 //---------------------------------------------------------------------------------------------------------------------
543 /**
544  * @brief appendPP add new pattern piece.
545  *
546  * Method check if not exist pattern piece with the same name and change name active pattern piece name, send signal
547  * about change pattern piece. Doen't add pattern piece to file structure. This task make SPoint tool.
548  * @param name pattern peace name.
549  * @return true if success.
550  */
appendPP(const QString & name)551 bool VAbstractPattern::appendPP(const QString &name)
552 {
553     Q_ASSERT_X(not name.isEmpty(), Q_FUNC_INFO, "name pattern piece is empty");
554     if (name.isEmpty())
555     {
556         return false;
557     }
558     if (CheckExistNamePP(name) == false)
559     {
560         SetActivPP(name);
561         return true;
562     }
563     return false;
564 }
565 
566 //---------------------------------------------------------------------------------------------------------------------
getCursor() const567 quint32 VAbstractPattern::getCursor() const
568 {
569     return cursor;
570 }
571 
572 //---------------------------------------------------------------------------------------------------------------------
setCursor(const quint32 & value)573 void VAbstractPattern::setCursor(const quint32 &value)
574 {
575     if (cursor != value)
576     {
577         cursor = value;
578         emit ChangedCursor(cursor);
579     }
580 }
581 
582 //---------------------------------------------------------------------------------------------------------------------
setXMLContent(const QString & fileName)583 void VAbstractPattern::setXMLContent(const QString &fileName)
584 {
585     Clear();
586     VDomDocument::setXMLContent(fileName);
587     m_patternNumber = ReadPatternNumber();
588     m_labelDateFormat = ReadLabelDateFormat();
589     m_patternName = ReadPatternName();
590     m_MPath = ReadMPath();
591     m_watermarkPath = ReadWatermarkPath();
592     m_companyName = ReadCompanyName();
593     m_units = ReadUnits();
594 }
595 
596 //---------------------------------------------------------------------------------------------------------------------
Clear()597 void VAbstractPattern::Clear()
598 {
599     clear();
600     m_patternNumber.clear();
601     m_labelDateFormat.clear();
602     m_patternName.clear();
603     m_MPath.clear();
604     m_watermarkPath.clear();
605     m_companyName.clear();
606     m_units = Unit::LAST_UNIT_DO_NOT_USE;
607     modified = false;
608 }
609 
610 //---------------------------------------------------------------------------------------------------------------------
611 /**
612  * @brief getTool return tool from tool list.
613  * @param id tool id.
614  * @return tool.
615  */
getTool(quint32 id)616 VDataTool *VAbstractPattern::getTool(quint32 id)
617 {
618     ToolExists(id);
619     return tools.value(id);
620 }
621 
622 //---------------------------------------------------------------------------------------------------------------------
623 /**
624  * @brief AddTool add tool to list tools.
625  * @param id tool id.
626  * @param tool tool.
627  */
AddTool(quint32 id,VDataTool * tool)628 void VAbstractPattern::AddTool(quint32 id, VDataTool *tool)
629 {
630     Q_ASSERT_X(id != 0, Q_FUNC_INFO, "id == 0");
631     SCASSERT(tool != nullptr)
632             tools.insert(id, tool);
633 }
634 
635 //---------------------------------------------------------------------------------------------------------------------
RemoveTool(quint32 id)636 void VAbstractPattern::RemoveTool(quint32 id)
637 {
638     tools.remove(id);
639 }
640 
641 //---------------------------------------------------------------------------------------------------------------------
ParsePieceNodes(const QDomElement & domElement)642 VPiecePath VAbstractPattern::ParsePieceNodes(const QDomElement &domElement)
643 {
644     VPiecePath path;
645     const QDomNodeList nodeList = domElement.childNodes();
646     for (qint32 i = 0; i < nodeList.size(); ++i)
647     {
648         const QDomElement element = nodeList.at(i).toElement();
649         if (not element.isNull())
650         {
651             path.Append(ParseSANode(element));
652         }
653     }
654     return path;
655 }
656 
657 //---------------------------------------------------------------------------------------------------------------------
ParsePieceCSARecords(const QDomElement & domElement)658 QVector<CustomSARecord> VAbstractPattern::ParsePieceCSARecords(const QDomElement &domElement)
659 {
660     QVector<CustomSARecord> records;
661     const QDomNodeList nodeList = domElement.childNodes();
662     for (qint32 i = 0; i < nodeList.size(); ++i)
663     {
664         const QDomElement element = nodeList.at(i).toElement();
665         if (not element.isNull())
666         {
667             CustomSARecord record;
668             record.startPoint = GetParametrUInt(element, VAbstractPattern::AttrStart, NULL_ID_STR);
669             record.path = GetParametrUInt(element, VAbstractPattern::AttrPath, NULL_ID_STR);
670             record.endPoint = GetParametrUInt(element, VAbstractPattern::AttrEnd, NULL_ID_STR);
671             record.reverse = GetParametrBool(element, VAbstractPattern::AttrNodeReverse, falseStr);
672             record.includeType = static_cast<PiecePathIncludeType>(GetParametrUInt(element,
673                                                                                    VAbstractPattern::AttrIncludeAs,
674                                                                                    QChar('1')));
675             records.append(record);
676         }
677     }
678     return records;
679 }
680 
681 //---------------------------------------------------------------------------------------------------------------------
ParsePieceInternalPaths(const QDomElement & domElement)682 QVector<quint32> VAbstractPattern::ParsePieceInternalPaths(const QDomElement &domElement)
683 {
684     QVector<quint32> records;
685     const QDomNodeList nodeList = domElement.childNodes();
686     for (qint32 i = 0; i < nodeList.size(); ++i)
687     {
688         const QDomElement element = nodeList.at(i).toElement();
689         if (not element.isNull())
690         {
691             const quint32 path = GetParametrUInt(element, VAbstractPattern::AttrPath, NULL_ID_STR);
692             if (path > NULL_ID)
693             {
694                 records.append(path);
695             }
696         }
697     }
698     return records;
699 }
700 
701 //---------------------------------------------------------------------------------------------------------------------
ParsePiecePointRecords(const QDomElement & domElement)702 QVector<quint32> VAbstractPattern::ParsePiecePointRecords(const QDomElement &domElement)
703 {
704     QVector<quint32> records;
705     const QDomNodeList nodeList = domElement.childNodes();
706     for (qint32 i = 0; i < nodeList.size(); ++i)
707     {
708         const QDomElement element = nodeList.at(i).toElement();
709         if (not element.isNull())
710         {
711             const quint32 path = element.text().toUInt();
712             if (path > NULL_ID)
713             {
714                 records.append(path);
715             }
716         }
717     }
718     return records;
719 }
720 
721 //---------------------------------------------------------------------------------------------------------------------
ParseSANode(const QDomElement & domElement)722 VPieceNode VAbstractPattern::ParseSANode(const QDomElement &domElement)
723 {
724     const quint32 id = VDomDocument::GetParametrUInt(domElement, AttrIdObject, NULL_ID_STR);
725     const bool reverse = VDomDocument::GetParametrUInt(domElement, VAbstractPattern::AttrNodeReverse, QChar('0'));
726     const bool excluded = VDomDocument::GetParametrBool(domElement, VAbstractPattern::AttrNodeExcluded, falseStr);
727     const bool uniqeness = VDomDocument::GetParametrBool(domElement, VAbstractPattern::AttrCheckUniqueness, trueStr);
728     const QString saBefore = VDomDocument::GetParametrString(domElement, VAbstractPattern::AttrSABefore,
729                                                              currentSeamAllowance);
730     const QString saAfter = VDomDocument::GetParametrString(domElement, VAbstractPattern::AttrSAAfter,
731                                                             currentSeamAllowance);
732     const PieceNodeAngle angle = static_cast<PieceNodeAngle>(VDomDocument::GetParametrUInt(domElement, AttrAngle,
733                                                                                            QChar('0')));
734 
735     const bool passmark = VDomDocument::GetParametrBool(domElement, VAbstractPattern::AttrNodePassmark, falseStr);
736     const PassmarkLineType passmarkLine = StringToPassmarkLineType(VDomDocument::GetParametrString(domElement,
737                                                                                  VAbstractPattern::AttrNodePassmarkLine,
738                                                                                                    strOne));
739     const PassmarkAngleType passmarkAngle = StringToPassmarkAngleType(VDomDocument::GetParametrString(domElement,
740                                                                                 VAbstractPattern::AttrNodePassmarkAngle,
741                                                                                                    strStraightforward));
742 
743     const bool showSecond = VDomDocument::GetParametrBool(domElement, VAbstractPattern::AttrNodeShowSecondPassmark,
744                                                           trueStr);
745     const bool manualPassmarkLength =
746             VDomDocument::GetParametrBool(domElement, VAbstractPattern::AttrManualPassmarkLength, falseStr);
747     const QString passmarkLength =
748             VDomDocument::GetParametrEmptyString(domElement, VAbstractPattern::AttrPassmarkLength);
749 
750     const QString t = VDomDocument::GetParametrString(domElement, AttrType, VAbstractPattern::NodePoint);
751     Tool tool;
752 
753     const QStringList types
754     {
755         VAbstractPattern::NodePoint,
756         VAbstractPattern::NodeArc,
757         VAbstractPattern::NodeSpline,
758         VAbstractPattern::NodeSplinePath,
759         VAbstractPattern::NodeElArc
760     };
761 
762     switch (types.indexOf(t))
763     {
764         case 0: // VAbstractPattern::NodePoint
765             tool = Tool::NodePoint;
766             break;
767         case 1: // VAbstractPattern::NodeArc
768             tool = Tool::NodeArc;
769             break;
770         case 2: // VAbstractPattern::NodeSpline
771             tool = Tool::NodeSpline;
772             break;
773         case 3: // VAbstractPattern::NodeSplinePath
774             tool = Tool::NodeSplinePath;
775             break;
776         case 4: // NodeElArc
777             tool = Tool::NodeElArc;
778             break;
779         default:
780             VException e(QObject::tr("Wrong tag name '%1'.").arg(t));
781             throw e;
782     }
783     VPieceNode node(id, tool, reverse);
784     node.SetFormulaSABefore(saBefore);
785     node.SetFormulaSAAfter(saAfter);
786     node.SetAngleType(angle);
787     node.SetExcluded(excluded);
788     node.SetCheckUniqueness(uniqeness);
789     node.SetShowSecondPassmark(showSecond);
790     node.SetPassmark(passmark);
791     node.SetPassmarkLineType(passmarkLine);
792     node.SetPassmarkAngleType(passmarkAngle);
793     node.SetManualPassmarkLength(manualPassmarkLength);
794     node.SetFormulaPassmarkLength(passmarkLength);
795 
796     return node;
797 }
798 
799 //---------------------------------------------------------------------------------------------------------------------
AddToolOnRemove(VDataTool * tool)800 void VAbstractPattern::AddToolOnRemove(VDataTool *tool)
801 {
802     SCASSERT(tool != nullptr)
803     toolsOnRemove.append(tool);
804 }
805 
806 //---------------------------------------------------------------------------------------------------------------------
807 /**
808  * @brief getHistory return list with list of history records.
809  * @return list of history records.
810  */
getHistory()811 QVector<VToolRecord> *VAbstractPattern::getHistory()
812 {
813     return &history;
814 }
815 
816 //---------------------------------------------------------------------------------------------------------------------
getLocalHistory() const817 QVector<VToolRecord> VAbstractPattern::getLocalHistory() const
818 {
819     return getLocalHistory(GetNameActivPP());
820 }
821 
822 //---------------------------------------------------------------------------------------------------------------------
MPath() const823 QString VAbstractPattern::MPath() const
824 {
825     return m_MPath;
826 }
827 
828 //---------------------------------------------------------------------------------------------------------------------
SetMPath(const QString & path)829 void VAbstractPattern::SetMPath(const QString &path)
830 {
831     if (setTagText(TagMeasurements, path))
832     {
833         m_MPath = path;
834         patternLabelWasChanged = true;
835         modified = true;
836         emit patternChanged(false);
837     }
838     else
839     {
840         qDebug()<<"Can't save path to measurements"<<Q_FUNC_INFO;
841     }
842 }
843 
844 //---------------------------------------------------------------------------------------------------------------------
SiblingNodeId(const quint32 & nodeId) const845 quint32 VAbstractPattern::SiblingNodeId(const quint32 &nodeId) const
846 {
847     // This check helps to find missed tools in the switch
848     Q_STATIC_ASSERT_X(static_cast<int>(Tool::LAST_ONE_DO_NOT_USE) == 55, "Check if need to ignore modeling tools.");
849 
850     quint32 siblingId = NULL_ID;
851 
852     const QVector<VToolRecord> history = getLocalHistory();
853     for (qint32 i = 0; i < history.size(); ++i)
854     {
855         const VToolRecord tool = history.at(i);
856         if (nodeId == tool.getId())
857         {
858             if (i == 0)
859             {
860                 siblingId = NULL_ID;
861             }
862             else
863             {
864                 for (qint32 j = i; j > 0; --j)
865                 {
866                     const VToolRecord tool = history.at(j-1);
867                     switch ( tool.getTypeTool() )
868                     {
869                         case Tool::Arrow:
870                         case Tool::Piece:
871                         case Tool::UnionDetails:
872                         case Tool::NodeArc:
873                         case Tool::NodeElArc:
874                         case Tool::NodePoint:
875                         case Tool::NodeSpline:
876                         case Tool::NodeSplinePath:
877                         case Tool::PlaceLabel:
878                         case Tool::Pin:
879                         case Tool::PiecePath:
880                         case Tool::InsertNode:
881                         case Tool::DuplicateDetail:
882                             continue;
883                         default:
884                             siblingId = tool.getId();
885                             j = 0;// break loop
886                             break;
887                     }
888                 }
889             }
890         }
891     }
892     return siblingId;
893 }
894 
895 //---------------------------------------------------------------------------------------------------------------------
getPatternPieces() const896 QStringList VAbstractPattern::getPatternPieces() const
897 {
898     return patternPieces;
899 }
900 
901 //---------------------------------------------------------------------------------------------------------------------
GetDescription() const902 QString VAbstractPattern::GetDescription() const
903 {
904     return UniqueTagText(TagDescription);
905 }
906 
907 //---------------------------------------------------------------------------------------------------------------------
SetDescription(const QString & text)908 void VAbstractPattern::SetDescription(const QString &text)
909 {
910     CheckTagExists(TagDescription);
911     setTagText(TagDescription, text);
912     modified = true;
913     emit patternChanged(false);
914 }
915 
916 //---------------------------------------------------------------------------------------------------------------------
GetNotes() const917 QString VAbstractPattern::GetNotes() const
918 {
919     return UniqueTagText(TagNotes);
920 }
921 
922 //---------------------------------------------------------------------------------------------------------------------
SetNotes(const QString & text)923 void VAbstractPattern::SetNotes(const QString &text)
924 {
925     CheckTagExists(TagNotes);
926     setTagText(TagNotes, text);
927     modified = true;
928     emit patternChanged(false);
929 }
930 
931 //---------------------------------------------------------------------------------------------------------------------
GetPatternName() const932 QString VAbstractPattern::GetPatternName() const
933 {
934     return m_patternName;
935 }
936 
937 //---------------------------------------------------------------------------------------------------------------------
SetPatternName(const QString & qsName)938 void VAbstractPattern::SetPatternName(const QString &qsName)
939 {
940     m_patternName = qsName;
941     CheckTagExists(TagPatternName);
942     setTagText(TagPatternName, m_patternName);
943     patternLabelWasChanged = true;
944     modified = true;
945     emit patternChanged(false);
946 }
947 
948 //---------------------------------------------------------------------------------------------------------------------
GetCompanyName() const949 QString VAbstractPattern::GetCompanyName() const
950 {
951     return m_companyName;
952 }
953 
954 //---------------------------------------------------------------------------------------------------------------------
SetCompanyName(const QString & qsName)955 void VAbstractPattern::SetCompanyName(const QString& qsName)
956 {
957     m_companyName = qsName;
958     CheckTagExists(TagCompanyName);
959     setTagText(TagCompanyName, m_companyName);
960     patternLabelWasChanged = true;
961     modified = true;
962     emit patternChanged(false);
963 }
964 
965 //---------------------------------------------------------------------------------------------------------------------
GetPatternNumber() const966 QString VAbstractPattern::GetPatternNumber() const
967 {
968     return m_patternNumber;
969 }
970 
971 //---------------------------------------------------------------------------------------------------------------------
SetPatternNumber(const QString & qsNum)972 void VAbstractPattern::SetPatternNumber(const QString& qsNum)
973 {
974     m_patternNumber = qsNum;
975     CheckTagExists(TagPatternNum);
976     setTagText(TagPatternNum, m_patternNumber);
977     patternLabelWasChanged = true;
978     modified = true;
979     emit patternChanged(false);
980 }
981 
982 //---------------------------------------------------------------------------------------------------------------------
GetCustomerName() const983 QString VAbstractPattern::GetCustomerName() const
984 {
985     return UniqueTagText(TagCustomerName);
986 }
987 
988 //---------------------------------------------------------------------------------------------------------------------
SetCustomerName(const QString & qsName)989 void VAbstractPattern::SetCustomerName(const QString& qsName)
990 {
991     CheckTagExists(TagCustomerName);
992     setTagText(TagCustomerName, qsName);
993     patternLabelWasChanged = true;
994     modified = true;
995     emit patternChanged(false);
996 }
997 
998 //---------------------------------------------------------------------------------------------------------------------
GetCustomerBirthDate() const999 QDate VAbstractPattern::GetCustomerBirthDate() const
1000 {
1001     return QDate::fromString(UniqueTagText(TagCustomerBirthDate), "yyyy-MM-dd");
1002 }
1003 
1004 //---------------------------------------------------------------------------------------------------------------------
SetCustomerBirthDate(const QDate & date)1005 void VAbstractPattern::SetCustomerBirthDate(const QDate &date)
1006 {
1007     CheckTagExists(TagCustomerBirthDate);
1008     setTagText(TagCustomerBirthDate, date.toString("yyyy-MM-dd"));
1009     patternLabelWasChanged = true;
1010     modified = true;
1011     emit patternChanged(false);
1012 }
1013 
1014 //---------------------------------------------------------------------------------------------------------------------
GetCustomerEmail() const1015 QString VAbstractPattern::GetCustomerEmail() const
1016 {
1017     return UniqueTagText(TagCustomerEmail);
1018 }
1019 
1020 //---------------------------------------------------------------------------------------------------------------------
SetCustomerEmail(const QString & email)1021 void VAbstractPattern::SetCustomerEmail(const QString &email)
1022 {
1023     CheckTagExists(TagCustomerEmail);
1024     setTagText(TagCustomerEmail, email);
1025     patternLabelWasChanged = true;
1026     modified = true;
1027     emit patternChanged(false);
1028 }
1029 
1030 //---------------------------------------------------------------------------------------------------------------------
GetLabelDateFormat() const1031 QString VAbstractPattern::GetLabelDateFormat() const
1032 {
1033     return m_labelDateFormat;
1034 }
1035 
1036 //---------------------------------------------------------------------------------------------------------------------
SetLabelDateFormat(const QString & format)1037 void VAbstractPattern::SetLabelDateFormat(const QString &format)
1038 {
1039     m_labelDateFormat = format;
1040     QDomElement tag = CheckTagExists(TagPatternLabel);
1041     SetAttribute(tag, AttrDateFormat, m_labelDateFormat);
1042     patternLabelWasChanged = true;
1043     modified = true;
1044     emit patternChanged(false);
1045 }
1046 
1047 //---------------------------------------------------------------------------------------------------------------------
GetLabelTimeFormat() const1048 QString VAbstractPattern::GetLabelTimeFormat() const
1049 {
1050     QString globalLabelTimeFormat = VAbstractApplication::VApp()->Settings()->GetLabelTimeFormat();
1051 
1052     const QDomNodeList list = elementsByTagName(TagPatternLabel);
1053     if (list.isEmpty())
1054     {
1055         return globalLabelTimeFormat;
1056     }
1057 
1058     QDomElement tag = list.at(0).toElement();
1059     return GetParametrString(tag, AttrTimeFormat, globalLabelTimeFormat);
1060 }
1061 
1062 //---------------------------------------------------------------------------------------------------------------------
SetLabelTimeFormat(const QString & format)1063 void VAbstractPattern::SetLabelTimeFormat(const QString &format)
1064 {
1065     QDomElement tag = CheckTagExists(TagPatternLabel);
1066     SetAttribute(tag, AttrTimeFormat, format);
1067     patternLabelWasChanged = true;
1068     modified = true;
1069     emit patternChanged(false);
1070 }
1071 
1072 //---------------------------------------------------------------------------------------------------------------------
SetPatternLabelTemplate(const QVector<VLabelTemplateLine> & lines)1073 void VAbstractPattern::SetPatternLabelTemplate(const QVector<VLabelTemplateLine> &lines)
1074 {
1075     QDomElement tag = CheckTagExists(TagPatternLabel);
1076     RemoveAllChildren(tag);
1077     SetLabelTemplate(tag, lines);
1078     patternLabelLines = lines;
1079     patternLabelWasChanged = true;
1080     modified = true;
1081     emit patternChanged(false);
1082 }
1083 
1084 //---------------------------------------------------------------------------------------------------------------------
GetPatternLabelTemplate() const1085 QVector<VLabelTemplateLine> VAbstractPattern::GetPatternLabelTemplate() const
1086 {
1087     if (patternLabelLines.isEmpty())
1088     {
1089         const QDomNodeList list = elementsByTagName(TagPatternLabel);
1090         if (list.isEmpty() || list.at(0).childNodes().count() == 0)
1091         {
1092             return QVector<VLabelTemplateLine>();
1093         }
1094 
1095         patternLabelLines = GetLabelTemplate(list.at(0).toElement());
1096     }
1097 
1098     return patternLabelLines;
1099 }
1100 
1101 //---------------------------------------------------------------------------------------------------------------------
SetWatermarkPath(const QString & path)1102 bool VAbstractPattern::SetWatermarkPath(const QString &path)
1103 {
1104     QDomElement tag = CheckTagExists(TagWatermark);
1105 
1106     if (path.isEmpty())
1107     {
1108         QDomNode parent = tag.parentNode();
1109         parent.removeChild(tag);
1110 
1111         emit patternChanged(false);
1112         patternLabelWasChanged = true;
1113         m_watermarkPath = path;
1114         modified = true;
1115         return true;
1116     }
1117     else
1118     {
1119         if (setTagText(tag, path))
1120         {
1121             emit patternChanged(false);
1122             patternLabelWasChanged = true;
1123             m_watermarkPath = path;
1124             modified = true;
1125             return true;
1126         }
1127         else
1128         {
1129             qDebug() << "Can't save path to watermark" << Q_FUNC_INFO;
1130             return false;
1131         }
1132     }
1133 }
1134 
1135 //---------------------------------------------------------------------------------------------------------------------
GetWatermarkPath() const1136 QString VAbstractPattern::GetWatermarkPath() const
1137 {
1138     return m_watermarkPath;
1139 }
1140 
1141 //---------------------------------------------------------------------------------------------------------------------
SetPatternMaterials(const QMap<int,QString> & materials)1142 void VAbstractPattern::SetPatternMaterials(const QMap<int, QString> &materials)
1143 {
1144     QDomElement tag = CheckTagExists(TagPatternMaterials);
1145     RemoveAllChildren(tag);
1146     SetMaterials(tag, materials);
1147     patternMaterials = materials;
1148     patternLabelWasChanged = true;
1149     modified = true;
1150     emit patternChanged(false);
1151 }
1152 
1153 //---------------------------------------------------------------------------------------------------------------------
GetPatternMaterials() const1154 QMap<int, QString> VAbstractPattern::GetPatternMaterials() const
1155 {
1156     if (patternMaterials.isEmpty())
1157     {
1158         const QDomNodeList list = elementsByTagName(TagPatternMaterials);
1159         if (list.isEmpty() || list.at(0).childNodes().count() == 0)
1160         {
1161             return QMap<int, QString>();
1162         }
1163 
1164         patternMaterials = GetMaterials(list.at(0).toElement());
1165     }
1166 
1167     return AdjustMaterials(patternMaterials);
1168 }
1169 
1170 //---------------------------------------------------------------------------------------------------------------------
GetFinalMeasurements() const1171 QVector<VFinalMeasurement> VAbstractPattern::GetFinalMeasurements() const
1172 {
1173     const QDomNodeList list = elementsByTagName(TagFinalMeasurements);
1174     if (list.isEmpty() || list.at(0).childNodes().count() == 0)
1175     {
1176         return QVector<VFinalMeasurement>();
1177     }
1178 
1179     return GetFMeasurements(list.at(0).toElement());
1180 }
1181 
1182 //---------------------------------------------------------------------------------------------------------------------
SetFinalMeasurements(const QVector<VFinalMeasurement> & measurements)1183 void VAbstractPattern::SetFinalMeasurements(const QVector<VFinalMeasurement> &measurements)
1184 {
1185     QDomElement tag = CheckTagExists(TagFinalMeasurements);
1186     RemoveAllChildren(tag);
1187     SetFMeasurements(tag, measurements);
1188     modified = true;
1189     emit patternChanged(false);
1190 }
1191 
1192 //---------------------------------------------------------------------------------------------------------------------
SetPatternWasChanged(bool changed)1193 void VAbstractPattern::SetPatternWasChanged(bool changed)
1194 {
1195     patternLabelWasChanged = changed;
1196 }
1197 
1198 //---------------------------------------------------------------------------------------------------------------------
GetPatternWasChanged() const1199 bool VAbstractPattern::GetPatternWasChanged() const
1200 {
1201     return patternLabelWasChanged;
1202 }
1203 
1204 //---------------------------------------------------------------------------------------------------------------------
GetPassmarkLengthVariable() const1205 QString VAbstractPattern::GetPassmarkLengthVariable() const
1206 {
1207     const QDomElement pattern = documentElement();
1208 
1209     if (pattern.isNull())
1210     {
1211         return {};
1212     }
1213 
1214     return GetParametrEmptyString(pattern, AttrPassmarkLength);
1215 }
1216 
1217 //---------------------------------------------------------------------------------------------------------------------
SetPassmarkLengthVariable(const QString & name)1218 void VAbstractPattern::SetPassmarkLengthVariable(const QString &name)
1219 {
1220     QDomElement pattern = documentElement();
1221 
1222     if (not pattern.isNull())
1223     {
1224         SetAttribute(pattern, AttrPassmarkLength, name);
1225         modified = true;
1226     }
1227 }
1228 
1229 //---------------------------------------------------------------------------------------------------------------------
GetImage() const1230 QString VAbstractPattern::GetImage() const
1231 {
1232     return UniqueTagText(TagImage);
1233 }
1234 
1235 //---------------------------------------------------------------------------------------------------------------------
GetImageExtension() const1236 QString VAbstractPattern::GetImageExtension() const
1237 {
1238     const QString defExt =  QStringLiteral("PNG");
1239     const QDomNodeList nodeList = this->elementsByTagName(TagImage);
1240     if (nodeList.isEmpty())
1241     {
1242         return defExt;
1243     }
1244     else
1245     {
1246         const QDomNode domNode = nodeList.at(0);
1247         if (domNode.isNull() == false && domNode.isElement())
1248         {
1249             const QDomElement domElement = domNode.toElement();
1250             if (domElement.isNull() == false)
1251             {
1252                 const QString ext = domElement.attribute(AttrExtension, defExt);
1253                 return ext;
1254             }
1255         }
1256     }
1257     return defExt;
1258 }
1259 
1260 //---------------------------------------------------------------------------------------------------------------------
SetImage(const QString & text,const QString & extension)1261 void VAbstractPattern::SetImage(const QString &text, const QString &extension)
1262 {
1263     QDomElement imageElement = CheckTagExists(TagImage);
1264     setTagText(imageElement, text);
1265     CheckTagExists(TagImage).setAttribute(AttrExtension, extension);
1266     modified = true;
1267     emit patternChanged(false);
1268 }
1269 
1270 //---------------------------------------------------------------------------------------------------------------------
DeleteImage()1271 void VAbstractPattern::DeleteImage()
1272 {
1273     QDomElement pattern = documentElement();
1274     pattern.removeChild(CheckTagExists(TagImage));
1275     modified = true;
1276     emit patternChanged(false);
1277 }
1278 
1279 //---------------------------------------------------------------------------------------------------------------------
GetVersion() const1280 QString VAbstractPattern::GetVersion() const
1281 {
1282     return UniqueTagText(TagVersion, VPatternConverter::PatternMaxVerStr);
1283 }
1284 
1285 //---------------------------------------------------------------------------------------------------------------------
SetVersion()1286 void VAbstractPattern::SetVersion()
1287 {
1288     setTagText(TagVersion, VPatternConverter::PatternMaxVerStr);
1289     emit patternChanged(false);
1290 }
1291 
1292 //---------------------------------------------------------------------------------------------------------------------
1293 /**
1294  * @brief haveLiteChange we have unsaved change.
1295  */
haveLiteChange()1296 void VAbstractPattern::haveLiteChange()
1297 {
1298     emit patternChanged(false);
1299 }
1300 
1301 //---------------------------------------------------------------------------------------------------------------------
NeedFullParsing()1302 void VAbstractPattern::NeedFullParsing()
1303 {
1304     emit UndoCommand();
1305 }
1306 
1307 //---------------------------------------------------------------------------------------------------------------------
ClearScene()1308 void VAbstractPattern::ClearScene()
1309 {
1310     emit ClearMainWindow();
1311 }
1312 
1313 //---------------------------------------------------------------------------------------------------------------------
CheckInLayoutList()1314 void VAbstractPattern::CheckInLayoutList()
1315 {
1316     emit UpdateInLayoutList();
1317 }
1318 
1319 //---------------------------------------------------------------------------------------------------------------------
SelectedDetail(quint32 id)1320 void VAbstractPattern::SelectedDetail(quint32 id)
1321 {
1322     emit ShowDetail(id);
1323 }
1324 
1325 //---------------------------------------------------------------------------------------------------------------------
UpdateVisiblityGroups()1326 void VAbstractPattern::UpdateVisiblityGroups()
1327 {
1328     emit UpdateGroups();
1329 }
1330 
1331 //---------------------------------------------------------------------------------------------------------------------
ToolExists(const quint32 & id)1332 void VAbstractPattern::ToolExists(const quint32 &id)
1333 {
1334     if (tools.contains(id) == false)
1335     {
1336         throw VExceptionBadId(tr("Can't find tool in table."), id);
1337     }
1338 }
1339 
1340 //---------------------------------------------------------------------------------------------------------------------
ParsePathNodes(const QDomElement & domElement)1341 VPiecePath VAbstractPattern::ParsePathNodes(const QDomElement &domElement)
1342 {
1343     VPiecePath path;
1344     const QDomNodeList nodeList = domElement.childNodes();
1345     for (qint32 i = 0; i < nodeList.size(); ++i)
1346     {
1347         const QDomElement element = nodeList.at(i).toElement();
1348         if (not element.isNull() && element.tagName() == VAbstractPattern::TagNode)
1349         {
1350             path.Append(ParseSANode(element));
1351         }
1352     }
1353     return path;
1354 }
1355 
1356 //---------------------------------------------------------------------------------------------------------------------
1357 /**
1358  * @brief SetActivPP set current pattern piece.
1359  * @param name pattern peace name.
1360  */
SetActivPP(const QString & name)1361 void VAbstractPattern::SetActivPP(const QString &name)
1362 {
1363     Q_ASSERT_X(not name.isEmpty(), Q_FUNC_INFO, "name pattern piece is empty");
1364     this->nameActivPP = name;
1365     emit ChangedActivPP(name);
1366 }
1367 
1368 //---------------------------------------------------------------------------------------------------------------------
CheckTagExists(const QString & tag)1369 QDomElement VAbstractPattern::CheckTagExists(const QString &tag)
1370 {
1371     const QDomNodeList list = elementsByTagName(tag);
1372     QDomElement element;
1373     if (list.isEmpty())
1374     {
1375         const QStringList tags
1376         {
1377             TagUnit, // 0
1378             TagImage, // 1
1379             TagDescription, // 2
1380             TagNotes, // 3
1381             TagPatternName, // 4
1382             TagPatternNum, // 5
1383             TagCompanyName, // 6
1384             TagCustomerName, // 7
1385             TagCustomerBirthDate, // 8
1386             TagCustomerEmail, // 9
1387             TagPatternLabel, // 10
1388             TagWatermark, // 11
1389             TagPatternMaterials, // 12
1390             TagFinalMeasurements // 13
1391         };
1392 
1393         switch (tags.indexOf(tag))
1394         {
1395             case 1: //TagImage
1396                 element = createElement(TagImage);
1397                 break;
1398             case 2: //TagDescription
1399                 element = createElement(TagDescription);
1400                 break;
1401             case 3: //TagNotes
1402                 element = createElement(TagNotes);
1403                 break;
1404             case 4: // TagPatternName
1405                 element = createElement(TagPatternName);
1406                 break;
1407             case 5: // TagPatternNum
1408                 element = createElement(TagPatternNum);
1409                 break;
1410             case 6: // TagCompanyName
1411                 element = createElement(TagCompanyName);
1412                 break;
1413             case 7: // TagCustomerName
1414                 element = createElement(TagCustomerName);
1415                 break;
1416             case 8: // TagCustomerBirthDate
1417                 element = createElement(TagCustomerBirthDate);
1418                 break;
1419             case 9: // TagCustomerEmail
1420                 element = createElement(TagCustomerEmail);
1421                 break;
1422             case 10: // TagPatternLabel
1423                 element = createElement(TagPatternLabel);
1424                 break;
1425             case 11: // TagWatermark
1426                 element = createElement(TagWatermark);
1427                 break;
1428             case 12: // TagPatternMaterials
1429                 element = createElement(TagPatternMaterials);
1430                 break;
1431             case 13: // TagFinalMeasurements
1432                 element = createElement(TagFinalMeasurements);
1433                 break;
1434             case 0: //TagUnit (Mandatory tag)
1435             default:
1436                 return QDomElement();
1437         }
1438         InsertTag(tags, element);
1439         return element;
1440     }
1441     return list.at(0).toElement();
1442 }
1443 
1444 //---------------------------------------------------------------------------------------------------------------------
InsertTag(const QStringList & tags,const QDomElement & element)1445 void VAbstractPattern::InsertTag(const QStringList &tags, const QDomElement &element)
1446 {
1447     QDomElement pattern = documentElement();
1448     for (int i = tags.indexOf(element.tagName())-1; i >= 0; --i)
1449     {
1450         const QDomNodeList list = elementsByTagName(tags.at(i));
1451         if (not list.isEmpty())
1452         {
1453             pattern.insertAfter(element, list.at(0));
1454             break;
1455         }
1456     }
1457     SetVersion();
1458 }
1459 
1460 //---------------------------------------------------------------------------------------------------------------------
GetIndexActivPP() const1461 int VAbstractPattern::GetIndexActivPP() const
1462 {
1463     const QDomNodeList drawList = elementsByTagName(TagDraw);
1464 
1465     int index = 0;
1466     if (not drawList.isEmpty())
1467     {
1468         for (int i = 0; i < drawList.size(); ++i)
1469         {
1470             QDomElement node = drawList.at(i).toElement();
1471             if (node.attribute(AttrName) == nameActivPP)
1472             {
1473                 index = i;
1474                 break;
1475             }
1476         }
1477     }
1478 
1479     return index;
1480 }
1481 
1482 //---------------------------------------------------------------------------------------------------------------------
ListIncrements() const1483 QStringList VAbstractPattern::ListIncrements() const
1484 {
1485     QStringList increments;
1486 
1487     auto GetExpressions = [&increments, this](const QString &type)
1488     {
1489         const QDomNodeList list = elementsByTagName(type);
1490         for (int i=0; i < list.size(); ++i)
1491         {
1492             const QString name = GetParametrEmptyString(list.at(i).toElement(), AttrName);
1493             if (not name.isEmpty())
1494             {
1495                 increments.append(name);
1496             }
1497         }
1498     };
1499 
1500     GetExpressions(TagIncrement);
1501     GetExpressions(TagPreviewCalculations);
1502 
1503     return increments;
1504 }
1505 
1506 //---------------------------------------------------------------------------------------------------------------------
ListExpressions() const1507 QVector<VFormulaField> VAbstractPattern::ListExpressions() const
1508 {
1509     // If new tool bring absolutely new type and has formula(s) create new method to cover it.
1510     // Note. Tool Union Details also contains formulas, but we don't use them for union and keep only to simplifying
1511     // working with nodes. Same code for saving reading.
1512     auto futurePointExpressions = QtConcurrent::run(this, &VAbstractPattern::ListPointExpressions);
1513     auto futureArcExpressions = QtConcurrent::run(this, &VAbstractPattern::ListArcExpressions);
1514     auto futureElArcExpressions = QtConcurrent::run(this, &VAbstractPattern::ListElArcExpressions);
1515     auto futureSplineExpressions = QtConcurrent::run(this, &VAbstractPattern::ListSplineExpressions);
1516     auto futureIncrementExpressions = QtConcurrent::run(this, &VAbstractPattern::ListIncrementExpressions);
1517     auto futureOperationExpressions = QtConcurrent::run(this, &VAbstractPattern::ListOperationExpressions);
1518     auto futurePathExpressions = QtConcurrent::run(this, &VAbstractPattern::ListPathExpressions);
1519     auto futurePieceExpressions = QtConcurrent::run(this, &VAbstractPattern::ListPieceExpressions);
1520     auto futureFinalMeasurementsExpressions = QtConcurrent::run(this,
1521                                                                 &VAbstractPattern::ListFinalMeasurementsExpressions);
1522 
1523     QVector<VFormulaField> list;
1524     list << futurePointExpressions.result();
1525     list << futureArcExpressions.result();
1526     list << futureElArcExpressions.result();
1527     list << futureSplineExpressions.result();
1528     list << futureIncrementExpressions.result();
1529     list << futureOperationExpressions.result();
1530     list << futurePathExpressions.result();
1531     list << futurePieceExpressions.result();
1532     list << futureFinalMeasurementsExpressions.result();
1533 
1534     return list;
1535 }
1536 
1537 //---------------------------------------------------------------------------------------------------------------------
ListPointExpressions() const1538 QVector<VFormulaField> VAbstractPattern::ListPointExpressions() const
1539 {
1540     // Check if new tool doesn't bring new attribute with a formula.
1541     // If no just increment a number.
1542     // If new tool bring absolutely new type and has formula(s) create new method to cover it.
1543     Q_STATIC_ASSERT(static_cast<int>(Tool::LAST_ONE_DO_NOT_USE) == 55);
1544 
1545     QVector<VFormulaField> expressions;
1546     const QDomNodeList list = elementsByTagName(TagPoint);
1547     for (int i=0; i < list.size(); ++i)
1548     {
1549         const QDomElement dom = list.at(i).toElement();
1550 
1551         // Each tag can contains several attributes.
1552         ReadExpressionAttribute(expressions, dom, AttrLength);
1553         ReadExpressionAttribute(expressions, dom, AttrAngle);
1554         ReadExpressionAttribute(expressions, dom, AttrC1Radius);
1555         ReadExpressionAttribute(expressions, dom, AttrC2Radius);
1556         ReadExpressionAttribute(expressions, dom, AttrCRadius);
1557         ReadExpressionAttribute(expressions, dom, AttrRadius);
1558         ReadExpressionAttribute(expressions, dom, AttrWidth);
1559         ReadExpressionAttribute(expressions, dom, AttrHeight);
1560     }
1561 
1562     return expressions;
1563 }
1564 
1565 //---------------------------------------------------------------------------------------------------------------------
ListArcExpressions() const1566 QVector<VFormulaField> VAbstractPattern::ListArcExpressions() const
1567 {
1568     // Check if new tool doesn't bring new attribute with a formula.
1569     // If no just increment number.
1570     // If new tool bring absolutely new type and has formula(s) create new method to cover it.
1571     Q_STATIC_ASSERT(static_cast<int>(Tool::LAST_ONE_DO_NOT_USE) == 55);
1572 
1573     QVector<VFormulaField> expressions;
1574     const QDomNodeList list = elementsByTagName(TagArc);
1575     for (int i=0; i < list.size(); ++i)
1576     {
1577         const QDomElement dom = list.at(i).toElement();
1578 
1579         // Each tag can contains several attributes.
1580         ReadExpressionAttribute(expressions, dom, AttrAngle1);
1581         ReadExpressionAttribute(expressions, dom, AttrAngle2);
1582         ReadExpressionAttribute(expressions, dom, AttrRadius);
1583         ReadExpressionAttribute(expressions, dom, AttrLength);
1584     }
1585 
1586     return expressions;
1587 }
1588 
1589 //---------------------------------------------------------------------------------------------------------------------
ListElArcExpressions() const1590 QVector<VFormulaField> VAbstractPattern::ListElArcExpressions() const
1591 {
1592     // Check if new tool doesn't bring new attribute with a formula.
1593     // If no just increment number.
1594     // If new tool bring absolutely new type and has formula(s) create new method to cover it.
1595     Q_STATIC_ASSERT(static_cast<int>(Tool::LAST_ONE_DO_NOT_USE) == 55);
1596 
1597     QVector<VFormulaField> expressions;
1598     const QDomNodeList list = elementsByTagName(TagElArc);
1599     for (int i=0; i < list.size(); ++i)
1600     {
1601         const QDomElement dom = list.at(i).toElement();
1602 
1603         // Each tag can contains several attributes.
1604         ReadExpressionAttribute(expressions, dom, AttrRadius1);
1605         ReadExpressionAttribute(expressions, dom, AttrRadius2);
1606         ReadExpressionAttribute(expressions, dom, AttrAngle1);
1607         ReadExpressionAttribute(expressions, dom, AttrAngle2);
1608         ReadExpressionAttribute(expressions, dom, AttrRotationAngle);
1609     }
1610 
1611     return expressions;
1612 }
1613 
1614 //---------------------------------------------------------------------------------------------------------------------
ListSplineExpressions() const1615 QVector<VFormulaField> VAbstractPattern::ListSplineExpressions() const
1616 {
1617     QVector<VFormulaField> expressions;
1618     expressions << ListPathPointExpressions();
1619     return expressions;
1620 }
1621 
1622 //---------------------------------------------------------------------------------------------------------------------
ListPathPointExpressions() const1623 QVector<VFormulaField> VAbstractPattern::ListPathPointExpressions() const
1624 {
1625     // Check if new tool doesn't bring new attribute with a formula.
1626     // If no just increment number.
1627     // If new tool bring absolutely new type and has formula(s) create new method to cover it.
1628     Q_STATIC_ASSERT(static_cast<int>(Tool::LAST_ONE_DO_NOT_USE) == 55);
1629 
1630     QVector<VFormulaField> expressions;
1631     const QDomNodeList list = elementsByTagName(AttrPathPoint);
1632     for (int i=0; i < list.size(); ++i)
1633     {
1634         const QDomElement dom = list.at(i).toElement();
1635 
1636         // Each tag can contains several attributes.
1637         ReadExpressionAttribute(expressions, dom, AttrKAsm1);
1638         ReadExpressionAttribute(expressions, dom, AttrKAsm2);
1639         ReadExpressionAttribute(expressions, dom, AttrAngle);
1640     }
1641 
1642     return expressions;
1643 }
1644 
1645 //---------------------------------------------------------------------------------------------------------------------
ListIncrementExpressions() const1646 QVector<VFormulaField> VAbstractPattern::ListIncrementExpressions() const
1647 {
1648     QVector<VFormulaField> expressions;
1649     const QDomNodeList list = elementsByTagName(TagIncrement);
1650     for (int i=0; i < list.size(); ++i)
1651     {
1652         const QDomElement dom = list.at(i).toElement();
1653 
1654         ReadExpressionAttribute(expressions, dom, AttrFormula);
1655     }
1656 
1657     return expressions;
1658 }
1659 
1660 //---------------------------------------------------------------------------------------------------------------------
ListOperationExpressions() const1661 QVector<VFormulaField> VAbstractPattern::ListOperationExpressions() const
1662 {
1663     // Check if new tool doesn't bring new attribute with a formula.
1664     // If no just increment number.
1665     // If new tool bring absolutely new type and has formula(s) create new method to cover it.
1666     Q_STATIC_ASSERT(static_cast<int>(Tool::LAST_ONE_DO_NOT_USE) == 55);
1667 
1668     QVector<VFormulaField> expressions;
1669     const QDomNodeList list = elementsByTagName(TagOperation);
1670     for (int i=0; i < list.size(); ++i)
1671     {
1672         const QDomElement dom = list.at(i).toElement();
1673 
1674         // Each tag can contains several attributes.
1675         ReadExpressionAttribute(expressions, dom, AttrAngle);
1676         ReadExpressionAttribute(expressions, dom, AttrLength);
1677     }
1678 
1679     return expressions;
1680 }
1681 
1682 //---------------------------------------------------------------------------------------------------------------------
ListNodesExpressions(const QDomElement & nodes) const1683 QVector<VFormulaField> VAbstractPattern::ListNodesExpressions(const QDomElement &nodes) const
1684 {
1685     // Check if new tool doesn't bring new attribute with a formula.
1686     // If no just increment number.
1687     // If new tool bring absolutely new type and has formula(s) create new method to cover it.
1688     Q_STATIC_ASSERT(static_cast<int>(Tool::LAST_ONE_DO_NOT_USE) == 55);
1689 
1690     QVector<VFormulaField> expressions;
1691 
1692     const QDomNodeList nodeList = nodes.childNodes();
1693     for (qint32 i = 0; i < nodeList.size(); ++i)
1694     {
1695         const QDomElement element = nodeList.at(i).toElement();
1696         if (not element.isNull() && element.tagName() == VAbstractPattern::TagNode)
1697         {
1698             ReadExpressionAttribute(expressions, element, VAbstractPattern::AttrSABefore);
1699             ReadExpressionAttribute(expressions, element, VAbstractPattern::AttrSAAfter);
1700             ReadExpressionAttribute(expressions, element, VAbstractPattern::AttrPassmarkLength);
1701         }
1702     }
1703     return expressions;
1704 }
1705 
1706 //---------------------------------------------------------------------------------------------------------------------
ListPathExpressions() const1707 QVector<VFormulaField> VAbstractPattern::ListPathExpressions() const
1708 {
1709     // Check if new tool doesn't bring new attribute with a formula.
1710     // If no just increment number.
1711     // If new tool bring absolutely new type and has formula(s) create new method to cover it.
1712     Q_STATIC_ASSERT(static_cast<int>(Tool::LAST_ONE_DO_NOT_USE) == 55);
1713 
1714     QVector<VFormulaField> expressions;
1715     const QDomNodeList list = elementsByTagName(TagPath);
1716     for (int i=0; i < list.size(); ++i)
1717     {
1718         const QDomElement dom = list.at(i).toElement();
1719         if (dom.isNull())
1720         {
1721             continue;
1722         }
1723 
1724         expressions << ListNodesExpressions(dom.firstChildElement(TagNodes));
1725     }
1726 
1727     return expressions;
1728 }
1729 
1730 //---------------------------------------------------------------------------------------------------------------------
ListGrainlineExpressions(const QDomElement & element) const1731 QVector<VFormulaField> VAbstractPattern::ListGrainlineExpressions(const QDomElement &element) const
1732 {
1733     QVector<VFormulaField> expressions;
1734     if (not element.isNull())
1735     {
1736         // Each tag can contains several attributes.
1737         ReadExpressionAttribute(expressions, element, AttrRotation);
1738         ReadExpressionAttribute(expressions, element, AttrLength);
1739     }
1740 
1741     return expressions;
1742 }
1743 
1744 //---------------------------------------------------------------------------------------------------------------------
ListPieceExpressions() const1745 QVector<VFormulaField> VAbstractPattern::ListPieceExpressions() const
1746 {
1747     // Check if new tool doesn't bring new attribute with a formula.
1748     // If no just increment number.
1749     // If new tool bring absolutely new type and has formula(s) create new method to cover it.
1750     Q_STATIC_ASSERT(static_cast<int>(Tool::LAST_ONE_DO_NOT_USE) == 55);
1751 
1752     QVector<VFormulaField> expressions;
1753     const QDomNodeList list = elementsByTagName(TagDetail);
1754     for (int i=0; i < list.size(); ++i)
1755     {
1756         const QDomElement dom = list.at(i).toElement();
1757         if (dom.isNull())
1758         {
1759             continue;
1760         }
1761 
1762         // Each tag can contains several attributes.
1763         ReadExpressionAttribute(expressions, dom, AttrWidth);
1764 
1765         expressions << ListNodesExpressions(dom.firstChildElement(TagNodes));
1766         expressions << ListGrainlineExpressions(dom.firstChildElement(TagGrainline));
1767     }
1768 
1769     return expressions;
1770 }
1771 
1772 //---------------------------------------------------------------------------------------------------------------------
ListFinalMeasurementsExpressions() const1773 QVector<VFormulaField> VAbstractPattern::ListFinalMeasurementsExpressions() const
1774 {
1775     QVector<VFormulaField> expressions;
1776     const QDomNodeList list = elementsByTagName(TagFMeasurement);
1777     for (int i=0; i < list.size(); ++i)
1778     {
1779         const QDomElement dom = list.at(i).toElement();
1780         if (dom.isNull())
1781         {
1782             continue;
1783         }
1784 
1785         // Each tag can contains several attributes.
1786         ReadExpressionAttribute(expressions, dom, AttrFormula);
1787     }
1788 
1789     return expressions;
1790 }
1791 
1792 //---------------------------------------------------------------------------------------------------------------------
IsVariable(const QString & token) const1793 bool VAbstractPattern::IsVariable(const QString &token) const
1794 {
1795     for (auto &var : builInVariables)
1796     {
1797         if (token.indexOf( var ) == 0)
1798         {
1799             if (var == currentLength || var == currentSeamAllowance)
1800             {
1801                 return token == var;
1802             }
1803             else
1804             {
1805                 return true;
1806             }
1807         }
1808     }
1809 
1810     if (token.startsWith('#'))
1811     {
1812         return true;
1813     }
1814 
1815     return false;
1816 }
1817 
1818 //---------------------------------------------------------------------------------------------------------------------
IsFunction(const QString & token) const1819 bool VAbstractPattern::IsFunction(const QString &token) const
1820 {
1821     for (auto &fn : builInFunctions)
1822     {
1823         if (token.indexOf(fn) == 0)
1824         {
1825             return true;
1826         }
1827     }
1828 
1829     return false;
1830 }
1831 
1832 //---------------------------------------------------------------------------------------------------------------------
ParseItemElement(const QDomElement & domElement)1833 QPair<bool, QMap<quint32, quint32> > VAbstractPattern::ParseItemElement(const QDomElement &domElement)
1834 {
1835     Q_ASSERT_X(not domElement.isNull(), Q_FUNC_INFO, "domElement is null");
1836 
1837     try
1838     {
1839         const bool visible = GetParametrBool(domElement, AttrVisible, trueStr);
1840 
1841         QMap<quint32, quint32> items;
1842 
1843         const QDomNodeList nodeList = domElement.childNodes();
1844         const qint32 num = nodeList.size();
1845         for (qint32 i = 0; i < num; ++i)
1846         {
1847             const QDomElement element = nodeList.at(i).toElement();
1848             if (not element.isNull() && element.tagName() == TagGroupItem)
1849             {
1850                 const quint32 object = GetParametrUInt(element, AttrObject, NULL_ID_STR);
1851                 const quint32 tool = GetParametrUInt(element, AttrTool, NULL_ID_STR);
1852                 items.insert(object, tool);
1853             }
1854         }
1855 
1856         QPair<bool, QMap<quint32, quint32> > group;
1857         group.first = visible;
1858         group.second = items;
1859 
1860         return group;
1861     }
1862     catch (const VExceptionBadId &e)
1863     {
1864         VExceptionObjectError excep(tr("Error creating or updating group"), domElement);
1865         excep.AddMoreInformation(e.ErrorMessage());
1866         throw excep;
1867     }
1868 }
1869 
1870 //---------------------------------------------------------------------------------------------------------------------
GetMaterials(const QDomElement & element) const1871 QMap<int, QString> VAbstractPattern::GetMaterials(const QDomElement &element) const
1872 {
1873     QMap<int, QString> materials;
1874 
1875     if (not element.isNull())
1876     {
1877         QDomElement tagMaterial = element.firstChildElement();
1878         while (tagMaterial.isNull() == false)
1879         {
1880             if (tagMaterial.tagName() == TagMaterial)
1881             {
1882                 const int number = static_cast<int>(GetParametrUInt(tagMaterial, AttrNumber, QChar('0')));
1883                 const QString name = GetParametrEmptyString(tagMaterial, AttrName);
1884 
1885                 if (number > 0 && number <= userMaterialPlaceholdersQuantity)
1886                 {
1887                     materials.insert(number, name);
1888                 }
1889             }
1890             tagMaterial = tagMaterial.nextSiblingElement(TagMaterial);
1891         }
1892     }
1893 
1894     return materials;
1895 }
1896 
1897 //---------------------------------------------------------------------------------------------------------------------
SetMaterials(QDomElement & element,const QMap<int,QString> & materials)1898 void VAbstractPattern::SetMaterials(QDomElement &element, const QMap<int, QString> &materials)
1899 {
1900     if (not element.isNull())
1901     {
1902         QMap<int, QString>::const_iterator i = materials.constBegin();
1903         while (i != materials.constEnd())
1904         {
1905             QDomElement tagMaterial = createElement(TagMaterial);
1906 
1907             SetAttribute(tagMaterial, AttrNumber, i.key());
1908             SetAttribute(tagMaterial, AttrName, i.value());
1909 
1910             element.appendChild(tagMaterial);
1911             ++i;
1912         }
1913     }
1914 }
1915 
1916 //---------------------------------------------------------------------------------------------------------------------
GetFMeasurements(const QDomElement & element) const1917 QVector<VFinalMeasurement> VAbstractPattern::GetFMeasurements(const QDomElement &element) const
1918 {
1919     QVector<VFinalMeasurement> measurements;
1920 
1921     if (not element.isNull())
1922     {
1923         QDomElement tagFMeasurement = element.firstChildElement();
1924         while (not tagFMeasurement.isNull())
1925         {
1926             if (tagFMeasurement.tagName() == TagFMeasurement)
1927             {
1928                 VFinalMeasurement m;
1929 
1930                 m.name = GetParametrString(tagFMeasurement, AttrName, tr("measurement"));
1931                 m.formula = GetParametrString(tagFMeasurement, AttrFormula, QChar('0'));
1932                 m.description = GetParametrEmptyString(tagFMeasurement, AttrDescription);
1933 
1934                 measurements.append(m);
1935             }
1936             tagFMeasurement = tagFMeasurement.nextSiblingElement(TagFMeasurement);
1937         }
1938     }
1939 
1940     return measurements;
1941 }
1942 
1943 //---------------------------------------------------------------------------------------------------------------------
SetFMeasurements(QDomElement & element,const QVector<VFinalMeasurement> & measurements)1944 void VAbstractPattern::SetFMeasurements(QDomElement &element, const QVector<VFinalMeasurement> &measurements)
1945 {
1946     if (not element.isNull())
1947     {
1948         for (auto &m : measurements)
1949         {
1950             QDomElement tagFMeasurement = createElement(TagFMeasurement);
1951 
1952             SetAttribute(tagFMeasurement, AttrName, m.name);
1953             SetAttribute(tagFMeasurement, AttrFormula, m.formula);
1954             SetAttributeOrRemoveIf(tagFMeasurement, AttrDescription, m.description, m.description.isEmpty());
1955 
1956             element.appendChild(tagFMeasurement);
1957         }
1958     }
1959 }
1960 
1961 //---------------------------------------------------------------------------------------------------------------------
1962 /**
1963  * @brief IsModified state of the document for cases that do not cover QUndoStack.
1964  * @return true if the document was modified without using QUndoStack.
1965  */
IsModified() const1966 bool VAbstractPattern::IsModified() const
1967 {
1968     return modified;
1969 }
1970 
1971 //---------------------------------------------------------------------------------------------------------------------
SetModified(bool modified)1972 void VAbstractPattern::SetModified(bool modified)
1973 {
1974     this->modified = modified;
1975 }
1976 
1977 //---------------------------------------------------------------------------------------------------------------------
GetDraw(const QString & name) const1978 QDomElement VAbstractPattern::GetDraw(const QString &name) const
1979 {
1980     const QDomNodeList draws = documentElement().elementsByTagName(TagDraw);
1981     for (int i=0; i < draws.size(); ++i)
1982     {
1983         QDomElement draw = draws.at(i).toElement();
1984         if (draw.isNull())
1985         {
1986             continue;
1987         }
1988 
1989         if (draw.attribute(AttrName) == name)
1990         {
1991             return draw;
1992         }
1993     }
1994     return QDomElement();
1995 }
1996 
1997 //---------------------------------------------------------------------------------------------------------------------
CreateGroups()1998 QDomElement VAbstractPattern::CreateGroups()
1999 {
2000     QDomElement draw;
2001     if (GetActivDrawElement(draw))
2002     {
2003         QDomElement groups = draw.firstChildElement(TagGroups);
2004 
2005         if (groups.isNull())
2006         {
2007             groups = createElement(TagGroups);
2008             draw.appendChild(groups);
2009         }
2010 
2011         return groups;
2012     }
2013     return QDomElement();
2014 }
2015 
2016 //---------------------------------------------------------------------------------------------------------------------
CreateGroup(quint32 id,const QString & name,const QStringList & tags,const QMap<quint32,quint32> & groupData,vidtype tool)2017 QDomElement VAbstractPattern::CreateGroup(quint32 id, const QString &name, const QStringList &tags,
2018                                           const QMap<quint32, quint32> &groupData, vidtype tool)
2019 {
2020     if (id == NULL_ID || groupData.isEmpty())
2021     {
2022         return QDomElement();
2023     }
2024 
2025     const QString preparedTags = PrepareGroupTags(tags);
2026 
2027     QDomElement group = createElement(TagGroup);
2028     SetAttribute(group, AttrId, id);
2029     SetAttribute(group, AttrName, name);
2030     SetAttribute(group, AttrVisible, true);
2031     SetAttributeOrRemoveIf(group, AttrTool, tool, tool == null_id);
2032     SetAttributeOrRemoveIf(group, AttrTags, preparedTags, preparedTags.isEmpty());
2033 
2034     auto i = groupData.constBegin();
2035     while (i != groupData.constEnd())
2036     {
2037         QDomElement item = createElement(TagGroupItem);
2038         item.setAttribute(AttrObject, i.key());
2039         item.setAttribute(AttrTool, i.value());
2040         group.appendChild(item);
2041         ++i;
2042     }
2043 
2044     return group;
2045 }
2046 //---------------------------------------------------------------------------------------------------------------------
GroupLinkedToTool(vidtype toolId) const2047 vidtype VAbstractPattern::GroupLinkedToTool(vidtype toolId) const
2048 {
2049     const QDomNodeList groups = elementsByTagName(TagGroup);
2050     for (int i=0; i < groups.size(); ++i)
2051     {
2052         const QDomElement group = groups.at(i).toElement();
2053         if (not group.isNull() && group.hasAttribute(AttrTool))
2054         {
2055             const quint32 id = GetParametrUInt(group, AttrTool, NULL_ID_STR);
2056 
2057             if (toolId == id)
2058             {
2059                 return GetParametrUInt(group, AttrId, NULL_ID_STR);
2060             }
2061         }
2062     }
2063 
2064     return null_id;
2065 }
2066 
2067 //---------------------------------------------------------------------------------------------------------------------
GetGroupName(quint32 id)2068 QString VAbstractPattern::GetGroupName(quint32 id)
2069 {
2070     QString name = tr("New group");
2071     QDomElement group = elementById(id, TagGroup);
2072     if (group.isElement())
2073     {
2074         name = GetParametrString(group, AttrName, name);
2075 
2076     }
2077 
2078     return name;
2079 }
2080 
2081 //---------------------------------------------------------------------------------------------------------------------
SetGroupName(quint32 id,const QString & name)2082 void VAbstractPattern::SetGroupName(quint32 id, const QString &name)
2083 {
2084     QDomElement group = elementById(id, TagGroup);
2085     if (group.isElement())
2086     {
2087         group.setAttribute(AttrName, name);
2088         modified = true;
2089         emit patternChanged(false);
2090     }
2091 }
2092 
2093 //---------------------------------------------------------------------------------------------------------------------
GetGroupTags(vidtype id)2094 QStringList VAbstractPattern::GetGroupTags(vidtype id)
2095 {
2096     QStringList tags;
2097     QDomElement group = elementById(id, TagGroup);
2098     if (group.isElement())
2099     {
2100         tags = FilterGroupTags(GetParametrEmptyString(group, AttrTags));
2101     }
2102 
2103     return tags;
2104 }
2105 
2106 //---------------------------------------------------------------------------------------------------------------------
SetGroupTags(quint32 id,const QStringList & tags)2107 void VAbstractPattern::SetGroupTags(quint32 id, const QStringList &tags)
2108 {
2109     QDomElement group = elementById(id, TagGroup);
2110     if (group.isElement())
2111     {
2112         const QString rawTags = tags.join(',');
2113         SetAttributeOrRemoveIf(group, AttrTags, rawTags, rawTags.isEmpty());
2114         modified = true;
2115         emit patternChanged(false);
2116     }
2117 }
2118 
2119 //---------------------------------------------------------------------------------------------------------------------
GetGroupCategories() const2120 QStringList VAbstractPattern::GetGroupCategories() const
2121 {
2122     QSet<QString> categories;
2123 
2124     const QDomNodeList groups = elementsByTagName(TagGroup);
2125     for (int i=0; i < groups.size(); ++i)
2126     {
2127         const QDomElement group = groups.at(i).toElement();
2128         if (not group.isNull() && group.hasAttribute(AttrTags))
2129         {
2130             QStringList groupTags = VAbstractPattern::FilterGroupTags(GetParametrEmptyString(group, AttrTags));
2131             categories.unite(ConvertToSet<QString>(groupTags));
2132         }
2133     }
2134 
2135     return ConvertToList(categories);
2136 }
2137 
2138 //---------------------------------------------------------------------------------------------------------------------
GetGroups()2139 QMap<quint32, VGroupData> VAbstractPattern::GetGroups()
2140 {
2141     QMap<quint32, VGroupData> data;
2142 
2143     try
2144     {
2145         QDomElement groups = CreateGroups();
2146         if (not groups.isNull())
2147         {
2148             QDomNode domNode = groups.firstChild();
2149             while (domNode.isNull() == false)
2150             {
2151                 if (domNode.isElement())
2152                 {
2153                     const QDomElement group = domNode.toElement();
2154                     if (group.isNull() == false)
2155                     {
2156                         if (group.tagName() == TagGroup)
2157                         {
2158                             VGroupData groupData;
2159                             const quint32 id = GetParametrUInt(group, AttrId, QChar('0'));
2160                             groupData.visible = GetParametrBool(group, AttrVisible, trueStr);
2161                             groupData.name = GetParametrString(group, AttrName, tr("New group"));
2162                             groupData.tags = FilterGroupTags(GetParametrEmptyString(group, AttrTags));
2163 
2164                             data.insert(id, groupData);
2165                         }
2166                     }
2167                 }
2168                 domNode = domNode.nextSibling();
2169             }
2170         }
2171         else
2172         {
2173             qDebug("Can't get tag Groups.");
2174         }
2175     }
2176     catch (const VExceptionConversionError &)
2177     {
2178         return QMap<quint32, VGroupData>();
2179     }
2180 
2181     return data;
2182 }
2183 
2184 //---------------------------------------------------------------------------------------------------------------------
2185 /**
2186  * @brief Returns the groups that contain or do not contain the item identified by the toolid and the objectid
2187  * @param toolId tool id
2188  * @param objectId object id
2189  * @param containItem |true if the groups have to contain the given item, false if they musn't contain the item
2190  * @return groups that contain or do not contain the item identified by the toolid and the objectid
2191  */
GetGroupsContainingItem(quint32 toolId,quint32 objectId,bool containItem)2192 QMap<quint32, QString> VAbstractPattern::GetGroupsContainingItem(quint32 toolId, quint32 objectId, bool containItem)
2193 {
2194     QMap<quint32, QString> data;
2195 
2196     if(objectId == 0)
2197     {
2198         objectId = toolId;
2199     }
2200 
2201     // TODO : order in alphabetical order
2202 
2203     QDomElement groups = CreateGroups();
2204     if (not groups.isNull())
2205     {
2206         QDomNode domNode = groups.firstChild();
2207         while (domNode.isNull() == false) // iterate through the groups
2208         {
2209             if (domNode.isElement())
2210             {
2211                 const QDomElement group = domNode.toElement();
2212                 if (group.isNull() == false)
2213                 {
2214                     if (group.tagName() == TagGroup)
2215                     {
2216                         bool groupHasItem = GroupHasItem(group, toolId, objectId);
2217                         if((containItem && groupHasItem) || (not containItem && not groupHasItem))
2218                         {
2219                             const quint32 groupId = GetParametrUInt(group, AttrId, QChar('0'));
2220                             const QString name = GetParametrString(group, AttrName, tr("New group"));
2221                             data.insert(groupId, name);
2222                         }
2223                     }
2224                 }
2225             }
2226             domNode = domNode.nextSibling();
2227         }
2228     }
2229     else
2230     {
2231         qDebug("Can't get tag Groups.");
2232     }
2233 
2234     return data;
2235 }
2236 //---------------------------------------------------------------------------------------------------------------------
2237 /**
2238  * @brief Checks if the given group has the item with the given toolId and objectId
2239  * @param groupDomElement group dom element
2240  * @param toolId tool id
2241  * @param objectId object id
2242  * @return true if the given group has the item with the given toolId and objectId
2243  */
GroupHasItem(const QDomElement & groupDomElement,quint32 toolId,quint32 objectId)2244 bool VAbstractPattern::GroupHasItem(const QDomElement &groupDomElement, quint32 toolId, quint32 objectId)
2245 {
2246     bool result = false;
2247 
2248     QDomNode itemNode = groupDomElement.firstChild();
2249     while (itemNode.isNull() == false) // iterate through the items of the group
2250     {
2251         if (itemNode.isElement())
2252         {
2253             const QDomElement item = itemNode.toElement();
2254             if (item.isNull() == false)
2255             {
2256                 quint32 toolIdIterate= GetParametrUInt(item, AttrTool, QChar('0'));
2257                 quint32 objectIdIterate= GetParametrUInt(item, AttrObject, QChar('0'));
2258 
2259                 if(toolIdIterate == toolId && objectIdIterate == objectId)
2260                 {
2261                     result = true;
2262                     break;
2263                 }
2264             }
2265         }
2266         itemNode = itemNode.nextSibling();
2267     }
2268     return result;
2269 }
2270 
2271 //---------------------------------------------------------------------------------------------------------------------
ReadUnits() const2272 auto VAbstractPattern::ReadUnits() const -> Unit
2273 {
2274     Unit units = StrToUnits(UniqueTagText(TagUnit, unitCM));
2275 
2276     if (units == Unit::Px)
2277     {
2278         units = Unit::Cm;
2279     }
2280 
2281     return units;
2282 }
2283 
2284 //---------------------------------------------------------------------------------------------------------------------
ReadPatternNumber() const2285 QString VAbstractPattern::ReadPatternNumber() const
2286 {
2287     return UniqueTagText(TagPatternNum);
2288 }
2289 
2290 //---------------------------------------------------------------------------------------------------------------------
ReadLabelDateFormat() const2291 QString VAbstractPattern::ReadLabelDateFormat() const
2292 {
2293     const QString globalLabelDateFormat = VAbstractApplication::VApp()->Settings()->GetLabelDateFormat();
2294 
2295     const QDomNodeList list = elementsByTagName(TagPatternLabel);
2296     if (list.isEmpty())
2297     {
2298         return globalLabelDateFormat;
2299     }
2300 
2301     QString labelDateFormat;
2302 
2303     try
2304     {
2305         labelDateFormat = GetParametrString(list.at(0).toElement(), AttrDateFormat);
2306     }
2307     catch (const VExceptionEmptyParameter &)
2308     {
2309         return globalLabelDateFormat;
2310     }
2311     return labelDateFormat;
2312 }
2313 
2314 //---------------------------------------------------------------------------------------------------------------------
ReadPatternName() const2315 QString VAbstractPattern::ReadPatternName() const
2316 {
2317     return UniqueTagText(TagPatternName);
2318 }
2319 
2320 //---------------------------------------------------------------------------------------------------------------------
ReadMPath() const2321 QString VAbstractPattern::ReadMPath() const
2322 {
2323     return UniqueTagText(TagMeasurements);
2324 }
2325 
2326 //---------------------------------------------------------------------------------------------------------------------
ReadWatermarkPath() const2327 QString VAbstractPattern::ReadWatermarkPath() const
2328 {
2329     return UniqueTagText(TagWatermark);
2330 }
2331 
2332 //---------------------------------------------------------------------------------------------------------------------
ReadCompanyName() const2333 QString VAbstractPattern::ReadCompanyName() const
2334 {
2335     return UniqueTagText(TagCompanyName);
2336 }
2337 
2338 //---------------------------------------------------------------------------------------------------------------------
2339 /**
2340  * @brief Adds an item to the given group with the given toolId and objectId
2341  * @param toolId tool id
2342  * @param objectId object id
2343  * @param groupId group id
2344  * @return group element
2345  */
AddItemToGroup(quint32 toolId,quint32 objectId,quint32 groupId)2346 QDomElement VAbstractPattern::AddItemToGroup(quint32 toolId, quint32 objectId, quint32 groupId)
2347 {
2348     QDomElement group = elementById(groupId, TagGroup);
2349 
2350     if (group.isNull() == false)
2351     {
2352         if(objectId == 0)
2353         {
2354             objectId = toolId;
2355         }
2356 
2357         QDomElement item = createElement(TagGroupItem);
2358         item.setAttribute(AttrTool, toolId);
2359         item.setAttribute(AttrObject, objectId);
2360         group.appendChild(item);
2361 
2362         // to signalised that the pattern was changed and need to be saved
2363         modified = true;
2364         emit patternChanged(false);
2365 
2366         // to update the group table of the gui
2367         emit UpdateGroups();
2368 
2369         // parse the groups to update the drawing, in case the item was added to an invisible group
2370         QDomElement groups = CreateGroups();
2371         if (not groups.isNull())
2372         {
2373             ParseGroups(groups);
2374         }
2375 
2376         return item;
2377     }
2378     else
2379     {
2380         qDebug() << "The group of id " << groupId << " doesn't exist";
2381     }
2382 
2383     return QDomElement();
2384 }
2385 
2386 //---------------------------------------------------------------------------------------------------------------------
2387 /**
2388  * @brief Removes the item of given toolId and objectId from the group of given groupId
2389  * @param toolId tool id
2390  * @param objectId object id
2391  * @param groupId group id
2392  * @return item element or null element is none
2393  */
RemoveItemFromGroup(quint32 toolId,quint32 objectId,quint32 groupId)2394 QDomElement VAbstractPattern::RemoveItemFromGroup(quint32 toolId, quint32 objectId, quint32 groupId)
2395 {
2396     QDomElement group = elementById(groupId, TagGroup);
2397 
2398     if (group.isNull() == false)
2399     {
2400         if(objectId == 0)
2401         {
2402             objectId = toolId;
2403         }
2404 
2405         QDomNode itemNode = group.firstChild();
2406         while (itemNode.isNull() == false) // iterate through the items of the group
2407         {
2408             if (itemNode.isElement())
2409             {
2410                 const QDomElement item = itemNode.toElement();
2411                 if (item.isNull() == false)
2412                 {
2413                     quint32 toolIdIterate= GetParametrUInt(item, AttrTool, QChar('0'));
2414                     quint32 objectIdIterate= GetParametrUInt(item, AttrObject, QChar('0'));
2415 
2416                     if(toolIdIterate == toolId && objectIdIterate == objectId)
2417                     {
2418                         group.removeChild(itemNode);
2419 
2420                         // to signalised that the pattern was changed and need to be saved
2421                         modified = true;
2422                         emit patternChanged(false);
2423 
2424                         // to update the group table of the gui
2425                         emit UpdateGroups();
2426 
2427                         // parse the groups to update the drawing, in case the item was removed from an invisible group
2428                         QDomElement groups = CreateGroups();
2429                         if (not groups.isNull())
2430                         {
2431                             ParseGroups(groups);
2432                         }
2433 
2434                         return item;
2435                     }
2436                 }
2437             }
2438             itemNode = itemNode.nextSibling();
2439         }
2440     }
2441     else
2442     {
2443         qDebug() << "The group of id " << groupId << " doesn't exist";
2444     }
2445 
2446     return QDomElement();
2447 }
2448 
2449 //---------------------------------------------------------------------------------------------------------------------
2450 /**
2451  * @brief Returns true if the given group is empty
2452  * @param id group id
2453  * @return true if the given group is empty
2454  */
GroupIsEmpty(quint32 id)2455 bool VAbstractPattern::GroupIsEmpty(quint32 id)
2456 {
2457     QDomElement group = elementById(id, TagGroup);
2458 
2459     if (group.isNull() == false)
2460     {
2461         return not group.hasChildNodes();
2462     }
2463     else
2464     {
2465         qDebug() << "The group of id " << id << " doesn't exist";
2466         return true;
2467     }
2468 }
2469 
2470 //---------------------------------------------------------------------------------------------------------------------
GetGroupVisibility(quint32 id)2471 bool VAbstractPattern::GetGroupVisibility(quint32 id)
2472 {
2473     QDomElement group = elementById(id, TagGroup);
2474     if (group.isElement())
2475     {
2476         return GetParametrBool(group, AttrVisible, trueStr);
2477     }
2478     else
2479     {
2480         qDebug("Can't get group by id = %u.", id);
2481         return true;
2482     }
2483 }
2484 
2485 //---------------------------------------------------------------------------------------------------------------------
PieceDrawName(quint32 id)2486 QString VAbstractPattern::PieceDrawName(quint32 id)
2487 {
2488     const QDomElement detail = elementById(id, VAbstractPattern::TagDetail);
2489     if (detail.isNull())
2490     {
2491         return QString();
2492     }
2493 
2494     const QDomElement draw = detail.parentNode().parentNode().toElement();
2495     if (draw.isNull() || not draw.hasAttribute(VAbstractPattern::AttrName))
2496     {
2497         return QString();
2498     }
2499 
2500     return  draw.attribute(VAbstractPattern::AttrName);
2501 }
2502 
2503 //---------------------------------------------------------------------------------------------------------------------
GetCompleteData() const2504 VContainer VAbstractPattern::GetCompleteData() const
2505 {
2506     return VContainer(nullptr, nullptr, VContainer::UniqueNamespace());
2507 }
2508 
2509 //---------------------------------------------------------------------------------------------------------------------
GetCompletePPData(const QString & name) const2510 VContainer VAbstractPattern::GetCompletePPData(const QString &name) const
2511 {
2512     Q_UNUSED(name)
2513     return VContainer(nullptr, nullptr, VContainer::UniqueNamespace());
2514 }
2515 
2516 //---------------------------------------------------------------------------------------------------------------------
Units() const2517 Unit VAbstractPattern::Units() const
2518 {
2519     return m_units;
2520 }
2521 
2522 //---------------------------------------------------------------------------------------------------------------------
FilterGroupTags(const QString & tags)2523 QStringList VAbstractPattern::FilterGroupTags(const QString &tags)
2524 {
2525     if (tags.isEmpty())
2526     {
2527         return QStringList();
2528     }
2529 
2530     QStringList list = tags.split(',');
2531     for (auto &tag : list)
2532     {
2533         tag = tag.simplified();
2534     }
2535 
2536     list.removeAll("");
2537 
2538     return ConvertToList(ConvertToSet<QString>(list));
2539 }
2540