diff --git a/ChangeLog.txt b/ChangeLog.txt index e6c37c571..6f7921148 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -46,6 +46,7 @@ - [#667] Check for updates - Test version. - [#808] New feature. Global line width option. - [#814] Make "\" valid character. +- [#818] Improve Piece path validation. Check uniqueness. # Version 0.5.1 - [#683] Tool Seam allowance's dialog is off screen on small resolutions. diff --git a/src/libs/ifc/schema.qrc b/src/libs/ifc/schema.qrc index bac9fdb05..77a854a8c 100644 --- a/src/libs/ifc/schema.qrc +++ b/src/libs/ifc/schema.qrc @@ -48,6 +48,7 @@ schema/pattern/v0.7.4.xsd schema/pattern/v0.7.5.xsd schema/pattern/v0.7.6.xsd + schema/pattern/v0.7.7.xsd schema/standard_measurements/v0.3.0.xsd schema/standard_measurements/v0.4.0.xsd schema/standard_measurements/v0.4.1.xsd diff --git a/src/libs/ifc/schema/pattern/v0.7.7.xsd b/src/libs/ifc/schema/pattern/v0.7.7.xsd new file mode 100644 index 000000000..7d8cf8c75 --- /dev/null +++ b/src/libs/ifc/schema/pattern/v0.7.7.xsd @@ -0,0 +1,1061 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/libs/ifc/xml/vabstractpattern.cpp b/src/libs/ifc/xml/vabstractpattern.cpp index 6aced9eaa..e712fe573 100644 --- a/src/libs/ifc/xml/vabstractpattern.cpp +++ b/src/libs/ifc/xml/vabstractpattern.cpp @@ -129,6 +129,7 @@ const QString VAbstractPattern::AttrEnd = QStringLiteral("end"); const QString VAbstractPattern::AttrIncludeAs = QStringLiteral("includeAs"); const QString VAbstractPattern::AttrRotation = QStringLiteral("rotation"); const QString VAbstractPattern::AttrNumber = QStringLiteral("number"); +const QString VAbstractPattern::AttrCheckUniqueness = QStringLiteral("checkUniqueness"); const QString VAbstractPattern::AttrAll = QStringLiteral("all"); @@ -686,6 +687,7 @@ VPieceNode VAbstractPattern::ParseSANode(const QDomElement &domElement) const quint32 id = VDomDocument::GetParametrUInt(domElement, AttrIdObject, NULL_ID_STR); const bool reverse = VDomDocument::GetParametrUInt(domElement, VAbstractPattern::AttrNodeReverse, "0"); const bool excluded = VDomDocument::GetParametrBool(domElement, VAbstractPattern::AttrNodeExcluded, falseStr); + const bool uniqeness = VDomDocument::GetParametrBool(domElement, VAbstractPattern::AttrCheckUniqueness, trueStr); const QString saBefore = VDomDocument::GetParametrString(domElement, VAbstractPattern::AttrSABefore, currentSeamAllowance); const QString saAfter = VDomDocument::GetParametrString(domElement, VAbstractPattern::AttrSAAfter, @@ -738,6 +740,7 @@ VPieceNode VAbstractPattern::ParseSANode(const QDomElement &domElement) node.SetFormulaSAAfter(saAfter); node.SetAngleType(angle); node.SetExcluded(excluded); + node.SetCheckUniqueness(uniqeness); node.SetShowSecondPassmark(showSecond); node.SetPassmark(passmark); node.SetPassmarkLineType(passmarkLine); diff --git a/src/libs/ifc/xml/vabstractpattern.h b/src/libs/ifc/xml/vabstractpattern.h index 1bfcd63e3..248b9da29 100644 --- a/src/libs/ifc/xml/vabstractpattern.h +++ b/src/libs/ifc/xml/vabstractpattern.h @@ -271,6 +271,7 @@ public: static const QString AttrIncludeAs; static const QString AttrRotation; static const QString AttrNumber; + static const QString AttrCheckUniqueness; static const QString AttrAll; diff --git a/src/libs/ifc/xml/vpatternconverter.cpp b/src/libs/ifc/xml/vpatternconverter.cpp index 4ca4ae9fa..dfa836f1c 100644 --- a/src/libs/ifc/xml/vpatternconverter.cpp +++ b/src/libs/ifc/xml/vpatternconverter.cpp @@ -58,8 +58,8 @@ class QDomElement; */ const QString VPatternConverter::PatternMinVerStr = QStringLiteral("0.1.0"); -const QString VPatternConverter::PatternMaxVerStr = QStringLiteral("0.7.6"); -const QString VPatternConverter::CurrentSchema = QStringLiteral("://schema/pattern/v0.7.6.xsd"); +const QString VPatternConverter::PatternMaxVerStr = QStringLiteral("0.7.7"); +const QString VPatternConverter::CurrentSchema = QStringLiteral("://schema/pattern/v0.7.7.xsd"); //VPatternConverter::PatternMinVer; // <== DON'T FORGET TO UPDATE TOO!!!! //VPatternConverter::PatternMaxVer; // <== DON'T FORGET TO UPDATE TOO!!!! @@ -222,7 +222,8 @@ QString VPatternConverter::XSDSchema(int ver) const std::make_pair(0x000703, QStringLiteral("://schema/pattern/v0.7.3.xsd")), std::make_pair(0x000704, QStringLiteral("://schema/pattern/v0.7.4.xsd")), std::make_pair(0x000705, QStringLiteral("://schema/pattern/v0.7.5.xsd")), - std::make_pair(0x000706, CurrentSchema) + std::make_pair(0x000706, QStringLiteral("://schema/pattern/v0.7.6.xsd")), + std::make_pair(0x000707, CurrentSchema) }; if (schemas.contains(ver)) @@ -429,6 +430,10 @@ void VPatternConverter::ApplyPatches() ValidateXML(XSDSchema(0x000706), m_convertedFileName); V_FALLTHROUGH case (0x000706): + ToV0_7_7(); + ValidateXML(XSDSchema(0x000707), m_convertedFileName); + V_FALLTHROUGH + case (0x000707): break; default: InvalidVersion(m_ver); @@ -446,7 +451,7 @@ void VPatternConverter::DowngradeToCurrentMaxVersion() bool VPatternConverter::IsReadOnly() const { // Check if attribute readOnly was not changed in file format - Q_STATIC_ASSERT_X(VPatternConverter::PatternMaxVer == CONVERTER_VERSION_CHECK(0, 7, 6), + Q_STATIC_ASSERT_X(VPatternConverter::PatternMaxVer == CONVERTER_VERSION_CHECK(0, 7, 7), "Check attribute readOnly."); // Possibly in future attribute readOnly will change position etc. @@ -980,6 +985,16 @@ void VPatternConverter::ToV0_7_6() Save(); } +//--------------------------------------------------------------------------------------------------------------------- +void VPatternConverter::ToV0_7_7() +{ + // TODO. Delete if minimal supported version is 0.7.7 + Q_STATIC_ASSERT_X(VPatternConverter::PatternMinVer < CONVERTER_VERSION_CHECK(0, 7, 7), + "Time to refactor the code."); + SetVersion(QStringLiteral("0.7.7")); + Save(); +} + //--------------------------------------------------------------------------------------------------------------------- void VPatternConverter::TagUnitToV0_2_0() { diff --git a/src/libs/ifc/xml/vpatternconverter.h b/src/libs/ifc/xml/vpatternconverter.h index a025a9e53..1ba761f8d 100644 --- a/src/libs/ifc/xml/vpatternconverter.h +++ b/src/libs/ifc/xml/vpatternconverter.h @@ -53,7 +53,7 @@ public: static const QString PatternMaxVerStr; static const QString CurrentSchema; static Q_DECL_CONSTEXPR const int PatternMinVer = CONVERTER_VERSION_CHECK(0, 1, 0); - static Q_DECL_CONSTEXPR const int PatternMaxVer = CONVERTER_VERSION_CHECK(0, 7, 6); + static Q_DECL_CONSTEXPR const int PatternMaxVer = CONVERTER_VERSION_CHECK(0, 7, 7); protected: virtual int MinVer() const Q_DECL_OVERRIDE; @@ -119,6 +119,7 @@ private: void ToV0_7_4(); void ToV0_7_5(); void ToV0_7_6(); + void ToV0_7_7(); void TagUnitToV0_2_0(); void TagIncrementToV0_2_0(); diff --git a/src/libs/vpatterndb/vpiecenode.cpp b/src/libs/vpatterndb/vpiecenode.cpp index 66c2ffb4d..a8971cf1b 100644 --- a/src/libs/vpatterndb/vpiecenode.cpp +++ b/src/libs/vpatterndb/vpiecenode.cpp @@ -311,6 +311,18 @@ void VPieceNode::SetShowSecondPassmark(bool value) d->m_isShowSecondPassmark = value; } +//--------------------------------------------------------------------------------------------------------------------- +bool VPieceNode::IsCheckUniqueness() const +{ + return d->m_checkUniqueness; +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPieceNode::SetCheckUniqueness(bool value) +{ + d->m_checkUniqueness = (d->m_typeTool == Tool::NodePoint ? value : true); +} + //--------------------------------------------------------------------------------------------------------------------- bool VPieceNode::IsExcluded() const { diff --git a/src/libs/vpatterndb/vpiecenode.h b/src/libs/vpatterndb/vpiecenode.h index 341994334..6754aed07 100644 --- a/src/libs/vpatterndb/vpiecenode.h +++ b/src/libs/vpatterndb/vpiecenode.h @@ -99,6 +99,9 @@ public: bool IsShowSecondPassmark() const; void SetShowSecondPassmark(bool value); + + bool IsCheckUniqueness() const; + void SetCheckUniqueness(bool value); private: QSharedDataPointer d; }; diff --git a/src/libs/vpatterndb/vpiecenode_p.h b/src/libs/vpatterndb/vpiecenode_p.h index bdd201d23..d6cd6e3c6 100644 --- a/src/libs/vpatterndb/vpiecenode_p.h +++ b/src/libs/vpatterndb/vpiecenode_p.h @@ -53,7 +53,8 @@ public: m_angleType(PieceNodeAngle::ByLength), m_passmarkLineType(PassmarkLineType::OneLine), m_passmarkAngleType(PassmarkAngleType::Straightforward), - m_isShowSecondPassmark(true) + m_isShowSecondPassmark(true), + m_checkUniqueness(true) {} VPieceNodeData(quint32 id, Tool typeTool, bool reverse) @@ -68,7 +69,8 @@ public: m_angleType(PieceNodeAngle::ByLength), m_passmarkLineType(PassmarkLineType::OneLine), m_passmarkAngleType(PassmarkAngleType::Straightforward), - m_isShowSecondPassmark(true) + m_isShowSecondPassmark(true), + m_checkUniqueness(true) { if (m_typeTool == Tool::NodePoint) { @@ -89,7 +91,8 @@ public: m_angleType(node.m_angleType), m_passmarkLineType(node.m_passmarkLineType), m_passmarkAngleType(node.m_passmarkAngleType), - m_isShowSecondPassmark(node.m_isShowSecondPassmark) + m_isShowSecondPassmark(node.m_isShowSecondPassmark), + m_checkUniqueness(node.m_checkUniqueness) {} ~VPieceNodeData() Q_DECL_EQ_DEFAULT; @@ -126,6 +129,11 @@ public: bool m_isShowSecondPassmark; + /** @brief m_checkUniqueness need in cases where different points have the same coordinates, become one point. + * By default the check enabled. Disable it only if in a path cannot be used just one point. For example if + * gradation change a piece shape and the seond point should be remaind.*/ + bool m_checkUniqueness; + private: VPieceNodeData &operator=(const VPieceNodeData &) Q_DECL_EQ_DELETE; }; diff --git a/src/libs/vtools/dialogs/tools/dialogtool.cpp b/src/libs/vtools/dialogs/tools/dialogtool.cpp index ac84fa973..309376244 100644 --- a/src/libs/vtools/dialogs/tools/dialogtool.cpp +++ b/src/libs/vtools/dialogs/tools/dialogtool.cpp @@ -95,6 +95,40 @@ VPieceNode RowNode(QListWidget *listWidget, int i) SCASSERT(rowItem != nullptr); return qvariant_cast(rowItem->data(Qt::UserRole)); } + +//--------------------------------------------------------------------------------------------------------------------- +bool DoublePoint(const VPieceNode &firstNode, const VPieceNode &secondNode, const VContainer *data) +{ + if (firstNode.GetTypeTool() == Tool::NodePoint && not (firstNode.GetId() == NULL_ID) + && secondNode.GetTypeTool() == Tool::NodePoint && not (secondNode.GetId() == NULL_ID)) + { + // don't ignore the same point twice + if (firstNode.GetId() == secondNode.GetId()) + { + return true; + } + + // But ignore the same coordinate if a user wants + if (not firstNode.IsCheckUniqueness() || not secondNode.IsCheckUniqueness()) + { + return false; + } + + try + { + const QSharedPointer firstPoint = data->GeometricObject(firstNode.GetId()); + const QSharedPointer secondPoint = data->GeometricObject(secondNode.GetId()); + + return firstPoint->toQPointF() == secondPoint->toQPointF(); + } + catch(const VExceptionBadId &) + { + return true; + } + } + + return false; +} } //--------------------------------------------------------------------------------------------------------------------- @@ -508,20 +542,7 @@ bool DialogTool::FirstPointEqualLast(QListWidget *listWidget, const VContainer * const VPieceNode topNode = RowNode(listWidget, FindNotExcludedNodeDown(listWidget, 0)); const VPieceNode bottomNode = RowNode(listWidget, FindNotExcludedNodeUp(listWidget, listWidget->count()-1)); - QSharedPointer firstPoint; - if (topNode.GetTypeTool() == Tool::NodePoint) - { - firstPoint = data->GeometricObject(topNode.GetId()); - } - - QSharedPointer secondPoint; - if (bottomNode.GetTypeTool() == Tool::NodePoint) - { - secondPoint = data->GeometricObject(bottomNode.GetId()); - } - - return topNode.GetId() == bottomNode.GetId() || (not firstPoint.isNull() && not secondPoint.isNull() - && firstPoint->toQPointF() == secondPoint->toQPointF()); + return DoublePoint(topNode, bottomNode, data); } return false; } @@ -536,20 +557,7 @@ bool DialogTool::DoublePoints(QListWidget *listWidget, const VContainer *data) const VPieceNode firstNode = RowNode(listWidget, firstIndex); const VPieceNode secondNode = RowNode(listWidget, FindNotExcludedNodeDown(listWidget, firstIndex+1)); - QSharedPointer firstPoint; - if (firstNode.GetTypeTool() == Tool::NodePoint && not (firstNode.GetId() == NULL_ID)) - { - firstPoint = data->GeometricObject(firstNode.GetId()); - } - - QSharedPointer secondPoint; - if (secondNode.GetTypeTool() == Tool::NodePoint && not (secondNode.GetId() == NULL_ID)) - { - secondPoint = data->GeometricObject(secondNode.GetId()); - } - - if (firstNode.GetId() == secondNode.GetId() || (not firstPoint.isNull() && not secondPoint.isNull() - && firstPoint->toQPointF() == secondPoint->toQPointF())) + if (DoublePoint(firstNode, secondNode, data)) { return true; } @@ -616,27 +624,35 @@ QString DialogTool::GetNodeName(const VPieceNode &node, bool showPassmark) const name = QLatin1String("- ") + name; } } - else if (showPassmark && node.IsPassmark()) + else { - switch(node.GetPassmarkLineType()) + if (showPassmark && node.IsPassmark()) { - case PassmarkLineType::OneLine: - name += QLatin1Char('|'); - break; - case PassmarkLineType::TwoLines: - name += QLatin1Literal("||"); - break; - case PassmarkLineType::ThreeLines: - name += QLatin1Literal("|||"); - break; - case PassmarkLineType::TMark: - name += QString("┴"); - break; - case PassmarkLineType::VMark: - name += QLatin1Char('^'); - break; - default: - break; + switch(node.GetPassmarkLineType()) + { + case PassmarkLineType::OneLine: + name += QLatin1Char('|'); + break; + case PassmarkLineType::TwoLines: + name += QLatin1Literal("||"); + break; + case PassmarkLineType::ThreeLines: + name += QLatin1Literal("|||"); + break; + case PassmarkLineType::TMark: + name += QString("┴"); + break; + case PassmarkLineType::VMark: + name += QLatin1Char('^'); + break; + default: + break; + } + } + + if (not node.IsCheckUniqueness()) + { + name = QLatin1Char('[') + name + QLatin1Char(']'); } } diff --git a/src/libs/vtools/dialogs/tools/piece/dialogpiecepath.cpp b/src/libs/vtools/dialogs/tools/piece/dialogpiecepath.cpp index 589e42a26..fa8af20d8 100644 --- a/src/libs/vtools/dialogs/tools/piece/dialogpiecepath.cpp +++ b/src/libs/vtools/dialogs/tools/piece/dialogpiecepath.cpp @@ -284,6 +284,7 @@ void DialogPiecePath::ShowContextMenu(const QPoint &pos) VPieceNode rowNode = qvariant_cast(rowItem->data(Qt::UserRole)); QAction *actionPassmark = nullptr; + QAction *actionUniqueness = nullptr; QAction *actionReverse = nullptr; if (rowNode.GetTypeTool() != Tool::NodePoint) { @@ -296,6 +297,10 @@ void DialogPiecePath::ShowContextMenu(const QPoint &pos) actionPassmark = menu->addAction(tr("Passmark")); actionPassmark->setCheckable(true); actionPassmark->setChecked(rowNode.IsPassmark()); + + actionUniqueness = menu->addAction(tr("Check uniqueness")); + actionUniqueness->setCheckable(true); + actionUniqueness->setChecked(rowNode.IsCheckUniqueness()); } QAction *actionDelete = menu->addAction(QIcon::fromTheme("edit-delete"), tr("Delete")); @@ -317,6 +322,12 @@ void DialogPiecePath::ShowContextMenu(const QPoint &pos) rowItem->setData(Qt::UserRole, QVariant::fromValue(rowNode)); rowItem->setText(GetNodeName(rowNode, true)); } + else if (selectedAction == actionUniqueness) + { + rowNode.SetCheckUniqueness(not rowNode.IsCheckUniqueness()); + rowItem->setData(Qt::UserRole, QVariant::fromValue(rowNode)); + rowItem->setText(GetNodeName(rowNode, true)); + } ValidObjects(PathIsValid()); ListChanged(); diff --git a/src/libs/vtools/dialogs/tools/piece/dialogseamallowance.cpp b/src/libs/vtools/dialogs/tools/piece/dialogseamallowance.cpp index 0f31d8b0d..53ebd6238 100644 --- a/src/libs/vtools/dialogs/tools/piece/dialogseamallowance.cpp +++ b/src/libs/vtools/dialogs/tools/piece/dialogseamallowance.cpp @@ -613,6 +613,7 @@ void DialogSeamAllowance::ShowMainPathContextMenu(const QPoint &pos) VPieceNode rowNode = qvariant_cast(rowItem->data(Qt::UserRole)); QAction *actionPassmark = nullptr; + QAction *actionUniqueness = nullptr; QAction *actionReverse = nullptr; if (rowNode.GetTypeTool() != Tool::NodePoint) { @@ -625,6 +626,10 @@ void DialogSeamAllowance::ShowMainPathContextMenu(const QPoint &pos) actionPassmark = menu->addAction(tr("Passmark")); actionPassmark->setCheckable(true); actionPassmark->setChecked(rowNode.IsPassmark()); + + actionUniqueness = menu->addAction(tr("Check uniqueness")); + actionUniqueness->setCheckable(true); + actionUniqueness->setChecked(rowNode.IsCheckUniqueness()); } QAction *actionExcluded = menu->addAction(tr("Excluded")); @@ -657,6 +662,12 @@ void DialogSeamAllowance::ShowMainPathContextMenu(const QPoint &pos) rowItem->setData(Qt::UserRole, QVariant::fromValue(rowNode)); rowItem->setText(GetNodeName(rowNode, true)); } + else if (selectedAction == actionUniqueness) + { + rowNode.SetCheckUniqueness(not rowNode.IsCheckUniqueness()); + rowItem->setData(Qt::UserRole, QVariant::fromValue(rowNode)); + rowItem->setText(GetNodeName(rowNode, true)); + } ValidObjects(MainPathIsValid()); ListChanged(); diff --git a/src/libs/vtools/tools/vabstracttool.cpp b/src/libs/vtools/tools/vabstracttool.cpp index eee96a778..60d62678a 100644 --- a/src/libs/vtools/tools/vabstracttool.cpp +++ b/src/libs/vtools/tools/vabstracttool.cpp @@ -535,6 +535,18 @@ QDomElement VAbstractTool::AddSANode(VAbstractPattern *doc, const QString &tagNa } } + { + const bool uniqueness = node.IsCheckUniqueness(); + if (not uniqueness) + { + doc->SetAttribute(nod, VAbstractPattern::AttrCheckUniqueness, uniqueness); + } + else + { // For backward compatebility. + nod.removeAttribute(VAbstractPattern::AttrCheckUniqueness); + } + } + switch (type) { case (Tool::NodeArc): diff --git a/src/libs/vtools/undocommands/savepieceoptions.cpp b/src/libs/vtools/undocommands/savepieceoptions.cpp index f96e27752..c4ff37590 100644 --- a/src/libs/vtools/undocommands/savepieceoptions.cpp +++ b/src/libs/vtools/undocommands/savepieceoptions.cpp @@ -179,7 +179,8 @@ bool SavePieceOptions::mergeWith(const QUndoCommand *command) for (int i = 0; i < nodes.size(); ++i) { - if (nodes.at(i).IsExcluded() != candidateNodes.at(i).IsExcluded()) + if (nodes.at(i).IsExcluded() != candidateNodes.at(i).IsExcluded() + || nodes.at(i).IsCheckUniqueness() != candidateNodes.at(i).IsCheckUniqueness()) { return false; } diff --git a/src/libs/vtools/undocommands/savepiecepathoptions.cpp b/src/libs/vtools/undocommands/savepiecepathoptions.cpp index de55b19a5..2ce89619a 100644 --- a/src/libs/vtools/undocommands/savepiecepathoptions.cpp +++ b/src/libs/vtools/undocommands/savepiecepathoptions.cpp @@ -150,7 +150,8 @@ bool SavePiecePathOptions::mergeWith(const QUndoCommand *command) for (int i = 0; i < nodes.size(); ++i) { - if (nodes.at(i).IsExcluded() != candidateNodes.at(i).IsExcluded()) + if (nodes.at(i).IsExcluded() != candidateNodes.at(i).IsExcluded() + || nodes.at(i).IsCheckUniqueness() != candidateNodes.at(i).IsCheckUniqueness()) { return false; }