/*************************************************************************** * Copyright (c) 2014 Abdullah Tahiri * * * * This file is part of the FreeCAD CAx development system. * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Library General Public * * License as published by the Free Software Foundation; either * * version 2 of the License, or (at your option) any later version. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU Library General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this library; see the file COPYING.LIB. If not, * * write to the Free Software Foundation, Inc., 59 Temple Place, * * Suite 330, Boston, MA 02111-1307, USA * * * ***************************************************************************/ #include "PreCompiled.h" #ifndef _PreComp_ #include #include #include #endif #include #include #include "PropertyConstraintListItem.h" using namespace SketcherGui; using namespace Gui::PropertyEditor; PROPERTYITEM_SOURCE(SketcherGui::PropertyConstraintListItem) PropertyConstraintListItem::PropertyConstraintListItem() { blockEvent = false; onlyUnnamed = false; } PropertyConstraintListItem::~PropertyConstraintListItem() {} QString PropertyConstraintListItem::toString(const QVariant& prop) const { const QList& value = prop.value>(); std::stringstream out; out << "["; for (QList::const_iterator it = value.begin(); it != value.end(); ++it) { if (it != value.begin()) { out << ";"; } out << it->getUserString(); } out << "]"; return QString::fromStdString(out.str()); } void PropertyConstraintListItem::initialize() { const Sketcher::PropertyConstraintList* list = static_cast(getPropertyData()[0]); const std::vector& vals = list->getValues(); int id = 1; int iNamed = 0; std::vector unnamed; for (std::vector::const_iterator it = vals.begin(); it != vals.end(); ++it, ++id) { if ((*it)->Type == Sketcher::Distance || // Datum constraint (*it)->Type == Sketcher::DistanceX || (*it)->Type == Sketcher::DistanceY || (*it)->Type == Sketcher::Radius || (*it)->Type == Sketcher::Diameter || (*it)->Type == Sketcher::Angle) { PropertyUnitItem* item = static_cast(PropertyUnitItem::create()); // Get the name QString internalName = QStringLiteral("Constraint%1").arg(id); QString name = QString::fromUtf8((*it)->Name.c_str()); if (name.isEmpty()) { name = internalName; item->setPropertyName(name); unnamed.push_back(item); } else { iNamed++; item->setParent(this); item->setPropertyName(name); // The call of 'setPropertyName' calls 'setObjectName'. But 'name' can contain // some non-7-bit ASCII characters and thus the delegation of a property to the // parent item may fail because 'qPrintable(objectName())' is used therefore and // may return a different string. See 'PropertyItem::setData()' for more details. // To make the delegation to work properly we set a different object name which is // guaranteed to be 7-bit ASCII. // // See also PropertyConstraintListItem::value() // See also PropertyConstraintListItem::event() item->setObjectName(internalName); this->appendChild(item); } item->bind(list->createPath(id - 1)); item->setAutoApply(false); } } // now deal with the unnamed if (iNamed == 0) { onlyUnnamed = true; for (std::vector::const_iterator it = unnamed.begin(); it != unnamed.end(); ++it) { (*it)->setParent(this); this->appendChild((*it)); } } else { onlyUnnamed = false; if (!unnamed.empty()) { PropertyConstraintListItem* item = static_cast(PropertyConstraintListItem::create()); item->setParent(this); item->setPropertyName(tr("Unnamed")); this->appendChild(item); for (std::vector::const_iterator it = unnamed.begin(); it != unnamed.end(); ++it) { (*it)->setParent(item); item->appendChild((*it)); } } } } void PropertyConstraintListItem::assignProperty(const App::Property* prop) { // Hint: When renaming a constraint that was unnamed before then it can happen that // a constraint appears twice in the property editor, one time in this group and a // second time inside the Unnamed group if (!prop->isDerivedFrom()) { return; } const Sketcher::PropertyConstraintList* list = static_cast(prop); const std::vector& vals = list->getValues(); // search for the group of unnamed items if available and take it out int numUnnamed = 0; PropertyConstraintListItem* unnamed = nullptr; for (int i = this->childCount() - 1; i >= 0; i--) { unnamed = qobject_cast(this->child(i)); if (unnamed) { numUnnamed = unnamed->childCount(); this->takeChild(i); break; } } int id = 1; int namedIndex = 0; int unnamedIndex = 0; int numNamed = this->childCount(); this->onlyUnnamed = true; for (std::vector::const_iterator it = vals.begin(); it != vals.end(); ++it, ++id) { if ((*it)->Type == Sketcher::Distance || // Datum constraint (*it)->Type == Sketcher::DistanceX || (*it)->Type == Sketcher::DistanceY || (*it)->Type == Sketcher::Radius || (*it)->Type == Sketcher::Diameter || (*it)->Type == Sketcher::Angle) { PropertyUnitItem* child = nullptr; if ((*it)->Name.empty()) { // search inside the group item for unnamed constraints if (!unnamed) { unnamed = static_cast( PropertyConstraintListItem::create()); unnamed->setPropertyName(tr("Unnamed")); } if (unnamedIndex < numUnnamed) { child = static_cast(unnamed->child(unnamedIndex)); } else { child = static_cast(PropertyUnitItem::create()); unnamed->appendChild(child); child->setParent(unnamed); } unnamedIndex++; } else { // search inside this item if (namedIndex < numNamed) { child = dynamic_cast(this->child(namedIndex)); } if (!child) { child = static_cast(PropertyUnitItem::create()); this->appendChild(child); child->setParent(this); } namedIndex++; this->onlyUnnamed = false; } // Get the name QString internalName = QStringLiteral("Constraint%1").arg(id); QString name = QString::fromUtf8((*it)->Name.c_str()); if (name.isEmpty()) { name = internalName; } if (child->objectName() != internalName) { child->setPropertyName(name); child->setObjectName(internalName); child->bind(list->createPath(id - 1)); child->setAutoApply(false); } } } // at the Unnamed group at very the end if (unnamed) { this->appendChild(unnamed); unnamed->setParent(this); } } QVariant PropertyConstraintListItem::value(const App::Property* prop) const { assert(prop && prop->isDerivedFrom()); PropertyConstraintListItem* self = const_cast(this); int id = 1; QList quantities; QList subquantities; bool onlyNamed = true; const std::vector& vals = static_cast(prop)->getValues(); for (std::vector::const_iterator it = vals.begin(); it != vals.end(); ++it, ++id) { if ((*it)->Type == Sketcher::Distance || // Datum constraint (*it)->Type == Sketcher::DistanceX || (*it)->Type == Sketcher::DistanceY || (*it)->Type == Sketcher::Radius || (*it)->Type == Sketcher::Diameter || (*it)->Type == Sketcher::Angle) { Base::Quantity quant; if ((*it)->Type == Sketcher::Angle) { double datum = Base::toDegrees((*it)->getValue()); quant.setUnit(Base::Unit::Angle); quant.setValue(datum); } else { quant.setUnit(Base::Unit::Length); quant.setValue((*it)->getValue()); } quantities.append(quant); // Use a 7-bit ASCII string for the internal name. // See also comment in PropertyConstraintListItem::initialize() QString internalName = QStringLiteral("Constraint%1").arg(id); if ((*it)->Name.empty() && !onlyUnnamed) { onlyNamed = false; subquantities.append(quant); PropertyItem* child = self->child(self->childCount() - 1); PropertyConstraintListItem* unnamednode = qobject_cast(child); if (unnamednode) { unnamednode->blockEvent = true; unnamednode->setProperty(internalName.toLatin1(), QVariant::fromValue(quant)); unnamednode->blockEvent = false; } else { qWarning() << "Item is not of type PropertyConstraintListItem but" << typeid(*child).name(); } } else { self->blockEvent = true; self->setProperty(internalName.toLatin1(), QVariant::fromValue(quant)); self->blockEvent = false; } } } // The quantities of unnamed constraints are only needed for display purposes inside toString() if (!onlyUnnamed && !onlyNamed) { self->blockEvent = true; self->setProperty("Unnamed", QVariant::fromValue>(subquantities)); self->blockEvent = false; } return QVariant::fromValue>(quantities); } bool PropertyConstraintListItem::event(QEvent* ev) { if (ev->type() == QEvent::DynamicPropertyChange) { if (!blockEvent) { QDynamicPropertyChangeEvent* ce = static_cast(ev); // Get property via internal name of a PropertyUnit QVariant prop = property(ce->propertyName()); QString propName = QString::fromLatin1(ce->propertyName()); Base::Quantity quant = prop.value(); Sketcher::PropertyConstraintList* item; int id = 0; if (dynamic_cast(this->parent())) { item = static_cast( this->parent()->getFirstProperty()); } else { item = static_cast(getFirstProperty()); } const std::vector& vals = item->getValues(); for (std::vector::const_iterator it = vals.begin(); it != vals.end(); ++it, ++id) { if ((*it)->Type == Sketcher::Distance || // Datum constraint (*it)->Type == Sketcher::DistanceX || (*it)->Type == Sketcher::DistanceY || (*it)->Type == Sketcher::Radius || (*it)->Type == Sketcher::Diameter || (*it)->Type == Sketcher::Angle) { // Get the internal name QString internalName = QStringLiteral("Constraint%1").arg(id + 1); if (internalName == propName) { double datum = quant.getValue(); if ((*it)->Type == Sketcher::Angle) { datum = Base::toRadians(datum); } std::unique_ptr copy((*it)->clone()); copy->setValue(datum); item->set1Value(id, copy.get()); break; } } } } } return PropertyItem::event(ev); } void PropertyConstraintListItem::setValue(const QVariant& value) { // see PropertyConstraintListItem::event Q_UNUSED(value); } QWidget* PropertyConstraintListItem::createEditor(QWidget* parent, const std::function& method) const { Q_UNUSED(method); QLineEdit* le = new QLineEdit(parent); le->setFrame(false); le->setReadOnly(true); return le; } void PropertyConstraintListItem::setEditorData(QWidget* editor, const QVariant& data) const { QLineEdit* le = qobject_cast(editor); le->setText(toString(data)); } QVariant PropertyConstraintListItem::editorData(QWidget* editor) const { QLineEdit* le = qobject_cast(editor); return QVariant(le->text()); } #include "moc_PropertyConstraintListItem.cpp"