diff --git a/ChangeLog.txt b/ChangeLog.txt index af5c298fe..b864e7f40 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -1,5 +1,7 @@ # Version 0.7.40 (unreleased) - New function Warning. +- [smart-pattern/valentina#80] Allow insertion of multiple nodes. +- [smart-pattern/valentina#81] Tape crash on opening. # Version 0.7.39 Nov 17, 2020 - Fix crash for Line tool notes. diff --git a/src/app/tape/tmainwindow.cpp b/src/app/tape/tmainwindow.cpp index e02bdfe23..2733fb09b 100644 --- a/src/app/tape/tmainwindow.cpp +++ b/src/app/tape/tmainwindow.cpp @@ -635,9 +635,12 @@ void TMainWindow::changeEvent(QEvent *event) } { - labelPatternUnit->setText(tr("Pattern unit:")); + if (labelPatternUnit) + { + labelPatternUnit->setText(tr("Pattern unit:")); + } - if (comboBoxUnits != nullptr) + if (comboBoxUnits) { const qint32 index = comboBoxUnits->currentIndex(); comboBoxUnits->blockSignals(true); @@ -4302,6 +4305,11 @@ void TMainWindow::InitComboBoxUnits() //--------------------------------------------------------------------------------------------------------------------- void TMainWindow::InitMeasurementUnits() { + if (not m) + { + return; + } + ui->comboBoxMUnits->blockSignals(true); int current = -1; diff --git a/src/app/valentina/mainwindow.cpp b/src/app/valentina/mainwindow.cpp index ace489e75..9c7cfb216 100644 --- a/src/app/valentina/mainwindow.cpp +++ b/src/app/valentina/mainwindow.cpp @@ -1336,7 +1336,7 @@ void MainWindow::ClosedDialogInsertNode(int result) { const QPointer dTool = qobject_cast(dialogTool); SCASSERT(not dTool.isNull()) - VToolSeamAllowance::InsertNode(dTool->GetNode(), dTool->GetPieceId(), sceneDetails, pattern, doc); + VToolSeamAllowance::InsertNode(dTool->GetNodes(), dTool->GetPieceId(), sceneDetails, pattern, doc); } ArrowTool(true); doc->LiteParseTree(Document::LiteParse); @@ -1493,9 +1493,12 @@ void MainWindow::ToolTrueDarts(bool checked) //--------------------------------------------------------------------------------------------------------------------- void MainWindow::ToolInsertNode(bool checked) { - ToolSelectAllDrawObjects(); + ToolSelectOperationObjects(); + const QString tooltip = tr("Select one or more objects, hold %1 - for multiple selection, " + "%2 - finish creation") + .arg(VModifierKey::Control(), VModifierKey::EnterKey()); SetToolButton(checked, Tool::InsertNode, "://cursor/insert_node_cursor.png", - tr("Select an item to insert"), &MainWindow::ClosedDialogInsertNode); + tooltip, &MainWindow::ClosedDialogInsertNode); } //--------------------------------------------------------------------------------------------------------------------- diff --git a/src/libs/vtools/dialogs/tools/dialogtool.cpp b/src/libs/vtools/dialogs/tools/dialogtool.cpp index a9248548c..d773502b6 100644 --- a/src/libs/vtools/dialogs/tools/dialogtool.cpp +++ b/src/libs/vtools/dialogs/tools/dialogtool.cpp @@ -449,7 +449,7 @@ QString DialogTool::GetNodeName(const VPieceNode &node, bool showPassmarkDetails } //--------------------------------------------------------------------------------------------------------------------- -void DialogTool::NewNodeItem(QListWidget *listWidget, const VPieceNode &node, bool showPassmark) +void DialogTool::NewNodeItem(QListWidget *listWidget, const VPieceNode &node, bool showPassmark, bool showExclusion) { SCASSERT(listWidget != nullptr); SCASSERT(node.GetId() > NULL_ID); @@ -485,7 +485,7 @@ void DialogTool::NewNodeItem(QListWidget *listWidget, const VPieceNode &node, bo if(canAddNewPoint) { QListWidgetItem *item = new QListWidgetItem(name); - item->setFont(NodeFont(item->font(), node.IsExcluded())); + item->setFont(NodeFont(item->font(), showExclusion ? node.IsExcluded() : false)); item->setData(Qt::UserRole, QVariant::fromValue(node)); listWidget->addItem(item); listWidget->setCurrentRow(listWidget->count()-1); diff --git a/src/libs/vtools/dialogs/tools/dialogtool.h b/src/libs/vtools/dialogs/tools/dialogtool.h index f045b87e3..4ce2f771d 100644 --- a/src/libs/vtools/dialogs/tools/dialogtool.h +++ b/src/libs/vtools/dialogs/tools/dialogtool.h @@ -214,7 +214,8 @@ protected: virtual void SaveData() {} quint32 DNumber(const QString &baseName) const; QString GetNodeName(const VPieceNode &node, bool showPassmarkDetails = false) const; - void NewNodeItem(QListWidget *listWidget, const VPieceNode &node, bool showPassmark = true); + void NewNodeItem(QListWidget *listWidget, const VPieceNode &node, bool showPassmark = true, + bool showExclusion = true); void InitNodeAngles(QComboBox *box); private: diff --git a/src/libs/vtools/dialogs/tools/piece/dialoginsertnode.cpp b/src/libs/vtools/dialogs/tools/piece/dialoginsertnode.cpp index 31ad3295b..a833b1d08 100644 --- a/src/libs/vtools/dialogs/tools/piece/dialoginsertnode.cpp +++ b/src/libs/vtools/dialogs/tools/piece/dialoginsertnode.cpp @@ -30,24 +30,24 @@ #include "ui_dialoginsertnode.h" #include "../vpatterndb/vcontainer.h" +#include + //--------------------------------------------------------------------------------------------------------------------- DialogInsertNode::DialogInsertNode(const VContainer *data, quint32 toolId, QWidget *parent) : DialogTool(data, toolId, parent), - ui(new Ui::DialogInsertNode), - m_node(), - m_flagItem(false), - m_flagError(false) + ui(new Ui::DialogInsertNode) { ui->setupUi(this); InitOkCancel(ui); CheckPieces(); - CheckItem(); connect(ui->comboBoxPiece, QOverload::of(&QComboBox::currentIndexChanged), this, [this]() { CheckPieces(); }); + + connect(ui->listWidget, &QListWidget::customContextMenuRequested, this, &DialogInsertNode::ShowContextMenu); } //--------------------------------------------------------------------------------------------------------------------- @@ -96,73 +96,134 @@ void DialogInsertNode::SetPieceId(quint32 id) } //--------------------------------------------------------------------------------------------------------------------- -VPieceNode DialogInsertNode::GetNode() const +QVector DialogInsertNode::GetNodes() const { - return m_node; + QVector nodes; + for (qint32 i = 0; i < ui->listWidget->count(); ++i) + { + nodes.append(qvariant_cast(ui->listWidget->item(i)->data(Qt::UserRole))); + } + return nodes; } //--------------------------------------------------------------------------------------------------------------------- -void DialogInsertNode::SetNode(const VPieceNode &node) +void DialogInsertNode::ShowDialog(bool click) { - m_node = node; - m_flagItem = true; - QString name = tr("Uknown"); - try + if (not click) { - name = data->GetGObject(m_node.GetId())->ObjectName(); - } - catch (const VExceptionBadId &) - { - m_flagItem = false; - // Broken id - } - - ui->labelItemName->setText(name); - ui->labelItemName->setToolTip(name); - - CheckItem(); -} - -//--------------------------------------------------------------------------------------------------------------------- -void DialogInsertNode::ChosenObject(quint32 id, const SceneObject &type) -{ - if (not prepare) - { - VPieceNode node; - switch (type) + if (m_nodes.isEmpty()) { - case SceneObject::Arc: - node = VPieceNode(id, Tool::NodeArc); - break; - case SceneObject::ElArc: - node = VPieceNode(id, Tool::NodeElArc); - break; - case SceneObject::Point: - node = VPieceNode(id, Tool::NodePoint); - break; - case SceneObject::Spline: - node = VPieceNode(id, Tool::NodeSpline); - break; - case SceneObject::SplinePath: - node = VPieceNode(id, Tool::NodeSplinePath); - break; - case (SceneObject::Line): - case (SceneObject::Detail): - case (SceneObject::Unknown): - default: - qDebug() << "Got wrong scene object. Ignore."; - return; + return; } - node.SetExcluded(true); - SetNode(node); + for (auto &node : m_nodes) + { + NewNodeItem(ui->listWidget, node, false, false); + } + + m_nodes.clear(); + + CheckNodes(); prepare = true; - this->setModal(true); - this->show(); + setModal(true); + emit ToolTip(QString()); + show(); } } +//--------------------------------------------------------------------------------------------------------------------- +void DialogInsertNode::SelectedObject(bool selected, quint32 object, quint32 tool) +{ + Q_UNUSED(tool) + + if (prepare) + { + return; + } + + auto nodeIterator = std::find_if(m_nodes.begin(), m_nodes.end(), + [object](const VPieceNode &node) { return node.GetId() == object; }); + if (selected) + { + if (nodeIterator == m_nodes.cend()) + { + GOType type = GOType::Unknown; + try + { + type = data->GetGObject(object)->getType(); + } + catch (const VExceptionBadId &) + { + qDebug() << "Cannot find an object with id" << object; + return; + } + + VPieceNode node; + switch (type) + { + case GOType::Arc: + node = VPieceNode(object, Tool::NodeArc); + break; + case GOType::EllipticalArc: + node = VPieceNode(object, Tool::NodeElArc); + break; + case GOType::Point: + node = VPieceNode(object, Tool::NodePoint); + break; + case GOType::Spline: + case GOType::CubicBezier: + node = VPieceNode(object, Tool::NodeSpline); + break; + case GOType::SplinePath: + case GOType::CubicBezierPath: + node = VPieceNode(object, Tool::NodeSplinePath); + break; + case GOType::Unknown: + case GOType::PlaceLabel: + default: + qDebug() << "Got unexpected object type. Ignore."; + return; + } + + node.SetExcluded(true); + m_nodes.append(node); + } + } + else + { + if (nodeIterator != m_nodes.end()) + { + m_nodes.erase(nodeIterator); + } + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void DialogInsertNode::ShowContextMenu(const QPoint &pos) +{ + const int row = ui->listWidget->currentRow(); + if (ui->listWidget->count() == 0 || row == -1 || row >= ui->listWidget->count()) + { + return; + } + + QScopedPointer menu(new QMenu()); + + QListWidgetItem *rowItem = ui->listWidget->item(row); + SCASSERT(rowItem != nullptr); + + QAction *actionDelete = menu->addAction(QIcon::fromTheme(editDeleteIcon), tr("Delete")); + + QAction *selectedAction = menu->exec(ui->listWidget->viewport()->mapToGlobal(pos)); + if (selectedAction == actionDelete) + { + delete rowItem; + } + + CheckNodes(); +} + //--------------------------------------------------------------------------------------------------------------------- void DialogInsertNode::CheckPieces() { @@ -182,10 +243,8 @@ void DialogInsertNode::CheckPieces() } //--------------------------------------------------------------------------------------------------------------------- -void DialogInsertNode::CheckItem() +void DialogInsertNode::CheckNodes() { - QColor color; - m_flagItem ? color = OkColor(this) : color = errorColor; - ChangeColor(ui->labelItem, color); + m_flagNodes = ui->listWidget->count() > 0; CheckState(); } diff --git a/src/libs/vtools/dialogs/tools/piece/dialoginsertnode.h b/src/libs/vtools/dialogs/tools/piece/dialoginsertnode.h index 027a54342..428b6c8bc 100644 --- a/src/libs/vtools/dialogs/tools/piece/dialoginsertnode.h +++ b/src/libs/vtools/dialogs/tools/piece/dialoginsertnode.h @@ -50,31 +50,35 @@ public: quint32 GetPieceId() const; void SetPieceId(quint32 id); - VPieceNode GetNode() const; - void SetNode(const VPieceNode &node); + QVector GetNodes() const; + + virtual void ShowDialog(bool click) override; public slots: - virtual void ChosenObject(quint32 id, const SceneObject &type) override; + virtual void SelectedObject(bool selected, quint32 object, quint32 tool) override; protected: virtual bool IsValid() const final; +private slots: + void ShowContextMenu(const QPoint &pos); + private: Q_DISABLE_COPY(DialogInsertNode) Ui::DialogInsertNode *ui; - VPieceNode m_node; - bool m_flagItem; - bool m_flagError; + QVector m_nodes{}; + bool m_flagNodes{false}; + bool m_flagError{false}; void CheckPieces(); - void CheckItem(); + void CheckNodes(); }; //--------------------------------------------------------------------------------------------------------------------- inline bool DialogInsertNode::IsValid() const { - return m_flagItem && m_flagError; + return m_flagNodes && m_flagError; } #endif // DIALOGINSERTNODE_H diff --git a/src/libs/vtools/dialogs/tools/piece/dialoginsertnode.ui b/src/libs/vtools/dialogs/tools/piece/dialoginsertnode.ui index 6b034c86f..1219877a7 100644 --- a/src/libs/vtools/dialogs/tools/piece/dialoginsertnode.ui +++ b/src/libs/vtools/dialogs/tools/piece/dialoginsertnode.ui @@ -6,45 +6,34 @@ 0 0 - 244 - 103 + 411 + 399 - Insert node + Insert nodes - + :/icon/64x64/icon64x64.png:/icon/64x64/icon64x64.png + + + QFormLayout::ExpandingFieldsGrow - - - Item: - - - - - - - item name - - - - Piece: - + @@ -62,7 +51,7 @@ - + diff --git a/src/libs/vtools/tools/drawTools/toolcurve/vabstractspline.cpp b/src/libs/vtools/tools/drawTools/toolcurve/vabstractspline.cpp index 739a5efa6..d56785d93 100644 --- a/src/libs/vtools/tools/drawTools/toolcurve/vabstractspline.cpp +++ b/src/libs/vtools/tools/drawTools/toolcurve/vabstractspline.cpp @@ -502,14 +502,17 @@ QString VAbstractSpline::GetAliasSuffix() const } //--------------------------------------------------------------------------------------------------------------------- -void VAbstractSpline::SetAliasSuffix(const QString &alias) +void VAbstractSpline::SetAliasSuffix(QString alias) { QSharedPointer curve = VAbstractTool::data.GeometricObject(m_id); const QString oldAliasSuffix = curve->GetAliasSuffix(); + alias = alias.simplified().replace(QChar(QChar::Space), QChar('_')); curve->SetAliasSuffix(alias); - if (alias.isEmpty() || VAbstractTool::data.IsUnique(curve->GetAlias())) + QRegularExpression rx(NameRegExp()); + + if (alias.isEmpty() || (rx.match(curve->GetAlias()).hasMatch() && VAbstractTool::data.IsUnique(curve->GetAlias()))) { QSharedPointer obj = qSharedPointerCast(curve); SaveOption(obj); diff --git a/src/libs/vtools/tools/drawTools/toolcurve/vabstractspline.h b/src/libs/vtools/tools/drawTools/toolcurve/vabstractspline.h index 5d0b2b430..d6a9dd008 100644 --- a/src/libs/vtools/tools/drawTools/toolcurve/vabstractspline.h +++ b/src/libs/vtools/tools/drawTools/toolcurve/vabstractspline.h @@ -97,7 +97,7 @@ public: quint32 GetDuplicate() const; QString GetAliasSuffix() const; - void SetAliasSuffix(const QString &alias); + void SetAliasSuffix(QString alias); virtual void GroupVisibility(quint32 object, bool visible) override; public slots: diff --git a/src/libs/vtools/tools/drawTools/toolpoint/toolsinglepoint/toolcut/vtoolcut.cpp b/src/libs/vtools/tools/drawTools/toolpoint/toolsinglepoint/toolcut/vtoolcut.cpp index 7c4e747d5..e92ea1ba4 100644 --- a/src/libs/vtools/tools/drawTools/toolpoint/toolsinglepoint/toolcut/vtoolcut.cpp +++ b/src/libs/vtools/tools/drawTools/toolpoint/toolsinglepoint/toolcut/vtoolcut.cpp @@ -42,6 +42,7 @@ #include "../../../../vabstracttool.h" #include "../../../vdrawtool.h" #include "../vtoolsinglepoint.h" +#include "../qmuparser/qmudef.h" //--------------------------------------------------------------------------------------------------------------------- VToolCut::VToolCut(const VToolCutInitData &initData, QGraphicsItem *parent) @@ -108,14 +109,17 @@ QString VToolCut::GetAliasSuffix1() const } //--------------------------------------------------------------------------------------------------------------------- -void VToolCut::SetAliasSuffix1(const QString &alias) +void VToolCut::SetAliasSuffix1(QString alias) { QSharedPointer curve = VAbstractTool::data.GeometricObject(baseCurveId); const QString oldAliasSuffix = curve->GetAliasSuffix(); + alias = alias.simplified().replace(QChar(QChar::Space), QChar('_')); curve->SetAliasSuffix(alias); - if (alias.isEmpty() || VAbstractTool::data.IsUnique(curve->GetAlias())) + QRegularExpression rx(NameRegExp()); + + if (alias.isEmpty() || (rx.match(curve->GetAlias()).hasMatch() && VAbstractTool::data.IsUnique(curve->GetAlias()))) { m_aliasSuffix1 = alias; QSharedPointer obj = VAbstractTool::data.GetGObject(m_id); @@ -134,14 +138,17 @@ QString VToolCut::GetAliasSuffix2() const } //--------------------------------------------------------------------------------------------------------------------- -void VToolCut::SetAliasSuffix2(const QString &alias) +void VToolCut::SetAliasSuffix2(QString alias) { QSharedPointer curve = VAbstractTool::data.GeometricObject(baseCurveId); const QString oldAliasSuffix = curve->GetAliasSuffix(); + alias = alias.simplified().replace(QChar(QChar::Space), QChar('_')); curve->SetAliasSuffix(alias); - if (alias.isEmpty() || VAbstractTool::data.IsUnique(curve->GetAlias())) + QRegularExpression rx(NameRegExp()); + + if (alias.isEmpty() || (rx.match(curve->GetAlias()).hasMatch() && VAbstractTool::data.IsUnique(curve->GetAlias()))) { m_aliasSuffix2 = alias; QSharedPointer obj = VAbstractTool::data.GetGObject(m_id); diff --git a/src/libs/vtools/tools/drawTools/toolpoint/toolsinglepoint/toolcut/vtoolcut.h b/src/libs/vtools/tools/drawTools/toolpoint/toolsinglepoint/toolcut/vtoolcut.h index d18ef52d6..58ac516c6 100644 --- a/src/libs/vtools/tools/drawTools/toolpoint/toolsinglepoint/toolcut/vtoolcut.h +++ b/src/libs/vtools/tools/drawTools/toolpoint/toolsinglepoint/toolcut/vtoolcut.h @@ -69,10 +69,10 @@ public: void SetFormulaLength(const VFormula &value); QString GetAliasSuffix1() const; - void SetAliasSuffix1(const QString &alias); + void SetAliasSuffix1(QString alias); QString GetAliasSuffix2() const; - void SetAliasSuffix2(const QString &alias); + void SetAliasSuffix2(QString alias); QString CurveName() const; diff --git a/src/libs/vtools/tools/vtoolseamallowance.cpp b/src/libs/vtools/tools/vtoolseamallowance.cpp index 347ab5d85..f23c8c115 100644 --- a/src/libs/vtools/tools/vtoolseamallowance.cpp +++ b/src/libs/vtools/tools/vtoolseamallowance.cpp @@ -225,14 +225,14 @@ void VToolSeamAllowance::RemoveWithConfirm(bool ask) } //--------------------------------------------------------------------------------------------------------------------- -void VToolSeamAllowance::InsertNode(VPieceNode node, quint32 pieceId, VMainGraphicsScene *scene, +void VToolSeamAllowance::InsertNode(const QVector &nodes, quint32 pieceId, VMainGraphicsScene *scene, VContainer *data, VAbstractPattern *doc) { SCASSERT(scene != nullptr) SCASSERT(data != nullptr) SCASSERT(doc != nullptr) - if (pieceId > NULL_ID) + if (pieceId > NULL_ID && not nodes.isEmpty()) { VPiece oldDet; try @@ -246,21 +246,24 @@ void VToolSeamAllowance::InsertNode(VPieceNode node, quint32 pieceId, VMainGraph VPiece newDet = oldDet; - const quint32 id = PrepareNode(node, scene, doc, data); - if (id == NULL_ID) + for (auto node : nodes) { - return; + const quint32 id = PrepareNode(node, scene, doc, data); + if (id == NULL_ID) + { + return; + } + + node.SetId(id); + newDet.GetPath().Append(node); + + // Seam allowance tool already initializated and can't init the node + VToolSeamAllowance *saTool = qobject_cast(VAbstractPattern::getTool(pieceId)); + SCASSERT(saTool != nullptr); + + InitNode(node, scene, data, doc, saTool); } - node.SetId(id); - newDet.GetPath().Append(node); - - // Seam allowance tool already initializated and can't init the node - VToolSeamAllowance *saTool = qobject_cast(VAbstractPattern::getTool(pieceId)); - SCASSERT(saTool != nullptr); - - InitNode(node, scene, data, doc, saTool); - qApp->getUndoStack()->push(new SavePieceOptions(oldDet, newDet, doc, pieceId)); } } diff --git a/src/libs/vtools/tools/vtoolseamallowance.h b/src/libs/vtools/tools/vtoolseamallowance.h index 9de9c5d8b..64022a839 100644 --- a/src/libs/vtools/tools/vtoolseamallowance.h +++ b/src/libs/vtools/tools/vtoolseamallowance.h @@ -91,8 +91,8 @@ public: void RemoveWithConfirm(bool ask); - static void InsertNode(VPieceNode node, quint32 pieceId, VMainGraphicsScene *scene, VContainer *data, - VAbstractPattern *doc); + static void InsertNode(const QVector &nodes, quint32 pieceId, VMainGraphicsScene *scene, + VContainer *data, VAbstractPattern *doc); static void AddAttributes(VAbstractPattern *doc, QDomElement &domElement, quint32 id, const VPiece &piece); static void AddCSARecord(VAbstractPattern *doc, QDomElement &domElement, CustomSARecord record);